@@ -3,6 +3,7 @@ import Logging
3
3
4
4
struct QueryResult {
5
5
enum Value : Equatable {
6
+ case emptyResponse
6
7
case noRows( String )
7
8
case rowDescription( [ RowDescription . Column ] )
8
9
}
@@ -19,6 +20,7 @@ final class PSQLRowStream: @unchecked Sendable {
19
20
enum Source {
20
21
case stream( [ RowDescription . Column ] , PSQLRowsDataSource )
21
22
case noRows( Result < String , Error > )
23
+ case emptyResponse
22
24
}
23
25
24
26
let eventLoop : EventLoop
@@ -27,14 +29,20 @@ final class PSQLRowStream: @unchecked Sendable {
27
29
private enum BufferState {
28
30
case streaming( buffer: CircularBuffer < DataRow > , dataSource: PSQLRowsDataSource )
29
31
case finished( buffer: CircularBuffer < DataRow > , commandTag: String )
32
+ case empty
30
33
case failure( Error )
31
34
}
32
-
35
+
36
+ private enum Consumed {
37
+ case tag( String )
38
+ case emptyResponse
39
+ }
40
+
33
41
private enum DownstreamState {
34
42
case waitingForConsumer( BufferState )
35
43
case iteratingRows( onRow: ( PostgresRow ) throws -> ( ) , EventLoopPromise < Void > , PSQLRowsDataSource )
36
44
case waitingForAll( [ PostgresRow ] , EventLoopPromise < [ PostgresRow ] > , PSQLRowsDataSource )
37
- case consumed( Result < String , Error > )
45
+ case consumed( Result < Consumed , Error > )
38
46
case asyncSequence( AsyncSequenceSource , PSQLRowsDataSource , onFinish: @Sendable ( ) -> ( ) )
39
47
}
40
48
@@ -58,6 +66,9 @@ final class PSQLRowStream: @unchecked Sendable {
58
66
case . noRows( . failure( let error) ) :
59
67
self . rowDescription = [ ]
60
68
bufferState = . failure( error)
69
+ case . emptyResponse:
70
+ self . rowDescription = [ ]
71
+ bufferState = . empty
61
72
}
62
73
63
74
self . downstreamState = . waitingForConsumer( bufferState)
@@ -98,11 +109,16 @@ final class PSQLRowStream: @unchecked Sendable {
98
109
self . downstreamState = . asyncSequence( source, dataSource, onFinish: onFinish)
99
110
self . executeActionBasedOnYieldResult ( yieldResult, source: dataSource)
100
111
112
+ case . empty:
113
+ source. finish ( )
114
+ onFinish ( )
115
+ self . downstreamState = . consumed( . success( . emptyResponse) )
116
+
101
117
case . finished( let buffer, let commandTag) :
102
118
_ = source. yield ( contentsOf: buffer)
103
119
source. finish ( )
104
120
onFinish ( )
105
- self . downstreamState = . consumed( . success( commandTag) )
121
+ self . downstreamState = . consumed( . success( . tag ( commandTag) ) )
106
122
107
123
case . failure( let error) :
108
124
source. finish ( error)
@@ -195,12 +211,16 @@ final class PSQLRowStream: @unchecked Sendable {
195
211
PostgresRow ( data: $0, lookupTable: self . lookupTable, columns: self . rowDescription)
196
212
}
197
213
198
- self . downstreamState = . consumed( . success( commandTag) )
214
+ self . downstreamState = . consumed( . success( . tag ( commandTag) ) )
199
215
return self . eventLoop. makeSucceededFuture ( rows)
200
216
201
217
case . failure( let error) :
202
218
self . downstreamState = . consumed( . failure( error) )
203
219
return self . eventLoop. makeFailedFuture ( error)
220
+
221
+ case . empty:
222
+ self . downstreamState = . consumed( . success( . emptyResponse) )
223
+ return self . eventLoop. makeSucceededFuture ( [ ] )
204
224
}
205
225
}
206
226
@@ -247,7 +267,11 @@ final class PSQLRowStream: @unchecked Sendable {
247
267
}
248
268
249
269
return promise. futureResult
250
-
270
+
271
+ case . empty:
272
+ self . downstreamState = . consumed( . success( . emptyResponse) )
273
+ return self . eventLoop. makeSucceededVoidFuture ( )
274
+
251
275
case . finished( let buffer, let commandTag) :
252
276
do {
253
277
for data in buffer {
@@ -259,7 +283,7 @@ final class PSQLRowStream: @unchecked Sendable {
259
283
try onRow ( row)
260
284
}
261
285
262
- self . downstreamState = . consumed( . success( commandTag) )
286
+ self . downstreamState = . consumed( . success( . tag ( commandTag) ) )
263
287
return self . eventLoop. makeSucceededVoidFuture ( )
264
288
} catch {
265
289
self . downstreamState = . consumed( . failure( error) )
@@ -290,9 +314,9 @@ final class PSQLRowStream: @unchecked Sendable {
290
314
buffer. append ( contentsOf: newRows)
291
315
self . downstreamState = . waitingForConsumer( . streaming( buffer: buffer, dataSource: dataSource) )
292
316
293
- case . waitingForConsumer( . finished) , . waitingForConsumer( . failure) :
317
+ case . waitingForConsumer( . finished) , . waitingForConsumer( . failure) , . waitingForConsumer ( . empty ) :
294
318
preconditionFailure ( " How can new rows be received, if an end was already signalled? " )
295
-
319
+
296
320
case . iteratingRows( let onRow, let promise, let dataSource) :
297
321
do {
298
322
for data in newRows {
@@ -353,20 +377,23 @@ final class PSQLRowStream: @unchecked Sendable {
353
377
preconditionFailure ( " How can we get another end, if an end was already signalled? " )
354
378
355
379
case . iteratingRows( _, let promise, _) :
356
- self . downstreamState = . consumed( . success( commandTag) )
380
+ self . downstreamState = . consumed( . success( . tag ( commandTag) ) )
357
381
promise. succeed ( ( ) )
358
382
359
383
case . waitingForAll( let rows, let promise, _) :
360
- self . downstreamState = . consumed( . success( commandTag) )
384
+ self . downstreamState = . consumed( . success( . tag ( commandTag) ) )
361
385
promise. succeed ( rows)
362
386
363
387
case . asyncSequence( let source, _, let onFinish) :
364
- self . downstreamState = . consumed( . success( commandTag) )
388
+ self . downstreamState = . consumed( . success( . tag ( commandTag) ) )
365
389
source. finish ( )
366
390
onFinish ( )
367
391
368
- case . consumed:
392
+ case . consumed( . success ( . tag ) ) , . consumed ( . failure ) :
369
393
break
394
+
395
+ case . consumed( . success( . emptyResponse) ) , . waitingForConsumer( . empty) :
396
+ preconditionFailure ( " How can we get an end for empty query response? " )
370
397
}
371
398
}
372
399
@@ -375,7 +402,7 @@ final class PSQLRowStream: @unchecked Sendable {
375
402
case . waitingForConsumer( . streaming) :
376
403
self . downstreamState = . waitingForConsumer( . failure( error) )
377
404
378
- case . waitingForConsumer( . finished) , . waitingForConsumer( . failure) :
405
+ case . waitingForConsumer( . finished) , . waitingForConsumer( . failure) , . waitingForConsumer ( . empty ) :
379
406
preconditionFailure ( " How can we get another end, if an end was already signalled? " )
380
407
381
408
case . iteratingRows( _, let promise, _) :
@@ -391,8 +418,11 @@ final class PSQLRowStream: @unchecked Sendable {
391
418
consumer. finish ( error)
392
419
onFinish ( )
393
420
394
- case . consumed:
421
+ case . consumed( . success ( . tag ) ) , . consumed ( . failure ) :
395
422
break
423
+
424
+ case . consumed( . success( . emptyResponse) ) :
425
+ preconditionFailure ( " How can we get an error for empty query response? " )
396
426
}
397
427
}
398
428
@@ -413,10 +443,15 @@ final class PSQLRowStream: @unchecked Sendable {
413
443
}
414
444
415
445
var commandTag : String {
416
- guard case . consumed( . success( let commandTag ) ) = self . downstreamState else {
446
+ guard case . consumed( . success( let consumed ) ) = self . downstreamState else {
417
447
preconditionFailure ( " commandTag may only be called if all rows have been consumed " )
418
448
}
419
- return commandTag
449
+ switch consumed {
450
+ case . tag( let tag) :
451
+ return tag
452
+ case . emptyResponse:
453
+ return " "
454
+ }
420
455
}
421
456
}
422
457
0 commit comments