Last active
December 12, 2018 13:46
-
-
Save randomguy0815/b469067c835b9f2d5e5ddb76a27acab2 to your computer and use it in GitHub Desktop.
Mantle to JSON
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typealias JSONDictionary = [String : Any] | |
typealias JSONArray = [Any] | |
struct JSONCodingKeys: CodingKey { | |
var stringValue: String | |
init?(stringValue: String) { | |
self.stringValue = stringValue | |
} | |
var intValue: Int? | |
init?(intValue: Int) { | |
self.init(stringValue: "\(intValue)") | |
self.intValue = intValue | |
} | |
} | |
private enum CodableToMantleError: Error { | |
case castError(String) | |
} | |
extension KeyedDecodingContainer { | |
func decodeLegacyMantleModel<T: MTLModel>(key: K) throws -> T { | |
let jsonDictionary = try decodeJSONDictionary(forKey: key) | |
// the JSON dictionary is forwared to Mantle | |
// any "legacy" decoding library could be used here | |
let maybeModel = try MTLJSONAdapter.model(of: T.self, fromJSONDictionary: jsonDictionary) as? T | |
guard let model = maybeModel else { | |
throw CodableToMantleError.castError("Could not cast to model of class \(T.self)") | |
} | |
return model | |
} | |
func decodeLegacyMantleModelIfPresent<T: MTLModel>(key: K) throws -> T? { | |
guard let jsonDictionary = try decodeJSONDictionaryIfPresent(forKey: key) else { | |
return nil | |
} | |
let maybeModel = try MTLJSONAdapter.model(of: T.self, fromJSONDictionary: jsonDictionary) as? T | |
guard let model = maybeModel else { | |
throw CodableToMantleError.castError("Could not cast to model of class \(T.self)") | |
} | |
return model | |
} | |
func decodeLegacyMantleModels<T: MTLModel>(key: K) throws -> [T] { | |
let jsonArray = try decodeJSONArray(forKey: key) | |
guard let model = try MTLJSONAdapter.models(of: T.self, fromJSONArray: jsonArray) as? [T] else { | |
throw CodableToMantleError.castError("Could not cast to model of class \(T.self)") | |
} | |
return model | |
} | |
func decodeLegacyMantleModelArrayOmitingInvalidObjects<T: MTLModel>(key: K) -> [T] { | |
guard let jsonArray = try? decodeJSONArrayIfPresent(forKey: key) else { | |
return [] | |
} | |
return jsonArray?.compactMap({ | |
guard let dic = $0 as? JSONDictionary, let model = try? MTLJSONAdapter.model(of: T.self, fromJSONDictionary: dic) as? T else { | |
return nil | |
} | |
return model | |
}) ?? [] | |
} | |
func decodeJSONDictionary(forKey key: K) throws -> JSONDictionary { | |
let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key) | |
return try container.decodeJSONDictionary() | |
} | |
func decodeJSONDictionaryIfPresent(forKey key: K) throws -> JSONDictionary? { | |
guard contains(key), try decodeNil(forKey: key) == false else { return nil } | |
return try decodeJSONDictionary(forKey: key) | |
} | |
func decodeJSONArray(forKey key: K) throws -> JSONArray { | |
var container = try self.nestedUnkeyedContainer(forKey: key) | |
return try container.decodeJSONArray() | |
} | |
func decodeJSONArrayIfPresent(forKey key: K) throws -> JSONArray? { | |
guard contains(key), try decodeNil(forKey: key) == false else { return nil } | |
return try decodeJSONArray(forKey: key) | |
} | |
func decodeAnyArrayIfPresent(forKey key: K) throws -> JSONArray? { | |
guard contains(key) else { | |
return nil | |
} | |
return try decodeJSONArray(forKey: key) | |
} | |
fileprivate func decodeJSONDictionary() throws -> JSONDictionary { | |
var dictionary = JSONDictionary() | |
for key in allKeys { | |
if let boolValue = try? decode(Bool.self, forKey: key) { | |
dictionary[key.stringValue] = boolValue | |
} | |
else if let stringValue = try? decode(String.self, forKey: key) { | |
dictionary[key.stringValue] = stringValue | |
} | |
else if let intValue = try? decode(Int.self, forKey: key) { | |
dictionary[key.stringValue] = intValue | |
} | |
else if let doubleValue = try? decode(Double.self, forKey: key) { | |
dictionary[key.stringValue] = doubleValue | |
} | |
else if let nestedDictionary = try? decodeJSONDictionary(forKey: key) { | |
dictionary[key.stringValue] = nestedDictionary | |
} | |
else if let nestedArray = try? decodeJSONArray(forKey: key) { | |
dictionary[key.stringValue] = nestedArray | |
} | |
else if try decodeNil(forKey: key) { | |
continue | |
} | |
} | |
return dictionary | |
} | |
} | |
extension UnkeyedDecodingContainer { | |
mutating func decodeJSONArray() throws -> JSONArray { | |
var array = JSONArray() | |
while isAtEnd == false { | |
if let value = try? decode(Bool.self) { | |
array.append(value) | |
} | |
else if let value = try? decode(Double.self) { | |
array.append(value) | |
} | |
else if let value = try? decode(String.self) { | |
array.append(value) | |
} | |
else if let nestedDictionary = try? decodeJSONDictionary() { | |
array.append(nestedDictionary) | |
} | |
else if let nestedArray = try? decodeJSONArray() { | |
array.append(nestedArray) | |
} | |
else if try decodeNil() { | |
continue | |
} | |
} | |
return array | |
} | |
mutating func decodeJSONDictionary() throws -> JSONDictionary { | |
let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self) | |
return try nestedContainer.decodeJSONDictionary() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment