Skip to content

Instantly share code, notes, and snippets.

@randomguy0815
Last active December 12, 2018 13:46
Show Gist options
  • Save randomguy0815/b469067c835b9f2d5e5ddb76a27acab2 to your computer and use it in GitHub Desktop.
Save randomguy0815/b469067c835b9f2d5e5ddb76a27acab2 to your computer and use it in GitHub Desktop.
Mantle to JSON
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