graphql 1.12.21 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/mutation_generator.rb +1 -1
- data/lib/generators/graphql/type_generator.rb +0 -1
- data/lib/graphql/analysis/ast/field_usage.rb +2 -2
- data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
- data/lib/graphql/analysis/ast/visitor.rb +4 -4
- data/lib/graphql/backtrace/table.rb +1 -1
- data/lib/graphql/dataloader.rb +55 -22
- data/lib/graphql/directive.rb +0 -4
- data/lib/graphql/enum_type.rb +5 -1
- data/lib/graphql/execution/errors.rb +1 -0
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -2
- data/lib/graphql/execution/interpreter/runtime.rb +20 -12
- data/lib/graphql/execution/lookahead.rb +2 -2
- data/lib/graphql/execution/multiplex.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +2 -2
- data/lib/graphql/introspection/input_value_type.rb +4 -4
- data/lib/graphql/introspection/schema_type.rb +2 -2
- data/lib/graphql/introspection/type_type.rb +10 -10
- data/lib/graphql/language/block_string.rb +0 -4
- data/lib/graphql/language/document_from_schema_definition.rb +4 -2
- data/lib/graphql/language/lexer.rb +0 -3
- data/lib/graphql/language/lexer.rl +0 -4
- data/lib/graphql/language/nodes.rb +2 -1
- data/lib/graphql/language/parser.rb +442 -434
- data/lib/graphql/language/parser.y +5 -4
- data/lib/graphql/language/printer.rb +6 -1
- data/lib/graphql/language/sanitized_printer.rb +5 -5
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/query/arguments.rb +1 -1
- data/lib/graphql/query/arguments_cache.rb +1 -1
- data/lib/graphql/query/context.rb +5 -2
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/query/null_context.rb +12 -7
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
- data/lib/graphql/query/variables.rb +5 -1
- data/lib/graphql/relay/edges_instrumentation.rb +0 -1
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/schema/addition.rb +37 -28
- data/lib/graphql/schema/argument.rb +6 -6
- data/lib/graphql/schema/build_from_definition.rb +5 -5
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +2 -2
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +2 -2
- data/lib/graphql/schema/enum.rb +57 -9
- data/lib/graphql/schema/enum_value.rb +4 -0
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +92 -17
- data/lib/graphql/schema/find_inherited_value.rb +1 -0
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/input_object.rb +6 -5
- data/lib/graphql/schema/interface.rb +8 -19
- data/lib/graphql/schema/member/accepts_definition.rb +8 -1
- data/lib/graphql/schema/member/build_type.rb +0 -4
- data/lib/graphql/schema/member/has_arguments.rb +55 -13
- data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +76 -18
- data/lib/graphql/schema/member/has_interfaces.rb +90 -0
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/object.rb +7 -74
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +29 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
- data/lib/graphql/schema/resolver.rb +19 -5
- data/lib/graphql/schema/subscription.rb +11 -1
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +18 -4
- data/lib/graphql/schema/union.rb +6 -1
- data/lib/graphql/schema/validator/format_validator.rb +0 -4
- data/lib/graphql/schema/validator/numericality_validator.rb +1 -0
- data/lib/graphql/schema/warden.rb +116 -52
- data/lib/graphql/schema.rb +87 -15
- data/lib/graphql/static_validation/base_visitor.rb +5 -5
- data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
- data/lib/graphql/static_validation/literal_validator.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +7 -7
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +6 -4
- data/lib/graphql/subscriptions/event.rb +20 -12
- data/lib/graphql/subscriptions.rb +17 -19
- data/lib/graphql/types/relay/has_node_field.rb +1 -1
- data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +9 -31
- metadata +10 -5
@@ -61,9 +61,9 @@ module GraphQL
|
|
61
61
|
defn.default_directive = self.default_directive
|
62
62
|
defn.ast_node = ast_node
|
63
63
|
defn.metadata[:type_class] = self
|
64
|
-
|
64
|
+
all_argument_definitions.each do |arg_defn|
|
65
65
|
arg_graphql = arg_defn.to_graphql
|
66
|
-
defn.arguments[arg_graphql.name] = arg_graphql
|
66
|
+
defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
67
67
|
end
|
68
68
|
# Make a reference to a classic-style Arguments class
|
69
69
|
defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(defn)
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -46,18 +46,66 @@ module GraphQL
|
|
46
46
|
def value(*args, **kwargs, &block)
|
47
47
|
kwargs[:owner] = self
|
48
48
|
value = enum_value_class.new(*args, **kwargs, &block)
|
49
|
-
|
50
|
-
|
49
|
+
key = value.graphql_name
|
50
|
+
prev_value = own_values[key]
|
51
|
+
case prev_value
|
52
|
+
when nil
|
53
|
+
own_values[key] = value
|
54
|
+
when GraphQL::Schema::EnumValue
|
55
|
+
own_values[key] = [prev_value, value]
|
56
|
+
when Array
|
57
|
+
prev_value << value
|
58
|
+
else
|
59
|
+
raise "Invariant: Unexpected enum value for #{key.inspect}: #{prev_value.inspect}"
|
60
|
+
end
|
61
|
+
value
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Array<GraphQL::Schema::EnumValue>] Possible values of this enum
|
65
|
+
def enum_values(context = GraphQL::Query::NullContext)
|
66
|
+
inherited_values = superclass.respond_to?(:enum_values) ? superclass.enum_values(context) : nil
|
67
|
+
visible_values = []
|
68
|
+
warden = Warden.from_context(context)
|
69
|
+
own_values.each do |key, values_entry|
|
70
|
+
if (v = Warden.visible_entry?(:visible_enum_value?, values_entry, context, warden))
|
71
|
+
visible_values << v
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if inherited_values
|
76
|
+
# Local values take precedence over inherited ones
|
77
|
+
inherited_values.each do |i_val|
|
78
|
+
if !visible_values.any? { |v| v.graphql_name == i_val.graphql_name }
|
79
|
+
visible_values << i_val
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
visible_values
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Array<Schema::EnumValue>] An unfiltered list of all definitions
|
88
|
+
def all_enum_value_definitions
|
89
|
+
all_defns = if superclass.respond_to?(:all_enum_value_definitions)
|
90
|
+
superclass.all_enum_value_definitions
|
91
|
+
else
|
92
|
+
[]
|
51
93
|
end
|
52
|
-
|
53
|
-
|
94
|
+
|
95
|
+
@own_values && @own_values.each do |_key, value|
|
96
|
+
if value.is_a?(Array)
|
97
|
+
all_defns.concat(value)
|
98
|
+
else
|
99
|
+
all_defns << value
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
all_defns
|
54
104
|
end
|
55
105
|
|
56
|
-
# @return [Hash<String => GraphQL::Schema::
|
57
|
-
def values
|
58
|
-
|
59
|
-
# Local values take precedence over inherited ones
|
60
|
-
inherited_values.merge(own_values)
|
106
|
+
# @return [Hash<String => GraphQL::Schema::EnumValue>] Possible values of this enum, keyed by name.
|
107
|
+
def values(context = GraphQL::Query::NullContext)
|
108
|
+
enum_values(context).each_with_object({}) { |val, obj| obj[val.graphql_name] = val }
|
61
109
|
end
|
62
110
|
|
63
111
|
# @return [GraphQL::EnumType]
|
@@ -85,6 +85,10 @@ module GraphQL
|
|
85
85
|
enum_value
|
86
86
|
end
|
87
87
|
|
88
|
+
def inspect
|
89
|
+
"#<#{self.class} #{path} @value=#{@value.inspect}#{description ? " @description=#{description.inspect}" : ""}>"
|
90
|
+
end
|
91
|
+
|
88
92
|
def visible?(_ctx); true; end
|
89
93
|
def accessible?(_ctx); true; end
|
90
94
|
def authorized?(_ctx); true; end
|
@@ -42,7 +42,7 @@ module GraphQL
|
|
42
42
|
value.after_value ||= original_arguments[:after]
|
43
43
|
value.last_value ||= original_arguments[:last]
|
44
44
|
value.before_value ||= original_arguments[:before]
|
45
|
-
value.arguments ||= original_arguments
|
45
|
+
value.arguments ||= original_arguments # rubocop:disable Development/ContextIsPassedCop -- unrelated .arguments method
|
46
46
|
value.field ||= field
|
47
47
|
if field.has_max_page_size? && !value.has_max_page_size_override?
|
48
48
|
value.max_page_size = field.max_page_size
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -5,10 +5,6 @@ require "graphql/schema/field/scope_extension"
|
|
5
5
|
module GraphQL
|
6
6
|
class Schema
|
7
7
|
class Field
|
8
|
-
if !String.method_defined?(:-@)
|
9
|
-
using GraphQL::StringDedupBackport
|
10
|
-
end
|
11
|
-
|
12
8
|
include GraphQL::Schema::Member::CachedGraphQLDefinition
|
13
9
|
include GraphQL::Schema::Member::AcceptsDefinition
|
14
10
|
include GraphQL::Schema::Member::HasArguments
|
@@ -61,7 +57,7 @@ module GraphQL
|
|
61
57
|
end
|
62
58
|
|
63
59
|
def inspect
|
64
|
-
"#<#{self.class} #{path}#{
|
60
|
+
"#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
|
65
61
|
end
|
66
62
|
|
67
63
|
alias :mutation :resolver
|
@@ -212,7 +208,7 @@ module GraphQL
|
|
212
208
|
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
213
209
|
# @param validates [Array<Hash>] Configurations for validating this field
|
214
210
|
# @param legacy_edge_class [Class, nil] (DEPRECATED) If present, pass this along to the legacy field definition
|
215
|
-
def initialize(type: nil, name: nil, owner: nil, null:
|
211
|
+
def initialize(type: nil, name: nil, owner: nil, null: true, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, legacy_edge_class: nil, &definition_block)
|
216
212
|
if name.nil?
|
217
213
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
218
214
|
end
|
@@ -220,9 +216,6 @@ module GraphQL
|
|
220
216
|
if type.nil?
|
221
217
|
raise ArgumentError, "missing second `type` argument or keyword `type:`"
|
222
218
|
end
|
223
|
-
if null.nil?
|
224
|
-
raise ArgumentError, "missing keyword argument null:"
|
225
|
-
end
|
226
219
|
end
|
227
220
|
if (field || function || resolve) && extras.any?
|
228
221
|
raise ArgumentError, "keyword `extras:` may only be used with method-based resolve and class-based field such as mutation class, please remove `field:`, `function:` or `resolve:`"
|
@@ -281,10 +274,15 @@ module GraphQL
|
|
281
274
|
@legacy_edge_class = legacy_edge_class
|
282
275
|
|
283
276
|
arguments.each do |name, arg|
|
284
|
-
|
277
|
+
case arg
|
278
|
+
when Hash
|
285
279
|
argument(name: name, **arg)
|
286
|
-
|
280
|
+
when GraphQL::Schema::Argument
|
287
281
|
add_argument(arg)
|
282
|
+
when Array
|
283
|
+
arg.each { |a| add_argument(a) }
|
284
|
+
else
|
285
|
+
raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
|
288
286
|
end
|
289
287
|
end
|
290
288
|
|
@@ -411,6 +409,57 @@ module GraphQL
|
|
411
409
|
end
|
412
410
|
end
|
413
411
|
|
412
|
+
def calculate_complexity(query:, nodes:, child_complexity:)
|
413
|
+
if respond_to?(:complexity_for)
|
414
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
415
|
+
complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
|
416
|
+
elsif connection?
|
417
|
+
arguments = query.arguments_for(nodes.first, self)
|
418
|
+
max_possible_page_size = nil
|
419
|
+
if arguments[:first]
|
420
|
+
max_possible_page_size = arguments[:first]
|
421
|
+
end
|
422
|
+
if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
|
423
|
+
max_possible_page_size = arguments[:last]
|
424
|
+
end
|
425
|
+
|
426
|
+
if max_possible_page_size.nil?
|
427
|
+
max_possible_page_size = max_page_size || query.schema.default_max_page_size
|
428
|
+
end
|
429
|
+
|
430
|
+
if max_possible_page_size.nil?
|
431
|
+
raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
|
432
|
+
else
|
433
|
+
metadata_complexity = 0
|
434
|
+
lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
|
435
|
+
|
436
|
+
if (page_info_lookahead = lookahead.selection(:page_info)).selected?
|
437
|
+
metadata_complexity += 1 # pageInfo
|
438
|
+
metadata_complexity += page_info_lookahead.selections.size # subfields
|
439
|
+
end
|
440
|
+
|
441
|
+
if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
|
442
|
+
metadata_complexity += 1
|
443
|
+
end
|
444
|
+
# Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
|
445
|
+
items_complexity = child_complexity - metadata_complexity
|
446
|
+
# Add 1 for _this_ field
|
447
|
+
1 + (max_possible_page_size * items_complexity) + metadata_complexity
|
448
|
+
end
|
449
|
+
else
|
450
|
+
defined_complexity = complexity
|
451
|
+
case defined_complexity
|
452
|
+
when Proc
|
453
|
+
arguments = query.arguments_for(nodes.first, self)
|
454
|
+
defined_complexity.call(query.context, arguments.keyword_arguments, child_complexity)
|
455
|
+
when Numeric
|
456
|
+
defined_complexity + child_complexity
|
457
|
+
else
|
458
|
+
raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
414
463
|
def complexity(new_complexity = nil)
|
415
464
|
case new_complexity
|
416
465
|
when Proc
|
@@ -493,9 +542,9 @@ module GraphQL
|
|
493
542
|
field_defn.subscription_scope = @subscription_scope
|
494
543
|
field_defn.ast_node = ast_node
|
495
544
|
|
496
|
-
|
545
|
+
all_argument_definitions.each do |defn|
|
497
546
|
arg_graphql = defn.to_graphql
|
498
|
-
field_defn.arguments[arg_graphql.name] = arg_graphql
|
547
|
+
field_defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
499
548
|
end
|
500
549
|
|
501
550
|
# Support a passed-in proc, one way or another
|
@@ -559,10 +608,36 @@ module GraphQL
|
|
559
608
|
# The resolver will check itself during `resolve()`
|
560
609
|
@resolver_class.authorized?(object, context)
|
561
610
|
else
|
611
|
+
if (arg_values = context[:current_arguments])
|
612
|
+
# ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
|
613
|
+
using_arg_values = true
|
614
|
+
arg_values = arg_values.argument_values
|
615
|
+
else
|
616
|
+
arg_values = args
|
617
|
+
using_arg_values = false
|
618
|
+
end
|
562
619
|
# Faster than `.any?`
|
563
|
-
arguments.each_value do |arg|
|
564
|
-
|
565
|
-
|
620
|
+
arguments(context).each_value do |arg|
|
621
|
+
arg_key = arg.keyword
|
622
|
+
if arg_values.key?(arg_key)
|
623
|
+
arg_value = arg_values[arg_key]
|
624
|
+
if using_arg_values
|
625
|
+
if arg_value.default_used?
|
626
|
+
# pass -- no auth required for default used
|
627
|
+
next
|
628
|
+
else
|
629
|
+
application_arg_value = arg_value.value
|
630
|
+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
|
631
|
+
application_arg_value.keyword_arguments
|
632
|
+
end
|
633
|
+
end
|
634
|
+
else
|
635
|
+
application_arg_value = arg_value
|
636
|
+
end
|
637
|
+
|
638
|
+
if !arg.authorized?(object, application_arg_value, context)
|
639
|
+
return false
|
640
|
+
end
|
566
641
|
end
|
567
642
|
end
|
568
643
|
true
|
@@ -659,7 +734,7 @@ module GraphQL
|
|
659
734
|
ruby_kwargs = graphql_args.to_kwargs
|
660
735
|
maybe_lazies = []
|
661
736
|
# Apply any `prepare` methods. Not great code organization, can this go somewhere better?
|
662
|
-
arguments.each do |name, arg_defn|
|
737
|
+
arguments(field_ctx).each do |name, arg_defn|
|
663
738
|
ruby_kwargs_key = arg_defn.keyword
|
664
739
|
|
665
740
|
if ruby_kwargs.key?(ruby_kwargs_key)
|
@@ -38,7 +38,7 @@ module GraphQL
|
|
38
38
|
|
39
39
|
find_in_directive(directive, path: path)
|
40
40
|
else
|
41
|
-
type = schema.get_type(type_or_directive)
|
41
|
+
type = schema.get_type(type_or_directive) # rubocop:disable Development/ContextIsPassedCop -- build-time
|
42
42
|
|
43
43
|
if type.nil?
|
44
44
|
raise MemberNotFoundError, "Could not find type `#{type_or_directive}` in schema."
|
@@ -56,7 +56,7 @@ module GraphQL
|
|
56
56
|
|
57
57
|
def find_in_directive(directive, path:)
|
58
58
|
argument_name = path.shift
|
59
|
-
argument = directive.
|
59
|
+
argument = directive.get_argument(argument_name) # rubocop:disable Development/ContextIsPassedCop -- build-time
|
60
60
|
|
61
61
|
if argument.nil?
|
62
62
|
raise MemberNotFoundError, "Could not find argument `#{argument_name}` on directive #{directive}."
|
@@ -102,7 +102,7 @@ module GraphQL
|
|
102
102
|
|
103
103
|
def find_in_field(field, path:)
|
104
104
|
argument_name = path.shift
|
105
|
-
argument = field.
|
105
|
+
argument = field.get_argument(argument_name) # rubocop:disable Development/ContextIsPassedCop -- build-time
|
106
106
|
|
107
107
|
if argument.nil?
|
108
108
|
raise MemberNotFoundError, "Could not find argument `#{argument_name}` on field `#{field.name}`."
|
@@ -119,7 +119,7 @@ module GraphQL
|
|
119
119
|
|
120
120
|
def find_in_input_object(input_object, path:)
|
121
121
|
field_name = path.shift
|
122
|
-
input_field = input_object.
|
122
|
+
input_field = input_object.get_argument(field_name) # rubocop:disable Development/ContextIsPassedCop -- build-time
|
123
123
|
|
124
124
|
if input_field.nil?
|
125
125
|
raise MemberNotFoundError, "Could not find input field `#{field_name}` on input object type `#{input_object.graphql_name}`."
|
@@ -136,7 +136,7 @@ module GraphQL
|
|
136
136
|
|
137
137
|
def find_in_enum_type(enum_type, path:)
|
138
138
|
value_name = path.shift
|
139
|
-
enum_value = enum_type.
|
139
|
+
enum_value = enum_type.enum_values.find { |v| v.graphql_name == value_name } # rubocop:disable Development/ContextIsPassedCop -- build-time, not runtime
|
140
140
|
|
141
141
|
if enum_value.nil?
|
142
142
|
raise MemberNotFoundError, "Could not find enum value `#{value_name}` on enum type `#{enum_type.graphql_name}`."
|
@@ -31,7 +31,7 @@ module GraphQL
|
|
31
31
|
end
|
32
32
|
# Apply prepares, not great to have it duplicated here.
|
33
33
|
maybe_lazies = []
|
34
|
-
self.class.arguments.each_value do |arg_defn|
|
34
|
+
self.class.arguments(context).each_value do |arg_defn|
|
35
35
|
ruby_kwargs_key = arg_defn.keyword
|
36
36
|
|
37
37
|
if @ruby_style_hash.key?(ruby_kwargs_key)
|
@@ -129,6 +129,7 @@ module GraphQL
|
|
129
129
|
self[#{method_name.inspect}]
|
130
130
|
end
|
131
131
|
RUBY
|
132
|
+
argument_defn
|
132
133
|
end
|
133
134
|
|
134
135
|
def to_graphql
|
@@ -138,8 +139,8 @@ module GraphQL
|
|
138
139
|
type_defn.metadata[:type_class] = self
|
139
140
|
type_defn.mutation = mutation
|
140
141
|
type_defn.ast_node = ast_node
|
141
|
-
|
142
|
-
type_defn.arguments[arg.graphql_definition.name] = arg.graphql_definition
|
142
|
+
all_argument_definitions.each do |arg|
|
143
|
+
type_defn.arguments[arg.graphql_definition.name] = arg.graphql_definition # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
143
144
|
end
|
144
145
|
# Make a reference to a classic-style Arguments class
|
145
146
|
self.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(type_defn)
|
@@ -172,7 +173,7 @@ module GraphQL
|
|
172
173
|
end
|
173
174
|
|
174
175
|
# Inject missing required arguments
|
175
|
-
missing_required_inputs = self.arguments.reduce({}) do |m, (argument_name, argument)|
|
176
|
+
missing_required_inputs = self.arguments(ctx).reduce({}) do |m, (argument_name, argument)|
|
176
177
|
if !input.key?(argument_name) && argument.type.non_null? && warden.get_argument(self, argument_name)
|
177
178
|
m[argument_name] = nil
|
178
179
|
end
|
@@ -223,7 +224,7 @@ module GraphQL
|
|
223
224
|
|
224
225
|
result = {}
|
225
226
|
|
226
|
-
arguments.each do |input_key, input_field_defn|
|
227
|
+
arguments(ctx).each do |input_key, input_field_defn|
|
227
228
|
input_value = value[input_key]
|
228
229
|
if value.key?(input_key)
|
229
230
|
result[input_key] = if input_value.nil?
|
@@ -16,6 +16,7 @@ module GraphQL
|
|
16
16
|
include GraphQL::Schema::Member::HasAstNode
|
17
17
|
include GraphQL::Schema::Member::HasUnresolvedTypeError
|
18
18
|
include GraphQL::Schema::Member::HasDirectives
|
19
|
+
include GraphQL::Schema::Member::HasInterfaces
|
19
20
|
|
20
21
|
# Methods defined in this block will be:
|
21
22
|
# - Added as class methods to this interface
|
@@ -57,9 +58,10 @@ module GraphQL
|
|
57
58
|
child_class.extend(Schema::Interface::DefinitionMethods)
|
58
59
|
|
59
60
|
child_class.type_membership_class(self.type_membership_class)
|
60
|
-
child_class.
|
61
|
-
|
62
|
-
|
61
|
+
child_class.ancestors.reverse_each do |ancestor|
|
62
|
+
if ancestor.const_defined?(:DefinitionMethods)
|
63
|
+
child_class.extend(ancestor::DefinitionMethods)
|
64
|
+
end
|
63
65
|
end
|
64
66
|
|
65
67
|
# Use an instance variable to tell whether it's been included previously or not;
|
@@ -73,16 +75,13 @@ module GraphQL
|
|
73
75
|
end
|
74
76
|
child_class.introspection(introspection)
|
75
77
|
child_class.description(description)
|
76
|
-
if overridden_graphql_name
|
77
|
-
child_class.graphql_name(overridden_graphql_name)
|
78
|
-
end
|
79
78
|
# If interfaces are mixed into each other, only define this class once
|
80
79
|
if !child_class.const_defined?(:UnresolvedTypeError, false)
|
81
80
|
add_unresolved_type_error(child_class)
|
82
81
|
end
|
83
82
|
elsif child_class < GraphQL::Schema::Object
|
84
83
|
# This is being included into an object type, make sure it's using `implements(...)`
|
85
|
-
backtrace_line = caller(0, 10).find { |line| line.include?("schema/
|
84
|
+
backtrace_line = caller(0, 10).find { |line| line.include?("schema/member/has_interfaces.rb") && line.include?("in `implements'")}
|
86
85
|
if !backtrace_line
|
87
86
|
raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
|
88
87
|
end
|
@@ -108,9 +107,9 @@ module GraphQL
|
|
108
107
|
type_defn.orphan_types = orphan_types
|
109
108
|
type_defn.type_membership_class = self.type_membership_class
|
110
109
|
type_defn.ast_node = ast_node
|
111
|
-
fields.each do |field_name, field_inst|
|
110
|
+
fields.each do |field_name, field_inst| # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
112
111
|
field_defn = field_inst.graphql_definition
|
113
|
-
type_defn.fields[field_defn.name] = field_defn
|
112
|
+
type_defn.fields[field_defn.name] = field_defn # rubocop:disable Development/ContextIsPassedCop -- legacy-related
|
114
113
|
end
|
115
114
|
type_defn.metadata[:type_class] = self
|
116
115
|
if respond_to?(:resolve_type)
|
@@ -122,16 +121,6 @@ module GraphQL
|
|
122
121
|
def kind
|
123
122
|
GraphQL::TypeKinds::INTERFACE
|
124
123
|
end
|
125
|
-
|
126
|
-
protected
|
127
|
-
|
128
|
-
def own_interfaces
|
129
|
-
@own_interfaces ||= []
|
130
|
-
end
|
131
|
-
|
132
|
-
def interfaces
|
133
|
-
own_interfaces + (own_interfaces.map { |i| i.own_interfaces }).flatten
|
134
|
-
end
|
135
124
|
end
|
136
125
|
|
137
126
|
# Extend this _after_ `DefinitionMethods` is defined, so it will be used
|
@@ -85,8 +85,15 @@ module GraphQL
|
|
85
85
|
define_method(name) do |*args|
|
86
86
|
if args.any?
|
87
87
|
instance_variable_set(ivar_name, args)
|
88
|
+
else
|
89
|
+
if (v = instance_variable_get(ivar_name))
|
90
|
+
v
|
91
|
+
elsif (ancestor = ancestors.find { |i| i.respond_to?(name) && i != self })
|
92
|
+
ancestor.public_send(name)
|
93
|
+
else
|
94
|
+
nil
|
95
|
+
end
|
88
96
|
end
|
89
|
-
instance_variable_get(ivar_name) || ((int = interfaces.first { |i| i.respond_to?()}) && int.public_send(name))
|
90
97
|
end
|
91
98
|
end
|
92
99
|
end
|
@@ -4,10 +4,6 @@ module GraphQL
|
|
4
4
|
class Member
|
5
5
|
# @api private
|
6
6
|
module BuildType
|
7
|
-
if !String.method_defined?(:match?)
|
8
|
-
using GraphQL::StringMatchBackport
|
9
|
-
end
|
10
|
-
|
11
7
|
LIST_TYPE_ERROR = "Use an array of [T] or [T, null: true] for list types; other arrays are not supported"
|
12
8
|
|
13
9
|
module_function
|
@@ -78,30 +78,72 @@ module GraphQL
|
|
78
78
|
# @return [GraphQL::Schema::Argument]
|
79
79
|
def add_argument(arg_defn)
|
80
80
|
@own_arguments ||= {}
|
81
|
-
own_arguments[arg_defn.name]
|
81
|
+
prev_defn = own_arguments[arg_defn.name]
|
82
|
+
case prev_defn
|
83
|
+
when nil
|
84
|
+
own_arguments[arg_defn.name] = arg_defn
|
85
|
+
when Array
|
86
|
+
prev_defn << arg_defn
|
87
|
+
when GraphQL::Schema::Argument
|
88
|
+
own_arguments[arg_defn.name] = [prev_defn, arg_defn]
|
89
|
+
else
|
90
|
+
raise "Invariant: unexpected `@own_arguments[#{arg_defn.name.inspect}]`: #{prev_defn.inspect}"
|
91
|
+
end
|
82
92
|
arg_defn
|
83
93
|
end
|
84
94
|
|
85
95
|
# @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
|
86
|
-
def arguments
|
87
|
-
inherited_arguments = ((self.is_a?(Class) && superclass.respond_to?(:arguments)) ? superclass.arguments : nil)
|
96
|
+
def arguments(context = GraphQL::Query::NullContext)
|
97
|
+
inherited_arguments = ((self.is_a?(Class) && superclass.respond_to?(:arguments)) ? superclass.arguments(context) : nil)
|
88
98
|
# Local definitions override inherited ones
|
99
|
+
if own_arguments.any?
|
100
|
+
own_arguments_that_apply = {}
|
101
|
+
own_arguments.each do |name, args_entry|
|
102
|
+
if (visible_defn = Warden.visible_entry?(:visible_argument?, args_entry, context))
|
103
|
+
own_arguments_that_apply[visible_defn.graphql_name] = visible_defn
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
89
108
|
if inherited_arguments
|
90
|
-
|
109
|
+
if own_arguments_that_apply
|
110
|
+
inherited_arguments.merge(own_arguments_that_apply)
|
111
|
+
else
|
112
|
+
inherited_arguments
|
113
|
+
end
|
91
114
|
else
|
92
|
-
|
115
|
+
# might be nil if there are actually no arguments
|
116
|
+
own_arguments_that_apply || own_arguments
|
93
117
|
end
|
94
118
|
end
|
95
119
|
|
96
|
-
|
97
|
-
|
98
|
-
|
120
|
+
def all_argument_definitions
|
121
|
+
if self.is_a?(Class)
|
122
|
+
all_defns = {}
|
123
|
+
ancestors.reverse_each do |ancestor|
|
124
|
+
if ancestor.respond_to?(:own_arguments)
|
125
|
+
all_defns.merge!(ancestor.own_arguments)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
else
|
129
|
+
all_defns = own_arguments
|
130
|
+
end
|
131
|
+
all_defns = all_defns.values
|
132
|
+
all_defns.flatten!
|
133
|
+
all_defns
|
134
|
+
end
|
99
135
|
|
100
|
-
|
101
|
-
|
136
|
+
# @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
|
137
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
138
|
+
warden = Warden.from_context(context)
|
139
|
+
if !self.is_a?(Class)
|
140
|
+
a = own_arguments[argument_name]
|
141
|
+
a && Warden.visible_entry?(:visible_argument?, a, context, warden)
|
102
142
|
else
|
103
143
|
for ancestor in ancestors
|
104
|
-
if ancestor.respond_to?(:own_arguments) &&
|
144
|
+
if ancestor.respond_to?(:own_arguments) &&
|
145
|
+
(a = ancestor.own_arguments[argument_name]) &&
|
146
|
+
(a = Warden.visible_entry?(:visible_argument?, a, context, warden))
|
105
147
|
return a
|
106
148
|
end
|
107
149
|
end
|
@@ -125,7 +167,7 @@ module GraphQL
|
|
125
167
|
# @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
|
126
168
|
def coerce_arguments(parent_object, values, context, &block)
|
127
169
|
# Cache this hash to avoid re-merging it
|
128
|
-
arg_defns = self.arguments
|
170
|
+
arg_defns = self.arguments(context)
|
129
171
|
total_args_count = arg_defns.size
|
130
172
|
|
131
173
|
finished_args = nil
|
@@ -191,7 +233,7 @@ module GraphQL
|
|
191
233
|
def arguments_statically_coercible?
|
192
234
|
return @arguments_statically_coercible if defined?(@arguments_statically_coercible)
|
193
235
|
|
194
|
-
@arguments_statically_coercible =
|
236
|
+
@arguments_statically_coercible = all_argument_definitions.all?(&:statically_coercible?)
|
195
237
|
end
|
196
238
|
|
197
239
|
module ArgumentClassAccessor
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
7
7
|
# @return [String, nil] Explains why this member was deprecated (if present, this will be marked deprecated in introspection)
|
8
8
|
def deprecation_reason
|
9
9
|
dir = self.directives.find { |d| d.is_a?(GraphQL::Schema::Directive::Deprecated) }
|
10
|
-
dir && dir.arguments[:reason]
|
10
|
+
dir && dir.arguments[:reason] # rubocop:disable Development/ContextIsPassedCop -- definition-related
|
11
11
|
end
|
12
12
|
|
13
13
|
# Set the deprecation reason for this member, or remove it by assigning `nil`
|