Skip to content

Commit 977a5e0

Browse files
fix: Fixes scalar type serialization
Fixes #152
1 parent afbad07 commit 977a5e0

File tree

2 files changed

+601
-10
lines changed

2 files changed

+601
-10
lines changed

Sources/GraphQL/Type/Scalars.swift

Lines changed: 170 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,53 @@
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 = 2147483647;
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 = -2147483648;
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 let value = outputValue as? Double, Double(GRAPHQL_MIN_INT) <= value, value <= Double(GRAPHQL_MAX_INT), value.isFinite {
34+
return .int(Int(value))
35+
}
36+
if let value = outputValue as? Int, GRAPHQL_MIN_INT <= value, value <= GRAPHQL_MAX_INT {
37+
return .int(value)
38+
}
39+
throw GraphQLError(
40+
message: "Int cannot represent non-integer value: \(outputValue)"
41+
)
42+
},
43+
parseValue: { inputValue in
44+
if case let .number(value) = inputValue, Double(GRAPHQL_MIN_INT) <= value.doubleValue, value.doubleValue <= Double(GRAPHQL_MAX_INT), value.doubleValue.isFinite {
45+
return .number(value)
46+
}
47+
throw GraphQLError(
48+
message: "Int cannot represent non-integer value: \(inputValue)"
49+
)
50+
},
851
parseLiteral: { ast in
952
if let ast = ast as? IntValue, let int = Int(ast.value) {
1053
return .int(int)
@@ -23,8 +66,39 @@ public let GraphQLFloat = try! GraphQLScalarType(
2366
"The `Float` scalar type represents signed double-precision fractional " +
2467
"values as specified by " +
2568
"[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ",
26-
serialize: { try map(from: $0) },
27-
parseValue: { try .double($0.doubleValue(converting: true)) },
69+
serialize: { outputValue in
70+
if let value = outputValue as? Map {
71+
if case let .number(value) = value {
72+
return .double(value.doubleValue)
73+
}
74+
throw GraphQLError(
75+
message: "Float cannot represent non numeric value: \(value)"
76+
)
77+
}
78+
if let value = outputValue as? Bool {
79+
return value ? .double(1) : .double(0)
80+
}
81+
if let value = outputValue as? String, value != "", let double = Double(value) {
82+
return .double(double)
83+
}
84+
if let value = outputValue as? Double, value.isFinite {
85+
return .double(value)
86+
}
87+
if let value = outputValue as? Int {
88+
return .double(Double(value))
89+
}
90+
throw GraphQLError(
91+
message: "Float cannot represent non numeric value: \(outputValue)"
92+
)
93+
},
94+
parseValue: { inputValue in
95+
if case let .number(value) = inputValue, value.doubleValue.isFinite {
96+
return .number(value)
97+
}
98+
throw GraphQLError(
99+
message: "Float cannot represent non numeric value: \(inputValue)"
100+
)
101+
},
28102
parseLiteral: { ast in
29103
if let ast = ast as? FloatValue, let double = Double(ast.value) {
30104
return .double(double)
@@ -47,8 +121,39 @@ public let GraphQLString = try! GraphQLScalarType(
47121
"The `String` scalar type represents textual data, represented as UTF-8 " +
48122
"character sequences. The String type is most often used by GraphQL to " +
49123
"represent free-form human-readable text.",
50-
serialize: { try map(from: $0) },
51-
parseValue: { try .string($0.stringValue(converting: true)) },
124+
serialize: { outputValue in
125+
if let value = outputValue as? Map {
126+
if case let .string(value) = value {
127+
return .string(value)
128+
}
129+
throw GraphQLError(
130+
message: "String cannot represent a non string value: \(value)"
131+
)
132+
}
133+
if let value = outputValue as? String {
134+
return .string(value)
135+
}
136+
if let value = outputValue as? Bool {
137+
return value ? .string("true") : .string("false")
138+
}
139+
if let value = outputValue as? Int {
140+
return .string(value.description)
141+
}
142+
if let value = outputValue as? Double, value.isFinite {
143+
return .string(value.description)
144+
}
145+
throw GraphQLError(
146+
message: "String cannot represent value: \(outputValue)"
147+
)
148+
},
149+
parseValue: { outputValue in
150+
if case let .string(value) = outputValue {
151+
return .string(value)
152+
}
153+
throw GraphQLError(
154+
message: "String cannot represent a non string value: \(outputValue)"
155+
)
156+
},
52157
parseLiteral: { ast in
53158
if let ast = ast as? StringValue {
54159
return .string(ast.value)
@@ -64,8 +169,36 @@ public let GraphQLString = try! GraphQLScalarType(
64169
public let GraphQLBoolean = try! GraphQLScalarType(
65170
name: "Boolean",
66171
description: "The `Boolean` scalar type represents `true` or `false`.",
67-
serialize: { try map(from: $0) },
68-
parseValue: { try .bool($0.boolValue(converting: true)) },
172+
serialize: { outputValue in
173+
if let value = outputValue as? Map {
174+
if case let .bool(value) = value {
175+
return .bool(value)
176+
}
177+
if case let .number(value) = value {
178+
return .bool(value.intValue != 0)
179+
}
180+
throw GraphQLError(
181+
message: "Boolean cannot represent a non boolean value: \(value)"
182+
)
183+
}
184+
if let value = outputValue as? Bool {
185+
return .bool(value)
186+
}
187+
if let value = outputValue as? Int {
188+
return .bool(value != 0)
189+
}
190+
throw GraphQLError(
191+
message: "Boolean cannot represent a non boolean value: \(outputValue)"
192+
)
193+
},
194+
parseValue: { inputValue in
195+
if case let .bool(value) = inputValue {
196+
return inputValue
197+
}
198+
throw GraphQLError(
199+
message: "Boolean cannot represent a non boolean value: \(inputValue)"
200+
)
201+
},
69202
parseLiteral: { ast in
70203
if let ast = ast as? BooleanValue {
71204
return .bool(ast.value)
@@ -86,8 +219,35 @@ public let GraphQLID = try! GraphQLScalarType(
86219
"response as a String; however, it is not intended to be human-readable. " +
87220
"When expected as an input type, any string (such as `\"4\"`) or integer " +
88221
"(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)) },
222+
serialize: { outputValue in
223+
if let value = outputValue as? Map {
224+
if case let .string(value) = value {
225+
return .string(value)
226+
}
227+
if case let .number(value) = value {
228+
return .string(value.description)
229+
}
230+
throw GraphQLError(
231+
message: "ID cannot represent value: \(value)"
232+
)
233+
}
234+
if let value = outputValue as? String {
235+
return .string(value)
236+
}
237+
if let value = outputValue as? Int {
238+
return .string(value.description)
239+
}
240+
throw GraphQLError(message: "ID cannot represent value: \(outputValue)")
241+
},
242+
parseValue: { inputValue in
243+
if case let .string(value) = inputValue {
244+
return inputValue
245+
}
246+
if case let .number(value) = inputValue, value.storageType == .int {
247+
return .string(value.description)
248+
}
249+
throw GraphQLError(message: "ID cannot represent value: \(inputValue)")
250+
},
91251
parseLiteral: { ast in
92252
if let ast = ast as? StringValue {
93253
return .string(ast.value)

0 commit comments

Comments
 (0)