graphql 2.4.13 → 2.5.11
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/graphql/analysis/query_complexity.rb +87 -7
- data/lib/graphql/backtrace/table.rb +37 -14
- data/lib/graphql/current.rb +1 -1
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +27 -0
- data/lib/graphql/dashboard/statics/dashboard.js +74 -9
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +49 -1
- data/lib/graphql/dashboard.rb +45 -29
- data/lib/graphql/dataloader/active_record_association_source.rb +28 -8
- data/lib/graphql/dataloader/active_record_source.rb +26 -5
- data/lib/graphql/dataloader/null_dataloader.rb +7 -0
- data/lib/graphql/dataloader/source.rb +16 -4
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/execution/interpreter/resolve.rb +3 -3
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +34 -1
- data/lib/graphql/execution/interpreter/runtime.rb +163 -59
- data/lib/graphql/execution/interpreter.rb +5 -13
- data/lib/graphql/execution/multiplex.rb +6 -1
- data/lib/graphql/invalid_null_error.rb +15 -2
- data/lib/graphql/language/lexer.rb +9 -2
- data/lib/graphql/language/nodes.rb +5 -1
- data/lib/graphql/language/parser.rb +14 -6
- data/lib/graphql/query/context.rb +3 -8
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query.rb +59 -55
- data/lib/graphql/schema/addition.rb +3 -1
- data/lib/graphql/schema/always_visible.rb +1 -0
- data/lib/graphql/schema/argument.rb +9 -3
- data/lib/graphql/schema/build_from_definition.rb +96 -47
- data/lib/graphql/schema/directive/flagged.rb +2 -0
- data/lib/graphql/schema/directive.rb +33 -1
- data/lib/graphql/schema/field.rb +23 -1
- data/lib/graphql/schema/input_object.rb +38 -30
- data/lib/graphql/schema/list.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/member/has_dataloader.rb +4 -2
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_interfaces.rb +2 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +16 -2
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/resolver.rb +1 -0
- data/lib/graphql/schema/scalar.rb +1 -6
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/validator/required_validator.rb +15 -6
- data/lib/graphql/schema/visibility/migration.rb +2 -2
- data/lib/graphql/schema/visibility/profile.rb +107 -21
- data/lib/graphql/schema/visibility.rb +41 -29
- data/lib/graphql/schema/warden.rb +13 -5
- data/lib/graphql/schema.rb +228 -32
- data/lib/graphql/static_validation/all_rules.rb +2 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +78 -16
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +6 -2
- data/lib/graphql/testing/helpers.rb +5 -2
- data/lib/graphql/tracing/active_support_notifications_trace.rb +7 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +5 -0
- data/lib/graphql/tracing/appsignal_trace.rb +26 -61
- data/lib/graphql/tracing/data_dog_trace.rb +41 -164
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +34 -164
- data/lib/graphql/tracing/notifications_trace.rb +183 -37
- data/lib/graphql/tracing/null_trace.rb +1 -1
- data/lib/graphql/tracing/perfetto_trace.rb +16 -19
- data/lib/graphql/tracing/prometheus_trace.rb +47 -74
- data/lib/graphql/tracing/scout_trace.rb +25 -59
- data/lib/graphql/tracing/sentry_trace.rb +56 -99
- data/lib/graphql/tracing/statsd_trace.rb +24 -47
- data/lib/graphql/tracing/trace.rb +0 -17
- data/lib/graphql/tracing.rb +1 -0
- data/lib/graphql/type_kinds.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -1
- metadata +35 -26
- data/lib/graphql/dashboard/views/graphql/dashboard/traces/index.html.erb +0 -63
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
@@ -20,8 +20,8 @@ module GraphQL
|
|
20
20
|
from_document(schema_superclass, parser.parse_file(definition_path), **kwargs)
|
21
21
|
end
|
22
22
|
|
23
|
-
def from_document(schema_superclass, document, default_resolve:, using: {}, relay: false)
|
24
|
-
Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using)
|
23
|
+
def from_document(schema_superclass, document, default_resolve:, using: {}, base_types: {}, relay: false)
|
24
|
+
Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using, base_types: base_types)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -30,9 +30,18 @@ module GraphQL
|
|
30
30
|
include GraphQL::EmptyObjects
|
31
31
|
extend self
|
32
32
|
|
33
|
-
def build(schema_superclass, document, default_resolve:, using: {}, relay:)
|
33
|
+
def build(schema_superclass, document, default_resolve:, using: {}, base_types: {}, relay:)
|
34
34
|
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
|
35
35
|
|
36
|
+
base_types = {
|
37
|
+
object: GraphQL::Schema::Object,
|
38
|
+
interface: GraphQL::Schema::Interface,
|
39
|
+
union: GraphQL::Schema::Union,
|
40
|
+
scalar: GraphQL::Schema::Scalar,
|
41
|
+
enum: GraphQL::Schema::Enum,
|
42
|
+
input_object: GraphQL::Schema::InputObject,
|
43
|
+
}.merge!(base_types)
|
44
|
+
|
36
45
|
if default_resolve.is_a?(Hash)
|
37
46
|
default_resolve = ResolveMap.new(default_resolve)
|
38
47
|
end
|
@@ -53,7 +62,7 @@ module GraphQL
|
|
53
62
|
types[type_name] ||= begin
|
54
63
|
defn = document.definitions.find { |d| d.respond_to?(:name) && d.name == type_name }
|
55
64
|
if defn
|
56
|
-
build_definition_from_node(defn, directive_type_resolver, default_resolve)
|
65
|
+
build_definition_from_node(defn, directive_type_resolver, default_resolve, base_types)
|
57
66
|
elsif (built_in_defn = GraphQL::Schema::BUILT_IN_TYPES[type_name])
|
58
67
|
built_in_defn
|
59
68
|
else
|
@@ -77,14 +86,20 @@ module GraphQL
|
|
77
86
|
case definition
|
78
87
|
when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
|
79
88
|
nil # already handled
|
80
|
-
when GraphQL::Language::Nodes::SchemaExtension
|
89
|
+
when GraphQL::Language::Nodes::SchemaExtension,
|
90
|
+
GraphQL::Language::Nodes::ScalarTypeExtension,
|
91
|
+
GraphQL::Language::Nodes::ObjectTypeExtension,
|
92
|
+
GraphQL::Language::Nodes::InterfaceTypeExtension,
|
93
|
+
GraphQL::Language::Nodes::UnionTypeExtension,
|
94
|
+
GraphQL::Language::Nodes::EnumTypeExtension,
|
95
|
+
GraphQL::Language::Nodes::InputObjectTypeExtension
|
81
96
|
schema_extensions ||= []
|
82
97
|
schema_extensions << definition
|
83
98
|
else
|
84
99
|
# It's possible that this was already loaded by the directives
|
85
100
|
prev_type = types[definition.name]
|
86
101
|
if prev_type.nil? || prev_type.is_a?(Schema::LateBoundType)
|
87
|
-
types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve)
|
102
|
+
types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve, base_types)
|
88
103
|
end
|
89
104
|
end
|
90
105
|
end
|
@@ -124,6 +139,34 @@ module GraphQL
|
|
124
139
|
|
125
140
|
raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
|
126
141
|
|
142
|
+
schema_extensions&.each do |ext|
|
143
|
+
next if ext.is_a?(GraphQL::Language::Nodes::SchemaExtension)
|
144
|
+
|
145
|
+
built_type = types[ext.name]
|
146
|
+
|
147
|
+
case ext
|
148
|
+
when GraphQL::Language::Nodes::ScalarTypeExtension
|
149
|
+
build_directives(built_type, ext, type_resolver)
|
150
|
+
when GraphQL::Language::Nodes::ObjectTypeExtension
|
151
|
+
build_directives(built_type, ext, type_resolver)
|
152
|
+
build_fields(built_type, ext.fields, type_resolver, default_resolve: true)
|
153
|
+
build_interfaces(built_type, ext.interfaces, type_resolver)
|
154
|
+
when GraphQL::Language::Nodes::InterfaceTypeExtension
|
155
|
+
build_directives(built_type, ext, type_resolver)
|
156
|
+
build_fields(built_type, ext.fields, type_resolver, default_resolve: nil)
|
157
|
+
build_interfaces(built_type, ext.interfaces, type_resolver)
|
158
|
+
when GraphQL::Language::Nodes::UnionTypeExtension
|
159
|
+
build_directives(built_type, ext, type_resolver)
|
160
|
+
built_type.possible_types(*ext.types.map { |type_name| type_resolver.call(type_name) })
|
161
|
+
when GraphQL::Language::Nodes::EnumTypeExtension
|
162
|
+
build_directives(built_type, ext, type_resolver)
|
163
|
+
build_values(built_type, ext.values, type_resolver)
|
164
|
+
when GraphQL::Language::Nodes::InputObjectTypeExtension
|
165
|
+
build_directives(built_type, ext, type_resolver)
|
166
|
+
build_arguments(built_type, ext.fields, type_resolver)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
127
170
|
builder = self
|
128
171
|
|
129
172
|
found_types = types.values
|
@@ -144,6 +187,10 @@ module GraphQL
|
|
144
187
|
|
145
188
|
object_types.each do |t|
|
146
189
|
t.interfaces.each do |int_t|
|
190
|
+
if int_t.is_a?(LateBoundType)
|
191
|
+
int_t = types[int_t.graphql_name]
|
192
|
+
t.implements(int_t)
|
193
|
+
end
|
147
194
|
int_t.orphan_types(t)
|
148
195
|
end
|
149
196
|
end
|
@@ -192,8 +239,8 @@ module GraphQL
|
|
192
239
|
end
|
193
240
|
end
|
194
241
|
|
195
|
-
|
196
|
-
|
242
|
+
schema_extensions&.each do |ext|
|
243
|
+
if ext.is_a?(GraphQL::Language::Nodes::SchemaExtension)
|
197
244
|
build_directives(schema_class, ext, type_resolver)
|
198
245
|
end
|
199
246
|
end
|
@@ -205,20 +252,20 @@ module GraphQL
|
|
205
252
|
raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
|
206
253
|
}
|
207
254
|
|
208
|
-
def build_definition_from_node(definition, type_resolver, default_resolve)
|
255
|
+
def build_definition_from_node(definition, type_resolver, default_resolve, base_types)
|
209
256
|
case definition
|
210
257
|
when GraphQL::Language::Nodes::EnumTypeDefinition
|
211
|
-
build_enum_type(definition, type_resolver)
|
258
|
+
build_enum_type(definition, type_resolver, base_types[:enum])
|
212
259
|
when GraphQL::Language::Nodes::ObjectTypeDefinition
|
213
|
-
build_object_type(definition, type_resolver)
|
260
|
+
build_object_type(definition, type_resolver, base_types[:object])
|
214
261
|
when GraphQL::Language::Nodes::InterfaceTypeDefinition
|
215
|
-
build_interface_type(definition, type_resolver)
|
262
|
+
build_interface_type(definition, type_resolver, base_types[:interface])
|
216
263
|
when GraphQL::Language::Nodes::UnionTypeDefinition
|
217
|
-
build_union_type(definition, type_resolver)
|
264
|
+
build_union_type(definition, type_resolver, base_types[:union])
|
218
265
|
when GraphQL::Language::Nodes::ScalarTypeDefinition
|
219
|
-
build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
|
266
|
+
build_scalar_type(definition, type_resolver, base_types[:scalar], default_resolve: default_resolve)
|
220
267
|
when GraphQL::Language::Nodes::InputObjectTypeDefinition
|
221
|
-
build_input_object_type(definition, type_resolver)
|
268
|
+
build_input_object_type(definition, type_resolver, base_types[:input_object])
|
222
269
|
end
|
223
270
|
end
|
224
271
|
|
@@ -284,22 +331,26 @@ module GraphQL
|
|
284
331
|
end
|
285
332
|
end
|
286
333
|
|
287
|
-
def build_enum_type(enum_type_definition, type_resolver)
|
334
|
+
def build_enum_type(enum_type_definition, type_resolver, base_type)
|
288
335
|
builder = self
|
289
|
-
Class.new(
|
336
|
+
Class.new(base_type) do
|
290
337
|
graphql_name(enum_type_definition.name)
|
291
338
|
builder.build_directives(self, enum_type_definition, type_resolver)
|
292
339
|
description(enum_type_definition.description)
|
293
340
|
ast_node(enum_type_definition)
|
294
|
-
enum_type_definition.values
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
341
|
+
builder.build_values(self, enum_type_definition.values, type_resolver)
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def build_values(type_class, enum_value_definitions, type_resolver)
|
346
|
+
enum_value_definitions.each do |enum_value_definition|
|
347
|
+
type_class.value(enum_value_definition.name,
|
348
|
+
value: enum_value_definition.name,
|
349
|
+
deprecation_reason: build_deprecation_reason(enum_value_definition.directives),
|
350
|
+
description: enum_value_definition.description,
|
351
|
+
directives: prepare_directives(enum_value_definition, type_resolver),
|
352
|
+
ast_node: enum_value_definition,
|
353
|
+
)
|
303
354
|
end
|
304
355
|
end
|
305
356
|
|
@@ -313,9 +364,9 @@ module GraphQL
|
|
313
364
|
reason.value
|
314
365
|
end
|
315
366
|
|
316
|
-
def build_scalar_type(scalar_type_definition, type_resolver, default_resolve:)
|
367
|
+
def build_scalar_type(scalar_type_definition, type_resolver, base_type, default_resolve:)
|
317
368
|
builder = self
|
318
|
-
Class.new(
|
369
|
+
Class.new(base_type) do
|
319
370
|
graphql_name(scalar_type_definition.name)
|
320
371
|
description(scalar_type_definition.description)
|
321
372
|
ast_node(scalar_type_definition)
|
@@ -336,9 +387,9 @@ module GraphQL
|
|
336
387
|
end
|
337
388
|
end
|
338
389
|
|
339
|
-
def build_union_type(union_type_definition, type_resolver)
|
390
|
+
def build_union_type(union_type_definition, type_resolver, base_type)
|
340
391
|
builder = self
|
341
|
-
Class.new(
|
392
|
+
Class.new(base_type) do
|
342
393
|
graphql_name(union_type_definition.name)
|
343
394
|
description(union_type_definition.description)
|
344
395
|
possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) })
|
@@ -347,27 +398,28 @@ module GraphQL
|
|
347
398
|
end
|
348
399
|
end
|
349
400
|
|
350
|
-
def build_object_type(object_type_definition, type_resolver)
|
401
|
+
def build_object_type(object_type_definition, type_resolver, base_type)
|
351
402
|
builder = self
|
352
403
|
|
353
|
-
Class.new(
|
404
|
+
Class.new(base_type) do
|
354
405
|
graphql_name(object_type_definition.name)
|
355
406
|
description(object_type_definition.description)
|
356
407
|
ast_node(object_type_definition)
|
357
408
|
builder.build_directives(self, object_type_definition, type_resolver)
|
358
|
-
|
359
|
-
object_type_definition.interfaces.each do |interface_name|
|
360
|
-
interface_defn = type_resolver.call(interface_name)
|
361
|
-
implements(interface_defn)
|
362
|
-
end
|
363
|
-
|
409
|
+
builder.build_interfaces(self, object_type_definition.interfaces, type_resolver)
|
364
410
|
builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
|
365
411
|
end
|
366
412
|
end
|
367
413
|
|
368
|
-
def
|
414
|
+
def build_interfaces(type_class, interface_names, type_resolver)
|
415
|
+
interface_names.each do |interface_name|
|
416
|
+
type_class.implements(type_resolver.call(interface_name))
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
def build_input_object_type(input_object_type_definition, type_resolver, base_type)
|
369
421
|
builder = self
|
370
|
-
Class.new(
|
422
|
+
Class.new(base_type) do
|
371
423
|
graphql_name(input_object_type_definition.name)
|
372
424
|
description(input_object_type_definition.description)
|
373
425
|
ast_node(input_object_type_definition)
|
@@ -427,16 +479,13 @@ module GraphQL
|
|
427
479
|
end
|
428
480
|
end
|
429
481
|
|
430
|
-
def build_interface_type(interface_type_definition, type_resolver)
|
482
|
+
def build_interface_type(interface_type_definition, type_resolver, base_type)
|
431
483
|
builder = self
|
432
484
|
Module.new do
|
433
|
-
include
|
485
|
+
include base_type
|
434
486
|
graphql_name(interface_type_definition.name)
|
435
487
|
description(interface_type_definition.description)
|
436
|
-
interface_type_definition.interfaces
|
437
|
-
interface_defn = type_resolver.call(interface_name)
|
438
|
-
implements(interface_defn)
|
439
|
-
end
|
488
|
+
builder.build_interfaces(self, interface_type_definition.interfaces, type_resolver)
|
440
489
|
ast_node(interface_type_definition)
|
441
490
|
builder.build_directives(self, interface_type_definition, type_resolver)
|
442
491
|
|
@@ -474,7 +523,7 @@ module GraphQL
|
|
474
523
|
|
475
524
|
def define_field_resolve_method(owner, method_name, field_name)
|
476
525
|
owner.define_method(method_name) { |**args|
|
477
|
-
field_instance =
|
526
|
+
field_instance = context.types.field(owner, field_name)
|
478
527
|
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
479
528
|
}
|
480
529
|
end
|
@@ -9,6 +9,7 @@ module GraphQL
|
|
9
9
|
class Directive < GraphQL::Schema::Member
|
10
10
|
extend GraphQL::Schema::Member::HasArguments
|
11
11
|
extend GraphQL::Schema::Member::HasArguments::HasDirectiveArguments
|
12
|
+
extend GraphQL::Schema::Member::HasValidators
|
12
13
|
|
13
14
|
class << self
|
14
15
|
# Directives aren't types, they don't have kinds.
|
@@ -75,6 +76,10 @@ module GraphQL
|
|
75
76
|
yield
|
76
77
|
end
|
77
78
|
|
79
|
+
def validate!(arguments, context)
|
80
|
+
Schema::Validator.validate!(validators, self, context, arguments)
|
81
|
+
end
|
82
|
+
|
78
83
|
def on_field?
|
79
84
|
locations.include?(FIELD)
|
80
85
|
end
|
@@ -111,6 +116,9 @@ module GraphQL
|
|
111
116
|
# @return [GraphQL::Interpreter::Arguments]
|
112
117
|
attr_reader :arguments
|
113
118
|
|
119
|
+
class InvalidArgumentError < GraphQL::Error
|
120
|
+
end
|
121
|
+
|
114
122
|
def initialize(owner, **arguments)
|
115
123
|
@owner = owner
|
116
124
|
assert_valid_owner
|
@@ -119,7 +127,31 @@ module GraphQL
|
|
119
127
|
# - lazy resolution
|
120
128
|
# Probably, those won't be needed here, since these are configuration arguments,
|
121
129
|
# not runtime arguments.
|
122
|
-
|
130
|
+
context = Query::NullContext.instance
|
131
|
+
self.class.all_argument_definitions.each do |arg_defn|
|
132
|
+
if arguments.key?(arg_defn.keyword)
|
133
|
+
value = arguments[arg_defn.keyword]
|
134
|
+
# This is a Ruby-land value; convert it to graphql for validation
|
135
|
+
graphql_value = begin
|
136
|
+
arg_defn.type.unwrap.coerce_isolated_result(value)
|
137
|
+
rescue GraphQL::Schema::Enum::UnresolvedValueError
|
138
|
+
# Let validation handle this
|
139
|
+
value
|
140
|
+
end
|
141
|
+
else
|
142
|
+
value = graphql_value = nil
|
143
|
+
end
|
144
|
+
|
145
|
+
result = arg_defn.type.validate_input(graphql_value, context)
|
146
|
+
if !result.valid?
|
147
|
+
raise InvalidArgumentError, "@#{graphql_name}.#{arg_defn.graphql_name} on #{owner.path} is invalid (#{value.inspect}): #{result.problems.first["explanation"]}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
self.class.validate!(arguments, context)
|
151
|
+
@arguments = self.class.coerce_arguments(nil, arguments, context)
|
152
|
+
if @arguments.is_a?(GraphQL::ExecutionError)
|
153
|
+
raise @arguments
|
154
|
+
end
|
123
155
|
end
|
124
156
|
|
125
157
|
def graphql_name
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -41,10 +41,24 @@ module GraphQL
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
# @return [String, nil]
|
45
|
+
def deprecation_reason
|
46
|
+
super || @resolver_class&.deprecation_reason
|
47
|
+
end
|
48
|
+
|
44
49
|
def directives
|
45
50
|
if @resolver_class && !(r_dirs = @resolver_class.directives).empty?
|
46
51
|
if !(own_dirs = super).empty?
|
47
|
-
|
52
|
+
new_dirs = own_dirs.dup
|
53
|
+
r_dirs.each do |r_dir|
|
54
|
+
if r_dir.class.repeatable? ||
|
55
|
+
( (r_dir_name = r_dir.graphql_name) &&
|
56
|
+
(!new_dirs.any? { |d| d.graphql_name == r_dir_name })
|
57
|
+
)
|
58
|
+
new_dirs << r_dir
|
59
|
+
end
|
60
|
+
end
|
61
|
+
new_dirs
|
48
62
|
else
|
49
63
|
r_dirs
|
50
64
|
end
|
@@ -602,6 +616,14 @@ module GraphQL
|
|
602
616
|
end
|
603
617
|
end
|
604
618
|
|
619
|
+
def freeze
|
620
|
+
type
|
621
|
+
owner_type
|
622
|
+
arguments_statically_coercible?
|
623
|
+
connection?
|
624
|
+
super
|
625
|
+
end
|
626
|
+
|
605
627
|
class MissingReturnTypeError < GraphQL::Error; end
|
606
628
|
attr_writer :type
|
607
629
|
|
@@ -38,7 +38,7 @@ module GraphQL
|
|
38
38
|
# Weirdly, procs are applied during coercion, but not methods.
|
39
39
|
# Probably because these methods require a `self`.
|
40
40
|
if arg_defn.prepare.is_a?(Symbol) || context.nil?
|
41
|
-
prepared_value = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
|
41
|
+
prepared_value = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key], context: context)
|
42
42
|
overwrite_argument(ruby_kwargs_key, prepared_value)
|
43
43
|
end
|
44
44
|
end
|
@@ -64,14 +64,7 @@ module GraphQL
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def prepare
|
67
|
-
|
68
|
-
object = @context[:current_object]
|
69
|
-
# Pass this object's class with `as` so that messages are rendered correctly from inherited validators
|
70
|
-
Schema::Validator.validate!(self.class.validators, object, @context, @ruby_style_hash, as: self.class)
|
71
|
-
self
|
72
|
-
else
|
73
|
-
self
|
74
|
-
end
|
67
|
+
self
|
75
68
|
end
|
76
69
|
|
77
70
|
def unwrap_value(value)
|
@@ -111,6 +104,14 @@ module GraphQL
|
|
111
104
|
@ruby_style_hash.dup
|
112
105
|
end
|
113
106
|
|
107
|
+
# @api private
|
108
|
+
def validate_for(context)
|
109
|
+
object = context[:current_object]
|
110
|
+
# Pass this object's class with `as` so that messages are rendered correctly from inherited validators
|
111
|
+
Schema::Validator.validate!(self.class.validators, object, context, @ruby_style_hash, as: self.class)
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
114
115
|
class << self
|
115
116
|
def authorized?(obj, value, ctx)
|
116
117
|
# Authorize each argument (but this doesn't apply if `prepare` is implemented):
|
@@ -175,30 +176,37 @@ module GraphQL
|
|
175
176
|
return GraphQL::Query::InputValidationResult.from_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
176
177
|
end
|
177
178
|
|
178
|
-
# Inject missing required arguments
|
179
|
-
missing_required_inputs = ctx.types.arguments(self).reduce({}) do |m, (argument)|
|
180
|
-
if !input.key?(argument.graphql_name) && argument.type.non_null? && !argument.default_value? && types.argument(self, argument.graphql_name)
|
181
|
-
m[argument.graphql_name] = nil
|
182
|
-
end
|
183
|
-
|
184
|
-
m
|
185
|
-
end
|
186
179
|
|
187
180
|
result = nil
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
181
|
+
|
182
|
+
|
183
|
+
input.each do |argument_name, value|
|
184
|
+
argument = types.argument(self, argument_name)
|
185
|
+
if argument.nil? && ctx.is_a?(Query::NullContext) && argument_name.is_a?(Symbol)
|
186
|
+
# Validating definition directive arguments which come in as Symbols
|
187
|
+
argument = types.arguments(self).find { |arg| arg.keyword == argument_name }
|
188
|
+
end
|
189
|
+
# Items in the input that are unexpected
|
190
|
+
if argument.nil?
|
191
|
+
result ||= Query::InputValidationResult.new
|
192
|
+
result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
|
193
|
+
else
|
194
|
+
# Items in the input that are expected, but have invalid values
|
195
|
+
argument_result = argument.type.validate_input(value, ctx)
|
196
|
+
if !argument_result.valid?
|
198
197
|
result ||= Query::InputValidationResult.new
|
199
|
-
|
200
|
-
|
201
|
-
|
198
|
+
result.merge_result!(argument_name, argument_result)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Check for missing non-null arguments
|
204
|
+
ctx.types.arguments(self).each do |argument|
|
205
|
+
if !input.key?(argument.graphql_name) && argument.type.non_null? && !argument.default_value?
|
206
|
+
result ||= Query::InputValidationResult.new
|
207
|
+
argument_result = argument.type.validate_input(nil, ctx)
|
208
|
+
if !argument_result.valid?
|
209
|
+
result.merge_result!(argument.graphql_name, argument_result)
|
202
210
|
end
|
203
211
|
end
|
204
212
|
end
|
data/lib/graphql/schema/list.rb
CHANGED
@@ -4,7 +4,7 @@ module GraphQL
|
|
4
4
|
class Schema
|
5
5
|
# Represents a list type in the schema.
|
6
6
|
# Wraps a {Schema::Member} as a list type.
|
7
|
-
# @see
|
7
|
+
# @see Schema::Member::TypeSystemHelpers#to_list_type Create a list type from another GraphQL type
|
8
8
|
class List < GraphQL::Schema::Wrapper
|
9
9
|
include Schema::Member::ValidatesInput
|
10
10
|
|
@@ -370,8 +370,8 @@ module GraphQL
|
|
370
370
|
end
|
371
371
|
|
372
372
|
passes_possible_types_check = if context.types.loadable?(arg_loads_type, context)
|
373
|
-
if arg_loads_type.kind.
|
374
|
-
# This union is used in `loads:` but not otherwise visible to this query
|
373
|
+
if arg_loads_type.kind.abstract?
|
374
|
+
# This union/interface is used in `loads:` but not otherwise visible to this query
|
375
375
|
context.types.loadable_possible_types(arg_loads_type, context).include?(application_object_type)
|
376
376
|
else
|
377
377
|
true
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module GraphQL
|
4
4
|
class Schema
|
5
5
|
class Member
|
6
|
+
# @api public
|
7
|
+
# Shared methods for working with {Dataloader} inside GraphQL runtime objects.
|
6
8
|
module HasDataloader
|
7
9
|
# @return [GraphQL::Dataloader] The dataloader for the currently-running query
|
8
10
|
def dataloader
|
@@ -37,7 +39,7 @@ module GraphQL
|
|
37
39
|
source.load(find_by_value)
|
38
40
|
end
|
39
41
|
|
40
|
-
# Look up an associated record using a Rails association
|
42
|
+
# Look up an associated record using a Rails association (via {Dataloader::ActiveRecordAssociationSource})
|
41
43
|
# @param association_name [Symbol] A `belongs_to` or `has_one` association. (If a `has_many` association is named here, it will be selected without pagination.)
|
42
44
|
# @param record [ActiveRecord::Base] The object that the association belongs to.
|
43
45
|
# @param scope [ActiveRecord::Relation] A scope to look up the associated record in
|
@@ -45,7 +47,7 @@ module GraphQL
|
|
45
47
|
# @example Looking up a belongs_to on the current object
|
46
48
|
# dataload_association(:parent) # Equivalent to `object.parent`, but dataloaded
|
47
49
|
# @example Looking up an associated record on some other object
|
48
|
-
# dataload_association(:post
|
50
|
+
# dataload_association(comment, :post) # Equivalent to `comment.post`, but dataloaded
|
49
51
|
def dataload_association(record = object, association_name, scope: nil)
|
50
52
|
source = if scope
|
51
53
|
dataloader.with(Dataloader::ActiveRecordAssociationSource, association_name, scope)
|
@@ -18,6 +18,21 @@ module GraphQL
|
|
18
18
|
directive(GraphQL::Schema::Directive::Deprecated, reason: text)
|
19
19
|
end
|
20
20
|
end
|
21
|
+
|
22
|
+
def self.extended(child_class)
|
23
|
+
super
|
24
|
+
child_class.extend(ClassMethods)
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def deprecation_reason(new_reason = NOT_CONFIGURED)
|
29
|
+
if NOT_CONFIGURED.equal?(new_reason)
|
30
|
+
super()
|
31
|
+
else
|
32
|
+
self.deprecation_reason = new_reason
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
21
36
|
end
|
22
37
|
end
|
23
38
|
end
|
@@ -8,8 +8,8 @@ module GraphQL
|
|
8
8
|
new_memberships = []
|
9
9
|
new_interfaces.each do |int|
|
10
10
|
if int.is_a?(Module)
|
11
|
-
unless int.include?(GraphQL::Schema::Interface)
|
12
|
-
raise "#{int} cannot be implemented since it's not a GraphQL Interface. Use `include` for plain Ruby modules."
|
11
|
+
unless int.include?(GraphQL::Schema::Interface) && !int.is_a?(Class)
|
12
|
+
raise "#{int.respond_to?(:graphql_name) ? "#{int.graphql_name} (#{int})" : int.inspect} cannot be implemented since it's not a GraphQL Interface. Use `include` for plain Ruby modules."
|
13
13
|
end
|
14
14
|
|
15
15
|
new_memberships << int.type_membership_class.new(int, self, **options)
|
@@ -12,12 +12,26 @@ module GraphQL
|
|
12
12
|
|
13
13
|
# @return [Schema::NonNull] Make a non-null-type representation of this type
|
14
14
|
def to_non_null_type
|
15
|
-
@to_non_null_type
|
15
|
+
@to_non_null_type || begin
|
16
|
+
t = GraphQL::Schema::NonNull.new(self)
|
17
|
+
if frozen?
|
18
|
+
t
|
19
|
+
else
|
20
|
+
@to_non_null_type = t
|
21
|
+
end
|
22
|
+
end
|
16
23
|
end
|
17
24
|
|
18
25
|
# @return [Schema::List] Make a list-type representation of this type
|
19
26
|
def to_list_type
|
20
|
-
@to_list_type
|
27
|
+
@to_list_type || begin
|
28
|
+
t = GraphQL::Schema::List.new(self)
|
29
|
+
if frozen?
|
30
|
+
t
|
31
|
+
else
|
32
|
+
@to_list_type = t
|
33
|
+
end
|
34
|
+
end
|
21
35
|
end
|
22
36
|
|
23
37
|
# @return [Boolean] true if this is a non-nullable type. A nullable list of non-nullables is considered nullable.
|