class GraphQL::Execution::InputValues
Coerces input values (variables and arguments) for a query.
Static validation uses value_from_ast to check literal values, and the runtime uses it to coerce them.
Public Class Methods
Source
# File lib/graphql/execution/input_values.rb, line 10 def initialize(query) @query = query @schema = query.schema @variable_values = nil @coerced_literals = nil end
Public Instance Methods
# File lib/graphql/execution/input_values.rb, line 25 def argument_values(owner_defn, argument_nodes, field_resolve_step) arg_defns = @query.types.arguments(owner_defn) if arg_defns.empty? return [EmptyObjects::EMPTY_HASH, nil] end errors = nil #: untyped argument_values = {} arg_defns.each do |argument_definition| arg_ruby_key = argument_definition.keyword arg_graphql_key = argument_definition.graphql_name arg_node = argument_nodes.find { |a| a.name == arg_graphql_key } if arg_node.nil? || (arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name)) if argument_definition.default_value? arg_value = value_from_ast(argument_definition.default_value, argument_definition.type) argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step) elsif argument_definition.type.non_null? # Add an error end else arg_value = value_from_ast(arg_node.value, argument_definition.type) argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step) end rescue GraphQL::RuntimeError => exec_err errors ||= [] errors << exec_err end return argument_values, errors end
# File lib/graphql/execution/input_values.rb, line 182 def value_from_ast(value_node, type, validate: false) if type.non_null? type = type.of_type if validate && (value_node.nil? || value_node.is_a?(Language::Nodes::NullValue)) raise InvalidLiteralError end end if value_node.nil? || (value_node.is_a?(Language::Nodes::NullValue) && (validate || !type.kind.leaf?)) nil elsif value_node.is_a?(GraphQL::Language::Nodes::VariableIdentifier) # Variables are checked by `VariableUsagesAreAllowed` during validation validate ? nil : variable_values.coerced_value(value_node.name) elsif type.list? inner_type = type.of_type if value_node.is_a?(Array) coerced_items = value_node.map do |inner_value_node| value_from_ast(inner_value_node, inner_type, validate: validate) end coerced_items.freeze else item_value = value_from_ast(value_node, inner_type, validate: validate) [item_value].freeze end elsif type.kind.input_object? coerced_obj = {} if value_node.is_a?(Hash) @query.types.arguments(type).each do |arg| arg_value = value_node[arg.keyword] arg_key = arg.keyword if arg_value.nil? if arg.default_value? coerced_obj[arg_key] = arg.default_value end next end coerced_obj[arg_key] = value_from_ast(arg_value, arg.type, validate: validate) end elsif value_node.is_a?(Language::Nodes::InputObject) if validate && type.one_of? && value_node.arguments.size != 1 # rubocop:disable Development/ContextIsPassedCop raise InvalidLiteralError, "`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{value_node.arguments.size})" # rubocop:disable Development/ContextIsPassedCop end arg_nodes_by_name = value_node.arguments.each_with_object({}) do |arg_node, acc| # rubocop:disable Development/ContextIsPassedCop acc[arg_node.name] = arg_node end @query.types.arguments(type).each do |arg| arg_node = arg_nodes_by_name[arg.graphql_name] arg_key = arg.keyword if arg_node.nil? || (!validate && arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name)) if arg.default_value? coerced_obj[arg_key] = arg.default_value elsif validate && arg.type.non_null? raise InvalidLiteralError end next end coerced_obj[arg_key] = value_from_ast(arg_node.value, arg.type, validate: validate) end if validate value_node.arguments.each do |arg_node| # rubocop:disable Development/ContextIsPassedCop if @query.types.argument(type, arg_node.name).nil? raise InvalidLiteralError end end end elsif validate raise InvalidLiteralError end coerced_obj elsif type.kind.enum? if validate enum_value_from_ast(value_node, type) else if value_node.is_a?(Language::Nodes::Enum) value_node = value_node.name end coerce_leaf_value(value_node, type) end elsif type.kind.scalar? if validate scalar_value_from_ast(value_node, type) elsif (literals = @coerced_literals&.[](type)) && literals.key?(value_node) # This literal was already coerced during validation literals[value_node] else if value_node.is_a?(Language::Nodes::AbstractNode) || value_node.is_a?(Array) value_node = coerce_untyped_input(value_node) end coerce_leaf_value(value_node, type) end elsif validate raise InvalidLiteralError else raise "Unexpected input type: #{type.to_type_signature}." end end
Coerce value_node (a literal from a query string or a default value) for type.
Parameters
-
value_node(GraphQL::Language::Nodes::AbstractNode, Object) -
type(Class<GraphQL::Schema::Member>) -
validate(Boolean) — When true, raiseInvalidLiteralErrorfor invalid values and treat variable references as valid.
Source
# File lib/graphql/execution/input_values.rb, line 17 def variable_values @variable_values ||= GraphQL::Execution::VariableValues.new( @query, @query.selected_operation&.variables || EmptyObjects::EMPTY_ARRAY, @query.provided_variables, ) end