@@ -154,41 +154,25 @@ internal struct MappedIncludes: Decodable {
154
154
}
155
155
156
156
init ( from decoder: Decoder ) throws {
157
- let container = try decoder. container ( keyedBy: CodingKeys . self)
158
-
159
- assets = try container. decodeIfPresent ( [ Asset ] . self, forKey: CodingKeys . assets)
157
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
158
+ assets = try container. decodeIfPresent ( [ Asset ] . self, forKey: . assets)
159
+ entries = try container. decodeHeterogeneousEntries ( forKey: . entries,
160
+ contentTypes: decoder. contentTypes,
161
+ throwIfNotPresent: false )
160
162
// Cache to enable link resolution.
161
163
if let assets = assets {
162
164
decoder. linkResolver. cache ( assets: assets)
163
165
}
164
-
165
- // A copy as an array of dictionaries just to extract "sys.type" field.
166
- guard let jsonItems = try container. decodeIfPresent ( Swift . Array< Any> . self , forKey: . entries) as? [ [ String : Any ] ] else {
167
- self . entries = nil
168
- return
169
- }
170
- var entriesJSONContainer = try container. nestedUnkeyedContainer ( forKey: . entries)
171
- var entries : [ EntryDecodable ] = [ ]
172
- let contentTypes = decoder. userInfo [ DecoderContext . contentTypesContextKey] as! [ ContentTypeId : EntryDecodable . Type ]
173
-
174
- while entriesJSONContainer. isAtEnd == false {
175
- let contentTypeInfo = try jsonItems. contentTypeInfo ( at: entriesJSONContainer. currentIndex)
176
-
177
- // For includes, if the type of this entry isn't defined by the user, we skip serialization.
178
- if let type = contentTypes [ contentTypeInfo. id] {
179
- let entryModellable = try type. popEntryDecodable ( from: & entriesJSONContainer)
180
- entries. append ( entryModellable)
181
- }
182
- }
183
- self . entries = entries
184
-
185
166
// Cache to enable link resolution.
186
- if let entries = self . entries {
167
+ if let entries = entries {
187
168
decoder. linkResolver. cache ( entryDecodables: entries)
188
169
}
189
170
}
190
171
}
191
172
173
+ // Empty type so that we can continue to the end of a UnkeyedContainer
174
+ internal struct EmptyDecodable : Decodable { }
175
+
192
176
extension MappedArrayResponse : Decodable {
193
177
194
178
public init ( from decoder: Decoder ) throws {
@@ -282,25 +266,9 @@ extension MixedMappedArrayResponse: Decodable {
282
266
283
267
// All items and includes.
284
268
includes = try container. decodeIfPresent ( MappedIncludes . self, forKey: . includes)
285
-
286
- // A copy as an array of dictionaries just to extract "sys.type" field.
287
- guard let jsonItems = try container. decode ( Swift . Array< Any> . self , forKey: . items) as? [ [ String : Any ] ] else {
288
- throw SDKError . unparseableJSON ( data: nil , errorMessage: " SDK was unable to serialize returned resources " )
289
- }
290
- var entriesJSONContainer = try container. nestedUnkeyedContainer ( forKey: . items)
291
- var entries : [ EntryDecodable ] = [ ]
292
- let contentTypes = decoder. userInfo [ DecoderContext . contentTypesContextKey] as! [ ContentTypeId : EntryDecodable . Type ]
293
-
294
- while entriesJSONContainer. isAtEnd == false {
295
- let contentTypeInfo = try jsonItems. contentTypeInfo ( at: entriesJSONContainer. currentIndex)
296
-
297
- // After implementing handling of the errors array, we can append an SDKError when the type isn't found.
298
- if let entryDecodableType = contentTypes [ contentTypeInfo. id] {
299
- let entryDecodable = try entryDecodableType. popEntryDecodable ( from: & entriesJSONContainer)
300
- entries. append ( entryDecodable)
301
- }
302
- }
303
- self . items = entries
269
+ items = try container. decodeHeterogeneousEntries ( forKey: . items,
270
+ contentTypes: decoder. contentTypes,
271
+ throwIfNotPresent: true ) ?? [ ]
304
272
305
273
// Cache to enable link resolution.
306
274
decoder. linkResolver. cache ( entryDecodables: self . items)
@@ -321,3 +289,37 @@ internal extension Swift.Array where Element == Dictionary<String, Any> {
321
289
return contentTypeInfo
322
290
}
323
291
}
292
+
293
+ extension KeyedDecodingContainer {
294
+
295
+ internal func decodeHeterogeneousEntries( forKey key: K ,
296
+ contentTypes: [ ContentTypeId : EntryDecodable . Type ] ,
297
+ throwIfNotPresent: Bool ) throws -> [ EntryDecodable ] ? {
298
+
299
+
300
+ guard let itemsAsDictionaries = try self . decodeIfPresent ( Swift . Array< Any> . self , forKey: key) as? [ [ String : Any ] ] else {
301
+ if throwIfNotPresent {
302
+ throw SDKError . unparseableJSON ( data: nil , errorMessage: " SDK was unable to serialize returned resources " )
303
+ } else {
304
+ return nil
305
+ }
306
+ }
307
+ var entriesJSONContainer = try self . nestedUnkeyedContainer ( forKey: key)
308
+
309
+ var entries : [ EntryDecodable ] = [ ]
310
+ while entriesJSONContainer. isAtEnd == false {
311
+ let contentTypeInfo = try itemsAsDictionaries. contentTypeInfo ( at: entriesJSONContainer. currentIndex)
312
+
313
+ // For includes, if the type of this entry isn't defined by the user, we skip serialization.
314
+ if let type = contentTypes [ contentTypeInfo. id] {
315
+ let entryModellable = try type. popEntryDecodable ( from: & entriesJSONContainer)
316
+ entries. append ( entryModellable)
317
+ } else {
318
+ // Another annoying workaround: there is no mechanism for incrementing the `currentIndex` of an
319
+ // UnkeyedCodingContainer other than actually decoding an item
320
+ _ = try ? entriesJSONContainer. decode ( EmptyDecodable . self)
321
+ }
322
+ }
323
+ return entries
324
+ }
325
+ }
0 commit comments