Skip to content

Commit 689e4aa

Browse files
authored
Use variadic generics to decode rows in Swift 5.9 (#341)
1 parent 8f8557b commit 689e4aa

File tree

6 files changed

+191
-14
lines changed

6 files changed

+191
-14
lines changed

Sources/PostgresNIO/New/PostgresRow-multi-decode.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// NOTE: THIS FILE IS AUTO-GENERATED BY dev/generate-postgresrow-multi-decode.sh
22

3+
#if compiler(<5.9)
34
extension PostgresRow {
45
@inlinable
56
@_alwaysEmitIntoClient
@@ -1171,3 +1172,4 @@ extension PostgresRow {
11711172
try self.decode((T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14).self, context: .default, file: file, line: line)
11721173
}
11731174
}
1175+
#endif

Sources/PostgresNIO/New/PostgresRowSequence-multi-decode.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// NOTE: THIS FILE IS AUTO-GENERATED BY dev/generate-postgresrowsequence-multi-decode.sh
22

3-
#if canImport(_Concurrency)
3+
#if compiler(<5.9)
44
extension AsyncSequence where Element == PostgresRow {
55
@inlinable
66
@_alwaysEmitIntoClient
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#if compiler(>=5.9)
2+
extension PostgresRow {
3+
// --- snip TODO: Remove once bug is fixed, that disallows tuples of one
4+
@inlinable
5+
public func decode<Column: PostgresDecodable>(
6+
_: Column.Type,
7+
file: String = #fileID,
8+
line: Int = #line
9+
) throws -> (Column) {
10+
try self.decode(Column.self, context: .default, file: file, line: line)
11+
}
12+
13+
@inlinable
14+
public func decode<Column: PostgresDecodable>(
15+
_: Column.Type,
16+
context: PostgresDecodingContext<some PostgresJSONDecoder>,
17+
file: String = #fileID,
18+
line: Int = #line
19+
) throws -> (Column) {
20+
precondition(self.columns.count >= 1)
21+
let columnIndex = 0
22+
var cellIterator = self.data.makeIterator()
23+
var cellData = cellIterator.next().unsafelyUnwrapped
24+
var columnIterator = self.columns.makeIterator()
25+
let column = columnIterator.next().unsafelyUnwrapped
26+
let swiftTargetType: Any.Type = Column.self
27+
28+
do {
29+
let r0 = try Column._decodeRaw(from: &cellData, type: column.dataType, format: column.format, context: context)
30+
31+
return (r0)
32+
} catch let code as PostgresDecodingError.Code {
33+
throw PostgresDecodingError(
34+
code: code,
35+
columnName: column.name,
36+
columnIndex: columnIndex,
37+
targetType: swiftTargetType,
38+
postgresType: column.dataType,
39+
postgresFormat: column.format,
40+
postgresData: cellData,
41+
file: file,
42+
line: line
43+
)
44+
}
45+
}
46+
// --- snap TODO: Remove once bug is fixed, that disallows tuples of one
47+
48+
@inlinable
49+
public func decode<each Column: PostgresDecodable>(
50+
_ columnType: (repeat each Column).Type,
51+
context: PostgresDecodingContext<some PostgresJSONDecoder>,
52+
file: String = #fileID,
53+
line: Int = #line
54+
) throws -> (repeat each Column) {
55+
let packCount = ComputeParameterPackLength.count(ofPack: repeat (each Column).self)
56+
precondition(self.columns.count >= packCount)
57+
58+
var columnIndex = 0
59+
var cellIterator = self.data.makeIterator()
60+
var columnIterator = self.columns.makeIterator()
61+
62+
return (
63+
repeat try Self.decodeNextColumn(
64+
(each Column).self,
65+
cellIterator: &cellIterator,
66+
columnIterator: &columnIterator,
67+
columnIndex: &columnIndex,
68+
context: context,
69+
file: file,
70+
line: line
71+
)
72+
)
73+
}
74+
75+
@inlinable
76+
static func decodeNextColumn<Column: PostgresDecodable>(
77+
_ columnType: Column.Type,
78+
cellIterator: inout IndexingIterator<DataRow>,
79+
columnIterator: inout IndexingIterator<[RowDescription.Column]>,
80+
columnIndex: inout Int,
81+
context: PostgresDecodingContext<some PostgresJSONDecoder>,
82+
file: String,
83+
line: Int
84+
) throws -> Column {
85+
defer { columnIndex += 1 }
86+
87+
let column = columnIterator.next().unsafelyUnwrapped
88+
var cellData = cellIterator.next().unsafelyUnwrapped
89+
do {
90+
return try Column._decodeRaw(from: &cellData, type: column.dataType, format: column.format, context: context)
91+
} catch let code as PostgresDecodingError.Code {
92+
throw PostgresDecodingError(
93+
code: code,
94+
columnName: column.name,
95+
columnIndex: columnIndex,
96+
targetType: Column.self,
97+
postgresType: column.dataType,
98+
postgresFormat: column.format,
99+
postgresData: cellData,
100+
file: file,
101+
line: line
102+
)
103+
}
104+
}
105+
106+
@inlinable
107+
public func decode<each Column: PostgresDecodable>(
108+
_ columnType: (repeat each Column).Type,
109+
file: String = #fileID,
110+
line: Int = #line
111+
) throws -> (repeat each Column) {
112+
try self.decode(columnType, context: .default, file: file, line: line)
113+
}
114+
}
115+
116+
extension AsyncSequence where Element == PostgresRow {
117+
// --- snip TODO: Remove once bug is fixed, that disallows tuples of one
118+
@inlinable
119+
public func decode<Column: PostgresDecodable>(
120+
_: Column.Type,
121+
context: PostgresDecodingContext<some PostgresJSONDecoder>,
122+
file: String = #fileID,
123+
line: Int = #line
124+
) -> AsyncThrowingMapSequence<Self, (Column)> {
125+
self.map { row in
126+
try row.decode(Column.self, context: context, file: file, line: line)
127+
}
128+
}
129+
130+
@inlinable
131+
public func decode<Column: PostgresDecodable>(
132+
_: Column.Type,
133+
file: String = #fileID,
134+
line: Int = #line
135+
) -> AsyncThrowingMapSequence<Self, (Column)> {
136+
self.decode(Column.self, context: .default, file: file, line: line)
137+
}
138+
// --- snap TODO: Remove once bug is fixed, that disallows tuples of one
139+
140+
public func decode<each Column: PostgresDecodable>(
141+
_ columnType: (repeat each Column).Type,
142+
context: PostgresDecodingContext<some PostgresJSONDecoder>,
143+
file: String = #fileID,
144+
line: Int = #line
145+
) -> AsyncThrowingMapSequence<Self, (repeat each Column)> {
146+
self.map { row in
147+
try row.decode(columnType, context: context, file: file, line: line)
148+
}
149+
}
150+
151+
public func decode<each Column: PostgresDecodable>(
152+
_ columnType: (repeat each Column).Type,
153+
file: String = #fileID,
154+
line: Int = #line
155+
) -> AsyncThrowingMapSequence<Self, (repeat each Column)> {
156+
self.decode(columnType, context: .default, file: file, line: line)
157+
}
158+
}
159+
160+
@usableFromInline
161+
enum ComputeParameterPackLength {
162+
@usableFromInline
163+
enum BoolConverter<T> {
164+
@usableFromInline
165+
typealias Bool = Swift.Bool
166+
}
167+
168+
@inlinable
169+
static func count<each T>(ofPack t: repeat each T) -> Int {
170+
MemoryLayout<(repeat BoolConverter<each T>.Bool)>.size / MemoryLayout<Bool>.stride
171+
}
172+
}
173+
#endif // compiler(>=5.9)
174+

Tests/IntegrationTests/AsyncTests.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import NIOPosix
88
import NIOCore
99

1010
final class AsyncPostgresConnectionTests: XCTestCase {
11-
1211
func test1kRoundTrips() async throws {
1312
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
1413
defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) }
@@ -37,7 +36,8 @@ final class AsyncPostgresConnectionTests: XCTestCase {
3736
try await withTestConnection(on: eventLoop) { connection in
3837
let rows = try await connection.query("SELECT generate_series(\(start), \(end));", logger: .psqlTest)
3938
var counter = 0
40-
for try await element in rows.decode(Int.self, context: .default) {
39+
for try await row in rows {
40+
let element = try row.decode(Int.self)
4141
XCTAssertEqual(element, counter + 1)
4242
counter += 1
4343
}
@@ -259,7 +259,8 @@ final class AsyncPostgresConnectionTests: XCTestCase {
259259
try await withTestConnection(on: eventLoop) { connection in
260260
let rows = try await connection.query("SELECT generate_series(\(start), \(end));", logger: .psqlTest)
261261
var counter = 1
262-
for try await element in rows.decode(Int.self, context: .default) {
262+
for try await row in rows {
263+
let element = try row.decode(Int.self, context: .default)
263264
XCTAssertEqual(element, counter)
264265
counter += 1
265266
}

Tests/IntegrationTests/PostgresNIOTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,10 +1246,10 @@ final class PostgresNIOTests: XCTestCase {
12461246
return EventLoopFuture.whenAllSucceed([a, b, c], on: self.eventLoop)
12471247
}).wait())
12481248
XCTAssertEqual(queries?.count, 3)
1249-
var resutIterator = queries?.makeIterator()
1250-
XCTAssertEqual(try resutIterator?.next()?.first?.decode(String.self, context: .default), "a")
1251-
XCTAssertEqual(try resutIterator?.next()?.first?.decode(String.self, context: .default), "b")
1252-
XCTAssertEqual(try resutIterator?.next()?.first?.decode(String.self, context: .default), "c")
1249+
var resultIterator = queries?.makeIterator()
1250+
XCTAssertEqual(try resultIterator?.next()?.first?.decode(String.self, context: .default), "a")
1251+
XCTAssertEqual(try resultIterator?.next()?.first?.decode(String.self, context: .default), "b")
1252+
XCTAssertEqual(try resultIterator?.next()?.first?.decode(String.self, context: .default), "c")
12531253
}
12541254

12551255
// https://github.com/vapor/postgres-nio/issues/122

Tests/PostgresNIOTests/New/PostgresRowSequenceTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ final class PostgresRowSequenceTests: XCTestCase {
5959

6060
var counter = 0
6161
for try await row in rowSequence {
62-
XCTAssertEqual(try row.decode(Int.self, context: .default), counter)
62+
XCTAssertEqual(try row.decode(Int.self), counter)
6363
counter += 1
6464

6565
if counter == 64 {
@@ -135,7 +135,7 @@ final class PostgresRowSequenceTests: XCTestCase {
135135

136136
var counter = 0
137137
for try await row in rowSequence {
138-
XCTAssertEqual(try row.decode(Int.self, context: .default), counter)
138+
XCTAssertEqual(try row.decode(Int.self), counter)
139139
counter += 1
140140
}
141141

@@ -163,7 +163,7 @@ final class PostgresRowSequenceTests: XCTestCase {
163163

164164
var counter = 0
165165
for try await row in rowSequence {
166-
XCTAssertEqual(try row.decode(Int.self, context: .default), counter)
166+
XCTAssertEqual(try row.decode(Int.self), counter)
167167
counter += 1
168168
}
169169

@@ -220,7 +220,7 @@ final class PostgresRowSequenceTests: XCTestCase {
220220
}
221221

222222
let row1 = try await rowIterator.next()
223-
XCTAssertEqual(try row1?.decode(Int.self, context: .default), 0)
223+
XCTAssertEqual(try row1?.decode(Int.self), 0)
224224

225225
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
226226
stream.receive(completion: .success("SELECT 1"))
@@ -252,7 +252,7 @@ final class PostgresRowSequenceTests: XCTestCase {
252252
}
253253

254254
let row1 = try await rowIterator.next()
255-
XCTAssertEqual(try row1?.decode(Int.self, context: .default), 0)
255+
XCTAssertEqual(try row1?.decode(Int.self), 0)
256256

257257
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
258258
stream.receive(completion: .failure(PSQLError.serverClosedConnection(underlying: nil)))
@@ -415,7 +415,7 @@ final class PostgresRowSequenceTests: XCTestCase {
415415
var counter = 1
416416
for _ in 0..<(2 * messagePerChunk - 1) {
417417
let row = try await rowIterator.next()
418-
XCTAssertEqual(try row?.decode(Int.self, context: .default), counter)
418+
XCTAssertEqual(try row?.decode(Int.self), counter)
419419
counter += 1
420420
}
421421

0 commit comments

Comments
 (0)