-
Notifications
You must be signed in to change notification settings - Fork 731
/
GraphQLSelectionSet.swift
128 lines (103 loc) · 3.39 KB
/
GraphQLSelectionSet.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
public typealias ResultMap = [String: Any?]
public protocol GraphQLSelectionSet {
static var selections: [GraphQLSelection] { get }
var resultMap: ResultMap { get }
init(unsafeResultMap: ResultMap)
}
public extension GraphQLSelectionSet {
init(jsonObject: JSONObject, variables: GraphQLMap? = nil) throws {
let executor = GraphQLExecutor { object, info in
.result(.success(object[info.responseKeyForField]))
}
executor.shouldComputeCachePath = false
self = try executor.execute(selections: Self.selections, on: jsonObject, variables: variables, accumulator: GraphQLSelectionSetMapper<Self>()).await()
}
var jsonObject: JSONObject {
return resultMap.jsonObject
}
}
extension GraphQLSelectionSet {
public init(_ selectionSet: GraphQLSelectionSet) throws {
try self.init(jsonObject: selectionSet.jsonObject)
}
}
public protocol GraphQLSelection {
}
public struct GraphQLField: GraphQLSelection {
let name: String
let alias: String?
let arguments: [String: GraphQLInputValue]?
var responseKey: String {
return alias ?? name
}
let type: GraphQLOutputType
public init(_ name: String, alias: String? = nil, arguments: [String: GraphQLInputValue]? = nil, type: GraphQLOutputType) {
self.name = name
self.alias = alias
self.arguments = arguments
self.type = type
}
func cacheKey(with variables: [String: JSONEncodable]?) throws -> String {
if let argumentValues = try arguments?.evaluate(with: variables), !argumentValues.isEmpty {
let argumentsKey = orderIndependentKey(for: argumentValues)
return "\(name)(\(argumentsKey))"
} else {
return name
}
}
}
public indirect enum GraphQLOutputType {
case scalar(JSONDecodable.Type)
case object([GraphQLSelection])
case nonNull(GraphQLOutputType)
case list(GraphQLOutputType)
var namedType: GraphQLOutputType {
switch self {
case .nonNull(let innerType), .list(let innerType):
return innerType.namedType
case .scalar, .object:
return self
}
}
}
private func orderIndependentKey(for object: JSONObject) -> String {
return object.sorted { $0.key < $1.key }.map {
if let object = $0.value as? JSONObject {
return "[\($0.key):\(orderIndependentKey(for: object))]"
} else {
return "\($0.key):\($0.value)"
}
}.joined(separator: ",")
}
public struct GraphQLBooleanCondition: GraphQLSelection {
let variableName: String
let inverted: Bool
let selections: [GraphQLSelection]
public init(variableName: String, inverted: Bool, selections: [GraphQLSelection]) {
self.variableName = variableName
self.inverted = inverted;
self.selections = selections;
}
}
public struct GraphQLTypeCondition: GraphQLSelection {
let possibleTypes: [String]
let selections: [GraphQLSelection]
public init(possibleTypes: [String], selections: [GraphQLSelection]) {
self.possibleTypes = possibleTypes
self.selections = selections;
}
}
public struct GraphQLFragmentSpread: GraphQLSelection {
let fragment: GraphQLFragment.Type
public init(_ fragment: GraphQLFragment.Type) {
self.fragment = fragment
}
}
public struct GraphQLTypeCase: GraphQLSelection {
let variants: [String: [GraphQLSelection]]
let `default`: [GraphQLSelection]
public init(variants: [String: [GraphQLSelection]], default: [GraphQLSelection]) {
self.variants = variants
self.default = `default`;
}
}