graphql 2.3.5 → 2.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/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/{ast/query_depth.rb → query_depth.rb} +23 -25
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/dataloader/async_dataloader.rb +2 -0
- data/lib/graphql/execution/interpreter/runtime.rb +6 -6
- data/lib/graphql/execution/interpreter.rb +1 -1
- data/lib/graphql/execution/lookahead.rb +10 -10
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +13 -3
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/language/document_from_schema_definition.rb +19 -26
- data/lib/graphql/language/lexer.rb +0 -3
- data/lib/graphql/language/sanitized_printer.rb +1 -1
- data/lib/graphql/language.rb +0 -1
- data/lib/graphql/query/context.rb +4 -0
- data/lib/graphql/query/null_context.rb +4 -0
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query.rb +26 -3
- data/lib/graphql/schema/always_visible.rb +1 -0
- data/lib/graphql/schema/argument.rb +19 -5
- data/lib/graphql/schema/directive.rb +2 -0
- data/lib/graphql/schema/enum.rb +4 -4
- data/lib/graphql/schema/field.rb +13 -1
- data/lib/graphql/schema/has_single_input_argument.rb +2 -1
- data/lib/graphql/schema/input_object.rb +8 -7
- data/lib/graphql/schema/introspection_system.rb +2 -14
- data/lib/graphql/schema/member/has_arguments.rb +7 -6
- data/lib/graphql/schema/member/has_fields.rb +6 -4
- data/lib/graphql/schema/resolver.rb +5 -5
- data/lib/graphql/schema/subset.rb +397 -0
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/validator/all_validator.rb +60 -0
- data/lib/graphql/schema/validator.rb +2 -0
- data/lib/graphql/schema/warden.rb +88 -1
- data/lib/graphql/schema.rb +44 -15
- data/lib/graphql/static_validation/base_visitor.rb +6 -5
- data/lib/graphql/static_validation/literal_validator.rb +4 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +7 -7
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +2 -2
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/event.rb +1 -1
- data/lib/graphql/subscriptions.rb +3 -3
- data/lib/graphql/testing/helpers.rb +2 -2
- data/lib/graphql/types/relay/connection_behaviors.rb +10 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +10 -0
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/version.rb +1 -1
- metadata +12 -13
- data/lib/graphql/analysis/ast/analyzer.rb +0 -91
- data/lib/graphql/analysis/ast/field_usage.rb +0 -84
- 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 -185
- data/lib/graphql/analysis/ast/visitor.rb +0 -284
- data/lib/graphql/analysis/ast.rb +0 -94
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
@@ -24,15 +24,8 @@ module GraphQL
|
|
24
24
|
@include_built_in_directives = include_built_in_directives
|
25
25
|
@include_one_of = false
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@warden = @schema.warden_class.new(
|
31
|
-
schema: @schema,
|
32
|
-
context: schema_context,
|
33
|
-
)
|
34
|
-
|
35
|
-
schema_context.warden = @warden
|
27
|
+
dummy_query = @schema.query_class.new(@schema, "{ __typename }", validate: false, context: context)
|
28
|
+
@types = dummy_query.types # rubocop:disable Development/ContextIsPassedCop
|
36
29
|
end
|
37
30
|
|
38
31
|
def document
|
@@ -44,9 +37,9 @@ module GraphQL
|
|
44
37
|
def build_schema_node
|
45
38
|
if !schema_respects_root_name_conventions?(@schema)
|
46
39
|
GraphQL::Language::Nodes::SchemaDefinition.new(
|
47
|
-
query:
|
48
|
-
mutation:
|
49
|
-
subscription:
|
40
|
+
query: @types.query_root&.graphql_name,
|
41
|
+
mutation: @types.mutation_root&.graphql_name,
|
42
|
+
subscription: @types.subscription_root&.graphql_name,
|
50
43
|
directives: definition_directives(@schema, :schema_directives)
|
51
44
|
)
|
52
45
|
else
|
@@ -57,7 +50,7 @@ module GraphQL
|
|
57
50
|
end
|
58
51
|
|
59
52
|
def build_object_type_node(object_type)
|
60
|
-
ints =
|
53
|
+
ints = @types.interfaces(object_type)
|
61
54
|
if ints.any?
|
62
55
|
ints.sort_by!(&:graphql_name)
|
63
56
|
ints.map! { |iface| build_type_name_node(iface) }
|
@@ -66,7 +59,7 @@ module GraphQL
|
|
66
59
|
GraphQL::Language::Nodes::ObjectTypeDefinition.new(
|
67
60
|
name: object_type.graphql_name,
|
68
61
|
interfaces: ints,
|
69
|
-
fields: build_field_nodes(
|
62
|
+
fields: build_field_nodes(@types.fields(object_type)),
|
70
63
|
description: object_type.description,
|
71
64
|
directives: directives(object_type),
|
72
65
|
)
|
@@ -75,7 +68,7 @@ module GraphQL
|
|
75
68
|
def build_field_node(field)
|
76
69
|
GraphQL::Language::Nodes::FieldDefinition.new(
|
77
70
|
name: field.graphql_name,
|
78
|
-
arguments: build_argument_nodes(
|
71
|
+
arguments: build_argument_nodes(@types.arguments(field)),
|
79
72
|
type: build_type_name_node(field.type),
|
80
73
|
description: field.description,
|
81
74
|
directives: directives(field),
|
@@ -86,7 +79,7 @@ module GraphQL
|
|
86
79
|
GraphQL::Language::Nodes::UnionTypeDefinition.new(
|
87
80
|
name: union_type.graphql_name,
|
88
81
|
description: union_type.description,
|
89
|
-
types:
|
82
|
+
types: @types.possible_types(union_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
|
90
83
|
directives: directives(union_type),
|
91
84
|
)
|
92
85
|
end
|
@@ -94,9 +87,9 @@ module GraphQL
|
|
94
87
|
def build_interface_type_node(interface_type)
|
95
88
|
GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
|
96
89
|
name: interface_type.graphql_name,
|
97
|
-
interfaces:
|
90
|
+
interfaces: @types.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
|
98
91
|
description: interface_type.description,
|
99
|
-
fields: build_field_nodes(
|
92
|
+
fields: build_field_nodes(@types.fields(interface_type)),
|
100
93
|
directives: directives(interface_type),
|
101
94
|
)
|
102
95
|
end
|
@@ -104,7 +97,7 @@ module GraphQL
|
|
104
97
|
def build_enum_type_node(enum_type)
|
105
98
|
GraphQL::Language::Nodes::EnumTypeDefinition.new(
|
106
99
|
name: enum_type.graphql_name,
|
107
|
-
values:
|
100
|
+
values: @types.enum_values(enum_type).sort_by(&:graphql_name).map do |enum_value|
|
108
101
|
build_enum_value_node(enum_value)
|
109
102
|
end,
|
110
103
|
description: enum_type.description,
|
@@ -149,7 +142,7 @@ module GraphQL
|
|
149
142
|
def build_input_object_node(input_object)
|
150
143
|
GraphQL::Language::Nodes::InputObjectTypeDefinition.new(
|
151
144
|
name: input_object.graphql_name,
|
152
|
-
fields: build_argument_nodes(
|
145
|
+
fields: build_argument_nodes(@types.arguments(input_object)),
|
153
146
|
description: input_object.description,
|
154
147
|
directives: directives(input_object),
|
155
148
|
)
|
@@ -159,7 +152,7 @@ module GraphQL
|
|
159
152
|
GraphQL::Language::Nodes::DirectiveDefinition.new(
|
160
153
|
name: directive.graphql_name,
|
161
154
|
repeatable: directive.repeatable?,
|
162
|
-
arguments: build_argument_nodes(
|
155
|
+
arguments: build_argument_nodes(@types.arguments(directive)),
|
163
156
|
locations: build_directive_location_nodes(directive.locations),
|
164
157
|
description: directive.description,
|
165
158
|
)
|
@@ -204,7 +197,7 @@ module GraphQL
|
|
204
197
|
when "INPUT_OBJECT"
|
205
198
|
GraphQL::Language::Nodes::InputObject.new(
|
206
199
|
arguments: default_value.to_h.map do |arg_name, arg_value|
|
207
|
-
args = @
|
200
|
+
args = @types.arguments(type)
|
208
201
|
arg = args.find { |a| a.keyword.to_s == arg_name.to_s }
|
209
202
|
if arg.nil?
|
210
203
|
raise ArgumentError, "No argument definition on #{type.graphql_name} for argument: #{arg_name.inspect} (expected one of: #{args.map(&:keyword)})"
|
@@ -260,13 +253,13 @@ module GraphQL
|
|
260
253
|
end
|
261
254
|
|
262
255
|
def build_definition_nodes
|
263
|
-
dirs_to_build =
|
256
|
+
dirs_to_build = @types.directives
|
264
257
|
if !include_built_in_directives
|
265
258
|
dirs_to_build = dirs_to_build.reject { |directive| directive.default_directive? }
|
266
259
|
end
|
267
260
|
definitions = build_directive_nodes(dirs_to_build)
|
268
|
-
|
269
|
-
type_nodes = build_type_definition_nodes(
|
261
|
+
all_types = @types.all_types
|
262
|
+
type_nodes = build_type_definition_nodes(all_types + schema.extra_types)
|
270
263
|
if @include_one_of
|
271
264
|
# This may have been set to true when iterating over all types
|
272
265
|
definitions.concat(build_directive_nodes([GraphQL::Schema::Directive::OneOf]))
|
@@ -351,7 +344,7 @@ module GraphQL
|
|
351
344
|
dirs
|
352
345
|
end
|
353
346
|
|
354
|
-
attr_reader :schema, :
|
347
|
+
attr_reader :schema, :always_include_schema,
|
355
348
|
:include_introspection_types, :include_built_in_directives, :include_built_in_scalars
|
356
349
|
end
|
357
350
|
end
|
@@ -345,17 +345,14 @@ module GraphQL
|
|
345
345
|
def self.tokenize(string)
|
346
346
|
lexer = GraphQL::Language::Lexer.new(string)
|
347
347
|
tokens = []
|
348
|
-
prev_token = nil
|
349
348
|
while (token_name = lexer.advance)
|
350
349
|
new_token = [
|
351
350
|
token_name,
|
352
351
|
lexer.line_number,
|
353
352
|
lexer.column_number,
|
354
353
|
lexer.debug_token_value(token_name),
|
355
|
-
prev_token,
|
356
354
|
]
|
357
355
|
tokens << new_token
|
358
|
-
prev_token = new_token
|
359
356
|
end
|
360
357
|
tokens
|
361
358
|
end
|
@@ -113,7 +113,7 @@ module GraphQL
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def print_field(field, indent: "")
|
116
|
-
@current_field = query.
|
116
|
+
@current_field = query.types.field(@current_type, field.name)
|
117
117
|
old_type = @current_type
|
118
118
|
@current_type = @current_field.type.unwrap
|
119
119
|
super
|
data/lib/graphql/language.rb
CHANGED
@@ -9,7 +9,6 @@ require "graphql/language/nodes"
|
|
9
9
|
require "graphql/language/cache"
|
10
10
|
require "graphql/language/parser"
|
11
11
|
require "graphql/language/static_visitor"
|
12
|
-
require "graphql/language/token"
|
13
12
|
require "graphql/language/visitor"
|
14
13
|
require "graphql/language/definition_slice"
|
15
14
|
require "strscan"
|
@@ -84,6 +84,10 @@ module GraphQL
|
|
84
84
|
|
85
85
|
def_delegators :@query, :trace, :interpreter?
|
86
86
|
|
87
|
+
def types
|
88
|
+
@query.types
|
89
|
+
end
|
90
|
+
|
87
91
|
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
|
88
92
|
# @!method []=(key, value)
|
89
93
|
# Reassign `key` to the hash passed to {Schema#execute} as `context:`
|
@@ -100,10 +100,10 @@ module GraphQL
|
|
100
100
|
# Depending on the analysis engine, we must use different analyzers
|
101
101
|
# remove this once everything has switched over to AST analyzers
|
102
102
|
if max_depth
|
103
|
-
qa << GraphQL::Analysis::
|
103
|
+
qa << GraphQL::Analysis::MaxQueryDepth
|
104
104
|
end
|
105
105
|
if max_complexity
|
106
|
-
qa << GraphQL::Analysis::
|
106
|
+
qa << GraphQL::Analysis::MaxQueryComplexity
|
107
107
|
end
|
108
108
|
qa
|
109
109
|
else
|
data/lib/graphql/query.rb
CHANGED
@@ -95,12 +95,24 @@ module GraphQL
|
|
95
95
|
# @param root_value [Object] the object used to resolve fields on the root type
|
96
96
|
# @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
|
97
97
|
# @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
|
98
|
-
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil)
|
98
|
+
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_schema_subset: nil)
|
99
99
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
100
100
|
variables ||= {}
|
101
101
|
@schema = schema
|
102
102
|
@context = schema.context_class.new(query: self, values: context)
|
103
|
-
|
103
|
+
|
104
|
+
if use_schema_subset.nil?
|
105
|
+
use_schema_subset = warden ? false : schema.use_schema_subset?
|
106
|
+
end
|
107
|
+
|
108
|
+
if use_schema_subset
|
109
|
+
@schema_subset = @schema.subset_class.new(self)
|
110
|
+
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
111
|
+
else
|
112
|
+
@schema_subset = nil
|
113
|
+
@warden = warden
|
114
|
+
end
|
115
|
+
|
104
116
|
@subscription_topic = subscription_topic
|
105
117
|
@root_value = root_value
|
106
118
|
@fragments = nil
|
@@ -195,7 +207,14 @@ module GraphQL
|
|
195
207
|
def lookahead
|
196
208
|
@lookahead ||= begin
|
197
209
|
ast_node = selected_operation
|
198
|
-
root_type =
|
210
|
+
root_type = case ast_node.operation_type
|
211
|
+
when nil, "query"
|
212
|
+
types.query_root # rubocop:disable Development/ContextIsPassedCop
|
213
|
+
when "mutation"
|
214
|
+
types.mutation_root # rubocop:disable Development/ContextIsPassedCop
|
215
|
+
when "subscription"
|
216
|
+
types.subscription_root # rubocop:disable Development/ContextIsPassedCop
|
217
|
+
end
|
199
218
|
GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
|
200
219
|
end
|
201
220
|
end
|
@@ -330,6 +349,10 @@ module GraphQL
|
|
330
349
|
|
331
350
|
def_delegators :warden, :get_type, :get_field, :possible_types, :root_type_for_operation
|
332
351
|
|
352
|
+
def types
|
353
|
+
@schema_subset || warden.schema_subset
|
354
|
+
end
|
355
|
+
|
333
356
|
# @param abstract_type [GraphQL::UnionType, GraphQL::InterfaceType]
|
334
357
|
# @param value [Object] Any runtime value
|
335
358
|
# @return [GraphQL::ObjectType, nil] The runtime type of `value` from {Schema#resolve_type}
|
@@ -312,10 +312,15 @@ module GraphQL
|
|
312
312
|
context.query.after_lazy(custom_loaded_value) do |custom_value|
|
313
313
|
if loads
|
314
314
|
if type.list?
|
315
|
-
loaded_values =
|
316
|
-
|
317
|
-
|
318
|
-
|
315
|
+
loaded_values = []
|
316
|
+
context.dataloader.run_isolated do
|
317
|
+
custom_value.each_with_index.map { |custom_val, idx|
|
318
|
+
id = coerced_value[idx]
|
319
|
+
context.dataloader.append_job do
|
320
|
+
loaded_values[idx] = load_method_owner.authorize_application_object(self, id, context, custom_val)
|
321
|
+
end
|
322
|
+
}
|
323
|
+
end
|
319
324
|
context.schema.after_any_lazies(loaded_values, &:itself)
|
320
325
|
else
|
321
326
|
load_method_owner.authorize_application_object(self, coerced_value, context, custom_loaded_value)
|
@@ -326,7 +331,16 @@ module GraphQL
|
|
326
331
|
end
|
327
332
|
elsif loads
|
328
333
|
if type.list?
|
329
|
-
loaded_values =
|
334
|
+
loaded_values = []
|
335
|
+
# We want to run these list items all together,
|
336
|
+
# but we also need to wait for the result so we can return it :S
|
337
|
+
context.dataloader.run_isolated do
|
338
|
+
coerced_value.each_with_index { |val, idx|
|
339
|
+
context.dataloader.append_job do
|
340
|
+
loaded_values[idx] = load_method_owner.load_and_authorize_application_object(self, val, context)
|
341
|
+
end
|
342
|
+
}
|
343
|
+
end
|
330
344
|
context.schema.after_any_lazies(loaded_values, &:itself)
|
331
345
|
else
|
332
346
|
load_method_owner.load_and_authorize_application_object(self, coerced_value, context)
|
@@ -188,6 +188,8 @@ module GraphQL
|
|
188
188
|
assert_has_location(SCALAR)
|
189
189
|
elsif @owner < GraphQL::Schema
|
190
190
|
assert_has_location(SCHEMA)
|
191
|
+
elsif @owner < GraphQL::Schema::Resolver
|
192
|
+
assert_has_location(FIELD_DEFINITION)
|
191
193
|
else
|
192
194
|
raise "Unexpected directive owner class: #{@owner}"
|
193
195
|
end
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -130,7 +130,7 @@ module GraphQL
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def validate_non_null_input(value_name, ctx, max_errors: nil)
|
133
|
-
allowed_values = ctx.
|
133
|
+
allowed_values = ctx.types.enum_values(self)
|
134
134
|
matching_value = allowed_values.find { |v| v.graphql_name == value_name }
|
135
135
|
|
136
136
|
if matching_value.nil?
|
@@ -141,8 +141,8 @@ module GraphQL
|
|
141
141
|
end
|
142
142
|
|
143
143
|
def coerce_result(value, ctx)
|
144
|
-
|
145
|
-
all_values =
|
144
|
+
types = ctx.types
|
145
|
+
all_values = types ? types.enum_values(self) : values.each_value
|
146
146
|
enum_value = all_values.find { |val| val.value == value }
|
147
147
|
if enum_value
|
148
148
|
enum_value.graphql_name
|
@@ -152,7 +152,7 @@ module GraphQL
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def coerce_input(value_name, ctx)
|
155
|
-
all_values = ctx.
|
155
|
+
all_values = ctx.types ? ctx.types.enum_values(self) : values.each_value
|
156
156
|
|
157
157
|
if v = all_values.find { |val| val.graphql_name == value_name }
|
158
158
|
v.value
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -41,6 +41,18 @@ module GraphQL
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def directives
|
45
|
+
if @resolver_class && (r_dirs = @resolver_class.directives).any?
|
46
|
+
if (own_dirs = super).any?
|
47
|
+
own_dirs + r_dirs
|
48
|
+
else
|
49
|
+
r_dirs
|
50
|
+
end
|
51
|
+
else
|
52
|
+
super
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
44
56
|
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
45
57
|
attr_accessor :owner
|
46
58
|
|
@@ -606,7 +618,7 @@ module GraphQL
|
|
606
618
|
using_arg_values = false
|
607
619
|
end
|
608
620
|
|
609
|
-
args = context.
|
621
|
+
args = context.types.arguments(self)
|
610
622
|
args.each do |arg|
|
611
623
|
arg_key = arg.keyword
|
612
624
|
if arg_values.key?(arg_key)
|
@@ -149,7 +149,8 @@ module GraphQL
|
|
149
149
|
|
150
150
|
def authorize_arguments(args, values)
|
151
151
|
# remove the `input` wrapper to match values
|
152
|
-
|
152
|
+
input_type = args.find { |a| a.graphql_name == "input" }.type.unwrap
|
153
|
+
input_args = context.types.arguments(input_type)
|
153
154
|
super(input_args, values)
|
154
155
|
end
|
155
156
|
end
|
@@ -23,7 +23,8 @@ module GraphQL
|
|
23
23
|
@ruby_style_hash = ruby_kwargs
|
24
24
|
@arguments = arguments
|
25
25
|
# Apply prepares, not great to have it duplicated here.
|
26
|
-
self.class.arguments(context).each_value
|
26
|
+
arg_defns = context ? context.types.arguments(self.class) : self.class.arguments(context).each_value
|
27
|
+
arg_defns.each do |arg_defn|
|
27
28
|
ruby_kwargs_key = arg_defn.keyword
|
28
29
|
if @ruby_style_hash.key?(ruby_kwargs_key)
|
29
30
|
# Weirdly, procs are applied during coercion, but not methods.
|
@@ -58,7 +59,7 @@ module GraphQL
|
|
58
59
|
def self.authorized?(obj, value, ctx)
|
59
60
|
# Authorize each argument (but this doesn't apply if `prepare` is implemented):
|
60
61
|
if value.respond_to?(:key?)
|
61
|
-
arguments(
|
62
|
+
ctx.types.arguments(self).each do |input_obj_arg|
|
62
63
|
if value.key?(input_obj_arg.keyword) &&
|
63
64
|
!input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
|
64
65
|
return false
|
@@ -149,7 +150,7 @@ module GraphQL
|
|
149
150
|
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object."
|
150
151
|
|
151
152
|
def validate_non_null_input(input, ctx, max_errors: nil)
|
152
|
-
|
153
|
+
types = ctx.types
|
153
154
|
|
154
155
|
if input.is_a?(Array)
|
155
156
|
return GraphQL::Query::InputValidationResult.from_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
@@ -161,9 +162,9 @@ module GraphQL
|
|
161
162
|
end
|
162
163
|
|
163
164
|
# Inject missing required arguments
|
164
|
-
missing_required_inputs =
|
165
|
-
if !input.key?(
|
166
|
-
m[
|
165
|
+
missing_required_inputs = ctx.types.arguments(self).reduce({}) do |m, (argument)|
|
166
|
+
if !input.key?(argument.graphql_name) && argument.type.non_null? && types.argument(self, argument.graphql_name)
|
167
|
+
m[argument.graphql_name] = nil
|
167
168
|
end
|
168
169
|
|
169
170
|
m
|
@@ -172,7 +173,7 @@ module GraphQL
|
|
172
173
|
result = nil
|
173
174
|
[input, missing_required_inputs].each do |args_to_validate|
|
174
175
|
args_to_validate.each do |argument_name, value|
|
175
|
-
argument =
|
176
|
+
argument = types.argument(self, argument_name)
|
176
177
|
# Items in the input that are unexpected
|
177
178
|
if argument.nil?
|
178
179
|
result ||= Query::InputValidationResult.new
|
@@ -69,7 +69,7 @@ module GraphQL
|
|
69
69
|
def resolve_late_bindings
|
70
70
|
@types.each do |name, t|
|
71
71
|
if t.kind.fields?
|
72
|
-
t.
|
72
|
+
t.all_field_definitions.each do |field_defn|
|
73
73
|
field_defn.type = resolve_late_binding(field_defn.type)
|
74
74
|
end
|
75
75
|
end
|
@@ -113,19 +113,7 @@ module GraphQL
|
|
113
113
|
|
114
114
|
def get_fields_from_class(class_sym:)
|
115
115
|
object_type_defn = load_constant(class_sym)
|
116
|
-
|
117
|
-
if object_type_defn.is_a?(Module)
|
118
|
-
object_type_defn.fields
|
119
|
-
else
|
120
|
-
extracted_field_defns = {}
|
121
|
-
object_class = object_type_defn.metadata[:type_class]
|
122
|
-
object_type_defn.all_fields.each do |field_defn|
|
123
|
-
inner_resolve = field_defn.resolve_proc
|
124
|
-
resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
|
125
|
-
extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
|
126
|
-
end
|
127
|
-
extracted_field_defns
|
128
|
-
end
|
116
|
+
object_type_defn.fields
|
129
117
|
end
|
130
118
|
|
131
119
|
# This is probably not 100% robust -- but it has to be good enough to avoid modifying the built-in introspection types
|
@@ -135,10 +135,11 @@ module GraphQL
|
|
135
135
|
|
136
136
|
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
137
137
|
warden = Warden.from_context(context)
|
138
|
+
skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)
|
138
139
|
for ancestor in ancestors
|
139
140
|
if ancestor.respond_to?(:own_arguments) &&
|
140
141
|
(a = ancestor.own_arguments[argument_name]) &&
|
141
|
-
(a = Warden.visible_entry?(:visible_argument?, a, context, warden))
|
142
|
+
(skip_visible || (a = Warden.visible_entry?(:visible_argument?, a, context, warden)))
|
142
143
|
return a
|
143
144
|
end
|
144
145
|
end
|
@@ -205,8 +206,8 @@ module GraphQL
|
|
205
206
|
# @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
|
206
207
|
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
207
208
|
warden = Warden.from_context(context)
|
208
|
-
if (arg_config = own_arguments[argument_name]) && (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden))
|
209
|
-
visible_arg
|
209
|
+
if (arg_config = own_arguments[argument_name]) && ((context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)) || (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden)))
|
210
|
+
visible_arg || arg_config
|
210
211
|
elsif defined?(@resolver_class) && @resolver_class
|
211
212
|
@resolver_class.get_field_argument(argument_name, context)
|
212
213
|
else
|
@@ -230,7 +231,7 @@ module GraphQL
|
|
230
231
|
# @return [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
|
231
232
|
def coerce_arguments(parent_object, values, context, &block)
|
232
233
|
# Cache this hash to avoid re-merging it
|
233
|
-
arg_defns = context.
|
234
|
+
arg_defns = context.types.arguments(self)
|
234
235
|
total_args_count = arg_defns.size
|
235
236
|
|
236
237
|
finished_args = nil
|
@@ -364,8 +365,8 @@ module GraphQL
|
|
364
365
|
end
|
365
366
|
|
366
367
|
if !(
|
367
|
-
context.
|
368
|
-
context.
|
368
|
+
context.types.possible_types(argument.loads).include?(application_object_type) ||
|
369
|
+
context.types.loadable?(argument.loads, context)
|
369
370
|
)
|
370
371
|
err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
|
371
372
|
application_object = load_application_object_failed(err)
|
@@ -99,11 +99,12 @@ module GraphQL
|
|
99
99
|
module InterfaceMethods
|
100
100
|
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
|
101
101
|
warden = Warden.from_context(context)
|
102
|
+
skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)
|
102
103
|
for ancestor in ancestors
|
103
104
|
if ancestor.respond_to?(:own_fields) &&
|
104
105
|
(f_entry = ancestor.own_fields[field_name]) &&
|
105
|
-
(
|
106
|
-
return
|
106
|
+
(skip_visible || (f_entry = Warden.visible_entry?(:visible_field?, f_entry, context, warden)))
|
107
|
+
return f_entry
|
107
108
|
end
|
108
109
|
end
|
109
110
|
nil
|
@@ -134,13 +135,14 @@ module GraphQL
|
|
134
135
|
# Objects need to check that the interface implementation is visible, too
|
135
136
|
warden = Warden.from_context(context)
|
136
137
|
ancs = ancestors
|
138
|
+
skip_visible = context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)
|
137
139
|
i = 0
|
138
140
|
while (ancestor = ancs[i])
|
139
141
|
if ancestor.respond_to?(:own_fields) &&
|
140
142
|
visible_interface_implementation?(ancestor, context, warden) &&
|
141
143
|
(f_entry = ancestor.own_fields[field_name]) &&
|
142
|
-
(
|
143
|
-
return
|
144
|
+
(skip_visible || (f_entry = Warden.visible_entry?(:visible_field?, f_entry, context, warden)))
|
145
|
+
return f_entry
|
144
146
|
end
|
145
147
|
i += 1
|
146
148
|
end
|
@@ -25,6 +25,7 @@ module GraphQL
|
|
25
25
|
extend GraphQL::Schema::Member::HasValidators
|
26
26
|
include Schema::Member::HasPath
|
27
27
|
extend Schema::Member::HasPath
|
28
|
+
extend Schema::Member::HasDirectives
|
28
29
|
|
29
30
|
# @param object [Object] The application object that this field is being resolved on
|
30
31
|
# @param context [GraphQL::Query::Context]
|
@@ -35,7 +36,7 @@ module GraphQL
|
|
35
36
|
@field = field
|
36
37
|
# Since this hash is constantly rebuilt, cache it for this call
|
37
38
|
@arguments_by_keyword = {}
|
38
|
-
|
39
|
+
context.types.arguments(self.class).each do |arg|
|
39
40
|
@arguments_by_keyword[arg.keyword] = arg
|
40
41
|
end
|
41
42
|
@prepared_arguments = nil
|
@@ -151,7 +152,7 @@ module GraphQL
|
|
151
152
|
# @return [Boolean, early_return_data] If `false`, execution will stop (and `early_return_data` will be returned instead, if present.)
|
152
153
|
def authorized?(**inputs)
|
153
154
|
arg_owner = @field # || self.class
|
154
|
-
args =
|
155
|
+
args = context.types.arguments(arg_owner)
|
155
156
|
authorize_arguments(args, inputs)
|
156
157
|
end
|
157
158
|
|
@@ -168,7 +169,7 @@ module GraphQL
|
|
168
169
|
private
|
169
170
|
|
170
171
|
def authorize_arguments(args, inputs)
|
171
|
-
args.
|
172
|
+
args.each do |argument|
|
172
173
|
arg_keyword = argument.keyword
|
173
174
|
if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
|
174
175
|
auth_result = argument.authorized?(self, arg_value, context)
|
@@ -181,10 +182,9 @@ module GraphQL
|
|
181
182
|
elsif auth_result == false
|
182
183
|
return auth_result
|
183
184
|
end
|
184
|
-
else
|
185
|
-
true
|
186
185
|
end
|
187
186
|
end
|
187
|
+
true
|
188
188
|
end
|
189
189
|
|
190
190
|
def load_arguments(args)
|