Skip to content

Commit dc9caf8

Browse files
authored
Improve docs before releasing PostgresClient (#461)
1 parent 7632411 commit dc9caf8

11 files changed

+336
-136
lines changed

README.md

+28-38
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,31 @@
2828
Features:
2929

3030
- A [`PostgresConnection`] which allows you to connect to, authorize with, query, and retrieve results from a PostgreSQL server
31+
- A [`PostgresClient`] which pools and manages connections
3132
- An async/await interface that supports backpressure
3233
- Automatic conversions between Swift primitive types and the Postgres wire format
33-
- Integrated with the Swift server ecosystem, including use of [SwiftLog].
34+
- Integrated with the Swift server ecosystem, including use of [SwiftLog] and [ServiceLifecycle].
3435
- Designed to run efficiently on all supported platforms (tested extensively on Linux and Darwin systems)
3536
- Support for `Network.framework` when available (e.g. on Apple platforms)
3637
- Supports running on Unix Domain Sockets
3738

38-
PostgresNIO does not provide a `ConnectionPool` as of today, but this is a [feature high on our list](https://github.com/vapor/postgres-nio/issues/256). If you need a `ConnectionPool` today, please have a look at Vapor's [PostgresKit].
39-
4039
## API Docs
4140

4241
Check out the [PostgresNIO API docs][Documentation] for a
4342
detailed look at all of the classes, structs, protocols, and more.
4443

4544
## Getting started
4645

46+
Interested in an example? We prepared a simple [Birthday example](/vapor/postgres-nio/tree/main/Snippets/Birthdays.swift)
47+
in the Snippets folder.
48+
4749
#### Adding the dependency
4850

4951
Add `PostgresNIO` as dependency to your `Package.swift`:
5052

5153
```swift
5254
dependencies: [
53-
.package(url: "https://github.com/vapor/postgres-nio.git", from: "1.14.0"),
55+
.package(url: "https://github.com/vapor/postgres-nio.git", from: "1.21.0"),
5456
...
5557
]
5658
```
@@ -64,14 +66,14 @@ Add `PostgresNIO` to the target you want to use it in:
6466
]
6567
```
6668

67-
#### Creating a connection
69+
#### Creating a client
6870

69-
To create a connection, first create a connection configuration object:
71+
To create a [`PostgresClient`], which pools connections for you, first create a configuration object:
7072

7173
```swift
7274
import PostgresNIO
7375

74-
let config = PostgresConnection.Configuration(
76+
let config = PostgresClient.Configuration(
7577
host: "localhost",
7678
port: 5432,
7779
username: "my_username",
@@ -81,50 +83,35 @@ let config = PostgresConnection.Configuration(
8183
)
8284
```
8385

84-
To create a connection we need a [`Logger`], that is used to log connection background events.
85-
86+
Next you can create you client with it:
8687
```swift
87-
import Logging
88-
89-
let logger = Logger(label: "postgres-logger")
88+
let client = PostgresClient(configuration: config)
9089
```
9190

92-
Now we can put it together:
93-
91+
Once you have create your client, you must [`run()`] it:
9492
```swift
95-
import PostgresNIO
96-
import Logging
97-
98-
let logger = Logger(label: "postgres-logger")
99-
100-
let config = PostgresConnection.Configuration(
101-
host: "localhost",
102-
port: 5432,
103-
username: "my_username",
104-
password: "my_password",
105-
database: "my_database",
106-
tls: .disable
107-
)
93+
await withTaskGroup(of: Void.self) { taskGroup in
94+
taskGroup.addTask {
95+
await client.run() // !important
96+
}
10897

109-
let connection = try await PostgresConnection.connect(
110-
configuration: config,
111-
id: 1,
112-
logger: logger
113-
)
98+
// You can use the client while the `client.run()` method is not cancelled.
11499

115-
// Close your connection once done
116-
try await connection.close()
100+
// To shutdown the client, cancel its run method, by cancelling the taskGroup.
101+
taskGroup.cancelAll()
102+
}
117103
```
118104

119105
#### Querying
120106

121-
Once a connection is established, queries can be sent to the server. This is very straightforward:
107+
Once a client is running, queries can be sent to the server. This is straightforward:
122108

123109
```swift
124-
let rows = try await connection.query("SELECT id, username, birthday FROM users", logger: logger)
110+
let rows = try await client.query("SELECT id, username, birthday FROM users")
125111
```
126112

127-
The query will return a [`PostgresRowSequence`], which is an AsyncSequence of [`PostgresRow`]s. The rows can be iterated one-by-one:
113+
The query will return a [`PostgresRowSequence`], which is an AsyncSequence of [`PostgresRow`]s.
114+
The rows can be iterated one-by-one:
128115

129116
```swift
130117
for try await row in rows {
@@ -160,7 +147,7 @@ Sending parameterized queries to the database is also supported (in the coolest
160147
let id = 1
161148
let username = "fancyuser"
162149
let birthday = Date()
163-
try await connection.query("""
150+
try await client.query("""
164151
INSERT INTO users (id, username, birthday) VALUES (\(id), \(username), \(birthday))
165152
""",
166153
logger: logger
@@ -184,6 +171,8 @@ Please see [SECURITY.md] for details on the security process.
184171
[Security.md]: https://github.com/vapor/.github/blob/main/SECURITY.md
185172

186173
[`PostgresConnection`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresconnection
174+
[`PostgresClient`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresclient
175+
[`run()`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresclient/run()
187176
[`query(_:logger:)`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresconnection/query(_:logger:file:line:)-9mkfn
188177
[`PostgresQuery`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresquery
189178
[`PostgresRow`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresrow
@@ -193,4 +182,5 @@ Please see [SECURITY.md] for details on the security process.
193182
[SwiftNIO]: https://github.com/apple/swift-nio
194183
[PostgresKit]: https://github.com/vapor/postgres-kit
195184
[SwiftLog]: https://github.com/apple/swift-log
185+
[ServiceLifecycle]: https://github.com/swift-server/swift-service-lifecycle
196186
[`Logger`]: https://apple.github.io/swift-log/docs/current/Logging/Structs/Logger.html

Snippets/Birthdays.swift

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import PostgresNIO
2+
import Foundation
3+
4+
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
5+
enum Birthday {
6+
static func main() async throws {
7+
// 1. Create a configuration to match server's parameters
8+
let config = PostgresClient.Configuration(
9+
host: "localhost",
10+
port: 5432,
11+
username: "test_username",
12+
password: "test_password",
13+
database: "test_database",
14+
tls: .disable
15+
)
16+
17+
// 2. Create a client
18+
let client = PostgresClient(configuration: config)
19+
20+
// 3. Run the client
21+
try await withThrowingTaskGroup(of: Void.self) { taskGroup in
22+
taskGroup.addTask {
23+
await client.run() // !important
24+
}
25+
26+
// 4. Create a friends table to store data into
27+
try await client.query("""
28+
CREATE TABLE IF NOT EXISTS "friends" (
29+
id SERIAL PRIMARY KEY,
30+
given_name TEXT,
31+
last_name TEXT,
32+
birthday TIMESTAMP WITH TIME ZONE
33+
)
34+
"""
35+
)
36+
37+
// 5. Create a Swift friend representation
38+
struct Friend {
39+
var firstName: String
40+
var lastName: String
41+
var birthday: Date
42+
}
43+
44+
// 6. Create John Appleseed with special birthday
45+
let dateFormatter = DateFormatter()
46+
dateFormatter.dateFormat = "yyyy-MM-dd"
47+
let johnsBirthday = dateFormatter.date(from: "1960-09-26")!
48+
let friend = Friend(firstName: "Hans", lastName: "Müller", birthday: johnsBirthday)
49+
50+
// 7. Store friend into the database
51+
try await client.query("""
52+
INSERT INTO "friends" (given_name, last_name, birthday)
53+
VALUES
54+
(\(friend.firstName), \(friend.lastName), \(friend.birthday));
55+
"""
56+
)
57+
58+
// 8. Query database for the friend we just inserted
59+
let rows = try await client.query("""
60+
SELECT id, given_name, last_name, birthday FROM "friends" WHERE given_name = \(friend.firstName)
61+
"""
62+
)
63+
64+
// 9. Iterate the returned rows, decoding the rows into Swift primitives
65+
for try await (id, firstName, lastName, birthday) in rows.decode((Int, String, String, Date).self) {
66+
print("\(id) | \(firstName) \(lastName), \(birthday)")
67+
}
68+
69+
// 10. Shutdown the client, by cancelling its run method, through cancelling the taskGroup.
70+
taskGroup.cancelAll()
71+
}
72+
}
73+
}
74+

Snippets/PostgresClient.swift

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import PostgresNIO
2+
import struct Foundation.UUID
3+
4+
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
5+
enum Runner {
6+
static func main() async throws {
7+
8+
// snippet.configuration
9+
let config = PostgresClient.Configuration(
10+
host: "localhost",
11+
port: 5432,
12+
username: "my_username",
13+
password: "my_password",
14+
database: "my_database",
15+
tls: .disable
16+
)
17+
// snippet.end
18+
19+
// snippet.makeClient
20+
let client = PostgresClient(configuration: config)
21+
// snippet.end
22+
23+
}
24+
25+
static func runAndCancel(client: PostgresClient) async {
26+
// snippet.run
27+
await withTaskGroup(of: Void.self) { taskGroup in
28+
taskGroup.addTask {
29+
await client.run() // !important
30+
}
31+
32+
// You can use the client while the `client.run()` method is not cancelled.
33+
34+
// To shutdown the client, cancel its run method, by cancelling the taskGroup.
35+
taskGroup.cancelAll()
36+
}
37+
// snippet.end
38+
}
39+
}
40+
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# PostgreSQL data types
2+
3+
Translate Swift data types to Postgres data types and vica versa. Learn how to write translations
4+
for your own custom Swift types.
5+
6+
## Topics
7+
8+
### Essentials
9+
10+
- ``PostgresCodable``
11+
- ``PostgresDataType``
12+
- ``PostgresFormat``
13+
- ``PostgresNumeric``
14+
15+
### Encoding
16+
17+
- ``PostgresEncodable``
18+
- ``PostgresNonThrowingEncodable``
19+
- ``PostgresDynamicTypeEncodable``
20+
- ``PostgresThrowingDynamicTypeEncodable``
21+
- ``PostgresArrayEncodable``
22+
- ``PostgresRangeEncodable``
23+
- ``PostgresRangeArrayEncodable``
24+
- ``PostgresEncodingContext``
25+
26+
### Decoding
27+
28+
- ``PostgresDecodable``
29+
- ``PostgresArrayDecodable``
30+
- ``PostgresRangeDecodable``
31+
- ``PostgresRangeArrayDecodable``
32+
- ``PostgresDecodingContext``
33+
34+
### JSON
35+
36+
- ``PostgresJSONEncoder``
37+
- ``PostgresJSONDecoder``
38+
39+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Deprecations
2+
3+
`PostgresNIO` follows SemVer 2.0.0. Learn which APIs are considered deprecated and how to migrate to
4+
their replacements.
5+
6+
``PostgresNIO`` reached 1.0 in April 2020. Since then the maintainers have been hard at work to
7+
guarantee API stability. However as the Swift and Swift on server ecosystem have matured approaches
8+
have changed. The introduction of structured concurrency changed what developers expect from a
9+
modern Swift library. Because of this ``PostgresNIO`` added various APIs that embrace the new Swift
10+
patterns. This means however, that PostgresNIO still offers APIs that have fallen out of favor.
11+
Those are documented here. All those APIs will be removed once the maintainers release the next
12+
major version. The maintainers recommend all adopters to move of those APIs sooner rather than
13+
later.
14+
15+
## Topics
16+
17+
### Migrate of deprecated APIs
18+
19+
- <doc:migrations>
20+
21+
### Deprecated APIs
22+
23+
These types are already deprecated or will be deprecated in the near future. All of them will be
24+
removed from the public API with the next major release.
25+
26+
- ``PostgresDatabase``
27+
- ``PostgresData``
28+
- ``PostgresDataConvertible``
29+
- ``PostgresQueryResult``
30+
- ``PostgresJSONCodable``
31+
- ``PostgresJSONBCodable``
32+
- ``PostgresMessageEncoder``
33+
- ``PostgresMessageDecoder``
34+
- ``PostgresRequest``
35+
- ``PostgresMessage``
36+
- ``PostgresMessageType``
37+
- ``PostgresFormatCode``
38+
- ``PostgresListenContext``
39+
- ``PreparedQuery``
40+
- ``SASLAuthenticationManager``
41+
- ``SASLAuthenticationMechanism``
42+
- ``SASLAuthenticationError``
43+
- ``SASLAuthenticationStepResult``

0 commit comments

Comments
 (0)