Files
2022-10-06 16:17:16 +03:00

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))
}
}
}