107 lines
3.0 KiB
Swift
107 lines
3.0 KiB
Swift
//
|
|
// 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<Resp: GraphQLResponse>: Decodable {
|
|
|
|
let result: Either<Resp, GraphQLResponseError>
|
|
|
|
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))
|
|
}
|
|
}
|
|
}
|