1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
# frozen_string_literal: true
module GraphQL
module Execution
class Interpreter
class ArgumentsCache
def initialize(query)
@query = query
@dataloader = query.context.dataloader
@storage = Hash.new do |h, argument_owner|
args_by_parent = if argument_owner.arguments_statically_coercible?
shared_values_cache = {}
Hash.new do |h2, ignored_parent_object|
h2[ignored_parent_object] = shared_values_cache
end
else
Hash.new do |h2, parent_object|
args_by_node = {}
args_by_node.compare_by_identity
h2[parent_object] = args_by_node
end
end
args_by_parent.compare_by_identity
h[argument_owner] = args_by_parent
end
@storage.compare_by_identity
end
def fetch(ast_node, argument_owner, parent_object)
# This runs eagerly if no block is given
@storage[argument_owner][parent_object][ast_node] ||= begin
args_hash = self.class.prepare_args_hash(@query, ast_node)
kwarg_arguments = argument_owner.coerce_arguments(parent_object, args_hash, @query.context)
@query.after_lazy(kwarg_arguments) do |resolved_args|
@storage[argument_owner][parent_object][ast_node] = resolved_args
end
end
end
# @yield [Interpreter::Arguments, Lazy<Interpreter::Arguments>] The finally-loaded arguments
def dataload_for(ast_node, argument_owner, parent_object, &block)
# First, normalize all AST or Ruby values to a plain Ruby hash
arg_storage = @storage[argument_owner][parent_object]
if (args = arg_storage[ast_node])
yield(args)
else
args_hash = self.class.prepare_args_hash(@query, ast_node)
argument_owner.coerce_arguments(parent_object, args_hash, @query.context) do |resolved_args|
arg_storage[ast_node] = resolved_args
yield(resolved_args)
end
end
nil
end
private
NO_ARGUMENTS = GraphQL::EmptyObjects::EMPTY_HASH
NO_VALUE_GIVEN = NOT_CONFIGURED
def self.prepare_args_hash(query, ast_arg_or_hash_or_value)
case ast_arg_or_hash_or_value
when Hash
if ast_arg_or_hash_or_value.empty?
return NO_ARGUMENTS
end
args_hash = {}
ast_arg_or_hash_or_value.each do |k, v|
args_hash[k] = prepare_args_hash(query, v)
end
args_hash
when Array
ast_arg_or_hash_or_value.map { |v| prepare_args_hash(query, v) }
when GraphQL::Language::Nodes::Field, GraphQL::Language::Nodes::InputObject, GraphQL::Language::Nodes::Directive
if ast_arg_or_hash_or_value.arguments.empty? # rubocop:disable Development/ContextIsPassedCop -- AST-related
return NO_ARGUMENTS
end
args_hash = {}
ast_arg_or_hash_or_value.arguments.each do |arg| # rubocop:disable Development/ContextIsPassedCop -- AST-related
v = prepare_args_hash(query, arg.value)
if v != NO_VALUE_GIVEN
args_hash[arg.name] = v
end
end
args_hash
when GraphQL::Language::Nodes::VariableIdentifier
if query.variables.key?(ast_arg_or_hash_or_value.name)
variable_value = query.variables[ast_arg_or_hash_or_value.name]
prepare_args_hash(query, variable_value)
else
NO_VALUE_GIVEN
end
when GraphQL::Language::Nodes::Enum
ast_arg_or_hash_or_value.name
when GraphQL::Language::Nodes::NullValue
nil
else
ast_arg_or_hash_or_value
end
end
end
end
end
end
|