@@ -86,12 +86,22 @@ extension QueryType {
8686 /// - Returns: An `INSERT` statement for the encodable objects
8787 public func insertMany( _ encodables: [ Encodable ] , userInfo: [ CodingUserInfoKey : Any ] = [ : ] ,
8888 otherSetters: [ Setter ] = [ ] ) throws -> Insert {
89- let combinedSetters = try encodables. map { encodable -> [ Setter ] in
90- let encoder = SQLiteEncoder ( userInfo: userInfo)
89+ let combinedSettersWithoutNils = try encodables. map { encodable -> [ Setter ] in
90+ let encoder = SQLiteEncoder ( userInfo: userInfo, forcingNilValueSetters : false )
9191 try encodable. encode ( to: encoder)
9292 return encoder. setters + otherSetters
9393 }
94- return self . insertMany ( combinedSetters)
94+ // requires the same number of setters per encodable
95+ guard Set ( combinedSettersWithoutNils. map ( \. count) ) . count == 1 else {
96+ // asymmetric sets of value insertions (some nil, some not), requires NULL value to satisfy INSERT query
97+ let combinedSymmetricSetters = try encodables. map { encodable -> [ Setter ] in
98+ let encoder = SQLiteEncoder ( userInfo: userInfo, forcingNilValueSetters: true )
99+ try encodable. encode ( to: encoder)
100+ return encoder. setters + otherSetters
101+ }
102+ return self . insertMany ( combinedSymmetricSetters)
103+ }
104+ return self . insertMany ( combinedSettersWithoutNils)
95105 }
96106
97107 /// Creates an `INSERT ON CONFLICT DO UPDATE` statement, aka upsert, by encoding the given object
@@ -165,9 +175,11 @@ private class SQLiteEncoder: Encoder {
165175
166176 let encoder : SQLiteEncoder
167177 let codingPath : [ CodingKey ] = [ ]
178+ let forcingNilValueSetters : Bool
168179
169- init ( encoder: SQLiteEncoder ) {
180+ init ( encoder: SQLiteEncoder , forcingNilValueSetters : Bool = false ) {
170181 self . encoder = encoder
182+ self . forcingNilValueSetters = forcingNilValueSetters
171183 }
172184
173185 func superEncoder( ) -> Swift . Encoder {
@@ -202,6 +214,46 @@ private class SQLiteEncoder: Encoder {
202214 encoder. setters. append ( Expression ( key. stringValue) <- value)
203215 }
204216
217+ func encodeIfPresent( _ value: Int ? , forKey key: SQLiteEncoder . SQLiteKeyedEncodingContainer < Key > . Key ) throws {
218+ if let value = value {
219+ encoder. setters. append ( Expression ( key. stringValue) <- value)
220+ } else if forcingNilValueSetters {
221+ encoder. setters. append ( Expression < Int ? > ( key. stringValue) <- nil )
222+ }
223+ }
224+
225+ func encodeIfPresent( _ value: Bool ? , forKey key: Key ) throws {
226+ if let value = value {
227+ encoder. setters. append ( Expression ( key. stringValue) <- value)
228+ } else if forcingNilValueSetters {
229+ encoder. setters. append ( Expression < Bool ? > ( key. stringValue) <- nil )
230+ }
231+ }
232+
233+ func encodeIfPresent( _ value: Float ? , forKey key: Key ) throws {
234+ if let value = value {
235+ encoder. setters. append ( Expression ( key. stringValue) <- Double ( value) )
236+ } else if forcingNilValueSetters{
237+ encoder. setters. append ( Expression < Double ? > ( key. stringValue) <- nil )
238+ }
239+ }
240+
241+ func encodeIfPresent( _ value: Double ? , forKey key: Key ) throws {
242+ if let value = value {
243+ encoder. setters. append ( Expression ( key. stringValue) <- value)
244+ } else if forcingNilValueSetters {
245+ encoder. setters. append ( Expression < Double ? > ( key. stringValue) <- nil )
246+ }
247+ }
248+
249+ func encodeIfPresent( _ value: String ? , forKey key: MyKey ) throws {
250+ if let value = value {
251+ encoder. setters. append ( Expression ( key. stringValue) <- value)
252+ } else if forcingNilValueSetters {
253+ encoder. setters. append ( Expression < String ? > ( key. stringValue) <- nil )
254+ }
255+ }
256+
205257 func encode< T> ( _ value: T , forKey key: Key ) throws where T: Swift . Encodable {
206258 switch value {
207259 case let data as Data :
@@ -217,6 +269,28 @@ private class SQLiteEncoder: Encoder {
217269 }
218270 }
219271
272+ func encodeIfPresent< T> ( _ value: T ? , forKey key: Key ) throws where T: Swift . Encodable {
273+ guard let value = value else {
274+ guard forcingNilValueSetters else {
275+ return
276+ }
277+ encoder. setters. append ( Expression < String ? > ( key. stringValue) <- nil )
278+ return
279+ }
280+ switch value {
281+ case let data as Data :
282+ encoder. setters. append ( Expression ( key. stringValue) <- data)
283+ case let date as Date :
284+ encoder. setters. append ( Expression ( key. stringValue) <- date. datatypeValue)
285+ case let uuid as UUID :
286+ encoder. setters. append ( Expression ( key. stringValue) <- uuid. datatypeValue)
287+ default :
288+ let encoded = try JSONEncoder ( ) . encode ( value)
289+ let string = String ( data: encoded, encoding: . utf8)
290+ encoder. setters. append ( Expression ( key. stringValue) <- string)
291+ }
292+ }
293+
220294 func encode( _ value: Int8 , forKey key: Key ) throws {
221295 throw EncodingError . invalidValue ( value, EncodingError . Context ( codingPath: codingPath,
222296 debugDescription: " encoding an Int8 is not supported " ) )
@@ -274,9 +348,11 @@ private class SQLiteEncoder: Encoder {
274348 fileprivate var setters : [ Setter ] = [ ]
275349 let codingPath : [ CodingKey ] = [ ]
276350 let userInfo : [ CodingUserInfoKey : Any ]
351+ let forcingNilValueSetters : Bool
277352
278- init ( userInfo: [ CodingUserInfoKey : Any ] ) {
353+ init ( userInfo: [ CodingUserInfoKey : Any ] , forcingNilValueSetters : Bool = false ) {
279354 self . userInfo = userInfo
355+ self . forcingNilValueSetters = forcingNilValueSetters
280356 }
281357
282358 func singleValueContainer( ) -> SingleValueEncodingContainer {
@@ -288,7 +364,7 @@ private class SQLiteEncoder: Encoder {
288364 }
289365
290366 func container< Key> ( keyedBy type: Key . Type ) -> KeyedEncodingContainer < Key > where Key: CodingKey {
291- KeyedEncodingContainer ( SQLiteKeyedEncodingContainer ( encoder: self ) )
367+ KeyedEncodingContainer ( SQLiteKeyedEncodingContainer ( encoder: self , forcingNilValueSetters : forcingNilValueSetters ) )
292368 }
293369}
294370
0 commit comments