Skip to content

Commit 8817a61

Browse files
authored
Updated to use new PostgresKit/PostgresNIO APIs (#207)
* Require Swift 5.7 * Revamp FluentPostgresConfiguration to use SQLPostgresConfiguration and FluentPostgresDatabase to use SQLDatabase for (almost) everything instead of duplicating PostgresKit's work. Ditch uses of old APIs. * General cleanup * CI cleanup * Add API breakage allowlist * Require the updated PostgresKit
1 parent c7e3976 commit 8817a61

14 files changed

+417
-381
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
API breakage: func DatabaseConfigurationFactory.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:decoder:sqlLogLevel:) has removed default argument from parameter 3
2+
API breakage: func DatabaseConfigurationFactory.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:decoder:sqlLogLevel:) has removed default argument from parameter 4
3+
API breakage: func DatabaseConfigurationFactory.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:decoder:sqlLogLevel:) has removed default argument from parameter 3
4+
API breakage: func DatabaseConfigurationFactory.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:decoder:sqlLogLevel:) has removed default argument from parameter 4
5+
API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:decoder:sqlLogLevel:) has removed default argument from parameter 8
6+
API breakage: func DatabaseConfigurationFactory.postgres(hostname:port:username:password:database:tlsConfiguration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:decoder:sqlLogLevel:) has removed default argument from parameter 9
7+
API breakage: func DatabaseConfigurationFactory.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:decoder:sqlLogLevel:) has removed default argument from parameter 3
8+
API breakage: func DatabaseConfigurationFactory.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encoder:decoder:sqlLogLevel:) has removed default argument from parameter 4

.github/workflows/projectboard.yml

+4-24
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,7 @@ on:
55
types: [reopened, closed, labeled, unlabeled, assigned, unassigned]
66

77
jobs:
8-
setup_matrix_input:
9-
runs-on: ubuntu-latest
10-
11-
steps:
12-
- id: set-matrix
13-
run: |
14-
output=$(curl ${{ github.event.issue.url }}/labels | jq '.[] | .name') || output=""
15-
16-
echo '======================'
17-
echo 'Process incoming data'
18-
echo '======================'
19-
json=$(echo $output | sed 's/"\s"/","/g')
20-
echo $json
21-
echo "::set-output name=matrix::$(echo $json)"
22-
outputs:
23-
issueTags: ${{ steps.set-matrix.outputs.matrix }}
24-
25-
Manage_project_issues:
26-
needs: setup_matrix_input
27-
uses: vapor/ci/.github/workflows/issues-to-project-board.yml@main
28-
with:
29-
labelsJson: ${{ needs.setup_matrix_input.outputs.issueTags }}
30-
secrets:
31-
PROJECT_BOARD_AUTOMATION_PAT: "${{ secrets.PROJECT_BOARD_AUTOMATION_PAT }}"
8+
update_project_boards:
9+
name: Update project boards
10+
uses: vapor/ci/.github/workflows/update-project-boards-for-issue.yml@reusable-workflows
11+
secrets: inherit

.github/workflows/test.yml

+5-19
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
push: { branches: ['main'] }
88

99
env:
10-
LOG_LEVEL: debug
10+
LOG_LEVEL: info
1111
SWIFT_DETERMINISTIC_HASHING: 1
1212
POSTGRES_HOSTNAME: 'psql-a'
1313
POSTGRES_HOSTNAME_A: 'psql-a'
@@ -31,7 +31,7 @@ jobs:
3131
- dbimage: postgres:15
3232
dbauth: scram-sha-256
3333
runs-on: ubuntu-latest
34-
container: swift:5.7-jammy
34+
container: swift:5.8-jammy
3535
services:
3636
psql-a:
3737
image: ${{ matrix.dbimage }}
@@ -61,11 +61,8 @@ jobs:
6161
- name: Submit coverage report to Codecov.io
6262
uses: vapor/[email protected]
6363
with:
64-
cc_flags: 'unittests'
6564
cc_env_vars: 'SWIFT_VERSION,SWIFT_PLATFORM,RUNNER_OS,RUNNER_ARCH,POSTGRES_VERSION,POSTGRES_AUTH_METHOD'
66-
cc_fail_ci_if_error: true
67-
cc_verbose: true
68-
cc_dry_run: false
65+
cc_fail_ci_if_error: false
6966

