Skip to content

Commit d52f328

Browse files
Merge pull request #153 from NeedleInAJayStack/fix/issue-152
Fixes scalar type serialization
2 parents afbad07 + 2a17bfc commit d52f328

File tree

2 files changed

+607
-10
lines changed

2 files changed

+607
-10
lines changed

Sources/GraphQL/Type/Scalars.swift

Lines changed: 176 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,59 @@
1+
/**
2+
* Maximum possible Int value as per GraphQL Spec (32-bit signed integer).
3+
* n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe up-to 2^53 - 1
4+
* */
5+
let GRAPHQL_MAX_INT = 2_147_483_647
6+
7+
/**
8+
* Minimum possible Int value as per GraphQL Spec (32-bit signed integer).
9+
* n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe starting at -(2^53 - 1)
10+
* */
11+
let GRAPHQL_MIN_INT = -2_147_483_648
12+
113
public let GraphQLInt = try! GraphQLScalarType(
214
name: "Int",
315
description:
416
"The `Int` scalar type represents non-fractional signed whole numeric " +
517
"values. Int can represent values between -(2^31) and 2^31 - 1.",
6-
serialize: { try map(from: $0) },
7-
parseValue: { try .int($0.intValue(converting: true)) },
18+
serialize: { outputValue in
19+
if let value = outputValue as? Map {
20+
if case let .number(value) = value {
21+
return .int(value.intValue)
22+
}
23+
throw GraphQLError(
24+
message: "Float cannot represent non numeric value: \(value)"
25+
)
26+
}
27+
if let value = outputValue as? Bool {
28+
return value ? .int(1) : .int(0)
29+
}
30+
if let value = outputValue as? String, value != "", let int = Int(value) {
31+
return .int(int)
32+
}
33+
if
34+
let value = outputValue as? Double, Double(GRAPHQL_MIN_INT) <= value,
35+
value <= Double(GRAPHQL_MAX_INT), value.isFinite
36+
{
37+
return .int(Int(value))
38+
}
39+
if let value = outputValue as? Int, GRAPHQL_MIN_INT <= value, value <= GRAPHQL_MAX_INT {
40+
return .int(value)
41+
}
42+
throw GraphQLError(
43+
message: "Int cannot represent non-integer value: \(outputValue)"
44+
)
45+
},
46+
parseValue: { inputValue in
47+
if
48+
case let .number(value) = inputValue, Double(GRAPHQL_MIN_INT) <= value.doubleValue,
49+
value.doubleValue <= Double(GRAPHQL_MAX_INT), value.doubleValue.isFinite
50+
{
51+
return .number(value)
52+
}
53+
throw GraphQLError(
54+
message: "Int cannot represent non-integer value: \(inputValue)"
55+
)
56+
},
857
parseLiteral: { ast in
958
if let ast = ast as? IntValue, let int = Int(ast.value) {
1059
return .int(int)
@@ -23,8 +72,39 @@ public let GraphQLFloat = try! GraphQLScalarType(
2372
"The `Float` scalar type represents signed double-precision fractional " +
2473
"values as specified by " +
2574
"[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ",
26-
serialize: { try map(from: $0) },
27-
parseValue: { try .double($0.doubleValue(converting: true)) },
75+
serialize: { outputValue in
76+
if let value = outputValue as? Map {
77+
if case let .number(value) = value {
78+
return .double(value.doubleValue)
79+
}
80+
throw GraphQLError(
81+
message: "Float cannot represent non numeric value: \(value)"
82+
)
83+
}
84+
if let value = outputValue as? Bool {
85+
return value ? .double(1) : .double(0)
86+
}
87+
if let value = outputValue as? String, value != "", let double = Double(value) {
88+
return .double(double)
89+
}
90+
if let value = outputValue as? Double, value.isFinite {
91+
return .double(value)
92+
}
93+
if let value = outputValue as? Int {
94+
return .double(Double(value))
95+
}
96+
throw GraphQLError(
97+
message: "Float cannot represent non numeric value: \(outputValue)"
98+
)
99+
},
100+
parseValue: { inputValue in
101+
if case let .number(value) = inputValue, value.doubleValue.isFinite {
102+
return .number(value)
103+
}
104+
throw GraphQLError(
105+
message: "Float cannot represent non numeric value: \(inputValue)"
106+
)
107+
},
28108
parseLiteral: { ast in
29109
if let ast = ast as? FloatValue, let double = Double(ast.value) {
30110
return .double(double)
@@ -47,8 +127,39 @@ public let GraphQLString = try! GraphQLScalarType(
47127
"The `String` scalar type represents textual data, represented as UTF-8 " +
48128
"character sequences. The String type is most often used by GraphQL to " +
49129
"represent free-form human-readable text.",
50-
serialize: { try map(from: $0) },
51-
parseValue: { try .string($0.stringValue(converting: true)) },
130+
serialize: { outputValue in
131+
if let value = outputValue as? Map {
132+
if case let .string(value) = value {
133+
return .string(value)
134+
}
135+
throw GraphQLError(
136+
message: "String cannot represent a non string value: \(value)"
137+
)
138+
}
139+
if let value = outputValue as? String {
140+
return .string(value)
141+
}
142+
if let value = outputValue as? Bool {
143+
return value ? .string("true") : .string("false")
144+
}
145+
if let value = outputValue as? Int {
146+
return .string(value.description)
147+
}
148+
if let value = outputValue as? Double, value.isFinite {
149+
return .string(value.description)
150+
}
151+
throw GraphQLError(
152+
message: "String cannot represent value: \(outputValue)"
153+
)
154+
},
155+
parseValue: { outputValue in
156+
if case let .string(value) = outputValue {
157+
return .string(value)
158+
}
159+
throw GraphQLError(
160+
message: "String cannot represent a non string value: \(outputValue)"
161+
)
162+
},
52163
parseLiteral: { ast in
53164
if let ast = ast as? StringValue {
54165
return .string(ast.value)
@@ -64,8 +175,36 @@ public let GraphQLString = try! GraphQLScalarType(
64175
public let GraphQLBoolean = try! GraphQLScalarType(
65176
name: "Boolean",
66177
description: "The `Boolean` scalar type represents `true` or `false`.",
67-
serialize: { try map(from: $0) },
68-
parseValue: { try .bool($0.boolValue(converting: true)) },
178+
serialize: { outputValue in
179+
if let value = outputValue as? Map {
180+
if case let .bool(value) = value {
181+
return .bool(value)
182+
}
183+
if case let .number(value) = value {
184+
return .bool(value.intValue != 0)
185+
}
186+
throw GraphQLError(
187+
message: "Boolean cannot represent a non boolean value: \(value)"
188+
)
189+
}
190+
if let value = outputValue as? Bool {
191+
return .bool(value)
192+
}
193+
if let value = outputValue as? Int {
194+
return .bool(value != 0)
195+
}
196+
throw GraphQLError(
197+
message: "Boolean cannot represent a non boolean value: \(outputValue)"
198+
)
199+
},
200+
parseValue: { inputValue in
201+
if case let .bool(value) = inputValue {
202+
return inputValue
203+
}
204+
throw GraphQLError(
205+
message: "Boolean cannot represent a non boolean value: \(inputValue)"
206+
)
207+
},
69208
parseLiteral: { ast in
70209
if let ast = ast as? BooleanValue {
71210
return .bool(ast.value)
@@ -86,8 +225,35 @@ public let GraphQLID = try! GraphQLScalarType(
86225
"response as a String; however, it is not intended to be human-readable. " +
87226
"When expected as an input type, any string (such as `\"4\"`) or integer " +
88227
"(such as `4`) input value will be accepted as an ID.",
89-
serialize: { try map(from: $0) },
90-
parseValue: { try .string($0.stringValue(converting: true)) },
228+
serialize: { outputValue in
229+
if let value = outputValue as? Map {
230+
if case let .string(value) = value {
231+
return .string(value)
232+
}
233+
if case let .number(value) = value {
234+
return .string(value.description)
235+
}
236+
throw GraphQLError(
237+
message: "ID cannot represent value: \(value)"
238+
)
239+
}
240+
if let value = outputValue as? String {
241+
return .string(value)
242+
}
243+
if let value = outputValue as? Int {
244+
return .string(value.description)
245+
}
246+
throw GraphQLError(message: "ID cannot represent value: \(outputValue)")
247+
},
248+
parseValue: { inputValue in
249+
if case let .string(value) = inputValue {
250+
return inputValue
251+
}
252+
if case let .number(value) = inputValue, value.storageType == .int {
253+
return .string(value.description)
254+
}
255+
throw GraphQLError(message: "ID cannot represent value: \(inputValue)")
256+
},
91257
parseLiteral: { ast in
92258
if let ast = ast as? StringValue {
93259
return .string(ast.value)

0 commit comments

Comments
 (0)