🐘 基于 SwiftNIO 构建的用于 PostgreSQL 的非阻塞、事件驱动 Swift 客户端。
特性:
- 一个
PostgresConnection,允许您连接、授权、查询并从 PostgreSQL 服务器获取结果 - 一个
PostgresClient,用于池化和连接管理 - 支持背压的 async/await 接口
- Swift 基本类型与 Postgres 线格式之间的自动转换
- 与 Swift 服务器生态系统集成,包括使用 SwiftLog 和 ServiceLifecycle。
- 设计为在所有受支持的平台上高效运行(在 Linux 和 Darwin 系统上进行了广泛测试)
- 在可用时支持
Network.framework(例如在 Apple 平台上) - 支持在 Unix 域套接字上运行
API 文档
查看 PostgresNIO API 文档,以详细了解所有类、结构体、协议等。
入门
想要一个示例?我们在 Snippets 文件夹中准备了一个简单的 生日示例
添加依赖项
将 PostgresNIO 作为依赖项添加到您的 Package.swift:
dependencies: [
.package(url: "https://github.com/vapor/postgres-nio.git", from: "1.21.0"),
...
]
将 PostgresNIO 添加到你要使用它的目标中:
targets: [
.target(name: "MyFancyTarget", dependencies: [
.product(name: "PostgresNIO", package: "postgres-nio"),
])
]
创建客户端
要创建一个 PostgresClient(它会为你池化连接),首先创建一个配置对象:
import PostgresNIO
let config = PostgresClient.Configuration(
host: "localhost",
port: 5432,
username: "my_username",
password: "my_password",
database: "my_database",
tls: .disable
)
接下来你可以使用它创建你的客户端:
let client = PostgresClient(configuration: config)
创建客户端后,你必须run()它:
await withTaskGroup(of: Void.self) { taskGroup in
taskGroup.addTask {
await client.run() // !important
}
// You can use the client while the `client.run()` method is not cancelled.
// To shutdown the client, cancel its run method, by cancelling the taskGroup.
taskGroup.cancelAll()
}
查询
客户端运行后,可以向服务器发送查询。这很简单:
let rows = try await client.query("SELECT id, username, birthday FROM users")
该查询将返回一个 PostgresRowSequence,它是一个 PostgresRow 的 AsyncSequence。
可以逐行迭代这些行:
for try await row in rows {
// do something with the row
}
从 PostgresRow 解码
然而,在大多数情况下,将行的字段请求为一组 Swift 类型要容易得多:
for try await (id, username, birthday) in rows.decode((Int, String, Date).self) {
// do something with the datatypes.
}
类型必须实现 PostgresDecodable 协议才能从行中解码。PostgresNIO 为大多数 Swift 内置类型以及 Foundation 提供的一些类型提供了默认实现:
BoolBytes,Data,ByteBufferDateUInt8,Int16,Int32,Int64,IntFloat,DoubleStringUUID
使用参数进行查询
向数据库发送参数化查询也是受支持的(以最酷的方式):
let id = 1
let username = "fancyuser"
let birthday = Date()
try await client.query("""
INSERT INTO users (id, username, birthday) VALUES (\(id), \(username), \(birthday))
""",
logger: logger
)
乍一看,这似乎是一个典型的 SQL 注入 😱 案例,但 PostgresNIO 的 API 确保了这种用法是安全的。query(_:logger:) 方法的第一个参数不是普通的 String,而是一个 PostgresQuery,它实现了 Swift 的 ExpressibleByStringInterpolation 协议。PostgresNIO 将提供的字符串的字面部分用作 SQL 查询,并将每个插值替换为参数绑定。只有实现了 PostgresEncodable 协议的值才能以这种方式进行插值。与 PostgresDecodable 一样,PostgresNIO 为大多数常见类型提供了默认实现。
某些查询不会从服务器接收任何行(最常见的是没有 RETURNING 子句的 INSERT、UPDATE 和 DELETE 查询,更不用说大多数 DDL 查询了)。为了支持这一点,query(_:logger:) 方法被标记为 @discardableResult,以便在返回值未被使用时,编译器不会发出警告。
安全
有关安全流程的详细信息,请参阅 SECURITY.md。