7067
# Check for API breakage versus main
7168
api-breakage:
@@ -85,7 +82,7 @@ jobs:
8582
fail-fast: false
8683
matrix:
8784
include:
88-
- {dbimage: 'postgres:11', dbauth: 'trust', swiftver: 'swift:5.6-focal'}
85+
- {dbimage: 'postgres:11', dbauth: 'trust', swiftver: 'swift:5.7-focal'}
8986
- {dbimage: 'postgres:13', dbauth: 'md5', swiftver: 'swift:5.7-jammy'}
9087
- {dbimage: 'postgres:15', dbauth: 'scram-sha-256', swiftver: 'swift:5.8-jammy'}
9188
- {dbimage: 'postgres:15', dbauth: 'scram-sha-256', swiftver: 'swiftlang/swift:nightly-5.9-jammy'}
@@ -123,7 +120,7 @@ jobs:
123120
include:
124121
- dbimage: postgresql@14
125122
dbauth: scram-sha-256
126-
macos: macos-12
123+
macos: macos-13
127124
xcode: latest-stable
128125
runs-on: ${{ matrix.macos }}
129126
env:
@@ -159,14 +156,3 @@ jobs:
159156
uses: actions/checkout@v3
160157
- name: Run all tests
161158
run: swift test --sanitize=thread
162-
163-
test-exports:
164-
name: Test exports
165-
runs-on: ubuntu-latest
166-
container: swift:5.8-jammy
167-
steps:
168-
- name: Check out Vapor
169-
uses: actions/checkout@v3
170-
with: { 'fetch-depth': 0 }
171-
- name: Build
172-
run: swift build -Xswiftc -DBUILDING_DOCC

Package.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.6
1+
// swift-tools-version:5.7
22
import PackageDescription
33

