From 0d1c3196bf311a526df0bc90690a6f239ef00195 Mon Sep 17 00:00:00 2001 From: panxi Date: Fri, 22 Nov 2019 14:33:42 -0500 Subject: [PATCH 1/2] add unkeyedcontainer --- MVMCore/MVMCore/Models/Model/Model.swift | 2 +- .../MVMCore/Models/Model/ModelRegistry.swift | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/MVMCore/MVMCore/Models/Model/Model.swift b/MVMCore/MVMCore/Models/Model/Model.swift index e2adaae..44e1025 100644 --- a/MVMCore/MVMCore/Models/Model/Model.swift +++ b/MVMCore/MVMCore/Models/Model/Model.swift @@ -10,7 +10,7 @@ import Foundation public protocol Model: Codable { - static var identifier: String { get set } + static var identifier: String { get } } diff --git a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift index 05fbfa6..cd40a83 100644 --- a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -24,6 +24,27 @@ public struct ModelRegistry { } } +extension UnkeyedDecodingContainer { + + public mutating func decodeUnKeyedIfPresent(_ type: T.Type, typeCodingKey: C) throws -> T? where T : Decodable { + let meta = try self.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 + } + let model = try self.decode(found) + + guard let m = model as? T else { + throw ModelRegistry.Error.decoderError + } + return m + } + +} extension KeyedDecodingContainer where Key: CodingKey { @@ -48,7 +69,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 } From b2eb88f7f69a3c4242343ff4dc0de8df557f7ae6 Mon Sep 17 00:00:00 2001 From: panxi Date: Sun, 24 Nov 2019 23:14:25 -0500 Subject: [PATCH 2/2] update array decoding method --- MVMCore/MVMCore/Models/Model/Model.swift | 14 +++++ .../MVMCore/Models/Model/ModelRegistry.swift | 59 +++++++++++-------- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/MVMCore/MVMCore/Models/Model/Model.swift b/MVMCore/MVMCore/Models/Model/Model.swift index 44e1025..8e37837 100644 --- a/MVMCore/MVMCore/Models/Model/Model.swift +++ b/MVMCore/MVMCore/Models/Model/Model.swift @@ -12,5 +12,19 @@ public protocol Model: Codable { 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 cd40a83..0b83a6f 100644 --- a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -24,28 +24,6 @@ public struct ModelRegistry { } } -extension UnkeyedDecodingContainer { - - public mutating func decodeUnKeyedIfPresent(_ type: T.Type, typeCodingKey: C) throws -> T? where T : Decodable { - let meta = try self.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 - } - let model = try self.decode(found) - - guard let m = model as? T else { - throw ModelRegistry.Error.decoderError - } - return m - } - -} - extension KeyedDecodingContainer where Key: CodingKey { private enum TypeCodingKey: String, CodingKey { @@ -79,17 +57,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 + } }