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

Scalar customizations #118

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 47 additions & 16 deletions Sources/Graphiti/Scalar/Scalar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import OrderedCollections
/// Represents a scalar type in the schema.
///
/// It is **highly** recommended that you do not subclass this type.
/// Instead, modify the encoding/decoding behavior through the `MapEncoder`/`MapDecoder` options available through
/// `Coders` or a custom encoding/decoding on the `ScalarType` itself.
/// Encoding/decoding behavior can be modified through the `MapEncoder`/`MapDecoder` options available through
/// `Coders` or a custom encoding/decoding on the `ScalarType` itself. If you need very custom serialization controls,
/// you may provide your own serialize, parseValue, and parseLiteral implementations.
open class Scalar<Resolver, Context, ScalarType: Codable>: TypeComponent<Resolver, Context> {
// TODO: Change this no longer be an open class

Expand All @@ -14,22 +15,34 @@ open class Scalar<Resolver, Context, ScalarType: Codable>: TypeComponent<Resolve
name: name,
description: description,
serialize: { value in
guard let scalar = value as? ScalarType else {
throw GraphQLError(
message: "Serialize expected type \(ScalarType.self) but got \(type(of: value))"
)
if let serialize = self.serialize {
return try serialize(value, coders)
} else {
guard let scalar = value as? ScalarType else {
throw GraphQLError(
message: "Serialize expected type \(ScalarType.self) but got \(type(of: value))"
)
}

return try self.serialize(scalar: scalar, encoder: coders.encoder)
}

return try self.serialize(scalar: scalar, encoder: coders.encoder)
},
parseValue: { map in
let scalar = try self.parse(map: map, decoder: coders.decoder)
return try self.serialize(scalar: scalar, encoder: coders.encoder)
if let parseValue = self.parseValue {
return try parseValue(map, coders)
} else {
let scalar = try self.parse(map: map, decoder: coders.decoder)
return try self.serialize(scalar: scalar, encoder: coders.encoder)
}
},
parseLiteral: { value in
let map = value.map
let scalar = try self.parse(map: map, decoder: coders.decoder)
return try self.serialize(scalar: scalar, encoder: coders.encoder)
if let parseLiteral = self.parseLiteral {
return try parseLiteral(value, coders)
} else {
let map = value.map
let scalar = try self.parse(map: map, decoder: coders.decoder)
return try self.serialize(scalar: scalar, encoder: coders.encoder)
}
}
)

Expand All @@ -40,18 +53,30 @@ open class Scalar<Resolver, Context, ScalarType: Codable>: TypeComponent<Resolve
try typeProvider.mapName(ScalarType.self, to: name)
}

// TODO: Remove open func, instead relying on a passed closure
open func serialize(scalar: ScalarType, encoder: MapEncoder) throws -> Map {
try encoder.encode(scalar)
}

// TODO: Remove open func, instead relying on a passed closure
open func parse(map: Map, decoder: MapDecoder) throws -> ScalarType {
try decoder.decode(ScalarType.self, from: map)
}

let serialize: ((Any, Coders) throws -> Map)?
let parseValue: ((Map, Coders) throws -> Map)?
let parseLiteral: ((GraphQL.Value, Coders) throws -> Map)?

init(
type _: ScalarType.Type,
name: String?
name: String?,
serialize: ((Any, Coders) throws -> Map)? = nil,
parseValue: ((Map, Coders) throws -> Map)? = nil,
parseLiteral: ((GraphQL.Value, Coders) throws -> Map)? = nil
) {
self.serialize = serialize
self.parseValue = parseValue
self.parseLiteral = parseLiteral
super.init(
name: name ?? Reflection.name(for: ScalarType.self),
type: .scalar
Expand All @@ -62,11 +87,17 @@ open class Scalar<Resolver, Context, ScalarType: Codable>: TypeComponent<Resolve
public extension Scalar {
convenience init(
_ type: ScalarType.Type,
as name: String? = nil
as name: String? = nil,
serialize: ((Any, Coders) throws -> Map)? = nil,
parseValue: ((Map, Coders) throws -> Map)? = nil,
parseLiteral: ((GraphQL.Value, Coders) throws -> Map)? = nil
) {
self.init(
type: type,
name: name
name: name,
serialize: serialize,
parseValue: parseValue,
parseLiteral: parseLiteral
)
}
}
Expand Down