diff --git a/MVMCore/MVMCore/Models/Model/Model.swift b/MVMCore/MVMCore/Models/Model/Model.swift index 36d6403..8e37837 100644 --- a/MVMCore/MVMCore/Models/Model/Model.swift +++ b/MVMCore/MVMCore/Models/Model/Model.swift @@ -9,6 +9,22 @@ import Foundation public protocol Model: Codable { - static var identifier: String { get set } + + static var identifier: String { get } + + static func mvmdecode(keyedContainer: KeyedDecodingContainer, codingKey: K) throws -> Self? + static func mvmdecode(unkeyedContainer: inout UnkeyedDecodingContainer) throws -> Self? +} + +extension Model { + static public func mvmdecode(keyedContainer: KeyedDecodingContainer, codingKey: K) throws -> Self? { + let m = try keyedContainer.decodeIfPresent(self, forKey: codingKey) + return m + } + + static public func mvmdecode(unkeyedContainer: inout UnkeyedDecodingContainer) throws -> Self? { + let m = try unkeyedContainer.decodeIfPresent(self) + return m + } } diff --git a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift index e5a83ef..b0246fe 100644 --- a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -24,7 +24,6 @@ public struct ModelRegistry { } } - extension KeyedDecodingContainer where Key: CodingKey { //MARK: - Decode @@ -44,7 +43,7 @@ extension KeyedDecodingContainer where Key: CodingKey { public func decodeIfPresent(codingKey: KeyedDecodingContainer.Key, typeCodingKey: C) throws -> T? { //get the type string - let meta = try self.nestedContainer(keyedBy: type(of: typeCodingKey), forKey: codingKey) + let meta = try self.nestedContainer(keyedBy: C.self, forKey: codingKey) guard let type = try meta.decodeIfPresent(String.self, forKey: typeCodingKey) else { return nil } @@ -54,17 +53,46 @@ extension KeyedDecodingContainer where Key: CodingKey { throw ModelRegistry.Error.decoderErrorModelNotMapped } - //get the decoder for the propertyKey - let decoder = try self.superDecoder(forKey: codingKey) - //decode the type using the decoder - let model = try found.init(from: decoder) + let model = try found.mvmdecode(keyedContainer: self, codingKey: codingKey) guard let m = model as? T else { throw ModelRegistry.Error.decoderError } + return m } + + + public func decodeArrayIfPresent(codingKey: KeyedDecodingContainer.Key, typeCodingKey: C) throws -> [Model]? { + + var unkeyedContainer = try nestedUnkeyedContainer(forKey: codingKey) + var otherUnkeyedContainer = try nestedUnkeyedContainer(forKey: codingKey) + var attributes = [Model.Type]() + while !unkeyedContainer.isAtEnd { + + let meta = try unkeyedContainer.nestedContainer(keyedBy: C.self) + guard let type = try meta.decodeIfPresent(String.self, forKey: typeCodingKey) else { + return nil + } + //get the type + guard let found = ModelRegistry.types[type] else { + throw ModelRegistry.Error.decoderErrorModelNotMapped + } + attributes.append(found) + } + + var i = 0 + var models = [Model]() + while !otherUnkeyedContainer.isAtEnd { + let foundModel = attributes[i] + if let model = try foundModel.mvmdecode(unkeyedContainer: &otherUnkeyedContainer) { + models.append(model) + } + i += 1 + } + return models.count > 0 ? models : nil + } }