Skip to content

Commit

Permalink
Merge pull request #153 from NeedleInAJayStack/fix/issue-152
Browse files Browse the repository at this point in the history
Fixes scalar type serialization
  • Loading branch information
NeedleInAJayStack authored Oct 18, 2024
2 parents afbad07 + 2a17bfc commit d52f328
Show file tree
Hide file tree
Showing 2 changed files with 607 additions and 10 deletions.
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

0 comments on commit d52f328

Please sign in to comment.