graphql 2.0.27 → 2.2.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/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 +2 -0
- data/lib/graphql/analysis/ast/analyzer.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +32 -7
- data/lib/graphql/analysis/ast/query_complexity.rb +80 -128
- data/lib/graphql/analysis/ast/query_depth.rb +7 -2
- data/lib/graphql/analysis/ast/visitor.rb +2 -2
- data/lib/graphql/analysis/ast.rb +21 -11
- data/lib/graphql/backtrace/trace.rb +12 -15
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +85 -0
- data/lib/graphql/dataloader/source.rb +11 -3
- data/lib/graphql/dataloader.rb +109 -142
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
- data/lib/graphql/execution/interpreter/runtime.rb +70 -248
- data/lib/graphql/execution/interpreter.rb +91 -157
- 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 +37 -37
- data/lib/graphql/language/lexer.rb +271 -177
- data/lib/graphql/language/nodes.rb +74 -56
- data/lib/graphql/language/parser.rb +697 -1986
- data/lib/graphql/language/printer.rb +299 -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 +1 -0
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +3 -3
- data/lib/graphql/pagination/connection.rb +28 -1
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +3 -3
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +36 -98
- data/lib/graphql/query/null_context.rb +4 -11
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +13 -22
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/schema/argument.rb +6 -1
- data/lib/graphql/schema/build_from_definition.rb +0 -11
- 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 +1 -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 +8 -5
- data/lib/graphql/schema/has_single_input_argument.rb +156 -0
- data/lib/graphql/schema/input_object.rb +2 -2
- data/lib/graphql/schema/interface.rb +10 -10
- data/lib/graphql/schema/introspection_system.rb +2 -0
- data/lib/graphql/schema/loader.rb +0 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +61 -38
- 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/scoped.rb +19 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- 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 +7 -3
- 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/warden.rb +96 -94
- data/lib/graphql/schema.rb +219 -72
- 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 +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 +1 -1
- 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 +3 -2
- data/lib/graphql/subscriptions/event.rb +8 -2
- data/lib/graphql/subscriptions.rb +14 -12
- data/lib/graphql/testing/helpers.rb +125 -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/data_dog_trace.rb +21 -34
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +2 -0
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/sentry_trace.rb +94 -0
- data/lib/graphql/tracing/trace.rb +1 -0
- data/lib/graphql/tracing.rb +3 -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 +3 -3
- data/readme.md +12 -2
- metadata +33 -25
- 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/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -0,0 +1,156 @@
|
|
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.argument_class(self.argument_class)
|
51
|
+
# TODO make this lazier?
|
52
|
+
d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
|
53
|
+
d
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def field_arguments(context = GraphQL::Query::NullContext.instance)
|
58
|
+
dummy.arguments(context)
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
|
62
|
+
dummy.get_argument(name, context)
|
63
|
+
end
|
64
|
+
|
65
|
+
def own_field_arguments
|
66
|
+
dummy.own_arguments
|
67
|
+
end
|
68
|
+
|
69
|
+
def any_field_arguments?
|
70
|
+
dummy.any_arguments?
|
71
|
+
end
|
72
|
+
|
73
|
+
def all_field_argument_definitions
|
74
|
+
dummy.all_argument_definitions
|
75
|
+
end
|
76
|
+
|
77
|
+
# Also apply this argument to the input type:
|
78
|
+
def argument(*args, own_argument: false, **kwargs, &block)
|
79
|
+
it = input_type # make sure any inherited arguments are already added to it
|
80
|
+
arg = super(*args, **kwargs, &block)
|
81
|
+
|
82
|
+
# This definition might be overriding something inherited;
|
83
|
+
# if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
|
84
|
+
prev_args = it.own_arguments[arg.graphql_name]
|
85
|
+
case prev_args
|
86
|
+
when GraphQL::Schema::Argument
|
87
|
+
if prev_args.owner != self
|
88
|
+
it.own_arguments.delete(arg.graphql_name)
|
89
|
+
end
|
90
|
+
when Array
|
91
|
+
prev_args.reject! { |a| a.owner != self }
|
92
|
+
if prev_args.empty?
|
93
|
+
it.own_arguments.delete(arg.graphql_name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it.add_argument(arg)
|
98
|
+
arg
|
99
|
+
end
|
100
|
+
|
101
|
+
# The base class for generated input object types
|
102
|
+
# @param new_class [Class] The base class to use for generating input object definitions
|
103
|
+
# @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})
|
104
|
+
def input_object_class(new_class = nil)
|
105
|
+
if new_class
|
106
|
+
@input_object_class = new_class
|
107
|
+
end
|
108
|
+
@input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
|
112
|
+
# @return [Class] The generated {Schema::InputObject} class for this mutation's `input`
|
113
|
+
def input_type(new_input_type = nil)
|
114
|
+
if new_input_type
|
115
|
+
@input_type = new_input_type
|
116
|
+
end
|
117
|
+
@input_type ||= generate_input_type
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
# Generate the input type for the `input:` argument
|
123
|
+
# To customize how input objects are generated, override this method
|
124
|
+
# @return [Class] a subclass of {.input_object_class}
|
125
|
+
def generate_input_type
|
126
|
+
mutation_args = all_argument_definitions
|
127
|
+
mutation_class = self
|
128
|
+
Class.new(input_object_class) do
|
129
|
+
class << self
|
130
|
+
def default_graphql_name
|
131
|
+
"#{self.mutation.graphql_name}Input"
|
132
|
+
end
|
133
|
+
|
134
|
+
def description(new_desc = nil)
|
135
|
+
super || "Autogenerated input type of #{self.mutation.graphql_name}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
mutation(mutation_class)
|
139
|
+
# these might be inherited:
|
140
|
+
mutation_args.each do |arg|
|
141
|
+
add_argument(arg)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def authorize_arguments(args, values)
|
150
|
+
# remove the `input` wrapper to match values
|
151
|
+
input_args = args["input"].type.unwrap.arguments(context)
|
152
|
+
super(input_args, values)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
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)
|
@@ -145,7 +145,7 @@ module GraphQL
|
|
145
145
|
end
|
146
146
|
|
147
147
|
# @api private
|
148
|
-
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object
|
148
|
+
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object."
|
149
149
|
|
150
150
|
def validate_non_null_input(input, ctx, max_errors: nil)
|
151
151
|
warden = ctx.warden
|
@@ -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
|
@@ -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
|
@@ -176,7 +176,6 @@ module GraphQL
|
|
176
176
|
while (of_type = unwrapped_field_hash["ofType"])
|
177
177
|
unwrapped_field_hash = of_type
|
178
178
|
end
|
179
|
-
type_name = unwrapped_field_hash["name"]
|
180
179
|
|
181
180
|
type_defn.field(
|
182
181
|
field_hash["name"],
|
@@ -186,7 +185,6 @@ module GraphQL
|
|
186
185
|
null: true,
|
187
186
|
camelize: false,
|
188
187
|
connection_extension: nil,
|
189
|
-
connection: type_name.end_with?("Connection"),
|
190
188
|
) do
|
191
189
|
if field_hash["args"].any?
|
192
190
|
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
|
|
@@ -109,7 +109,7 @@ module GraphQL
|
|
109
109
|
end
|
110
110
|
|
111
111
|
# @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
|
112
|
-
def arguments(context = GraphQL::Query::NullContext)
|
112
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
113
113
|
if own_arguments.any?
|
114
114
|
own_arguments_that_apply = {}
|
115
115
|
own_arguments.each do |name, args_entry|
|
@@ -122,6 +122,10 @@ module GraphQL
|
|
122
122
|
own_arguments_that_apply || own_arguments
|
123
123
|
end
|
124
124
|
|
125
|
+
def any_arguments?
|
126
|
+
own_arguments.any?
|
127
|
+
end
|
128
|
+
|
125
129
|
module ClassConfigured
|
126
130
|
def inherited(child_class)
|
127
131
|
super
|
@@ -129,7 +133,7 @@ module GraphQL
|
|
129
133
|
end
|
130
134
|
|
131
135
|
module InheritedArguments
|
132
|
-
def arguments(context = GraphQL::Query::NullContext)
|
136
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
133
137
|
own_arguments = super
|
134
138
|
inherited_arguments = superclass.arguments(context)
|
135
139
|
|
@@ -145,6 +149,10 @@ module GraphQL
|
|
145
149
|
end
|
146
150
|
end
|
147
151
|
|
152
|
+
def any_arguments?
|
153
|
+
super || superclass.any_arguments?
|
154
|
+
end
|
155
|
+
|
148
156
|
def all_argument_definitions
|
149
157
|
all_defns = {}
|
150
158
|
ancestors.reverse_each do |ancestor|
|
@@ -158,7 +166,7 @@ module GraphQL
|
|
158
166
|
end
|
159
167
|
|
160
168
|
|
161
|
-
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
169
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
162
170
|
warden = Warden.from_context(context)
|
163
171
|
for ancestor in ancestors
|
164
172
|
if ancestor.respond_to?(:own_arguments) &&
|
@@ -173,9 +181,9 @@ module GraphQL
|
|
173
181
|
end
|
174
182
|
|
175
183
|
module FieldConfigured
|
176
|
-
def arguments(context = GraphQL::Query::NullContext)
|
184
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
177
185
|
own_arguments = super
|
178
|
-
if
|
186
|
+
if @resolver_class
|
179
187
|
inherited_arguments = @resolver_class.field_arguments(context)
|
180
188
|
if own_arguments.any?
|
181
189
|
if inherited_arguments.any?
|
@@ -191,8 +199,12 @@ module GraphQL
|
|
191
199
|
end
|
192
200
|
end
|
193
201
|
|
202
|
+
def any_arguments?
|
203
|
+
super || (@resolver_class && @resolver_class.any_field_arguments?)
|
204
|
+
end
|
205
|
+
|
194
206
|
def all_argument_definitions
|
195
|
-
if
|
207
|
+
if @resolver_class
|
196
208
|
all_defns = {}
|
197
209
|
@resolver_class.all_field_argument_definitions.each do |arg_defn|
|
198
210
|
key = arg_defn.graphql_name
|
@@ -224,7 +236,7 @@ module GraphQL
|
|
224
236
|
end
|
225
237
|
|
226
238
|
# @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
|
227
|
-
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
239
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
228
240
|
warden = Warden.from_context(context)
|
229
241
|
if (arg_config = own_arguments[argument_name]) && (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden))
|
230
242
|
visible_arg
|
@@ -367,41 +379,52 @@ module GraphQL
|
|
367
379
|
def authorize_application_object(argument, id, context, loaded_application_object)
|
368
380
|
context.query.after_lazy(loaded_application_object) do |application_object|
|
369
381
|
if application_object.nil?
|
370
|
-
err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
|
371
|
-
load_application_object_failed(err)
|
382
|
+
err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
|
383
|
+
application_object = load_application_object_failed(err)
|
372
384
|
end
|
373
385
|
# Double-check that the located object is actually of this type
|
374
386
|
# (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
|
-
|
387
|
+
if application_object.nil?
|
388
|
+
nil
|
389
|
+
else
|
390
|
+
maybe_lazy_resolve_type = context.schema.resolve_type(argument.loads, application_object, context)
|
391
|
+
context.query.after_lazy(maybe_lazy_resolve_type) do |resolve_type_result|
|
392
|
+
if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
|
393
|
+
application_object_type, application_object = resolve_type_result
|
394
|
+
else
|
395
|
+
application_object_type = resolve_type_result
|
396
|
+
# application_object is already assigned
|
397
|
+
end
|
398
|
+
|
399
|
+
if !(
|
400
|
+
context.warden.possible_types(argument.loads).include?(application_object_type) ||
|
401
|
+
context.warden.loadable?(argument.loads, context)
|
402
|
+
)
|
403
|
+
err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
|
404
|
+
application_object = load_application_object_failed(err)
|
405
|
+
end
|
406
|
+
|
407
|
+
if application_object.nil?
|
408
|
+
nil
|
409
|
+
else
|
410
|
+
# This object was loaded successfully
|
411
|
+
# and resolved to the right type,
|
412
|
+
# now apply the `.authorized?` class method if there is one
|
413
|
+
context.query.after_lazy(application_object_type.authorized?(application_object, context)) do |authed|
|
414
|
+
if authed
|
415
|
+
application_object
|
403
416
|
else
|
404
|
-
|
417
|
+
err = GraphQL::UnauthorizedError.new(
|
418
|
+
object: application_object,
|
419
|
+
type: application_object_type,
|
420
|
+
context: context,
|
421
|
+
)
|
422
|
+
if self.respond_to?(:unauthorized_object)
|
423
|
+
err.set_backtrace(caller)
|
424
|
+
unauthorized_object(err)
|
425
|
+
else
|
426
|
+
raise err
|
427
|
+
end
|
405
428
|
end
|
406
429
|
end
|
407
430
|
end
|
@@ -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
|
@@ -15,6 +15,25 @@ module GraphQL
|
|
15
15
|
def scope_items(items, context)
|
16
16
|
items
|
17
17
|
end
|
18
|
+
|
19
|
+
def reauthorize_scoped_objects(new_value = nil)
|
20
|
+
if new_value.nil?
|
21
|
+
if @reauthorize_scoped_objects != nil
|
22
|
+
@reauthorize_scoped_objects
|
23
|
+
else
|
24
|
+
find_inherited_value(:reauthorize_scoped_objects, true)
|
25
|
+
end
|
26
|
+
else
|
27
|
+
@reauthorize_scoped_objects = new_value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def inherited(subclass)
|
32
|
+
super
|
33
|
+
subclass.class_eval do
|
34
|
+
@reauthorize_scoped_objects = nil
|
35
|
+
end
|
36
|
+
end
|
18
37
|
end
|
19
38
|
end
|
20
39
|
end
|
@@ -17,15 +17,15 @@ module GraphQL
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def valid_isolated_input?(v)
|
20
|
-
valid_input?(v, GraphQL::Query::NullContext)
|
20
|
+
valid_input?(v, GraphQL::Query::NullContext.instance)
|
21
21
|
end
|
22
22
|
|
23
23
|
def coerce_isolated_input(v)
|
24
|
-
coerce_input(v, GraphQL::Query::NullContext)
|
24
|
+
coerce_input(v, GraphQL::Query::NullContext.instance)
|
25
25
|
end
|
26
26
|
|
27
27
|
def coerce_isolated_result(v)
|
28
|
-
coerce_result(v, GraphQL::Query::NullContext)
|
28
|
+
coerce_result(v, GraphQL::Query::NullContext.instance)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -30,6 +30,10 @@ module GraphQL
|
|
30
30
|
# @see authorized_new to make instances
|
31
31
|
protected :new
|
32
32
|
|
33
|
+
def wrap_scoped(object, context)
|
34
|
+
scoped_new(object, context)
|
35
|
+
end
|
36
|
+
|
33
37
|
# This is called by the runtime to return an object to call methods on.
|
34
38
|
def wrap(object, context)
|
35
39
|
authorized_new(object, context)
|
@@ -91,6 +95,10 @@ module GraphQL
|
|
91
95
|
end
|
92
96
|
end
|
93
97
|
end
|
98
|
+
|
99
|
+
def scoped_new(object, context)
|
100
|
+
self.new(object, context)
|
101
|
+
end
|
94
102
|
end
|
95
103
|
|
96
104
|
def initialize(object, context)
|
@@ -36,15 +36,11 @@ module GraphQL
|
|
36
36
|
|
37
37
|
# @param schema [GraphQL::Schema]
|
38
38
|
# @param context [Hash]
|
39
|
-
# @param only [<#call(member, ctx)>]
|
40
|
-
# @param except [<#call(member, ctx)>]
|
41
39
|
# @param introspection [Boolean] Should include the introspection types in the string?
|
42
|
-
def initialize(schema, context: nil,
|
40
|
+
def initialize(schema, context: nil, introspection: false)
|
43
41
|
@document_from_schema = GraphQL::Language::DocumentFromSchemaDefinition.new(
|
44
42
|
schema,
|
45
43
|
context: context,
|
46
|
-
only: only,
|
47
|
-
except: except,
|
48
44
|
include_introspection_types: introspection,
|
49
45
|
)
|
50
46
|
|
@@ -61,7 +57,12 @@ module GraphQL
|
|
61
57
|
false
|
62
58
|
end
|
63
59
|
end
|
64
|
-
schema = Class.new(GraphQL::Schema) {
|
60
|
+
schema = Class.new(GraphQL::Schema) {
|
61
|
+
query(query_root)
|
62
|
+
def self.visible?(member, _ctx)
|
63
|
+
member.graphql_name != "Root"
|
64
|
+
end
|
65
|
+
}
|
65
66
|
|
66
67
|
introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
|
67
68
|
schema,
|
@@ -94,7 +95,7 @@ module GraphQL
|
|
94
95
|
|
95
96
|
class IntrospectionPrinter < GraphQL::Language::Printer
|
96
97
|
def print_schema_definition(schema)
|
97
|
-
"schema {\n query: Root\n}"
|
98
|
+
print_string("schema {\n query: Root\n}")
|
98
99
|
end
|
99
100
|
end
|
100
101
|
end
|