55// Created by Mathew Polzin on 8/31/18.
66//
77
8- public protocol RelationshipType : Codable { }
8+ public protocol RelationshipType : Codable {
9+ associatedtype LinksType
10+ associatedtype MetaType
11+
12+ var links : LinksType { get }
13+ var meta : MetaType { get }
14+ }
915
1016/// An Entity relationship that can be encoded to or decoded from
1117/// a JSON API "Resource Linkage."
1218/// See https://jsonapi.org/format/#document-resource-object-linkage
1319/// A convenient typealias might make your code much more legible: `One<EntityDescription>`
14- public struct ToOneRelationship < Relatable: JSONAPI . OptionalRelatable > : RelationshipType , Equatable {
20+ public struct ToOneRelationship < Relatable: JSONAPI . OptionalRelatable , MetaType : JSONAPI . Meta , LinksType : JSONAPI . Links > : RelationshipType , Equatable {
1521
1622 public let id : Relatable . WrappedIdentifier
1723
18- public init ( id: Relatable . WrappedIdentifier ) {
24+ public let meta : MetaType
25+ public let links : LinksType
26+
27+ public init ( id: Relatable . WrappedIdentifier , meta: MetaType , links: LinksType ) {
1928 self . id = id
29+ self . meta = meta
30+ self . links = links
31+ }
32+ }
33+
34+ extension ToOneRelationship where MetaType == NoMetadata , LinksType == NoLinks {
35+ public init ( id: Relatable . WrappedIdentifier ) {
36+ self . init ( id: id, meta: . none, links: . none)
2037 }
2138}
2239
2340extension ToOneRelationship where Relatable. WrappedIdentifier == Relatable . Identifier {
41+ public init < E: EntityType > ( entity: E , meta: MetaType , links: LinksType ) where E. Description == Relatable . Description , E. Id == Relatable . Identifier {
42+ self . init ( id: entity. id, meta: meta, links: links)
43+ }
44+ }
45+
46+ extension ToOneRelationship where Relatable. WrappedIdentifier == Relatable . Identifier , MetaType == NoMetadata , LinksType == NoLinks {
2447 public init < E: EntityType > ( entity: E ) where E. Description == Relatable . Description , E. Id == Relatable . Identifier {
25- id = entity. id
48+ self . init ( id : entity. id, meta : . none , links : . none )
2649 }
2750}
2851
2952extension ToOneRelationship where Relatable. WrappedIdentifier == Relatable . Identifier ? {
53+ public init < E: EntityType > ( entity: E ? , meta: MetaType , links: LinksType ) where E. Description == Relatable . Description , E. Id == Relatable . Identifier {
54+ self . init ( id: entity? . id, meta: meta, links: links)
55+ }
56+ }
57+
58+ extension ToOneRelationship where Relatable. WrappedIdentifier == Relatable . Identifier ? , MetaType == NoMetadata , LinksType == NoLinks {
3059 public init < E: EntityType > ( entity: E ? ) where E. Description == Relatable . Description , E. Id == Relatable . Identifier {
31- id = entity? . id
60+ self . init ( id : entity? . id, meta : . none , links : . none )
3261 }
3362}
3463
3564/// An Entity relationship that can be encoded to or decoded from
3665/// a JSON API "Resource Linkage."
3766/// See https://jsonapi.org/format/#document-resource-object-linkage
3867/// A convenient typealias might make your code much more legible: `Many<EntityDescription>`
39- public struct ToManyRelationship < Relatable: JSONAPI . Relatable > : RelationshipType , Equatable {
68+ public struct ToManyRelationship < Relatable: JSONAPI . Relatable , MetaType : JSONAPI . Meta , LinksType : JSONAPI . Links > : RelationshipType , Equatable {
4069
4170 public let ids : [ Relatable . Identifier ]
4271
43- public init ( ids: [ Relatable . Identifier ] ) {
72+ public let meta : MetaType
73+ public let links : LinksType
74+
75+ public init ( ids: [ Relatable . Identifier ] , meta: MetaType , links: LinksType ) {
4476 self . ids = ids
77+ self . meta = meta
78+ self . links = links
4579 }
4680
47- public init < T: JSONAPI . Relatable > ( relationships: [ ToOneRelationship < T > ] ) where T. WrappedIdentifier == Relatable . Identifier {
81+ public init < T: JSONAPI . Relatable > ( relationships: [ ToOneRelationship < T , NoMetadata , NoLinks > ] , meta : MetaType , links : LinksType ) where T. WrappedIdentifier == Relatable . Identifier {
4882 ids = relationships. map { $0. id }
83+ self . meta = meta
84+ self . links = links
85+ }
86+
87+ public init < E: EntityType > ( entities: [ E ] , meta: MetaType , links: LinksType ) where E. Description == Relatable . Description , E. Id == Relatable . Identifier {
88+ self . init ( ids: entities. map { $0. id } , meta: meta, links: links)
4989 }
5090
51- private init ( ) {
52- ids = [ ]
91+ private init ( meta : MetaType , links : LinksType ) {
92+ self . init ( ids: [ ] , meta : meta , links : links )
5393 }
5494
55- public static var none : ToManyRelationship {
56- return . init ( )
95+ public static func none( withMeta meta : MetaType , links : LinksType ) -> ToManyRelationship {
96+ return ToManyRelationship ( meta : meta , links : links )
5797 }
5898}
5999
60- extension ToManyRelationship {
100+ extension ToManyRelationship where MetaType == NoMetadata , LinksType == NoLinks {
101+
102+ public init ( ids: [ Relatable . Identifier ] ) {
103+ self . init ( ids: ids, meta: . none, links: . none)
104+ }
105+
106+ public init < T: JSONAPI . Relatable > ( relationships: [ ToOneRelationship < T , NoMetadata , NoLinks > ] ) where T. WrappedIdentifier == Relatable . Identifier {
107+ self . init ( relationships: relationships, meta: . none, links: . none)
108+ }
109+
110+ public static var none : ToManyRelationship {
111+ return . none( withMeta: . none, links: . none)
112+ }
113+
61114 public init < E: EntityType > ( entities: [ E ] ) where E. Description == Relatable . Description , E. Id == Relatable . Identifier {
62- ids = entities. map { $0 . id }
115+ self . init ( entities : entities, meta : . none , links : . none )
63116 }
64117}
65118
@@ -85,6 +138,8 @@ extension Optional: OptionalRelatable where Wrapped: Relatable {
85138// MARK: Codable
86139private enum ResourceLinkageCodingKeys : String , CodingKey {
87140 case data = " data "
141+ case meta = " meta "
142+ case links = " links "
88143}
89144private enum ResourceIdentifierCodingKeys : String , CodingKey {
90145 case id = " id "
@@ -103,6 +158,18 @@ extension ToOneRelationship {
103158 public init ( from decoder: Decoder ) throws {
104159 let container = try decoder. container ( keyedBy: ResourceLinkageCodingKeys . self)
105160
161+ if let noMeta = NoMetadata ( ) as? MetaType {
162+ meta = noMeta
163+ } else {
164+ meta = try container. decode ( MetaType . self, forKey: . meta)
165+ }
166+
167+ if let noLinks = NoLinks ( ) as? LinksType {
168+ links = noLinks
169+ } else {
170+ links = try container. decode ( LinksType . self, forKey: . links)
171+ }
172+
106173 // A little trickery follows. If the id is nil, the
107174 // container.decode(Identifier.self) will fail even if Identifier
108175 // is Optional. However, we can check if decoding nil
@@ -133,6 +200,14 @@ extension ToOneRelationship {
133200 try container. encodeNil ( forKey: . data)
134201 }
135202
203+ if MetaType . self != NoMetadata . self {
204+ try container. encode ( meta, forKey: . meta)
205+ }
206+
207+ if LinksType . self != NoLinks . self {
208+ try container. encode ( links, forKey: . links)
209+ }
210+
136211 var identifier = container. nestedContainer ( keyedBy: ResourceIdentifierCodingKeys . self, forKey: . data)
137212
138213 try identifier. encode ( id, forKey: . id)
@@ -143,7 +218,19 @@ extension ToOneRelationship {
143218extension ToManyRelationship {
144219 public init ( from decoder: Decoder ) throws {
145220 let container = try decoder. container ( keyedBy: ResourceLinkageCodingKeys . self)
146-
221+
222+ if let noMeta = NoMetadata ( ) as? MetaType {
223+ meta = noMeta
224+ } else {
225+ meta = try container. decode ( MetaType . self, forKey: . meta)
226+ }
227+
228+ if let noLinks = NoLinks ( ) as? LinksType {
229+ links = noLinks
230+ } else {
231+ links = try container. decode ( LinksType . self, forKey: . links)
232+ }
233+
147234 var identifiers = try container. nestedUnkeyedContainer ( forKey: . data)
148235
149236 var newIds = [ Relatable . Identifier] ( )
@@ -163,6 +250,15 @@ extension ToManyRelationship {
163250
164251 public func encode( to encoder: Encoder ) throws {
165252 var container = encoder. container ( keyedBy: ResourceLinkageCodingKeys . self)
253+
254+ if MetaType . self != NoMetadata . self {
255+ try container. encode ( meta, forKey: . meta)
256+ }
257+
258+ if LinksType . self != NoLinks . self {
259+ try container. encode ( links, forKey: . links)
260+ }
261+
166262 var identifiers = container. nestedUnkeyedContainer ( forKey: . data)
167263
168264 for id in ids {
0 commit comments