// // GraphQLResult.swift // // // Created by Juraldinio on 01.08.2022. // import Foundation import WalletFoundation protocol GraphQLResponse: Decodable { static var node: String { get } } struct GraphQLError: Decodable { let message: String } enum GraphQLResponseError: Decodable { enum Place: CustomStringConvertible { case node case failed var description: String { switch self { case .node: return "node" case .failed: return "failed" } } } case system(errors: [GraphQLError]) case application(error: String) case decode(Place) init(from decoder: Decoder) throws { self = .system(errors: []) } // MARK: - var networkServiceError: NetworkServiceError { switch self { case let .system(errors: errors): return .gqlSystem(errors.map { $0.message }) case let .application(error: error): return .gqlApplication(error) case let .decode(place): return .gqlDecode(place.description) } } } let KEY_ERRORS = "errors" struct GraphQLResult: Decodable { let result: Either private enum Common: String, CodingKey { case data case errors } private struct DynamicCodingKeys: CodingKey { var stringValue: String var intValue: Int? init?(stringValue: String) { self.stringValue = stringValue } init?(intValue: Int) { return nil } } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: Common.self) // System error catch if let errors = try? container.decode([GraphQLError].self, forKey: .errors) { self.result = .secondType(.system(errors: errors)) return } // If node is empty guard !Resp.node.isEmpty else { if let response = try? container.decode(Resp.self, forKey: .data) { self.result = .firstType(response) } else { self.result = .secondType(.decode(.failed)) } return } let dataContainer = try container.nestedContainer(keyedBy: DynamicCodingKeys.self, forKey: .data) guard let key = DynamicCodingKeys(stringValue: Resp.node) else { self.result = .secondType(.decode(.node)) return } if let responseContainer = try? dataContainer.nestedContainer(keyedBy: DynamicCodingKeys.self, forKey: key), let errorKey = DynamicCodingKeys(stringValue: KEY_ERRORS), let error = try? responseContainer.decode(String.self, forKey: errorKey) { self.result = .secondType(.application(error: error)) } else if let response = try? dataContainer.decode(Resp.self, forKey: key) { self.result = .firstType(response) } else { self.result = .secondType(.decode(.failed)) } } }