44
let package = Package(
@@ -15,7 +15,7 @@ let package = Package(
1515
dependencies: [
1616
.package(url: "https://github.com/vapor/async-kit.git", from: "1.14.0"),
1717
.package(url: "https://github.com/vapor/fluent-kit.git", from: "1.36.0"),
18-
.package(url: "https://github.com/vapor/postgres-kit.git", from: "2.10.1"),
18+
.package(url: "https://github.com/vapor/postgres-kit.git", from: "2.11.0"),
1919
],
2020
targets: [
2121
.target(name: "FluentPostgresDriver", dependencies: [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import FluentKit
2+
3+
extension DatabaseID {
4+
public static var psql: DatabaseID {
5+
return .init(string: "psql")
6+
}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import Logging
2+
import FluentKit
3+
import AsyncKit
4+
import NIOCore
5+
import NIOSSL
6+
import Foundation
7+
import PostgresKit
8+
import PostgresNIO
9+
10+
// N.B.: This excessive method duplication is required to maintain the original public API, which allowed defaulting
11+
// either the encoder, decoder, or both. The "defaulting both" versions now forward to the new API, the others are here.
12+
13+
// Factory methods accepting both encoder and decoder
14+
extension DatabaseConfigurationFactory {
15+
enum FluentPostgresError: Error {
16+
case invalidURL(String)
17+
}
18+
19+
@available(*, deprecated, message: "Use `.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
20+
public static func postgres(
21+
url: String, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
22+
encoder: PostgresDataEncoder, decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
23+
) throws -> DatabaseConfigurationFactory {
24+
guard let configuration = PostgresConfiguration(url: url) else { throw FluentPostgresError.invalidURL(url) }
25+
return .postgres(configuration: configuration,
26+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
27+
encoder: encoder, decoder: decoder, sqlLogLevel: sqlLogLevel
28+
)
29+
}
30+
31+
@available(*, deprecated, message: "Use `.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
32+
public static func postgres(
33+
url: URL, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
34+
encoder: PostgresDataEncoder, decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
35+
) throws -> DatabaseConfigurationFactory {
36+
guard let configuration = PostgresConfiguration(url: url) else { throw FluentPostgresError.invalidURL(url.absoluteString) }
37+
return .postgres( configuration: configuration,
38+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
39+
encoder: encoder, decoder: decoder, sqlLogLevel: sqlLogLevel
40+
)
41+
}
42+
43+
@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
44+
public static func postgres(
45+
hostname: String, port: Int = PostgresConfiguration.ianaPortNumber,
46+
username: String, password: String, database: String? = nil, tlsConfiguration: TLSConfiguration? = nil,
47+
maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
48+
encoder: PostgresDataEncoder, decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
49+
) -> DatabaseConfigurationFactory {
50+
.postgres(configuration: .init(
51+
hostname: hostname, port: port, username: username, password: password, database: database, tlsConfiguration: tlsConfiguration),
52+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
53+
encoder: encoder, decoder: decoder, sqlLogLevel: sqlLogLevel
54+
)
55+
}
56+
57+
@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
58+
public static func postgres(
59+
configuration: PostgresConfiguration,
60+
maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
61+
encoder: PostgresDataEncoder, decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
62+
) -> DatabaseConfigurationFactory {
63+
.postgres(
64+
configuration: .init(legacyConfiguration: configuration),
65+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
66+
encodingContext: .init(jsonEncoder: TypeErasedPostgresJSONEncoder(json: encoder.json)),
67+
decodingContext: .init(jsonDecoder: TypeErasedPostgresJSONDecoder(json: decoder.json)),
68+
sqlLogLevel: sqlLogLevel
69+
)
70+
}
71+
}
72+
73+
// Factory methods accepting only encoder or only decoder.
74+
extension DatabaseConfigurationFactory {
75+
@available(*, deprecated, message: "Use `.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
76+
public static func postgres(
77+
url: String, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
78+
encoder: PostgresDataEncoder, sqlLogLevel: Logger.Level = .debug
79+
) throws -> DatabaseConfigurationFactory {
80+
try .postgres(url: url,
81+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
82+
encoder: encoder, decoder: .init(), sqlLogLevel: sqlLogLevel
83+
)
84+
}
85+
86+
@available(*, deprecated, message: "Use `.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
87+
public static func postgres(
88+
url: String, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
89+
decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
90+
) throws -> DatabaseConfigurationFactory {
91+
try .postgres(url: url,
92+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
93+
encoder: .init(), decoder: decoder, sqlLogLevel: sqlLogLevel
94+
)
95+
}
96+
97+
@available(*, deprecated, message: "Use `.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
98+
public static func postgres(
99+
url: URL, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
100+
encoder: PostgresDataEncoder, sqlLogLevel: Logger.Level = .debug
101+
) throws -> DatabaseConfigurationFactory {
102+
try .postgres(url: url,
103+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
104+
encoder: encoder, decoder: .init(), sqlLogLevel: sqlLogLevel
105+
)
106+
}
107+
108+
@available(*, deprecated, message: "Use `.postgres(url:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
109+
public static func postgres(
110+
url: URL, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
111+
decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
112+
) throws -> DatabaseConfigurationFactory {
113+
try .postgres(url: url,
114+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
115+
encoder: .init(), decoder: decoder, sqlLogLevel: sqlLogLevel
116+
)
117+
}
118+
119+
@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
120+
public static func postgres(
121+
hostname: String, port: Int = PostgresConfiguration.ianaPortNumber,
122+
username: String, password: String, database: String? = nil, tlsConfiguration: TLSConfiguration? = nil,
123+
maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
124+
encoder: PostgresDataEncoder, sqlLogLevel: Logger.Level = .debug
125+
) -> DatabaseConfigurationFactory {
126+
.postgres(
127+
hostname: hostname, port: port, username: username, password: password, database: database, tlsConfiguration: tlsConfiguration,
128+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
129+
encoder: encoder, decoder: .init(), sqlLogLevel: sqlLogLevel
130+
)
131+
}
132+
133+
@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
134+
public static func postgres(
135+
hostname: String, port: Int = PostgresConfiguration.ianaPortNumber,
136+
username: String, password: String, database: String? = nil, tlsConfiguration: TLSConfiguration? = nil,
137+
maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
138+
decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
139+
) -> DatabaseConfigurationFactory {
140+
.postgres(
141+
hostname: hostname, port: port, username: username, password: password, database: database, tlsConfiguration: tlsConfiguration,
142+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
143+
encoder: .init(), decoder: decoder, sqlLogLevel: sqlLogLevel
144+
)
145+
}
146+
147+
@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
148+
public static func postgres(
149+
configuration: PostgresConfiguration, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
150+
encoder: PostgresDataEncoder, sqlLogLevel: Logger.Level = .debug
151+
) -> DatabaseConfigurationFactory {
152+
.postgres(configuration: configuration,
153+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
154+
encoder: encoder, decoder: .init(), sqlLogLevel: sqlLogLevel
155+
)
156+
}
157+
158+
@available(*, deprecated, message: "Use `.postgres(configuration:maxConnectionsPerEventLoop:connectionPoolTimeout:encodingContext:decodingContext:sqlLogLevel:)` instead.")
159+
public static func postgres(
160+
configuration: PostgresConfiguration, maxConnectionsPerEventLoop: Int = 1, connectionPoolTimeout: TimeAmount = .seconds(10),
161+
decoder: PostgresDataDecoder, sqlLogLevel: Logger.Level = .debug
162+
) -> DatabaseConfigurationFactory {
163+
.postgres(configuration: configuration,
164+
maxConnectionsPerEventLoop: maxConnectionsPerEventLoop, connectionPoolTimeout: connectionPoolTimeout,
165+
encoder: .init(), decoder: decoder, sqlLogLevel: sqlLogLevel
166+
)
167+
}
168+
}
169+
170+
// N.B.: If you change something in these two types, update the copies in PostgresKit too.
171+
fileprivate struct TypeErasedPostgresJSONDecoder: PostgresJSONDecoder {
172+
let json: any PostgresJSONDecoder
173+
func decode<T: Decodable>(_: T.Type, from: Data) throws -> T { try self.json.decode(T.self, from: from) }
174+
func decode<T: Decodable>(_: T.Type, from: ByteBuffer) throws -> T { try self.json.decode(T.self, from: from) }
175+
}
176+
177+
fileprivate struct TypeErasedPostgresJSONEncoder: PostgresJSONEncoder {
178+
let json: any PostgresJSONEncoder
179+
func encode<T: Encodable>(_ value: T) throws -> Data { try self.json.encode(value) }
180+
func encode<T: Encodable>(_ value: T, into: inout ByteBuffer) throws { try self.json.encode(value, into: &into) }
181+
}
+6-11
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
#if !BUILDING_DOCC
1+
#if swift(>=5.8)
22

3-
@_exported import FluentKit
4-
@_exported import PostgresKit
3+
@_documentation(visibility: internal) @_exported import FluentKit
4+
@_documentation(visibility: internal) @_exported import PostgresKit
55

6-
#else
6+
#else
77

8-
import FluentKit
9-
import PostgresKit
8+
@_exported import FluentKit
9+
@_exported import PostgresKit
1010

1111
#endif
1212

13-
extension DatabaseID {
14-
public static var psql: DatabaseID {
15-
return .init(string: "psql")
16-
}
17-
}

0 commit comments

Comments
 (0)