@@ -108,8 +108,12 @@ private struct _RowDecoder<R: FetchableRecord>: Decoder {
108108
109109 func singleValueContainer( ) throws -> SingleValueDecodingContainer {
110110 guard let key = codingPath. last else {
111- // Decoding an array of scalars from rows: pick the first column
112- return ColumnDecoder < R > ( row: row, columnIndex: 0 , codingPath: codingPath)
111+ // Not yet sure what we are decoding, this will be decided in the SingleValueDecodingContainer functions.
112+ // For decoding an array of scalars (in case of prefetched rows) we pick the first column.
113+ return SingleValueRowDecoder (
114+ columnDecoder: ColumnDecoder < R > ( row: row, columnIndex: 0 , codingPath: codingPath) ,
115+ columnDecodingStrategy: columnDecodingStrategy
116+ )
113117 }
114118 guard let index = row. index ( forColumn: key. stringValue) else {
115119 // Don't use DecodingError.keyNotFound:
@@ -346,7 +350,7 @@ private struct _RowDecoder<R: FetchableRecord>: Decoder {
346350
347351 // Unknown key
348352 //
349- // Should be throw an error? Well... The use case is the following:
353+ // Should we throw an error? Well... The use case is the following:
350354 //
351355 // // SELECT book.*, author.* FROM book
352356 // // JOIN author ON author.id = book.authorId
@@ -487,6 +491,50 @@ private struct _RowDecoder<R: FetchableRecord>: Decoder {
487491 }
488492}
489493
494+ private struct SingleValueRowDecoder < R: FetchableRecord > : SingleValueDecodingContainer {
495+ var columnDecoder : ColumnDecoder < R >
496+ var columnDecodingStrategy : DatabaseColumnDecodingStrategy
497+ let codingPath : [ any CodingKey ] = [ ]
498+
499+ func decodeNil( ) -> Bool { columnDecoder. decodeNil ( ) }
500+ func decode( _ type: Bool . Type ) throws -> Bool { try columnDecoder. decode ( type) }
501+ func decode( _ type: String . Type ) throws -> String { try columnDecoder. decode ( type) }
502+ func decode( _ type: Double . Type ) throws -> Double { try columnDecoder. decode ( type) }
503+ func decode( _ type: Float . Type ) throws -> Float { try columnDecoder. decode ( type) }
504+ func decode( _ type: Int . Type ) throws -> Int { try columnDecoder. decode ( type) }
505+ func decode( _ type: Int8 . Type ) throws -> Int8 { try columnDecoder. decode ( type) }
506+ func decode( _ type: Int16 . Type ) throws -> Int16 { try columnDecoder. decode ( type) }
507+ func decode( _ type: Int32 . Type ) throws -> Int32 { try columnDecoder. decode ( type) }
508+ func decode( _ type: Int64 . Type ) throws -> Int64 { try columnDecoder. decode ( type) }
509+ #if compiler(>=6)
510+ @available ( macOS 15 . 0 , iOS 18 . 0 , watchOS 11 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , * )
511+ func decode( _ type: Int128 . Type ) throws -> Int128 { try columnDecoder. decode ( type) }
512+ #endif
513+ func decode( _ type: UInt . Type ) throws -> UInt { try columnDecoder. decode ( type) }
514+ func decode( _ type: UInt8 . Type ) throws -> UInt8 { try columnDecoder. decode ( type) }
515+ func decode( _ type: UInt16 . Type ) throws -> UInt16 { try columnDecoder. decode ( type) }
516+ func decode( _ type: UInt32 . Type ) throws -> UInt32 { try columnDecoder. decode ( type) }
517+ func decode( _ type: UInt64 . Type ) throws -> UInt64 { try columnDecoder. decode ( type) }
518+ #if compiler(>=6)
519+ @available ( macOS 15 . 0 , iOS 18 . 0 , watchOS 11 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , * )
520+ func decode( _ type: UInt128 . Type ) throws -> UInt128 { try columnDecoder. decode ( type) }
521+ #endif
522+
523+ func decode< T> ( _ type: T . Type ) throws -> T where T: Decodable {
524+ if let type = T . self as? any FetchableRecord . Type {
525+ // Prefer FetchableRecord decoding over Decodable.
526+ return try type. init ( row: columnDecoder. row) as! T
527+ } else {
528+ let decoder = _RowDecoder < R > (
529+ row: columnDecoder. row,
530+ codingPath: [ ] ,
531+ columnDecodingStrategy: columnDecodingStrategy
532+ )
533+ return try T ( from: decoder)
534+ }
535+ }
536+ }
537+
490538// MARK: - PrefetchedRowsDecoder
491539
492540private struct PrefetchedRowsDecoder < R: FetchableRecord > : Decoder {
0 commit comments