@@ -39,7 +39,7 @@ public struct CoreDataEncoder {
39
39
fileprivate func encode< Encodable : CoreDataCodable > ( _ encodable: Encodable , codingPath: [ CodingKey ] ) throws -> NSManagedObject {
40
40
41
41
// get managed object
42
- let managedObject = try encodable. findOrCreate ( in: managedObjectContext)
42
+ let managedObject = try encodable. coreDataIdentifier . findOrCreate ( in: managedObjectContext)
43
43
44
44
// create encoder for managed object
45
45
let encoder = Encoder ( managedObjectContext: managedObjectContext,
@@ -274,10 +274,58 @@ fileprivate extension CoreDataEncoder {
274
274
// Custom
275
275
private mutating func encode( _ value: Data , forKey key: Key ) throws { try write ( box ( value) , forKey: key) }
276
276
private mutating func encode( _ value: Date , forKey key: Key ) throws { try write ( box ( value) , forKey: key) }
277
- private mutating func encode( _ value: UUID , forKey key: Key ) throws { try write ( box ( value) , forKey: key) }
278
- private mutating func encode( _ value: URL , forKey key: Key ) throws { try write ( box ( value) , forKey: key) }
279
277
private mutating func encode( _ value: Decimal , forKey key: Key ) throws { try write ( box ( value) , forKey: key) }
280
278
279
+ private mutating func encode( _ value: UUID , forKey key: Key ) throws {
280
+
281
+ // check if attribute is string
282
+ let attribute = container. entity. attributesByName [ key. stringValue] ? . attributeType ?? . undefinedAttributeType
283
+
284
+ switch attribute {
285
+
286
+ case . UUIDAttributeType:
287
+
288
+ try write ( box ( value) , forKey: key)
289
+
290
+ case . stringAttributeType:
291
+
292
+ try write ( box ( value. uuidString) , forKey: key)
293
+
294
+ default :
295
+
296
+ // set coding key context
297
+ codingPath. append ( key)
298
+ defer { codingPath. removeLast ( ) }
299
+
300
+ throw EncodingError . invalidValue ( value, EncodingError . Context ( codingPath: codingPath, debugDescription: " Invalid value type " ) )
301
+ }
302
+ }
303
+
304
+ private mutating func encode( _ value: URL , forKey key: Key ) throws {
305
+
306
+ // check if attribute is string
307
+ let attribute = container. entity. attributesByName [ key. stringValue] ? . attributeType ?? . undefinedAttributeType
308
+
309
+ switch attribute {
310
+
311
+ case . URIAttributeType:
312
+
313
+ try write ( box ( value) , forKey: key)
314
+
315
+ case . stringAttributeType:
316
+
317
+ try write ( box ( value. absoluteString) , forKey: key)
318
+
319
+ default :
320
+
321
+ // set coding key context
322
+ codingPath. append ( key)
323
+ defer { codingPath. removeLast ( ) }
324
+
325
+ throw EncodingError . invalidValue ( value, EncodingError . Context ( codingPath: codingPath, debugDescription: " Invalid value type " ) )
326
+ }
327
+ }
328
+
281
329
// Encodable
282
330
public mutating func encode< T: Swift . Encodable > ( _ value: T , forKey key: Key ) throws {
283
331
@@ -287,9 +335,7 @@ fileprivate extension CoreDataEncoder {
287
335
// identifier or to-one relationship
288
336
if let identifier = value as? CoreDataIdentifier {
289
337
290
- let encodable = encoder. encodable
291
-
292
- let identifierKey = type ( of: encodable) . identifierKey
338
+ let identifierKey = type ( of: encoder. encodable) . identifierKey. stringValue
293
339
294
340
// identifier
295
341
if key. stringValue == identifierKey {
@@ -402,25 +448,33 @@ fileprivate extension CoreDataEncoder {
402
448
403
449
private mutating func setRelationship( _ encodables: [ CoreDataCodable ] , forKey key: Key ) throws {
404
450
405
- let managedObjects = try encodables. map { ( try $0. findOrCreate ( in: encoder. managedObjectContext) , $0) }
451
+ let managedObjectContext = encoder. managedObjectContext
452
+
453
+ var managedObjects = [ NSManagedObject] ( )
454
+ managedObjects. reserveCapacity ( encodables. count)
406
455
407
- try managedObjects. forEach {
456
+ for (index, encodable) in encodables. enumerated ( ) {
457
+
458
+ let codingPath : [ CodingKey ] = self . codingPath + [ key, Index ( intValue: index) ]
459
+
460
+ let managedObject = try encodable. coreDataIdentifier. findOrCreate ( in: managedObjectContext)
461
+ managedObjects. append ( managedObject)
408
462
409
463
// create encoder for managed object
410
464
let encoder = Encoder ( managedObjectContext: self . encoder. managedObjectContext,
411
- managedObject: $0 ,
412
- encodable: $1 ,
413
- codingPath: self . encoder . codingPath,
465
+ managedObject: managedObject ,
466
+ encodable: encodable ,
467
+ codingPath: codingPath,
414
468
userInfo: self . encoder. userInfo,
415
469
log: self . encoder. log)
416
470
417
471
// encoder into container
418
- try $1 . encode ( to: encoder)
472
+ try encodable . encode ( to: encoder)
419
473
}
420
474
421
475
let isOrdered = self . encoder. managedObject. entity. relationshipsByName [ key. stringValue] ? . isOrdered ?? false
422
476
423
- let set : NSObject = isOrdered ? NSOrderedSet ( array: managedObjects. map ( { $0 . 0 } ) ) : NSSet ( array: managedObjects. map ( { $0 . 0 } ) )
477
+ let set : NSObject = isOrdered ? NSOrderedSet ( array: managedObjects) : NSSet ( array: managedObjects)
424
478
425
479
// set value
426
480
try write ( set, forKey: key)
@@ -437,13 +491,15 @@ fileprivate extension CoreDataEncoder {
437
491
438
492
private mutating func setRelationship( _ encodable: CoreDataCodable , forKey key: Key ) throws {
439
493
440
- let managedObject = try encodable. findOrCreate ( in: self . encoder. managedObjectContext)
494
+ let managedObject = try encodable. coreDataIdentifier. findOrCreate ( in: self . encoder. managedObjectContext)
495
+
496
+ let codingPath : [ CodingKey ] = self . codingPath + [ key]
441
497
442
498
// create encoder for managed object
443
499
let newEncoder = Encoder ( managedObjectContext: self . encoder. managedObjectContext,
444
500
managedObject: managedObject,
445
501
encodable: encodable,
446
- codingPath: self . encoder . codingPath,
502
+ codingPath: codingPath,
447
503
userInfo: self . encoder. userInfo,
448
504
log: self . encoder. log)
449
505
@@ -759,3 +815,30 @@ fileprivate extension CoreDataEncoder.Encoder {
759
815
}
760
816
}
761
817
}
818
+
819
+ fileprivate extension CoreDataEncoder {
820
+
821
+ struct Index : CodingKey {
822
+
823
+ public let index : Int
824
+
825
+ public init ( intValue: Int ) {
826
+
827
+ self . index = intValue
828
+ }
829
+
830
+ init ? ( stringValue: String ) {
831
+
832
+ return nil
833
+ }
834
+
835
+ public var intValue : Int ? {
836
+ return index
837
+ }
838
+
839
+ public var stringValue : String {
840
+ return " \( index) "
841
+ }
842
+ }
843
+ }
844
+
0 commit comments