Repository URL to install this package:
|
Version:
1.8.2 ▾
|
# frozen_string_literal: true
module GraphQL
# # GraphQL::ScalarType
#
# Scalars are plain values. They are leaf nodes in a GraphQL query tree.
#
# ## Built-in Scalars
#
# `GraphQL` comes with standard built-in scalars:
#
# |Constant | `.define` helper|
# |-------|--------|
# |`GraphQL::STRING_TYPE` | `types.String`|
# |`GraphQL::INT_TYPE` | `types.Int`|
# |`GraphQL::FLOAT_TYPE` | `types.Float`|
# |`GraphQL::ID_TYPE` | `types.ID`|
# |`GraphQL::BOOLEAN_TYPE` | `types.Boolean`|
#
# (`types` is an instance of `GraphQL::Definition::TypeDefiner`; `.String`, `.Float`, etc are methods which return built-in scalars.)
#
# ## Custom Scalars
#
# You can define custom scalars for your GraphQL server. It requires some special functions:
#
# - `coerce_input` is used to prepare incoming values for GraphQL execution. (Incoming values come from variables or literal values in the query string.)
# - `coerce_result` is used to turn Ruby values _back_ into serializable values for query responses.
#
# @example defining a type for Time
# TimeType = GraphQL::ScalarType.define do
# name "Time"
# description "Time since epoch in seconds"
#
# coerce_input ->(value, ctx) { Time.at(Float(value)) }
# coerce_result ->(value, ctx) { value.to_f }
# end
#
#
# You can customize the error message for invalid input values by raising a `GraphQL::CoercionError` within `coerce_input`:
#
# @example raising a custom error message
# TimeType = GraphQL::ScalarType.define do
# name "Time"
# description "Time since epoch in seconds"
#
# coerce_input ->(value, ctx) do
# begin
# Time.at(Float(value))
# rescue ArgumentError
# raise GraphQL::CoercionError, "cannot coerce `#{value.inspect}` to Float"
# end
# end
#
# coerce_result ->(value, ctx) { value.to_f }
# end
#
# This will result in the message of the `GraphQL::CoercionError` being used in the error response:
#
# @example custom error response
# {"message"=>"cannot coerce `"2"` to Float", "locations"=>[{"line"=>3, "column"=>9}], "fields"=>["arg"]}
#
class ScalarType < GraphQL::BaseType
accepts_definitions :coerce, :coerce_input, :coerce_result
ensure_defined :coerce_non_null_input, :coerce_result
module NoOpCoerce
def self.call(val, ctx)
val
end
end
def initialize
super
self.coerce = NoOpCoerce
end
def coerce=(proc)
self.coerce_input = proc
self.coerce_result = proc
end
def coerce_input=(coerce_input_fn)
if !coerce_input_fn.nil?
@coerce_input_proc = ensure_two_arg(coerce_input_fn, :coerce_input)
end
end
def coerce_result(value, ctx = nil)
if ctx.nil?
warn_deprecated_coerce("coerce_isolated_result")
ctx = GraphQL::Query::NullContext
end
@coerce_result_proc.call(value, ctx)
end
def coerce_result=(coerce_result_fn)
if !coerce_result_fn.nil?
@coerce_result_proc = ensure_two_arg(coerce_result_fn, :coerce_result)
end
end
def kind
GraphQL::TypeKinds::SCALAR
end
private
def ensure_two_arg(callable, method_name)
GraphQL::BackwardsCompatibility.wrap_arity(callable, from: 1, to: 2, name: "#{name}.#{method_name}(val, ctx)")
end
def coerce_non_null_input(value, ctx)
@coerce_input_proc.call(raw_coercion_input(value), ctx)
end
def raw_coercion_input(value)
if value.is_a?(GraphQL::Language::Nodes::InputObject)
value.to_h
elsif value.is_a?(Array)
value.map { |element| raw_coercion_input(element) }
elsif value.is_a?(GraphQL::Language::Nodes::Enum)
value.name
else
value
end
end
def validate_non_null_input(value, ctx)
result = Query::InputValidationResult.new
if coerce_non_null_input(value, ctx).nil?
result.add_problem("Could not coerce value #{GraphQL::Language.serialize(value)} to #{name}")
end
result
end
end
end