Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes scalar type serialization #153

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 176 additions & 10 deletions Sources/GraphQL/Type/Scalars.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,59 @@
/**
* Maximum possible Int value as per GraphQL Spec (32-bit signed integer).
* n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe up-to 2^53 - 1
* */
let GRAPHQL_MAX_INT = 2_147_483_647

/**
* Minimum possible Int value as per GraphQL Spec (32-bit signed integer).
* n.b. This differs from JavaScript's numbers that are IEEE 754 doubles safe starting at -(2^53 - 1)
* */
let GRAPHQL_MIN_INT = -2_147_483_648

public let GraphQLInt = try! GraphQLScalarType(
name: "Int",
description:
"The `Int` scalar type represents non-fractional signed whole numeric " +
"values. Int can represent values between -(2^31) and 2^31 - 1.",
serialize: { try map(from: $0) },
parseValue: { try .int($0.intValue(converting: true)) },
serialize: { outputValue in
if let value = outputValue as? Map {
if case let .number(value) = value {
return .int(value.intValue)
}
throw GraphQLError(
message: "Float cannot represent non numeric value: \(value)"
)
}
if let value = outputValue as? Bool {
return value ? .int(1) : .int(0)
}
if let value = outputValue as? String, value != "", let int = Int(value) {
return .int(int)
}
if
let value = outputValue as? Double, Double(GRAPHQL_MIN_INT) <= value,
value <= Double(GRAPHQL_MAX_INT), value.isFinite
{
return .int(Int(value))
}
if let value = outputValue as? Int, GRAPHQL_MIN_INT <= value, value <= GRAPHQL_MAX_INT {
return .int(value)
}
throw GraphQLError(
message: "Int cannot represent non-integer value: \(outputValue)"
)
},
parseValue: { inputValue in
if
case let .number(value) = inputValue, Double(GRAPHQL_MIN_INT) <= value.doubleValue,
value.doubleValue <= Double(GRAPHQL_MAX_INT), value.doubleValue.isFinite
{
return .number(value)
}
throw GraphQLError(
message: "Int cannot represent non-integer value: \(inputValue)"
)
},
parseLiteral: { ast in
if let ast = ast as? IntValue, let int = Int(ast.value) {
return .int(int)
Expand All @@ -23,8 +72,39 @@ public let GraphQLFloat = try! GraphQLScalarType(
"The `Float` scalar type represents signed double-precision fractional " +
"values as specified by " +
"[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ",
serialize: { try map(from: $0) },
parseValue: { try .double($0.doubleValue(converting: true)) },
serialize: { outputValue in
if let value = outputValue as? Map {
if case let .number(value) = value {
return .double(value.doubleValue)
}
throw GraphQLError(
message: "Float cannot represent non numeric value: \(value)"
)
}
if let value = outputValue as? Bool {
return value ? .double(1) : .double(0)
}
if let value = outputValue as? String, value != "", let double = Double(value) {
return .double(double)
}
if let value = outputValue as? Double, value.isFinite {
return .double(value)
}
if let value = outputValue as? Int {
return .double(Double(value))
}
throw GraphQLError(
message: "Float cannot represent non numeric value: \(outputValue)"
)
},
parseValue: { inputValue in
if case let .number(value) = inputValue, value.doubleValue.isFinite {
return .number(value)
}
throw GraphQLError(
message: "Float cannot represent non numeric value: \(inputValue)"
)
},
parseLiteral: { ast in
if let ast = ast as? FloatValue, let double = Double(ast.value) {
return .double(double)
Expand All @@ -47,8 +127,39 @@ public let GraphQLString = try! GraphQLScalarType(
"The `String` scalar type represents textual data, represented as UTF-8 " +
"character sequences. The String type is most often used by GraphQL to " +
"represent free-form human-readable text.",
serialize: { try map(from: $0) },
parseValue: { try .string($0.stringValue(converting: true)) },
serialize: { outputValue in
if let value = outputValue as? Map {
if case let .string(value) = value {
return .string(value)
}
throw GraphQLError(
message: "String cannot represent a non string value: \(value)"
)
}
if let value = outputValue as? String {
return .string(value)
}
if let value = outputValue as? Bool {
return value ? .string("true") : .string("false")
}
if let value = outputValue as? Int {
return .string(value.description)
}
if let value = outputValue as? Double, value.isFinite {
return .string(value.description)
}
throw GraphQLError(
message: "String cannot represent value: \(outputValue)"
)
},
parseValue: { outputValue in
if case let .string(value) = outputValue {
return .string(value)
}
throw GraphQLError(
message: "String cannot represent a non string value: \(outputValue)"
)
},
parseLiteral: { ast in
if let ast = ast as? StringValue {
return .string(ast.value)
Expand All @@ -64,8 +175,36 @@ public let GraphQLString = try! GraphQLScalarType(
public let GraphQLBoolean = try! GraphQLScalarType(
name: "Boolean",
description: "The `Boolean` scalar type represents `true` or `false`.",
serialize: { try map(from: $0) },
parseValue: { try .bool($0.boolValue(converting: true)) },
serialize: { outputValue in
if let value = outputValue as? Map {
if case let .bool(value) = value {
return .bool(value)
}
if case let .number(value) = value {
return .bool(value.intValue != 0)
}
throw GraphQLError(
message: "Boolean cannot represent a non boolean value: \(value)"
)
}
if let value = outputValue as? Bool {
return .bool(value)
}
if let value = outputValue as? Int {
return .bool(value != 0)
}
throw GraphQLError(
message: "Boolean cannot represent a non boolean value: \(outputValue)"
)
},
parseValue: { inputValue in
if case let .bool(value) = inputValue {
return inputValue
}
throw GraphQLError(
message: "Boolean cannot represent a non boolean value: \(inputValue)"
)
},
parseLiteral: { ast in
if let ast = ast as? BooleanValue {
return .bool(ast.value)
Expand All @@ -86,8 +225,35 @@ public let GraphQLID = try! GraphQLScalarType(
"response as a String; however, it is not intended to be human-readable. " +
"When expected as an input type, any string (such as `\"4\"`) or integer " +
"(such as `4`) input value will be accepted as an ID.",
serialize: { try map(from: $0) },
parseValue: { try .string($0.stringValue(converting: true)) },
serialize: { outputValue in
if let value = outputValue as? Map {
if case let .string(value) = value {
return .string(value)
}
if case let .number(value) = value {
return .string(value.description)
}
throw GraphQLError(
message: "ID cannot represent value: \(value)"
)
}
if let value = outputValue as? String {
return .string(value)
}
if let value = outputValue as? Int {
return .string(value.description)
}
throw GraphQLError(message: "ID cannot represent value: \(outputValue)")
},
parseValue: { inputValue in
if case let .string(value) = inputValue {
return inputValue
}
if case let .number(value) = inputValue, value.storageType == .int {
return .string(value.description)
}
throw GraphQLError(message: "ID cannot represent value: \(inputValue)")
},
parseLiteral: { ast in
if let ast = ast as? StringValue {
return .string(ast.value)
Expand Down
Loading
Loading