11import Async
2+ import CodableKit
23import FluentSQL
34import Foundation
45
@@ -17,13 +18,46 @@ extension PostgreSQLDatabase: QuerySupporting {
1718 // Dictionary values should be added to the parameterized array.
1819 let modelData : [ PostgreSQLData ]
1920 if let model = query. data {
20- let encoded = try PostgreSQLDataEncoder ( ) . encode ( model)
21+ let encoded = try CodableDataEncoder ( ) . encode ( model)
22+ print ( encoded)
2123 switch encoded {
2224 case . dictionary( let dict) :
2325 sqlQuery. columns += dict. keys. map { key in
2426 return DataColumn ( table: query. entity, name: key)
2527 }
26- modelData = . init( dict. values)
28+ modelData = try dict. values. map { codableData -> PostgreSQLData in
29+ switch codableData {
30+ case . bool( let value) : return try value. convertToPostgreSQLData ( )
31+ case . int( let value) : return try value. convertToPostgreSQLData ( )
32+ case . int8( let value) : return try value. convertToPostgreSQLData ( )
33+ case . int16( let value) : return try value. convertToPostgreSQLData ( )
34+ case . int32( let value) : return try value. convertToPostgreSQLData ( )
35+ case . int64( let value) : return try value. convertToPostgreSQLData ( )
36+ case . uint( let value) : return try value. convertToPostgreSQLData ( )
37+ case . uint8( let value) : return try value. convertToPostgreSQLData ( )
38+ case . uint16( let value) : return try value. convertToPostgreSQLData ( )
39+ case . uint32( let value) : return try value. convertToPostgreSQLData ( )
40+ case . uint64( let value) : return try value. convertToPostgreSQLData ( )
41+ case . float( let value) : return try value. convertToPostgreSQLData ( )
42+ case . double( let value) : return try value. convertToPostgreSQLData ( )
43+ case . string( let value) : return try value. convertToPostgreSQLData ( )
44+ case . null: return PostgreSQLData ( type: . void)
45+ case . encodable( let encodable) :
46+ guard let convertible = encodable as? PostgreSQLDataCustomConvertible else {
47+ let type = Swift . type ( of: encodable)
48+ throw PostgreSQLError (
49+ identifier: " convertible " ,
50+ reason: " Unsupported encodable type: \( type) " ,
51+ suggestedFixes: [
52+ " Conform \( type) to PostgreSQLDataCustomConvertible "
53+ ]
54+ )
55+ }
56+ return try convertible. convertToPostgreSQLData ( )
57+ case . array, . dictionary, . decoder:
58+ throw PostgreSQLError ( identifier: " codable " , reason: " Unsupported codable type: \( codableData) " )
59+ }
60+ }
2761 default :
2862 throw PostgreSQLError (
2963 identifier: " queryData " ,
@@ -41,11 +75,18 @@ extension PostgreSQLDatabase: QuerySupporting {
4175 // Combine the query data with bind values from filters.
4276 // All bind values must come _after_ the columns section of the query.
4377 let parameters = try modelData + bindValues. map { bind in
44- if let uuid = bind. encodable as? UUID {
45- return . uuid( uuid)
46- } else {
47- return try PostgreSQLDataEncoder ( ) . encode ( bind. encodable)
78+ let encodable = bind. encodable
79+ guard let convertible = encodable as? PostgreSQLDataCustomConvertible else {
80+ let type = Swift . type ( of: encodable)
81+ throw PostgreSQLError (
82+ identifier: " convertible " ,
83+ reason: " Unsupported encodable type: \( type) " ,
84+ suggestedFixes: [
85+ " Conform \( type) to PostgreSQLDataCustomConvertible "
86+ ]
87+ )
4888 }
89+ return try convertible. convertToPostgreSQLData ( )
4990 }
5091
5192 // Create a push stream to accept the psql output
@@ -55,8 +96,12 @@ extension PostgreSQLDatabase: QuerySupporting {
5596
5697 // Run the query
5798 return try connection. query ( sqlString, parameters) { row in
99+ let codableDict = row. mapValues { psqlData -> CodableData in
100+ return . decoder( PostgreSQLDataDecoder ( data: psqlData) )
101+ }
102+
58103 do {
59- let decoded = try PostgreSQLDataDecoder ( ) . decode ( D . self, from: . dictionary( row ) )
104+ let decoded = try CodableDataDecoder ( ) . decode ( D . self, from: . dictionary( codableDict ) )
60105 pushStream. push ( decoded)
61106 } catch {
62107 pushStream. error ( error)
@@ -87,7 +132,7 @@ extension PostgreSQLDatabase: QuerySupporting {
87132 case . didCreate:
88133 if M . ID. self == Int . self {
89134 return connection. simpleQuery ( " SELECT LASTVAL(); " ) . map ( to: Void . self) { row in
90- model. fluentID = row [ 0 ] [ " lastval " ] ? . int as? M . ID
135+ try ! model. fluentID = row [ 0 ] [ " lastval " ] ? . decode ( Int . self ) as? M . ID
91136 }
92137 }
93138 default : break
@@ -96,3 +141,62 @@ extension PostgreSQLDatabase: QuerySupporting {
96141 return . done
97142 }
98143}
144+
145+
146+ internal struct PostgreSQLDataDecoder : Decoder , SingleValueDecodingContainer {
147+
148+ var codingPath : [ CodingKey ]
149+ var userInfo : [ CodingUserInfoKey : Any ]
150+ let data : PostgreSQLData
151+ init ( data: PostgreSQLData ) {
152+ self . data = data
153+ self . userInfo = [ : ]
154+ self . codingPath = [ ]
155+ }
156+
157+ func singleValueContainer( ) throws -> SingleValueDecodingContainer { return self }
158+ func decodeNil( ) -> Bool { return data. data == nil }
159+ func decode( _ type: Int . Type ) throws -> Int { return try data. decode ( Int . self) }
160+ func decode( _ type: Int8 . Type ) throws -> Int8 { return try data. decode ( Int8 . self) }
161+ func decode( _ type: Int16 . Type ) throws -> Int16 { return try data. decode ( Int16 . self) }
162+ func decode( _ type: Int32 . Type ) throws -> Int32 { return try data. decode ( Int32 . self) }
163+ func decode( _ type: Int64 . Type ) throws -> Int64 { return try data. decode ( Int64 . self) }
164+ func decode( _ type: UInt . Type ) throws -> UInt { return try data. decode ( UInt . self) }
165+ func decode( _ type: UInt8 . Type ) throws -> UInt8 { return try data. decode ( UInt8 . self) }
166+ func decode( _ type: UInt16 . Type ) throws -> UInt16 { return try data. decode ( UInt16 . self) }
167+ func decode( _ type: UInt32 . Type ) throws -> UInt32 { return try data. decode ( UInt32 . self) }
168+ func decode( _ type: UInt64 . Type ) throws -> UInt64 { return try data. decode ( UInt64 . self) }
169+ func decode( _ type: Double . Type ) throws -> Double { return try data. decode ( Double . self) }
170+ func decode( _ type: Float . Type ) throws -> Float { return try data. decode ( Float . self) }
171+ func decode( _ type: Bool . Type ) throws -> Bool { return try data. decode ( Bool . self) }
172+ func decode( _ type: String . Type ) throws -> String { return try data. decode ( String . self) }
173+ func decode< T> ( _ type: T . Type ) throws -> T where T: Decodable {
174+ guard let convertible = type as? PostgreSQLDataCustomConvertible . Type else {
175+ throw PostgreSQLError (
176+ identifier: " convertible " ,
177+ reason: " Unsupported decodable type: \( type) " ,
178+ suggestedFixes: [
179+ " Conform \( type) to PostgreSQLDataCustomConvertible "
180+ ]
181+ )
182+ }
183+ return try convertible. convertFromPostgreSQLData ( data) as! T
184+ }
185+
186+ // unsupported
187+ func container< Key> ( keyedBy type: Key . Type ) throws -> KeyedDecodingContainer < Key > where Key : CodingKey {
188+ throw PostgreSQLError (
189+ identifier: " decoding " ,
190+ reason: " Keyed decoding container not supported " ,
191+ suggestedFixes: [ " Use a nested struct isntead " ]
192+ )
193+ }
194+
195+ func unkeyedContainer( ) throws -> UnkeyedDecodingContainer {
196+ throw PostgreSQLError (
197+ identifier: " decoding " ,
198+ reason: " Unkeyed decoding container not supported " ,
199+ suggestedFixes: [ " Use a nested struct isntead " ]
200+ )
201+ }
202+ }
0 commit comments