Merge branch 'feature/modelmapping' into 'feature/coding'

Feature/modelmapping

See merge request BPHV_MIPS/mvm_core!45
This commit is contained in:
Suresh, Kamlesh Jain 2019-11-26 13:37:43 -05:00
commit 347fd9557d
2 changed files with 51 additions and 7 deletions

View File

@ -9,6 +9,22 @@
import Foundation import Foundation
public protocol Model: Codable { public protocol Model: Codable {
static var identifier: String { get set }
static var identifier: String { get }
static func mvmdecode<K:CodingKey>(keyedContainer: KeyedDecodingContainer<K>, codingKey: K) throws -> Self?
static func mvmdecode(unkeyedContainer: inout UnkeyedDecodingContainer) throws -> Self?
}
extension Model {
static public func mvmdecode<K:CodingKey>(keyedContainer: KeyedDecodingContainer<K>, 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
}
} }

View File

@ -24,7 +24,6 @@ public struct ModelRegistry {
} }
} }
extension KeyedDecodingContainer where Key: CodingKey { extension KeyedDecodingContainer where Key: CodingKey {
//MARK: - Decode //MARK: - Decode
@ -44,7 +43,7 @@ extension KeyedDecodingContainer where Key: CodingKey {
public func decodeIfPresent<T, C:CodingKey>(codingKey: KeyedDecodingContainer<K>.Key, typeCodingKey: C) throws -> T? { public func decodeIfPresent<T, C:CodingKey>(codingKey: KeyedDecodingContainer<K>.Key, typeCodingKey: C) throws -> T? {
//get the type string //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 { guard let type = try meta.decodeIfPresent(String.self, forKey: typeCodingKey) else {
return nil return nil
} }
@ -54,17 +53,46 @@ extension KeyedDecodingContainer where Key: CodingKey {
throw ModelRegistry.Error.decoderErrorModelNotMapped throw ModelRegistry.Error.decoderErrorModelNotMapped
} }
//get the decoder for the propertyKey
let decoder = try self.superDecoder(forKey: codingKey)
//decode the type using the decoder //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 { guard let m = model as? T else {
throw ModelRegistry.Error.decoderError throw ModelRegistry.Error.decoderError
} }
return m return m
} }
public func decodeArrayIfPresent<C:CodingKey>(codingKey: KeyedDecodingContainer<K>.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
}
} }