module GraphQL::Schema::Member::HasArguments
Constants
- NO_ARGUMENTS
Public Class Methods
# File lib/graphql/schema/member/has_arguments.rb, line 11 def self.extended(cls) cls.extend(ArgumentClassAccessor) cls.include(ArgumentObjectLoader) end
# File lib/graphql/schema/member/has_arguments.rb, line 6 def self.included(cls) cls.extend(ArgumentClassAccessor) cls.include(ArgumentObjectLoader) end
Public Instance Methods
Register this argument with the class. @param arg_defn [GraphQL::Schema::Argument] @return [GraphQL::Schema::Argument]
# File lib/graphql/schema/member/has_arguments.rb, line 79 def add_argument(arg_defn) @own_arguments ||= {} prev_defn = own_arguments[arg_defn.name] case prev_defn when nil own_arguments[arg_defn.name] = arg_defn when Array prev_defn << arg_defn when GraphQL::Schema::Argument own_arguments[arg_defn.name] = [prev_defn, arg_defn] else raise "Invariant: unexpected `@own_arguments[#{arg_defn.name.inspect}]`: #{prev_defn.inspect}" end arg_defn end
# File lib/graphql/schema/member/has_arguments.rb, line 120 def all_argument_definitions if self.is_a?(Class) all_defns = {} ancestors.reverse_each do |ancestor| if ancestor.respond_to?(:own_arguments) all_defns.merge!(ancestor.own_arguments) end end else all_defns = own_arguments end all_defns = all_defns.values all_defns.flatten! all_defns end
@see {GraphQL::Schema::Argument#initialize} for parameters @return [GraphQL::Schema::Argument] An instance of {arguments_class}, created from `*args`
# File lib/graphql/schema/member/has_arguments.rb, line 18 def argument(*args, **kwargs, &block) kwargs[:owner] = self loads = kwargs[:loads] if loads name = args[0] name_as_string = name.to_s inferred_arg_name = case name_as_string when /_id$/ name_as_string.sub(/_id$/, "").to_sym when /_ids$/ name_as_string.sub(/_ids$/, "") .sub(/([^s])$/, "\\1s") .to_sym else name end kwargs[:as] ||= inferred_arg_name end arg_defn = self.argument_class.new(*args, **kwargs, &block) add_argument(arg_defn) if self.is_a?(Class) && !method_defined?(:"load_#{arg_defn.keyword}") method_owner = if self < GraphQL::Schema::InputObject || self < GraphQL::Schema::Directive "self." elsif self < GraphQL::Schema::Resolver "" else raise "Unexpected argument owner: #{self}" end if loads && arg_defn.type.list? class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method_owner}load_#{arg_defn.keyword}(values, context = nil) argument = get_argument("#{arg_defn.graphql_name}") (context || self.context).schema.after_lazy(values) do |values2| GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) }) end end RUBY elsif loads class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method_owner}load_#{arg_defn.keyword}(value, context = nil) argument = get_argument("#{arg_defn.graphql_name}") load_application_object(argument, value, context || self.context) end RUBY else class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{method_owner}load_#{arg_defn.keyword}(value, _context = nil) value end RUBY end end arg_defn end
@param new_arg_class [Class] A class to use for building argument definitions
# File lib/graphql/schema/member/has_arguments.rb, line 155 def argument_class(new_arg_class = nil) self.class.argument_class(new_arg_class) end
@return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
# File lib/graphql/schema/member/has_arguments.rb, line 96 def arguments(context = GraphQL::Query::NullContext) inherited_arguments = ((self.is_a?(Class) && superclass.respond_to?(:arguments)) ? superclass.arguments(context) : nil) # Local definitions override inherited ones if own_arguments.any? own_arguments_that_apply = {} own_arguments.each do |name, args_entry| if (visible_defn = Warden.visible_entry?(:visible_argument?, args_entry, context)) own_arguments_that_apply[visible_defn.graphql_name] = visible_defn end end end if inherited_arguments if own_arguments_that_apply inherited_arguments.merge(own_arguments_that_apply) else inherited_arguments end else # might be nil if there are actually no arguments own_arguments_that_apply || own_arguments end end
# File lib/graphql/schema/member/has_arguments.rb, line 233 def arguments_statically_coercible? return @arguments_statically_coercible if defined?(@arguments_statically_coercible) @arguments_statically_coercible = all_argument_definitions.all?(&:statically_coercible?) end
@api private If given a block, it will eventually yield the loaded args to the block.
If no block is given, it will immediately dataload (but might return a Lazy).
@param values [Hash<String, Object>] @param context [GraphQL::Query::Context] @yield [Interpreter::Arguments, Execution::Lazy
<Interpeter::Arguments>] @return [Interpreter::Arguments, Execution::Lazy
<Interpeter::Arguments>]
# File lib/graphql/schema/member/has_arguments.rb, line 168 def coerce_arguments(parent_object, values, context, &block) # Cache this hash to avoid re-merging it arg_defns = self.arguments(context) total_args_count = arg_defns.size finished_args = nil prepare_finished_args = -> { if total_args_count == 0 finished_args = GraphQL::Execution::Interpreter::Arguments::EMPTY if block_given? block.call(finished_args) end else argument_values = {} resolved_args_count = 0 raised_error = false arg_defns.each do |arg_name, arg_defn| context.dataloader.append_job do begin arg_defn.coerce_into_values(parent_object, values, context, argument_values) rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err raised_error = true finished_args = err if block_given? block.call(finished_args) end end resolved_args_count += 1 if resolved_args_count == total_args_count && !raised_error finished_args = context.schema.after_any_lazies(argument_values.values) { GraphQL::Execution::Interpreter::Arguments.new( argument_values: argument_values, ) } if block_given? block.call(finished_args) end end end end end } if block_given? prepare_finished_args.call nil else # This API returns eagerly, gotta run it now context.dataloader.run_isolated(&prepare_finished_args) finished_args end end
@return [GraphQL::Schema::Argument, nil] Argument
defined on this thing, fetched by name.
# File lib/graphql/schema/member/has_arguments.rb, line 137 def get_argument(argument_name, context = GraphQL::Query::NullContext) warden = Warden.from_context(context) if !self.is_a?(Class) a = own_arguments[argument_name] a && Warden.visible_entry?(:visible_argument?, a, context, warden) else for ancestor in ancestors if ancestor.respond_to?(:own_arguments) && (a = ancestor.own_arguments[argument_name]) && (a = Warden.visible_entry?(:visible_argument?, a, context, warden)) return a end end nil end end
# File lib/graphql/schema/member/has_arguments.rb, line 326 def own_arguments @own_arguments || NO_ARGUMENTS end
Usually, this is validated statically by RequiredArgumentsArePresent, but not for directives. TODO apply static validations on schema definitions?
# File lib/graphql/schema/member/has_arguments.rb, line 225 def validate_directive_argument(arg_defn, value) if arg_defn.owner.is_a?(Class) && arg_defn.owner < GraphQL::Schema::Directive if value.nil? && arg_defn.type.non_null? raise ArgumentError, "#{arg_defn.path} is required, but no value was given" end end end