Skip to content

Commit

Permalink
Improve docs
Browse files Browse the repository at this point in the history
  • Loading branch information
fabianfett committed Feb 22, 2024
1 parent 7632411 commit 2fb0ae6
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 134 deletions.
62 changes: 26 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,24 @@
Features:

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

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].

## API Docs

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

## Getting started

Interested in an example? We prepared a simple [Birthday example](/vapor/postgres-nio/tree/main/Snippets/Birthdays.swift)
in the Snippets folder.

#### Adding the dependency

Add `PostgresNIO` as dependency to your `Package.swift`:
Expand All @@ -64,14 +66,14 @@ Add `PostgresNIO` to the target you want to use it in:
]
```

#### Creating a connection
#### Creating a client

To create a connection, first create a connection configuration object:
To create a [`PostgresClient`], which pools connections for you, first create a configuration object:

```swift
import PostgresNIO

let config = PostgresConnection.Configuration(
let config = PostgresClient.Configuration(
host: "localhost",
port: 5432,
username: "my_username",
Expand All @@ -81,50 +83,35 @@ let config = PostgresConnection.Configuration(
)
```

To create a connection we need a [`Logger`], that is used to log connection background events.

Next you can create you client with it:
```swift
import Logging

let logger = Logger(label: "postgres-logger")
let client = PostgresClient(configuration: config)
```

Now we can put it together:

Once you have create your client, you must [`run()`] it:
```swift
import PostgresNIO
import Logging

let logger = Logger(label: "postgres-logger")

let config = PostgresConnection.Configuration(
host: "localhost",
port: 5432,
username: "my_username",
password: "my_password",
database: "my_database",
tls: .disable
)
await withTaskGroup(of: Void.self) { taskGroup in
taskGroup.addTask {
await client.run() // !important
}

let connection = try await PostgresConnection.connect(
configuration: config,
id: 1,
logger: logger
)
// You can use the client while the `client.run()` method is not cancelled.

// Close your connection once done
try await connection.close()
// To shutdown the client, cancel its run method, by cancelling the taskGroup.
taskGroup.cancelAll()
}
```

#### Querying

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

```swift
let rows = try await connection.query("SELECT id, username, birthday FROM users", logger: logger)
let rows = try await client.query("SELECT id, username, birthday FROM users")
```

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

```swift
for try await row in rows {
Expand Down Expand Up @@ -184,6 +171,8 @@ Please see [SECURITY.md] for details on the security process.
[Security.md]: https://github.com/vapor/.github/blob/main/SECURITY.md

[`PostgresConnection`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresconnection
[`PostgresClient`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresclient
[`run()`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresclient/run()
[`query(_:logger:)`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresconnection/query(_:logger:file:line:)-9mkfn
[`PostgresQuery`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresquery
[`PostgresRow`]: https://api.vapor.codes/postgresnio/documentation/postgresnio/postgresrow
Expand All @@ -193,4 +182,5 @@ Please see [SECURITY.md] for details on the security process.
[SwiftNIO]: https://github.com/apple/swift-nio
[PostgresKit]: https://github.com/vapor/postgres-kit
[SwiftLog]: https://github.com/apple/swift-log
[ServiceLifecycle]: https://github.com/swift-server/swift-service-lifecycle
[`Logger`]: https://apple.github.io/swift-log/docs/current/Logging/Structs/Logger.html
74 changes: 74 additions & 0 deletions Snippets/Birthdays.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import PostgresNIO
import Foundation

@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
enum Birthday {
static func main() async throws {
// 1. Create a configuration to match server's parameters
let config = PostgresClient.Configuration(
host: "localhost",
port: 5432,
username: "test_username",
password: "test_password",
database: "test_database",
tls: .disable
)

// 2. Create a client
let client = PostgresClient(configuration: config)

// 3. Run the client
try await withThrowingTaskGroup(of: Void.self) { taskGroup in
taskGroup.addTask {
await client.run() // !important
}

// 4. Create a friends table to store data into
try await client.query("""
CREATE TABLE IF NOT EXISTS "friends" (
id SERIAL PRIMARY KEY,
given_name TEXT,
last_name TEXT,
birthday TIMESTAMP WITH TIME ZONE
)
"""
)

// 5. Create a Swift friend representation
struct Friend {
var firstName: String
var lastName: String
var birthday: Date
}

// 6. Create John Appleseed with special birthday
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let johnsBirthday = dateFormatter.date(from: "1960-09-26")!
let friend = Friend(firstName: "Hans", lastName: "Müller", birthday: johnsBirthday)

// 7. Store friend into the database
try await client.query("""
INSERT INTO "friends" (given_name, last_name, birthday)
VALUES
(\(friend.firstName), \(friend.lastName), \(friend.birthday));
"""
)

// 8. Query database for the friend we just inserted
let rows = try await client.query("""
SELECT id, given_name, last_name, birthday FROM "friends" WHERE given_name = \(friend.firstName)
"""
)

// 9. Iterate the returned rows, decoding the rows into Swift primitives
for try await (id, firstName, lastName, birthday) in rows.decode((Int, String, String, Date).self) {
print("\(id) | \(firstName) \(lastName), \(birthday)")
}

// 10. Shutdown the client, by cancelling its run method, through cancelling the taskGroup.
taskGroup.cancelAll()
}
}
}

40 changes: 40 additions & 0 deletions Snippets/PostgresClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import PostgresNIO
import struct Foundation.UUID

@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
enum Runner {
static func main() async throws {

// snippet.configuration
let config = PostgresClient.Configuration(
host: "localhost",
port: 5432,
username: "my_username",
password: "my_password",
database: "my_database",
tls: .disable
)
// snippet.end

// snippet.makeClient
let client = PostgresClient(configuration: config)
// snippet.end

}

static func runAndCancel(client: PostgresClient) async {
// snippet.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()
}
// snippet.end
}
}

39 changes: 39 additions & 0 deletions Sources/PostgresNIO/Docs.docc/coding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# PostgreSQL data types

Translate Swift data types to Postgres data types and vica versa. Learn how to write translations
for your own custom Swift types.

## Topics

### Essentials

- ``PostgresCodable``
- ``PostgresDataType``
- ``PostgresFormat``
- ``PostgresNumeric``

### Encoding

- ``PostgresEncodable``
- ``PostgresNonThrowingEncodable``
- ``PostgresDynamicTypeEncodable``
- ``PostgresThrowingDynamicTypeEncodable``
- ``PostgresArrayEncodable``
- ``PostgresRangeEncodable``
- ``PostgresRangeArrayEncodable``
- ``PostgresEncodingContext``

### Decoding

- ``PostgresDecodable``
- ``PostgresArrayDecodable``
- ``PostgresRangeDecodable``
- ``PostgresRangeArrayDecodable``
- ``PostgresDecodingContext``

### JSON

- ``PostgresJSONEncoder``
- ``PostgresJSONDecoder``


43 changes: 43 additions & 0 deletions Sources/PostgresNIO/Docs.docc/deprecated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Deprecations

`PostgresNIO` follows SemVer 2.0.0. Learn which APIs are considered deprecated and how to migrate to
their replacements.

``PostgresNIO`` reached 1.0 in April 2020. Since then the maintainers have been hard at work to
guarantee API stability. However as the Swift and Swift on server ecosystem have matured approaches
have changed. The introduction of structured concurrency changed what developers expect from a
modern Swift library. Because of this ``PostgresNIO`` added various APIs that embrace the new Swift
patterns. This means however, that PostgresNIO still offers APIs that have fallen out of favor.
Those are documented here. All those APIs will be removed once the maintainers release the next
major version. The maintainers recommend all adopters to move of those APIs sooner rather than
later.

## Topics

### Migrate of deprecated APIs

- <doc:migrations>

### Deprecated APIs

These types are already deprecated or will be deprecated in the near future. All of them will be
removed from the public API with the next major release.

- ``PostgresDatabase``
- ``PostgresData``
- ``PostgresDataConvertible``
- ``PostgresQueryResult``
- ``PostgresJSONCodable``
- ``PostgresJSONBCodable``
- ``PostgresMessageEncoder``
- ``PostgresMessageDecoder``
- ``PostgresRequest``
- ``PostgresMessage``
- ``PostgresMessageType``
- ``PostgresFormatCode``
- ``PostgresListenContext``
- ``PreparedQuery``
- ``SASLAuthenticationManager``
- ``SASLAuthenticationMechanism``
- ``SASLAuthenticationError``
- ``SASLAuthenticationStepResult``
Loading

0 comments on commit 2fb0ae6

Please sign in to comment.