lib/graphql/execution/lookahead.rb in graphql-1.10.4 vs lib/graphql/execution/lookahead.rb in graphql-1.10.5

- old
+ new

@@ -49,11 +49,19 @@ # @return [GraphQL::Schema::Object, GraphQL::Schema::Union, GraphQL::Schema::Interface] attr_reader :owner_type # @return [Hash<Symbol, Object>] def arguments - @arguments ||= @field && ArgumentHelpers.arguments(@query, @field, ast_nodes.first) + if defined?(@arguments) + @arguments + else + @arguments = if @field + @query.arguments_for(@ast_nodes.first, @field) + else + nil + end + end end # True if this node has a selection on `field_name`. # If `field_name` is a String, it is treated as a GraphQL-style (camelized) # field name and used verbatim. If `field_name` is a Symbol, it is @@ -79,11 +87,11 @@ # It returns a null object (check with {#selected?}) # @return [GraphQL::Execution::Lookahead] def selection(field_name, selected_type: @selected_type, arguments: nil) next_field_name = normalize_name(field_name) - next_field_defn = FieldHelpers.get_field(@query.schema, selected_type, next_field_name) + next_field_defn = get_class_based_field(selected_type, next_field_name) if next_field_defn next_nodes = [] @ast_nodes.each do |ast_node| ast_node.selections.each do |selection| find_selected_nodes(selection, next_field_name, next_field_defn, arguments: arguments, matches: next_nodes) @@ -125,11 +133,11 @@ subselections = [] subselections_by_type.each do |type, ast_nodes_by_response_key| ast_nodes_by_response_key.each do |response_key, ast_nodes| - field_defn = FieldHelpers.get_field(@query.schema, type, ast_nodes.first.name) + field_defn = get_class_based_field(type, ast_nodes.first.name) lookahead = Lookahead.new(query: @query, ast_nodes: ast_nodes, field: field_defn, owner_type: type) subselections.push(lookahead) end end @@ -201,16 +209,23 @@ else keyword end end + # Wrap get_field and ensure that it returns a GraphQL::Schema::Field. + # Remove this when legacy execution is removed. + def get_class_based_field(type, name) + f = @query.get_field(type, name) + f && f.type_class + end + def skipped_by_directive?(ast_selection) ast_selection.directives.each do |directive| dir_defn = @query.schema.directives.fetch(directive.name) directive_class = dir_defn.type_class if directive_class - dir_args = GraphQL::Execution::Lookahead::ArgumentHelpers.arguments(@query, dir_defn, directive) + dir_args = @query.arguments_for(directive, dir_defn) return true unless directive_class.static_include?(dir_args, @query.context) end end false end @@ -225,11 +240,11 @@ if selections_on_type.key?(response_key) selections_on_type[response_key] << ast_selection elsif arguments.nil? || arguments.empty? selections_on_type[response_key] = [ast_selection] else - field_defn = FieldHelpers.get_field(@query.schema, selected_type, ast_selection.name) + field_defn = get_class_based_field(selected_type, ast_selection.name) if arguments_match?(arguments, field_defn, ast_selection) selections_on_type[response_key] = [ast_selection] end end when GraphQL::Language::Nodes::InlineFragment @@ -276,116 +291,14 @@ raise "Unexpected selection comparison on #{node.class.name} (#{node})" end end def arguments_match?(arguments, field_defn, field_node) - query_kwargs = ArgumentHelpers.arguments(@query, field_defn, field_node) + query_kwargs = @query.arguments_for(field_node, field_defn) arguments.all? do |arg_name, arg_value| arg_name = normalize_keyword(arg_name) # Make sure the constraint is present with a matching value query_kwargs.key?(arg_name) && query_kwargs[arg_name] == arg_value - end - end - - # TODO Dedup with interpreter - module ArgumentHelpers - module_function - - def arguments(query, arg_owner, ast_node) - kwarg_arguments = {} - arg_defns = arg_owner.arguments - ast_node.arguments.each do |arg| - arg_defn = arg_defns[arg.name] || raise("Invariant: missing argument definition for #{arg.name.inspect} in #{arg_defns.keys} from #{arg_owner}") - # Need to distinguish between client-provided `nil` - # and nothing-at-all - is_present, value = arg_to_value(query, arg_defn.type, arg.value) - if is_present - kwarg_arguments[arg_defn.keyword] = value - end - end - arg_defns.each do |name, arg_defn| - if arg_defn.default_value? && !kwarg_arguments.key?(arg_defn.keyword) - kwarg_arguments[arg_defn.keyword] = arg_defn.default_value - end - end - kwarg_arguments - end - - # Get a Ruby-ready value from a client query. - # @param graphql_object [Object] The owner of the field whose argument this is - # @param arg_type [Class, GraphQL::Schema::NonNull, GraphQL::Schema::List] - # @param ast_value [GraphQL::Language::Nodes::VariableIdentifier, String, Integer, Float, Boolean] - # @return [Array(is_present, value)] - def arg_to_value(query, arg_type, ast_value) - if ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier) - # If it's not here, it will get added later - if query.variables.key?(ast_value.name) - return true, query.variables[ast_value.name] - else - return false, nil - end - elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue) - return true, nil - elsif arg_type.is_a?(GraphQL::Schema::NonNull) - arg_to_value(query, arg_type.of_type, ast_value) - elsif arg_type.is_a?(GraphQL::Schema::List) - # Treat a single value like a list - arg_value = Array(ast_value) - list = [] - arg_value.map do |inner_v| - _present, value = arg_to_value(query, arg_type.of_type, inner_v) - list << value - end - return true, list - elsif arg_type.is_a?(Class) && arg_type < GraphQL::Schema::InputObject - # For these, `prepare` is applied during `#initialize`. - # Pass `nil` so it will be skipped in `#arguments`. - # What a mess. - args = arguments(query, nil, arg_type, ast_value) - # We're not tracking defaults_used, but for our purposes - # we compare the value to the default value. - return true, arg_type.new(ruby_kwargs: args, context: query.context, defaults_used: nil) - else - flat_value = flatten_ast_value(query, ast_value) - return true, arg_type.coerce_input(flat_value, query.context) - end - end - - def flatten_ast_value(query, v) - case v - when GraphQL::Language::Nodes::Enum - v.name - when GraphQL::Language::Nodes::InputObject - h = {} - v.arguments.each do |arg| - h[arg.name] = flatten_ast_value(query, arg.value) - end - h - when Array - v.map { |v2| flatten_ast_value(query, v2) } - when GraphQL::Language::Nodes::VariableIdentifier - flatten_ast_value(query.variables[v.name]) - else - v - end - end - end - - # TODO dedup with interpreter - module FieldHelpers - module_function - - def get_field(schema, owner_type, field_name) - field_defn = owner_type.get_field(field_name) - field_defn ||= if owner_type == schema.query.type_class && (entry_point_field = schema.introspection_system.entry_point(name: field_name)) - entry_point_field.type_class - elsif (dynamic_field = schema.introspection_system.dynamic_field(name: field_name)) - dynamic_field.type_class - else - nil - end - - field_defn end end end end end