graphql 2.0.30 → 2.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +3 -0
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +6 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +5 -0
- data/lib/graphql/analysis/analyzer.rb +89 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +183 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +282 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/backtrace/trace.rb +12 -15
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +88 -0
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +11 -3
- data/lib/graphql/dataloader.rb +112 -142
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
- data/lib/graphql/execution/interpreter/runtime.rb +163 -365
- data/lib/graphql/execution/interpreter.rb +92 -158
- data/lib/graphql/execution/lookahead.rb +88 -21
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/schema_type.rb +3 -1
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +38 -38
- data/lib/graphql/language/lexer.rb +305 -193
- data/lib/graphql/language/nodes.rb +113 -66
- data/lib/graphql/language/parser.rb +787 -1986
- data/lib/graphql/language/printer.rb +303 -146
- data/lib/graphql/language/sanitized_printer.rb +20 -22
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +20 -81
- data/lib/graphql/language.rb +61 -0
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +28 -1
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +66 -131
- data/lib/graphql/query/null_context.rb +4 -11
- data/lib/graphql/query/validation_pipeline.rb +4 -4
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +17 -26
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/schema/addition.rb +21 -11
- data/lib/graphql/schema/argument.rb +43 -8
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +9 -12
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive.rb +3 -1
- data/lib/graphql/schema/enum.rb +3 -3
- data/lib/graphql/schema/field/connection_extension.rb +1 -15
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +49 -35
- data/lib/graphql/schema/has_single_input_argument.rb +157 -0
- data/lib/graphql/schema/input_object.rb +4 -4
- data/lib/graphql/schema/interface.rb +10 -10
- data/lib/graphql/schema/introspection_system.rb +4 -2
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/list.rb +2 -2
- data/lib/graphql/schema/loader.rb +2 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +63 -73
- data/lib/graphql/schema/member/has_directives.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +8 -5
- data/lib/graphql/schema/member/has_interfaces.rb +23 -9
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -2
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +8 -0
- data/lib/graphql/schema/printer.rb +8 -7
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -128
- data/lib/graphql/schema/resolver.rb +27 -13
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/warden.rb +96 -95
- data/lib/graphql/schema.rb +323 -102
- data/lib/graphql/static_validation/all_rules.rb +1 -1
- data/lib/graphql/static_validation/base_visitor.rb +1 -1
- data/lib/graphql/static_validation/literal_validator.rb +2 -3
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
- 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 +2 -2
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +4 -3
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +1 -1
- data/lib/graphql/subscriptions/event.rb +8 -2
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +15 -13
- data/lib/graphql/testing/helpers.rb +151 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/appoptics_trace.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/prometheus_trace.rb +9 -9
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/trace.rb +1 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/type_kinds.rb +1 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +32 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +7 -0
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +13 -13
- data/readme.md +12 -2
- metadata +33 -26
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Schema
|
5
|
+
module HasSingleInputArgument
|
6
|
+
def resolve_with_support(**inputs)
|
7
|
+
if inputs[:input].is_a?(InputObject)
|
8
|
+
input = inputs[:input].to_kwargs
|
9
|
+
else
|
10
|
+
input = inputs[:input]
|
11
|
+
end
|
12
|
+
|
13
|
+
new_extras = field ? field.extras : []
|
14
|
+
all_extras = self.class.extras + new_extras
|
15
|
+
|
16
|
+
# Transfer these from the top-level hash to the
|
17
|
+
# shortcutted `input:` object
|
18
|
+
all_extras.each do |ext|
|
19
|
+
# It's possible that the `extra` was not passed along by this point,
|
20
|
+
# don't re-add it if it wasn't given here.
|
21
|
+
if inputs.key?(ext)
|
22
|
+
input[ext] = inputs[ext]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if input
|
27
|
+
# This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
|
28
|
+
input_kwargs = input.to_h
|
29
|
+
else
|
30
|
+
# Relay Classic Mutations with no `argument`s
|
31
|
+
# don't require `input:`
|
32
|
+
input_kwargs = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
if input_kwargs.any?
|
36
|
+
super(**input_kwargs)
|
37
|
+
else
|
38
|
+
super()
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.included(base)
|
43
|
+
base.extend(ClassMethods)
|
44
|
+
end
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
def dummy
|
48
|
+
@dummy ||= begin
|
49
|
+
d = Class.new(GraphQL::Schema::Resolver)
|
50
|
+
d.graphql_name "#{self.graphql_name}DummyResolver"
|
51
|
+
d.argument_class(self.argument_class)
|
52
|
+
# TODO make this lazier?
|
53
|
+
d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
|
54
|
+
d
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def field_arguments(context = GraphQL::Query::NullContext.instance)
|
59
|
+
dummy.arguments(context)
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
|
63
|
+
dummy.get_argument(name, context)
|
64
|
+
end
|
65
|
+
|
66
|
+
def own_field_arguments
|
67
|
+
dummy.own_arguments
|
68
|
+
end
|
69
|
+
|
70
|
+
def any_field_arguments?
|
71
|
+
dummy.any_arguments?
|
72
|
+
end
|
73
|
+
|
74
|
+
def all_field_argument_definitions
|
75
|
+
dummy.all_argument_definitions
|
76
|
+
end
|
77
|
+
|
78
|
+
# Also apply this argument to the input type:
|
79
|
+
def argument(*args, own_argument: false, **kwargs, &block)
|
80
|
+
it = input_type # make sure any inherited arguments are already added to it
|
81
|
+
arg = super(*args, **kwargs, &block)
|
82
|
+
|
83
|
+
# This definition might be overriding something inherited;
|
84
|
+
# if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
|
85
|
+
prev_args = it.own_arguments[arg.graphql_name]
|
86
|
+
case prev_args
|
87
|
+
when GraphQL::Schema::Argument
|
88
|
+
if prev_args.owner != self
|
89
|
+
it.own_arguments.delete(arg.graphql_name)
|
90
|
+
end
|
91
|
+
when Array
|
92
|
+
prev_args.reject! { |a| a.owner != self }
|
93
|
+
if prev_args.empty?
|
94
|
+
it.own_arguments.delete(arg.graphql_name)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it.add_argument(arg)
|
99
|
+
arg
|
100
|
+
end
|
101
|
+
|
102
|
+
# The base class for generated input object types
|
103
|
+
# @param new_class [Class] The base class to use for generating input object definitions
|
104
|
+
# @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})
|
105
|
+
def input_object_class(new_class = nil)
|
106
|
+
if new_class
|
107
|
+
@input_object_class = new_class
|
108
|
+
end
|
109
|
+
@input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
|
110
|
+
end
|
111
|
+
|
112
|
+
# @param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
|
113
|
+
# @return [Class] The generated {Schema::InputObject} class for this mutation's `input`
|
114
|
+
def input_type(new_input_type = nil)
|
115
|
+
if new_input_type
|
116
|
+
@input_type = new_input_type
|
117
|
+
end
|
118
|
+
@input_type ||= generate_input_type
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
# Generate the input type for the `input:` argument
|
124
|
+
# To customize how input objects are generated, override this method
|
125
|
+
# @return [Class] a subclass of {.input_object_class}
|
126
|
+
def generate_input_type
|
127
|
+
mutation_args = all_argument_definitions
|
128
|
+
mutation_class = self
|
129
|
+
Class.new(input_object_class) do
|
130
|
+
class << self
|
131
|
+
def default_graphql_name
|
132
|
+
"#{self.mutation.graphql_name}Input"
|
133
|
+
end
|
134
|
+
|
135
|
+
def description(new_desc = nil)
|
136
|
+
super || "Autogenerated input type of #{self.mutation.graphql_name}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
mutation(mutation_class)
|
140
|
+
# these might be inherited:
|
141
|
+
mutation_args.each do |arg|
|
142
|
+
add_argument(arg)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def authorize_arguments(args, values)
|
151
|
+
# remove the `input` wrapper to match values
|
152
|
+
input_args = args["input"].type.unwrap.arguments(context)
|
153
|
+
super(input_args, values)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -79,7 +79,7 @@ module GraphQL
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def self.one_of?
|
82
|
-
|
82
|
+
false # Re-defined when `OneOf` is added
|
83
83
|
end
|
84
84
|
|
85
85
|
def unwrap_value(value)
|
@@ -136,6 +136,7 @@ module GraphQL
|
|
136
136
|
def #{method_name}
|
137
137
|
self[#{method_name.inspect}]
|
138
138
|
end
|
139
|
+
alias_method :#{method_name}, :#{method_name}
|
139
140
|
RUBY
|
140
141
|
argument_defn
|
141
142
|
end
|
@@ -145,7 +146,7 @@ module GraphQL
|
|
145
146
|
end
|
146
147
|
|
147
148
|
# @api private
|
148
|
-
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object
|
149
|
+
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object."
|
149
150
|
|
150
151
|
def validate_non_null_input(input, ctx, max_errors: nil)
|
151
152
|
warden = ctx.warden
|
@@ -215,8 +216,7 @@ module GraphQL
|
|
215
216
|
if resolved_arguments.is_a?(GraphQL::Error)
|
216
217
|
raise resolved_arguments
|
217
218
|
else
|
218
|
-
|
219
|
-
input_obj_instance.prepare
|
219
|
+
self.new(resolved_arguments, ruby_kwargs: resolved_arguments.keyword_arguments, context: ctx, defaults_used: nil)
|
220
220
|
end
|
221
221
|
end
|
222
222
|
end
|
@@ -20,6 +20,15 @@ module GraphQL
|
|
20
20
|
# - Added as class methods to this interface
|
21
21
|
# - Added as class methods to all child interfaces
|
22
22
|
def definition_methods(&block)
|
23
|
+
# Use an instance variable to tell whether it's been included previously or not;
|
24
|
+
# You can't use constant detection because constants are brought into scope
|
25
|
+
# by `include`, which has already happened at this point.
|
26
|
+
if !defined?(@_definition_methods)
|
27
|
+
defn_methods_module = Module.new
|
28
|
+
@_definition_methods = defn_methods_module
|
29
|
+
const_set(:DefinitionMethods, defn_methods_module)
|
30
|
+
extend(self::DefinitionMethods)
|
31
|
+
end
|
23
32
|
self::DefinitionMethods.module_eval(&block)
|
24
33
|
end
|
25
34
|
|
@@ -47,20 +56,11 @@ module GraphQL
|
|
47
56
|
|
48
57
|
child_class.type_membership_class(self.type_membership_class)
|
49
58
|
child_class.ancestors.reverse_each do |ancestor|
|
50
|
-
if ancestor.const_defined?(:DefinitionMethods)
|
59
|
+
if ancestor.const_defined?(:DefinitionMethods) && ancestor != child_class
|
51
60
|
child_class.extend(ancestor::DefinitionMethods)
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
55
|
-
# Use an instance variable to tell whether it's been included previously or not;
|
56
|
-
# You can't use constant detection because constants are brought into scope
|
57
|
-
# by `include`, which has already happened at this point.
|
58
|
-
if !child_class.instance_variable_defined?(:@_definition_methods)
|
59
|
-
defn_methods_module = Module.new
|
60
|
-
child_class.instance_variable_set(:@_definition_methods, defn_methods_module)
|
61
|
-
child_class.const_set(:DefinitionMethods, defn_methods_module)
|
62
|
-
child_class.extend(child_class::DefinitionMethods)
|
63
|
-
end
|
64
64
|
child_class.introspection(introspection)
|
65
65
|
child_class.description(description)
|
66
66
|
# If interfaces are mixed into each other, only define this class once
|
@@ -25,10 +25,10 @@ module GraphQL
|
|
25
25
|
load_constant(:DirectiveLocationEnum)
|
26
26
|
]
|
27
27
|
@types = {}
|
28
|
-
@possible_types = {}
|
28
|
+
@possible_types = {}.tap(&:compare_by_identity)
|
29
29
|
type_defns.each do |t|
|
30
30
|
@types[t.graphql_name] = t
|
31
|
-
@possible_types[t
|
31
|
+
@possible_types[t] = [t]
|
32
32
|
end
|
33
33
|
@entry_point_fields =
|
34
34
|
if schema.disable_introspection_entry_points?
|
@@ -39,7 +39,9 @@ module GraphQL
|
|
39
39
|
entry_point_fields.delete('__type') if schema.disable_type_introspection_entry_point?
|
40
40
|
entry_point_fields
|
41
41
|
end
|
42
|
+
@entry_point_fields.each { |k, v| v.dynamic_introspection = true }
|
42
43
|
@dynamic_fields = get_fields_from_class(class_sym: :DynamicFields)
|
44
|
+
@dynamic_fields.each { |k, v| v.dynamic_introspection = true }
|
43
45
|
end
|
44
46
|
|
45
47
|
def entry_points
|
data/lib/graphql/schema/list.rb
CHANGED
@@ -52,7 +52,7 @@ module GraphQL
|
|
52
52
|
unless item_result.valid?
|
53
53
|
if max_errors
|
54
54
|
if max_errors == 0
|
55
|
-
|
55
|
+
add_max_errors_reached_message(result)
|
56
56
|
break
|
57
57
|
end
|
58
58
|
|
@@ -76,7 +76,7 @@ module GraphQL
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
def
|
79
|
+
def add_max_errors_reached_message(result)
|
80
80
|
message = "Too many errors processing list variable, max validation error limit reached. Execution aborted"
|
81
81
|
item_result = GraphQL::Query::InputValidationResult.from_problem(message)
|
82
82
|
result.merge_result!(nil, item_result)
|
@@ -32,7 +32,8 @@ module GraphQL
|
|
32
32
|
end
|
33
33
|
|
34
34
|
Class.new(GraphQL::Schema) do
|
35
|
-
|
35
|
+
add_type_and_traverse(types.values, root: false)
|
36
|
+
orphan_types(types.values.select { |t| t.kind.object? })
|
36
37
|
directives(directives)
|
37
38
|
description(schema["description"])
|
38
39
|
|
@@ -176,7 +177,6 @@ module GraphQL
|
|
176
177
|
while (of_type = unwrapped_field_hash["ofType"])
|
177
178
|
unwrapped_field_hash = of_type
|
178
179
|
end
|
179
|
-
type_name = unwrapped_field_hash["name"]
|
180
180
|
|
181
181
|
type_defn.field(
|
182
182
|
field_hash["name"],
|
@@ -186,7 +186,6 @@ module GraphQL
|
|
186
186
|
null: true,
|
187
187
|
camelize: false,
|
188
188
|
connection_extension: nil,
|
189
|
-
connection: type_name.end_with?("Connection"),
|
190
189
|
) do
|
191
190
|
if field_hash["args"].any?
|
192
191
|
loader.build_arguments(self, field_hash["args"], type_resolver)
|
@@ -102,7 +102,8 @@ module GraphQL
|
|
102
102
|
def default_graphql_name
|
103
103
|
@default_graphql_name ||= begin
|
104
104
|
raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
|
105
|
-
-name.split("::").last
|
105
|
+
g_name = -name.split("::").last
|
106
|
+
g_name.end_with?("Type") ? g_name.sub(/Type\Z/, "") : g_name
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|
@@ -38,39 +38,6 @@ module GraphQL
|
|
38
38
|
end
|
39
39
|
arg_defn = self.argument_class.new(*args, **kwargs, &block)
|
40
40
|
add_argument(arg_defn)
|
41
|
-
|
42
|
-
if self.is_a?(Class) && !method_defined?(:"load_#{arg_defn.keyword}")
|
43
|
-
method_owner = if self < GraphQL::Schema::InputObject || self < GraphQL::Schema::Directive
|
44
|
-
"self."
|
45
|
-
elsif self < GraphQL::Schema::Resolver
|
46
|
-
""
|
47
|
-
else
|
48
|
-
raise "Unexpected argument owner: #{self}"
|
49
|
-
end
|
50
|
-
if loads && arg_defn.type.list?
|
51
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
52
|
-
def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
|
53
|
-
argument = get_argument("#{arg_defn.graphql_name}")
|
54
|
-
(context || self.context).query.after_lazy(values) do |values2|
|
55
|
-
GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
|
56
|
-
end
|
57
|
-
end
|
58
|
-
RUBY
|
59
|
-
elsif loads
|
60
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
61
|
-
def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
|
62
|
-
argument = get_argument("#{arg_defn.graphql_name}")
|
63
|
-
load_application_object(argument, value, context || self.context)
|
64
|
-
end
|
65
|
-
RUBY
|
66
|
-
else
|
67
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
68
|
-
def #{method_owner}load_#{arg_defn.keyword}(value, _context = nil)
|
69
|
-
value
|
70
|
-
end
|
71
|
-
RUBY
|
72
|
-
end
|
73
|
-
end
|
74
41
|
arg_defn
|
75
42
|
end
|
76
43
|
|
@@ -109,7 +76,7 @@ module GraphQL
|
|
109
76
|
end
|
110
77
|
|
111
78
|
# @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
|
112
|
-
def arguments(context = GraphQL::Query::NullContext)
|
79
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
113
80
|
if own_arguments.any?
|
114
81
|
own_arguments_that_apply = {}
|
115
82
|
own_arguments.each do |name, args_entry|
|
@@ -122,6 +89,10 @@ module GraphQL
|
|
122
89
|
own_arguments_that_apply || own_arguments
|
123
90
|
end
|
124
91
|
|
92
|
+
def any_arguments?
|
93
|
+
own_arguments.any?
|
94
|
+
end
|
95
|
+
|
125
96
|
module ClassConfigured
|
126
97
|
def inherited(child_class)
|
127
98
|
super
|
@@ -129,7 +100,7 @@ module GraphQL
|
|
129
100
|
end
|
130
101
|
|
131
102
|
module InheritedArguments
|
132
|
-
def arguments(context = GraphQL::Query::NullContext)
|
103
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
133
104
|
own_arguments = super
|
134
105
|
inherited_arguments = superclass.arguments(context)
|
135
106
|
|
@@ -145,6 +116,10 @@ module GraphQL
|
|
145
116
|
end
|
146
117
|
end
|
147
118
|
|
119
|
+
def any_arguments?
|
120
|
+
super || superclass.any_arguments?
|
121
|
+
end
|
122
|
+
|
148
123
|
def all_argument_definitions
|
149
124
|
all_defns = {}
|
150
125
|
ancestors.reverse_each do |ancestor|
|
@@ -158,7 +133,7 @@ module GraphQL
|
|
158
133
|
end
|
159
134
|
|
160
135
|
|
161
|
-
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
136
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
162
137
|
warden = Warden.from_context(context)
|
163
138
|
for ancestor in ancestors
|
164
139
|
if ancestor.respond_to?(:own_arguments) &&
|
@@ -173,9 +148,9 @@ module GraphQL
|
|
173
148
|
end
|
174
149
|
|
175
150
|
module FieldConfigured
|
176
|
-
def arguments(context = GraphQL::Query::NullContext)
|
151
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
177
152
|
own_arguments = super
|
178
|
-
if
|
153
|
+
if @resolver_class
|
179
154
|
inherited_arguments = @resolver_class.field_arguments(context)
|
180
155
|
if own_arguments.any?
|
181
156
|
if inherited_arguments.any?
|
@@ -191,8 +166,12 @@ module GraphQL
|
|
191
166
|
end
|
192
167
|
end
|
193
168
|
|
169
|
+
def any_arguments?
|
170
|
+
super || (@resolver_class && @resolver_class.any_field_arguments?)
|
171
|
+
end
|
172
|
+
|
194
173
|
def all_argument_definitions
|
195
|
-
if
|
174
|
+
if @resolver_class
|
196
175
|
all_defns = {}
|
197
176
|
@resolver_class.all_field_argument_definitions.each do |arg_defn|
|
198
177
|
key = arg_defn.graphql_name
|
@@ -224,7 +203,7 @@ module GraphQL
|
|
224
203
|
end
|
225
204
|
|
226
205
|
# @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
|
227
|
-
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
206
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
228
207
|
warden = Warden.from_context(context)
|
229
208
|
if (arg_config = own_arguments[argument_name]) && (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden))
|
230
209
|
visible_arg
|
@@ -247,8 +226,8 @@ module GraphQL
|
|
247
226
|
#
|
248
227
|
# @param values [Hash<String, Object>]
|
249
228
|
# @param context [GraphQL::Query::Context]
|
250
|
-
# @yield [Interpreter::Arguments, Execution::Lazy<
|
251
|
-
# @return [Interpreter::Arguments, Execution::Lazy<
|
229
|
+
# @yield [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
|
230
|
+
# @return [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
|
252
231
|
def coerce_arguments(parent_object, values, context, &block)
|
253
232
|
# Cache this hash to avoid re-merging it
|
254
233
|
arg_defns = context.warden.arguments(self)
|
@@ -367,41 +346,52 @@ module GraphQL
|
|
367
346
|
def authorize_application_object(argument, id, context, loaded_application_object)
|
368
347
|
context.query.after_lazy(loaded_application_object) do |application_object|
|
369
348
|
if application_object.nil?
|
370
|
-
err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
|
371
|
-
load_application_object_failed(err)
|
349
|
+
err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
|
350
|
+
application_object = load_application_object_failed(err)
|
372
351
|
end
|
373
352
|
# Double-check that the located object is actually of this type
|
374
353
|
# (Don't want to allow arbitrary access to objects this way)
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
354
|
+
if application_object.nil?
|
355
|
+
nil
|
356
|
+
else
|
357
|
+
maybe_lazy_resolve_type = context.schema.resolve_type(argument.loads, application_object, context)
|
358
|
+
context.query.after_lazy(maybe_lazy_resolve_type) do |resolve_type_result|
|
359
|
+
if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
|
360
|
+
application_object_type, application_object = resolve_type_result
|
361
|
+
else
|
362
|
+
application_object_type = resolve_type_result
|
363
|
+
# application_object is already assigned
|
364
|
+
end
|
365
|
+
|
366
|
+
if !(
|
367
|
+
context.warden.possible_types(argument.loads).include?(application_object_type) ||
|
368
|
+
context.warden.loadable?(argument.loads, context)
|
369
|
+
)
|
370
|
+
err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
|
371
|
+
application_object = load_application_object_failed(err)
|
372
|
+
end
|
373
|
+
|
374
|
+
if application_object.nil?
|
375
|
+
nil
|
376
|
+
else
|
377
|
+
# This object was loaded successfully
|
378
|
+
# and resolved to the right type,
|
379
|
+
# now apply the `.authorized?` class method if there is one
|
380
|
+
context.query.after_lazy(application_object_type.authorized?(application_object, context)) do |authed|
|
381
|
+
if authed
|
382
|
+
application_object
|
403
383
|
else
|
404
|
-
|
384
|
+
err = GraphQL::UnauthorizedError.new(
|
385
|
+
object: application_object,
|
386
|
+
type: application_object_type,
|
387
|
+
context: context,
|
388
|
+
)
|
389
|
+
if self.respond_to?(:unauthorized_object)
|
390
|
+
err.set_backtrace(caller)
|
391
|
+
unauthorized_object(err)
|
392
|
+
else
|
393
|
+
raise err
|
394
|
+
end
|
405
395
|
end
|
406
396
|
end
|
407
397
|
end
|
@@ -91,7 +91,7 @@ module GraphQL
|
|
91
91
|
private
|
92
92
|
|
93
93
|
# Modify `target` by adding items from `dirs` such that:
|
94
|
-
# - Any name conflict is
|
94
|
+
# - Any name conflict is overridden by the incoming member of `dirs`
|
95
95
|
# - Any other member of `dirs` is appended
|
96
96
|
# @param target [Array<GraphQL::Schema::Directive>]
|
97
97
|
# @param dirs [Array<GraphQL::Schema::Directive>]
|
@@ -97,7 +97,7 @@ module GraphQL
|
|
97
97
|
end
|
98
98
|
|
99
99
|
module InterfaceMethods
|
100
|
-
def get_field(field_name, context = GraphQL::Query::NullContext)
|
100
|
+
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
|
101
101
|
warden = Warden.from_context(context)
|
102
102
|
for ancestor in ancestors
|
103
103
|
if ancestor.respond_to?(:own_fields) &&
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
110
110
|
end
|
111
111
|
|
112
112
|
# @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
|
113
|
-
def fields(context = GraphQL::Query::NullContext)
|
113
|
+
def fields(context = GraphQL::Query::NullContext.instance)
|
114
114
|
warden = Warden.from_context(context)
|
115
115
|
# Local overrides take precedence over inherited fields
|
116
116
|
visible_fields = {}
|
@@ -130,22 +130,25 @@ module GraphQL
|
|
130
130
|
end
|
131
131
|
|
132
132
|
module ObjectMethods
|
133
|
-
def get_field(field_name, context = GraphQL::Query::NullContext)
|
133
|
+
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
|
134
134
|
# Objects need to check that the interface implementation is visible, too
|
135
135
|
warden = Warden.from_context(context)
|
136
|
-
|
136
|
+
ancs = ancestors
|
137
|
+
i = 0
|
138
|
+
while (ancestor = ancs[i])
|
137
139
|
if ancestor.respond_to?(:own_fields) &&
|
138
140
|
visible_interface_implementation?(ancestor, context, warden) &&
|
139
141
|
(f_entry = ancestor.own_fields[field_name]) &&
|
140
142
|
(f = Warden.visible_entry?(:visible_field?, f_entry, context, warden))
|
141
143
|
return f
|
142
144
|
end
|
145
|
+
i += 1
|
143
146
|
end
|
144
147
|
nil
|
145
148
|
end
|
146
149
|
|
147
150
|
# @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
|
148
|
-
def fields(context = GraphQL::Query::NullContext)
|
151
|
+
def fields(context = GraphQL::Query::NullContext.instance)
|
149
152
|
# Objects need to check that the interface implementation is visible, too
|
150
153
|
warden = Warden.from_context(context)
|
151
154
|
# Local overrides take precedence over inherited fields
|
@@ -70,11 +70,20 @@ module GraphQL
|
|
70
70
|
end
|
71
71
|
|
72
72
|
module InheritedInterfaces
|
73
|
-
def interfaces(context = GraphQL::Query::NullContext)
|
73
|
+
def interfaces(context = GraphQL::Query::NullContext.instance)
|
74
74
|
visible_interfaces = super
|
75
|
-
|
76
|
-
visible_interfaces.
|
77
|
-
|
75
|
+
inherited_interfaces = superclass.interfaces(context)
|
76
|
+
if visible_interfaces.any?
|
77
|
+
if inherited_interfaces.any?
|
78
|
+
visible_interfaces.concat(inherited_interfaces)
|
79
|
+
visible_interfaces.uniq!
|
80
|
+
end
|
81
|
+
visible_interfaces
|
82
|
+
elsif inherited_interfaces.any?
|
83
|
+
inherited_interfaces
|
84
|
+
else
|
85
|
+
EmptyObjects::EMPTY_ARRAY
|
86
|
+
end
|
78
87
|
end
|
79
88
|
|
80
89
|
def interface_type_memberships
|
@@ -90,25 +99,30 @@ module GraphQL
|
|
90
99
|
end
|
91
100
|
|
92
101
|
# param context [Query::Context] If omitted, skip filtering.
|
93
|
-
def interfaces(context = GraphQL::Query::NullContext)
|
102
|
+
def interfaces(context = GraphQL::Query::NullContext.instance)
|
94
103
|
warden = Warden.from_context(context)
|
95
|
-
visible_interfaces =
|
104
|
+
visible_interfaces = nil
|
96
105
|
own_interface_type_memberships.each do |type_membership|
|
97
106
|
case type_membership
|
98
107
|
when Schema::TypeMembership
|
99
108
|
if warden.visible_type_membership?(type_membership, context)
|
109
|
+
visible_interfaces ||= []
|
100
110
|
visible_interfaces << type_membership.abstract_type
|
101
111
|
end
|
102
112
|
when String, Schema::LateBoundType
|
103
113
|
# During initialization, `type_memberships` can hold late-bound types
|
114
|
+
visible_interfaces ||= []
|
104
115
|
visible_interfaces << type_membership
|
105
116
|
else
|
106
117
|
raise "Invariant: Unexpected type_membership #{type_membership.class}: #{type_membership.inspect}"
|
107
118
|
end
|
108
119
|
end
|
109
|
-
visible_interfaces
|
110
|
-
|
111
|
-
|
120
|
+
if visible_interfaces
|
121
|
+
visible_interfaces.uniq!
|
122
|
+
visible_interfaces
|
123
|
+
else
|
124
|
+
EmptyObjects::EMPTY_ARRAY
|
125
|
+
end
|
112
126
|
end
|
113
127
|
|
114
128
|
private
|
@@ -76,7 +76,7 @@ module GraphQL
|
|
76
76
|
|
77
77
|
private
|
78
78
|
|
79
|
-
# If one of
|
79
|
+
# If one of these values is accessed, initialize all the instance variables to retain
|
80
80
|
# a consistent object shape.
|
81
81
|
def initialize_relay_metadata
|
82
82
|
if !defined?(@connection_type)
|