@@ -86,12 +86,22 @@ extension QueryType {
86
86
/// - Returns: An `INSERT` statement for the encodable objects
87
87
public func insertMany( _ encodables: [ Encodable ] , userInfo: [ CodingUserInfoKey : Any ] = [ : ] ,
88
88
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 )
91
91
try encodable. encode ( to: encoder)
92
92
return encoder. setters + otherSetters
93
93
}
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)
95
105
}
96
106
97
107
/// Creates an `INSERT ON CONFLICT DO UPDATE` statement, aka upsert, by encoding the given object
@@ -165,9 +175,11 @@ private class SQLiteEncoder: Encoder {
165
175
166
176
let encoder : SQLiteEncoder
167
177
let codingPath : [ CodingKey ] = [ ]
178
+ let forcingNilValueSetters : Bool
168
179
169
- init ( encoder: SQLiteEncoder ) {
180
+ init ( encoder: SQLiteEncoder , forcingNilValueSetters : Bool = false ) {
170
181
self . encoder = encoder
182
+ self . forcingNilValueSetters = forcingNilValueSetters
171
183
}
172
184
173
185
func superEncoder( ) -> Swift . Encoder {
@@ -202,6 +214,46 @@ private class SQLiteEncoder: Encoder {
202
214
encoder. setters. append ( Expression ( key. stringValue) <- value)
203
215
}
204
216
217
+ func encodeIfPresent( _ value: Int ? , forKey key: SQLiteEncoder . SQLiteKeyedEncodingContainer < Key > . Key ) throws {
218
+ if let value = value {
219
+ try encode ( value, forKey: key)
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
+ try encode ( value, forKey: key)
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
+ try encode ( value, forKey: key)
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
+ try encode ( value, forKey: key)
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
+ try encode ( value, forKey: key)
252
+ } else if forcingNilValueSetters {
253
+ encoder. setters. append ( Expression < String ? > ( key. stringValue) <- nil )
254
+ }
255
+ }
256
+
205
257
func encode< T> ( _ value: T , forKey key: Key ) throws where T: Swift . Encodable {
206
258
switch value {
207
259
case let data as Data :
@@ -217,6 +269,17 @@ private class SQLiteEncoder: Encoder {
217
269
}
218
270
}
219
271
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
+ try encode ( value, forKey: key)
281
+ }
282
+
220
283
func encode( _ value: Int8 , forKey key: Key ) throws {
221
284
throw EncodingError . invalidValue ( value, EncodingError . Context ( codingPath: codingPath,
222
285
debugDescription: " encoding an Int8 is not supported " ) )
@@ -274,9 +337,11 @@ private class SQLiteEncoder: Encoder {
274
337
fileprivate var setters : [ Setter ] = [ ]
275
338
let codingPath : [ CodingKey ] = [ ]
276
339
let userInfo : [ CodingUserInfoKey : Any ]
340
+ let forcingNilValueSetters : Bool
277
341
278
- init ( userInfo: [ CodingUserInfoKey : Any ] ) {
342
+ init ( userInfo: [ CodingUserInfoKey : Any ] , forcingNilValueSetters : Bool = false ) {
279
343
self . userInfo = userInfo
344
+ self . forcingNilValueSetters = forcingNilValueSetters
280
345
}
281
346
282
347
func singleValueContainer( ) -> SingleValueEncodingContainer {
@@ -288,7 +353,7 @@ private class SQLiteEncoder: Encoder {
288
353
}
289
354
290
355
func container< Key> ( keyedBy type: Key . Type ) -> KeyedEncodingContainer < Key > where Key: CodingKey {
291
- KeyedEncodingContainer ( SQLiteKeyedEncodingContainer ( encoder: self ) )
356
+ KeyedEncodingContainer ( SQLiteKeyedEncodingContainer ( encoder: self , forcingNilValueSetters : forcingNilValueSetters ) )
292
357
}
293
358
}
294
359
0 commit comments