graphql 2.0.27 → 2.2.6
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.
- 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
|