-
Notifications
You must be signed in to change notification settings - Fork 728
/
GraphQLEnum.swift
140 lines (123 loc) · 4.72 KB
/
GraphQLEnum.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
128
129
130
131
132
133
134
135
136
137
138
139
140
/// A generic enum type that wraps an ``EnumType`` from a generated GraphQL schema.
///
/// ``GraphQLEnum`` provides an ``unknown(_:)`` case that is used when the response returns a value
/// that is not recognized as a valid enum case. This is usually caused by future cases added to
/// the enum on the schema after code generation.
public enum GraphQLEnum<T: EnumType>: CaseIterable, Hashable, RawRepresentable {
public typealias RawValue = String
/// A recognized case of the wrapped enum.
case `case`(T)
/// An unrecognized value for the enum.
/// The associated value exposes the raw `String` name of the unknown enum case.
case unknown(String)
/// Initializer for use with a value of the wrapped ``EnumType``
///
/// - Parameter caseValue: A value of the wrapped ``EnumType``
@inlinable public init(_ caseValue: T) {
self = .case(caseValue)
}
/// Initializer for use with a raw value `String`. This initializer is used for initializing an
/// enum from a GraphQL response value.
///
/// The `rawValue` should represent a raw value for a case of the wrapped ``EnumType``, or an
/// ``unknown(_:)`` case with the `rawValue` will be returned.
///
/// - Parameter rawValue: The `String` value representing the enum value in a GraphQL response
@inlinable public init(rawValue: String) {
guard let caseValue = T(rawValue: rawValue) else {
self = .unknown(rawValue)
return
}
self = .case(caseValue)
}
/// Convenience initializer for use with a raw value `String`. This initializer is used for
/// initializing an enum from a GraphQL response value.
///
/// The `rawValue` should represent a raw value for a case of the wrapped ``EnumType``, or an
/// `unknown` case with the `rawValue` will be returned.
///
/// - Parameter rawValue: The `String` value representing the enum value in a GraphQL response
@inlinable public init(_ rawValue: String) {
self.init(rawValue: rawValue)
}
/// The underlying enum case. If the value is ``unknown(_:)``, this will be `nil`.
@inlinable public var value: T? {
switch self {
case let .case(value): return value
default: return nil
}
}
/// The `String` value representing the enum value in a GraphQL response.
@inlinable public var rawValue: String {
switch self {
case let .case(value): return value.rawValue
case let .unknown(value): return value
}
}
/// A collection of all known values of the wrapped enum.
/// This collection does not include the `unknown` case.
@inlinable public static var allCases: [GraphQLEnum<T>] {
return T.allCases.map { .case($0) }
}
}
// MARK: CustomScalarType
extension GraphQLEnum: CustomScalarType {
@inlinable public init(_jsonValue: JSONValue) throws {
guard let stringData = _jsonValue as? String else {
throw JSONDecodingError.couldNotConvert(value: _jsonValue, to: String.self)
}
self.init(rawValue: stringData)
}
}
// MARK: Equatable
extension GraphQLEnum {
@inlinable public static func ==(lhs: GraphQLEnum<T>, rhs: GraphQLEnum<T>) -> Bool {
return lhs.rawValue == rhs.rawValue
}
@inlinable public static func ==(lhs: GraphQLEnum<T>, rhs: T) -> Bool {
return lhs.rawValue == rhs.rawValue
}
@inlinable public static func !=(lhs: GraphQLEnum<T>, rhs: T) -> Bool {
return lhs.rawValue != rhs.rawValue
}
}
// MARK: Optional<GraphQLEnum<T>> Equatable
@inlinable public func ==<T: RawRepresentable & CaseIterable>(lhs: GraphQLEnum<T>?, rhs: T) -> Bool
where T.RawValue == String {
return lhs?.rawValue == rhs.rawValue
}
@inlinable public func !=<T: RawRepresentable & CaseIterable>(lhs: GraphQLEnum<T>?, rhs: T) -> Bool
where T.RawValue == String {
return lhs?.rawValue != rhs.rawValue
}
// MARK: Pattern Matching
extension GraphQLEnum {
/// Pattern Matching Operator overload for ``GraphQLEnum``
///
/// This operator allows for a ``GraphQLEnum`` to be matched against a `case` on the wrapped
/// ``EnumType``.
///
/// > Note: Because this is not a synthesized pattern, the Swift compiler cannot determine
/// switch case exhaustiveness. When used in a switch statement, you will be required to provide
/// a `default` case.
///
/// ```swift
/// let enumValue: GraphQLEnum<StarWarsAPI.Episode> = .case(.NEWHOPE)
///
/// switch enumValue {
/// case .NEWHOPE:
/// print("Success")
/// case .RETURN, .EMPIRE:
/// print("Fail")
/// default:
/// print("Fail") // This default case will never be executed but is required.
/// }
/// ```
@inlinable public static func ~=(lhs: T, rhs: GraphQLEnum<T>) -> Bool {
switch rhs {
case let .case(rhs) where rhs == lhs: return true
case let .unknown(rhsRawValue) where rhsRawValue == lhs.rawValue: return true
default: return false
}
}
}