@@ -55,8 +55,19 @@ internal final class ModelDataEncoder: Encoder {
5555 self . userInfo = userInfo
5656 self . log = log
5757 self . data = ModelData ( entity: entity. id, id: id)
58- self . attributes = . init( grouping: entity. attributes, by: { $0. id. rawValue } )
59- self . relationships = . init( grouping: entity. relationships, by: { $0. id. rawValue } )
58+ // properties cache
59+ var attributes = [ PropertyKey: Attribute] ( )
60+ attributes. reserveCapacity ( entity. attributes. count)
61+ for attribute in entity. attributes {
62+ attributes [ attribute. id] = attribute
63+ }
64+ self . attributes = attributes //.init(grouping: entity.attributes, by: { $0.id })
65+ var relationships = [ PropertyKey: Relationship] ( )
66+ relationships. reserveCapacity ( entity. relationships. count)
67+ for relationship in entity. relationships {
68+ relationships [ relationship. id] = relationship
69+ }
70+ self . relationships = relationships //.init(grouping: entity.relationships, by: { $0.id })
6071 }
6172
6273 func container< Key> ( keyedBy type: Key . Type ) -> Swift . KeyedEncodingContainer < Key > where Key : CodingKey {
@@ -67,13 +78,13 @@ internal final class ModelDataEncoder: Encoder {
6778
6879 func unkeyedContainer( ) -> Swift . UnkeyedEncodingContainer {
6980 log ? ( " Requested unkeyed container for path \" \( codingPath. path) \" " )
70- return ModelUnkeyedEncodingContainer ( encoder : self )
81+ return ModelUnkeyedEncodingContainer ( referencing : self )
7182 }
7283
7384 func singleValueContainer( ) -> Swift . SingleValueEncodingContainer {
7485 log ? ( " Requested single value container for path \" \( codingPath. path) \" " )
7586 assert ( self . codingPath. last != nil )
76- return ModelSingleValueEncodingContainer ( encoder : self )
87+ return ModelSingleValueEncodingContainer ( referencing : self )
7788 }
7889}
7990
@@ -272,7 +283,7 @@ struct ModelKeyedEncodingContainer<K : CodingKey> : KeyedEncodingContainerProtoc
272283
273284// MARK: - SingleValueEncodingContainer
274285
275- internal final class ModelSingleValueEncodingContainer : SingleValueEncodingContainer {
286+ struct ModelSingleValueEncodingContainer : SingleValueEncodingContainer {
276287
277288 // MARK: Properties
278289
@@ -372,3 +383,142 @@ internal final class ModelSingleValueEncodingContainer: SingleValueEncodingConta
372383 try encoder. setAttribute ( value. attributeValue, forKey: key)
373384 }
374385}
386+
387+
388+ // MARK: - UnkeyedEncodingContainer
389+
390+ internal final class ModelUnkeyedEncodingContainer : UnkeyedEncodingContainer {
391+
392+ // MARK: Properties
393+
394+ /// A reference to the encoder we're writing to.
395+ let encoder : ModelDataEncoder
396+
397+ /// The path of coding keys taken to get to this point in encoding.
398+ let codingPath : [ CodingKey ]
399+
400+ private var objectIDs = [ ObjectID] ( )
401+
402+ // MARK: Initialization
403+
404+ init ( referencing encoder: ModelDataEncoder ) {
405+ self . encoder = encoder
406+ self . codingPath = encoder. codingPath
407+ }
408+
409+ deinit {
410+ writeArray ( )
411+ }
412+
413+ // MARK: - Methods
414+
415+ var count : Int {
416+ objectIDs. count
417+ }
418+
419+ func encodeNil( ) throws {
420+ throw EncodingError . invalidValue ( type ( of: Optional< Any> . self ) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( Optional< Any> . self ) " ) )
421+ }
422+
423+ func encode( _ value: String ) throws {
424+ try encodeRelationship ( value)
425+ }
426+
427+ func encode( _ value: Bool ) throws {
428+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
429+ }
430+
431+ func encode( _ value: Double ) throws {
432+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
433+ }
434+
435+ func encode( _ value: Float ) throws {
436+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
437+ }
438+
439+ func encode( _ value: Int ) throws {
440+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
441+ }
442+
443+ func encode( _ value: Int8 ) throws {
444+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
445+ }
446+
447+ func encode( _ value: Int16 ) throws {
448+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
449+ }
450+
451+ func encode( _ value: Int32 ) throws {
452+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
453+ }
454+
455+ func encode( _ value: Int64 ) throws {
456+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
457+ }
458+
459+ func encode( _ value: UInt ) throws {
460+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
461+ }
462+
463+ func encode( _ value: UInt8 ) throws {
464+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
465+ }
466+
467+ func encode( _ value: UInt16 ) throws {
468+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
469+ }
470+
471+ func encode( _ value: UInt32 ) throws {
472+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
473+ }
474+
475+ func encode( _ value: UInt64 ) throws {
476+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
477+ }
478+
479+ func encode < T: Encodable > ( _ value: T ) throws {
480+ guard let stringConvertible = value as? CustomStringConvertible else {
481+ throw EncodingError . invalidValue ( type ( of: value) , EncodingError . Context ( codingPath: codingPath, debugDescription: " Cannot encode to-many relationship of \( type ( of: value) ) " ) )
482+ }
483+ let string = stringConvertible. description
484+ try encodeRelationship ( string)
485+ }
486+
487+ func nestedContainer< NestedKey> ( keyedBy keyType: NestedKey . Type ) -> KeyedEncodingContainer < NestedKey > where NestedKey : CodingKey {
488+ fatalError ( )
489+ }
490+
491+ func nestedUnkeyedContainer( ) -> UnkeyedEncodingContainer {
492+ fatalError ( )
493+ }
494+
495+ func superEncoder( ) -> Encoder {
496+ encoder
497+ }
498+
499+ // MARK: Private Methods
500+
501+ private func propertyKey( ) throws -> PropertyKey {
502+ guard let key = codingPath. first else {
503+ throw EncodingError . invalidValue ( Any . self, EncodingError . Context ( codingPath: codingPath, debugDescription: " Invalid coding path " ) )
504+ }
505+ return PropertyKey ( key)
506+ }
507+
508+ private func encodeRelationship( _ string: String ) throws {
509+ objectIDs. append ( ObjectID ( rawValue: string) )
510+ }
511+
512+ private func writeArray( ) {
513+ // set key to be written
514+ guard let codingKey = codingPath. first else {
515+ //throw EncodingError.invalidValue(Any.self, EncodingError.Context(codingPath: codingPath, debugDescription: "Invalid coding path"))
516+ return
517+ }
518+ let key = PropertyKey ( codingKey)
519+ // write final value
520+ let value = RelationshipValue . toMany ( objectIDs)
521+ encoder. log ? ( " Will set \( value) for relationship \" \( key) \" " )
522+ encoder. data. relationships [ key] = value
523+ }
524+ }
0 commit comments