Skip to content

Commit 2345531

Browse files
committed
Leverage better-performing new APIs from PostgresNIO, also solving (most) deprecation warnings. Also some additional minor improvements to connection handling.
1 parent 452b034 commit 2345531

File tree

5 files changed

+72
-61
lines changed

5 files changed

+72
-61
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ let package = Package(
1010
.library(name: "PostgresKit", targets: ["PostgresKit"]),
1111
],
1212
dependencies: [
13-
.package(url: "https://github.com/vapor/postgres-nio.git", from: "1.7.2"),
13+
.package(url: "https://github.com/vapor/postgres-nio.git", from: "1.9.0"),
1414
.package(url: "https://github.com/vapor/sql-kit.git", from: "3.16.0"),
1515
.package(url: "https://github.com/vapor/async-kit.git", from: "1.0.0"),
1616
],

Sources/PostgresKit/PostgresConfiguration.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public struct PostgresConfiguration {
1515
public static var ianaPortNumber: Int { 5432 }
1616

1717
internal var _hostname: String?
18+
internal var _port: Int?
1819

1920
public init?(url: String) {
2021
guard let url = URL(string: url) else {
@@ -67,6 +68,7 @@ public struct PostgresConfiguration {
6768
self.database = database
6869
self.tlsConfiguration = nil
6970
self._hostname = nil
71+
self._port = nil
7072
}
7173

7274
public init(
@@ -85,5 +87,6 @@ public struct PostgresConfiguration {
8587
self.password = password
8688
self.tlsConfiguration = tlsConfiguration
8789
self._hostname = hostname
90+
self._port = port
8891
}
8992
}

Sources/PostgresKit/PostgresConnectionSource.swift

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import NIOConcurrencyHelpers
2+
13
public struct PostgresConnectionSource: ConnectionPoolSource {
24
public let configuration: PostgresConfiguration
5+
private static let idGenerator = NIOAtomic.makeAtomic(value: 0)
36

47
public init(configuration: PostgresConfiguration) {
58
self.configuration = configuration
@@ -9,36 +12,59 @@ public struct PostgresConnectionSource: ConnectionPoolSource {
912
logger: Logger,
1013
on eventLoop: EventLoop
1114
) -> EventLoopFuture<PostgresConnection> {
12-
let address: SocketAddress
13-
do {
14-
address = try self.configuration.address()
15-
} catch {
16-
return eventLoop.makeFailedFuture(error)
17-
}
18-
return PostgresConnection.connect(
19-
to: address,
20-
tlsConfiguration: self.configuration.tlsConfiguration,
21-
serverHostname: self.configuration._hostname,
22-
logger: logger,
23-
on: eventLoop
24-
).flatMap { conn in
25-
return conn.authenticate(
26-
username: self.configuration.username,
27-
database: self.configuration.database,
28-
password: self.configuration.password,
15+
if let hostname = self.configuration._hostname {
16+
let future = PostgresConnection.connect(
17+
on: eventLoop,
18+
configuration: .init(
19+
connection: .init(host: hostname, port: self.configuration._port ?? PostgresConfiguration.ianaPortNumber),
20+
authentication: .init(username: self.configuration.username, database: self.configuration.database, password: self.configuration.password),
21+
tls: self.configuration.tlsConfiguration.map { .require(try! .init(configuration: $0)) } ?? .disable
22+
),
23+
id: Self.idGenerator.add(1),
2924
logger: logger
30-
).flatMap {
31-
if let searchPath = self.configuration.searchPath {
32-
let string = searchPath.map { "\"" + $0 + "\"" }.joined(separator: ", ")
33-
return conn.simpleQuery("SET search_path = \(string)")
34-
.map { _ in }
35-
} else {
36-
return eventLoop.makeSucceededFuture(())
25+
)
26+
27+
if let searchPath = self.configuration.searchPath {
28+
return future.flatMap { conn in
29+
let string = searchPath.map { #""\#($0)""# }.joined(separator: ", ")
30+
return conn.simpleQuery("SET search_path = \(string)").map { _ in conn }
31+
}
32+
} else {
33+
return future
34+
}
35+
} else {
36+
let address: SocketAddress
37+
do {
38+
address = try self.configuration.address()
39+
} catch {
40+
return eventLoop.makeFailedFuture(error)
41+
}
42+
43+
// Legacy code path until PostgresNIO regains support for connecting directly to a SocketAddress.
44+
return PostgresConnection.connect(
45+
to: address,
46+
tlsConfiguration: self.configuration.tlsConfiguration,
47+
serverHostname: self.configuration._hostname,
48+
logger: logger,
49+
on: eventLoop
50+
).flatMap { conn in
51+
return conn.authenticate(
52+
username: self.configuration.username,
53+
database: self.configuration.database,
54+
password: self.configuration.password,
55+
logger: logger
56+
).flatMap {
57+
if let searchPath = self.configuration.searchPath {
58+
let string = searchPath.map { "\"" + $0 + "\"" }.joined(separator: ", ")
59+
return conn.simpleQuery("SET search_path = \(string)").map { _ in conn }
60+
} else {
61+
return eventLoop.makeSucceededFuture(conn)
62+
}
63+
}.flatMapErrorThrowing { error in
64+
_ = conn.close()
65+
throw error
3766
}
38-
}.flatMapErrorThrowing { error in
39-
_ = conn.close()
40-
throw error
41-
}.map { conn }
67+
}
4268
}
4369
}
4470
}
Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
11
extension PostgresRow {
22
public func sql(decoder: PostgresDataDecoder = .init()) -> SQLRow {
3-
return _PostgreSQLRow(row: self, decoder: decoder)
3+
return _PostgresSQLRow(row: self.makeRandomAccess(), decoder: decoder)
44
}
55
}
66

77
// MARK: Private
88

9-
private struct _PostgreSQLRow: SQLRow {
10-
let row: PostgresRow
9+
private struct _PostgresSQLRow: SQLRow {
10+
let randomAccessView: PostgresRandomAccessRow
1111
let decoder: PostgresDataDecoder
1212

1313
enum _Error: Error {
1414
case missingColumn(String)
1515
}
16+
17+
init(row: PostgresRandomAccessRow, decoder: PostgresDataDecoder) {
18+
self.randomAccessView = row
19+
self.decoder = decoder
20+
}
1621

1722
var allColumns: [String] {
18-
self.row.rowDescription.fields.map { $0.name }
23+
self.randomAccessView.map { $0.columnName }
1924
}
2025

2126
func contains(column: String) -> Bool {
22-
self.row.rowDescription.fields
23-
.contains { $0.name == column }
27+
self.randomAccessView.contains(column)
2428
}
2529

2630
func decodeNil(column: String) throws -> Bool {
27-
self.row.column(column)?.value == nil
31+
self.randomAccessView.contains(column) && self.randomAccessView[column].bytes == nil
2832
}
2933

3034
func decode<D>(column: String, as type: D.Type) throws -> D where D : Decodable {
31-
guard let data = self.row.column(column) else {
35+
guard self.randomAccessView.contains(column) else {
3236
throw _Error.missingColumn(column)
3337
}
34-
return try self.decoder.decode(D.self, from: data)
38+
return try self.decoder.decode(D.self, from: self.randomAccessView[data: column])
3539
}
3640
}

Tests/PostgresKitTests/Utilities.swift

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import XCTest
22
import PostgresKit
3-
import NIOCore
43
import Logging
54
#if canImport(Darwin)
65
import Darwin.C
@@ -10,28 +9,7 @@ import Glibc
109

1110
extension PostgresConnection {
1211
static func test(on eventLoop: EventLoop) -> EventLoopFuture<PostgresConnection> {
13-
let config = PostgresConfiguration.test
14-
15-
return eventLoop.flatSubmit { () -> EventLoopFuture<PostgresConnection> in
16-
do {
17-
let address = try config.address()
18-
return self.connect(to: address, on: eventLoop)
19-
} catch {
20-
return eventLoop.makeFailedFuture(error)
21-
}
22-
}.flatMap { conn in
23-
return conn.authenticate(
24-
username: config.username,
25-
database: config.database,
26-
password: config.password
27-
)
28-
.map { conn }
29-
.flatMapError { error in
30-
conn.close().flatMapThrowing {
31-
throw error
32-
}
33-
}
34-
}
12+
return PostgresConnectionSource(configuration: .test).makeConnection(logger: .init(label: "vapor.codes.postgres-kit.test"), on: eventLoop)
3513
}
3614
}
3715

0 commit comments

Comments
 (0)