graphql 2.0.28 → 2.2.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/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/request.rb +5 -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 +79 -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 +75 -57
- data/lib/graphql/language/parser.rb +707 -1986
- data/lib/graphql/language/printer.rb +303 -146
- data/lib/graphql/language/sanitized_printer.rb +20 -22
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +20 -81
- data/lib/graphql/language.rb +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/base_64_encoder.rb +3 -5
- 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 +39 -35
- 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 +15 -11
- 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 +16 -8
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/warden.rb +96 -94
- data/lib/graphql/schema.rb +252 -78
- data/lib/graphql/static_validation/all_rules.rb +1 -1
- data/lib/graphql/static_validation/base_visitor.rb +1 -1
- data/lib/graphql/static_validation/literal_validator.rb +2 -3
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +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 +2 -2
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +3 -2
- data/lib/graphql/subscriptions/event.rb +8 -2
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +14 -12
- data/lib/graphql/testing/helpers.rb +129 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/appoptics_trace.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +2 -0
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/trace.rb +1 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/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 +6 -5
- data/readme.md +12 -2
- metadata +46 -38
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
data/lib/graphql/schema.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
require "logger"
|
|
2
3
|
require "graphql/schema/addition"
|
|
3
4
|
require "graphql/schema/always_visible"
|
|
4
5
|
require "graphql/schema/base_64_encoder"
|
|
@@ -37,10 +38,12 @@ require "graphql/schema/directive/skip"
|
|
|
37
38
|
require "graphql/schema/directive/feature"
|
|
38
39
|
require "graphql/schema/directive/flagged"
|
|
39
40
|
require "graphql/schema/directive/transform"
|
|
41
|
+
require "graphql/schema/directive/specified_by"
|
|
40
42
|
require "graphql/schema/type_membership"
|
|
41
43
|
|
|
42
44
|
require "graphql/schema/resolver"
|
|
43
45
|
require "graphql/schema/mutation"
|
|
46
|
+
require "graphql/schema/has_single_input_argument"
|
|
44
47
|
require "graphql/schema/relay_classic_mutation"
|
|
45
48
|
require "graphql/schema/subscription"
|
|
46
49
|
|
|
@@ -144,6 +147,19 @@ module GraphQL
|
|
|
144
147
|
@subscriptions = new_implementation
|
|
145
148
|
end
|
|
146
149
|
|
|
150
|
+
# @param new_mode [Symbol] If configured, this will be used when `context: { trace_mode: ... }` isn't set.
|
|
151
|
+
def default_trace_mode(new_mode = nil)
|
|
152
|
+
if new_mode
|
|
153
|
+
@default_trace_mode = new_mode
|
|
154
|
+
elsif defined?(@default_trace_mode)
|
|
155
|
+
@default_trace_mode
|
|
156
|
+
elsif superclass.respond_to?(:default_trace_mode)
|
|
157
|
+
superclass.default_trace_mode
|
|
158
|
+
else
|
|
159
|
+
:default
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
147
163
|
def trace_class(new_class = nil)
|
|
148
164
|
if new_class
|
|
149
165
|
trace_mode(:default, new_class)
|
|
@@ -151,46 +167,81 @@ module GraphQL
|
|
|
151
167
|
backtrace_class.include(GraphQL::Backtrace::Trace)
|
|
152
168
|
trace_mode(:default_backtrace, backtrace_class)
|
|
153
169
|
end
|
|
154
|
-
trace_class_for(:default)
|
|
170
|
+
trace_class_for(:default, build: true)
|
|
155
171
|
end
|
|
156
172
|
|
|
157
173
|
# @return [Class] Return the trace class to use for this mode, looking one up on the superclass if this Schema doesn't have one defined.
|
|
158
|
-
def trace_class_for(mode)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
end
|
|
168
|
-
Class.new(superclass_base_class)
|
|
169
|
-
when :default_backtrace
|
|
170
|
-
schema_base_class = trace_class_for(:default)
|
|
171
|
-
Class.new(schema_base_class) do
|
|
172
|
-
include(GraphQL::Backtrace::Trace)
|
|
173
|
-
end
|
|
174
|
-
else
|
|
175
|
-
mods = trace_modules_for(mode)
|
|
176
|
-
Class.new(trace_class_for(:default)) do
|
|
177
|
-
mods.any? && include(*mods)
|
|
178
|
-
end
|
|
179
|
-
end
|
|
174
|
+
def trace_class_for(mode, build: false)
|
|
175
|
+
if (trace_class = own_trace_modes[mode])
|
|
176
|
+
trace_class
|
|
177
|
+
elsif superclass.respond_to?(:trace_class_for) && (trace_class = superclass.trace_class_for(mode, build: false))
|
|
178
|
+
trace_class
|
|
179
|
+
elsif build
|
|
180
|
+
own_trace_modes[mode] = build_trace_mode(mode)
|
|
181
|
+
else
|
|
182
|
+
nil
|
|
180
183
|
end
|
|
181
184
|
end
|
|
182
185
|
|
|
183
186
|
# Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
|
|
184
|
-
#
|
|
187
|
+
# {default_trace_mode} is used when no `trace_mode: ...` is requested.
|
|
188
|
+
#
|
|
189
|
+
# When a `trace_class` is added this way, it will _not_ receive other modules added with `trace_with(...)`
|
|
190
|
+
# unless `trace_mode` is explicitly given. (This class will not recieve any default trace modules.)
|
|
191
|
+
#
|
|
192
|
+
# Subclasses of the schema will use `trace_class` as a base class for this mode and those
|
|
193
|
+
# subclass also will _not_ receive default tracing modules.
|
|
194
|
+
#
|
|
185
195
|
# @param mode_name [Symbol]
|
|
186
196
|
# @param trace_class [Class] subclass of GraphQL::Tracing::Trace
|
|
187
197
|
# @return void
|
|
188
198
|
def trace_mode(mode_name, trace_class)
|
|
189
|
-
|
|
190
|
-
@trace_modes[mode_name] = trace_class
|
|
199
|
+
own_trace_modes[mode_name] = trace_class
|
|
191
200
|
nil
|
|
192
201
|
end
|
|
193
202
|
|
|
203
|
+
def own_trace_modes
|
|
204
|
+
@own_trace_modes ||= {}
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
module DefaultTraceClass
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
private_constant :DefaultTraceClass
|
|
211
|
+
|
|
212
|
+
def build_trace_mode(mode)
|
|
213
|
+
case mode
|
|
214
|
+
when :default
|
|
215
|
+
# Use the superclass's default mode if it has one, or else start an inheritance chain at the built-in base class.
|
|
216
|
+
base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || GraphQL::Tracing::Trace
|
|
217
|
+
Class.new(base_class) do
|
|
218
|
+
include DefaultTraceClass
|
|
219
|
+
end
|
|
220
|
+
when :default_backtrace
|
|
221
|
+
schema_base_class = trace_class_for(:default, build: true)
|
|
222
|
+
Class.new(schema_base_class) do
|
|
223
|
+
include(GraphQL::Backtrace::Trace)
|
|
224
|
+
end
|
|
225
|
+
else
|
|
226
|
+
# First, see if the superclass has a custom-defined class for this.
|
|
227
|
+
# Then, if it doesn't, use this class's default trace
|
|
228
|
+
base_class = (superclass.respond_to?(:trace_class_for) && superclass.trace_class_for(mode)) || trace_class_for(:default, build: true)
|
|
229
|
+
# Prepare the default trace class if it hasn't been initialized yet
|
|
230
|
+
base_class ||= (own_trace_modes[:default] = build_trace_mode(:default))
|
|
231
|
+
mods = trace_modules_for(mode)
|
|
232
|
+
if base_class < DefaultTraceClass
|
|
233
|
+
mods = trace_modules_for(:default) + mods
|
|
234
|
+
end
|
|
235
|
+
# Copy the existing default options into this mode's options
|
|
236
|
+
default_options = trace_options_for(:default)
|
|
237
|
+
add_trace_options_for(mode, default_options)
|
|
238
|
+
|
|
239
|
+
Class.new(base_class) do
|
|
240
|
+
mods.any? && include(*mods)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
194
245
|
def own_trace_modules
|
|
195
246
|
@own_trace_modules ||= Hash.new { |h, k| h[k] = [] }
|
|
196
247
|
end
|
|
@@ -222,7 +273,7 @@ module GraphQL
|
|
|
222
273
|
# @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
|
|
223
274
|
# @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
|
|
224
275
|
# @return [Hash] GraphQL result
|
|
225
|
-
def as_json(
|
|
276
|
+
def as_json(context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
|
|
226
277
|
introspection_query = Introspection.query(
|
|
227
278
|
include_deprecated_args: include_deprecated_args,
|
|
228
279
|
include_schema_description: include_schema_description,
|
|
@@ -231,16 +282,14 @@ module GraphQL
|
|
|
231
282
|
include_specified_by_url: include_specified_by_url,
|
|
232
283
|
)
|
|
233
284
|
|
|
234
|
-
execute(introspection_query,
|
|
285
|
+
execute(introspection_query, context: context).to_h
|
|
235
286
|
end
|
|
236
287
|
|
|
237
288
|
# Return the GraphQL IDL for the schema
|
|
238
289
|
# @param context [Hash]
|
|
239
|
-
# @param only [<#call(member, ctx)>]
|
|
240
|
-
# @param except [<#call(member, ctx)>]
|
|
241
290
|
# @return [String]
|
|
242
|
-
def to_definition(
|
|
243
|
-
GraphQL::Schema::Printer.print_schema(self,
|
|
291
|
+
def to_definition(context: {})
|
|
292
|
+
GraphQL::Schema::Printer.print_schema(self, context: context)
|
|
244
293
|
end
|
|
245
294
|
|
|
246
295
|
# Return the GraphQL::Language::Document IDL AST for the schema
|
|
@@ -268,20 +317,6 @@ module GraphQL
|
|
|
268
317
|
@find_cache[path] ||= @finder.find(path)
|
|
269
318
|
end
|
|
270
319
|
|
|
271
|
-
def default_filter
|
|
272
|
-
GraphQL::Filter.new(except: default_mask)
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def default_mask(new_mask = nil)
|
|
276
|
-
if new_mask
|
|
277
|
-
line = caller(2, 10).find { |l| !l.include?("lib/graphql") }
|
|
278
|
-
GraphQL::Deprecation.warn("GraphQL::Filter and Schema.mask are deprecated and will be removed in v2.1.0. Implement `visible?` on your schema members instead (https://graphql-ruby.org/authorization/visibility.html).\n #{line}")
|
|
279
|
-
@own_default_mask = new_mask
|
|
280
|
-
else
|
|
281
|
-
@own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
320
|
def static_validator
|
|
286
321
|
GraphQL::StaticValidation::Validator.new(schema: self)
|
|
287
322
|
end
|
|
@@ -302,7 +337,7 @@ module GraphQL
|
|
|
302
337
|
# Build a map of `{ name => type }` and return it
|
|
303
338
|
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
|
304
339
|
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
|
305
|
-
def types(context = GraphQL::Query::NullContext)
|
|
340
|
+
def types(context = GraphQL::Query::NullContext.instance)
|
|
306
341
|
all_types = non_introspection_types.merge(introspection_system.types)
|
|
307
342
|
visible_types = {}
|
|
308
343
|
all_types.each do |k, v|
|
|
@@ -329,7 +364,7 @@ module GraphQL
|
|
|
329
364
|
|
|
330
365
|
# @param type_name [String]
|
|
331
366
|
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
|
332
|
-
def get_type(type_name, context = GraphQL::Query::NullContext)
|
|
367
|
+
def get_type(type_name, context = GraphQL::Query::NullContext.instance)
|
|
333
368
|
local_entry = own_types[type_name]
|
|
334
369
|
type_defn = case local_entry
|
|
335
370
|
when nil
|
|
@@ -360,6 +395,11 @@ module GraphQL
|
|
|
360
395
|
(superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
|
|
361
396
|
end
|
|
362
397
|
|
|
398
|
+
# @return [Boolean] Does this schema have _any_ definition for a type named `type_name`, regardless of visibility?
|
|
399
|
+
def has_defined_type?(type_name)
|
|
400
|
+
own_types.key?(type_name) || introspection_system.types.key?(type_name) || (superclass.respond_to?(:has_defined_type?) ? superclass.has_defined_type?(type_name) : false)
|
|
401
|
+
end
|
|
402
|
+
|
|
363
403
|
# @api private
|
|
364
404
|
attr_writer :connections
|
|
365
405
|
|
|
@@ -460,7 +500,7 @@ module GraphQL
|
|
|
460
500
|
# @param type [Module] The type definition whose possible types you want to see
|
|
461
501
|
# @return [Hash<String, Module>] All possible types, if no `type` is given.
|
|
462
502
|
# @return [Array<Module>] Possible types for `type`, if it's given.
|
|
463
|
-
def possible_types(type = nil, context = GraphQL::Query::NullContext)
|
|
503
|
+
def possible_types(type = nil, context = GraphQL::Query::NullContext.instance)
|
|
464
504
|
if type
|
|
465
505
|
# TODO duck-typing `.possible_types` would probably be nicer here
|
|
466
506
|
if type.kind.union?
|
|
@@ -513,18 +553,17 @@ module GraphQL
|
|
|
513
553
|
attr_writer :dataloader_class
|
|
514
554
|
|
|
515
555
|
def references_to(to_type = nil, from: nil)
|
|
516
|
-
@own_references_to ||=
|
|
556
|
+
@own_references_to ||= {}
|
|
517
557
|
if to_type
|
|
518
558
|
if !to_type.is_a?(String)
|
|
519
559
|
to_type = to_type.graphql_name
|
|
520
560
|
end
|
|
521
561
|
|
|
522
562
|
if from
|
|
523
|
-
@own_references_to[to_type]
|
|
563
|
+
refs = @own_references_to[to_type] ||= []
|
|
564
|
+
refs << from
|
|
524
565
|
else
|
|
525
|
-
|
|
526
|
-
inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
|
|
527
|
-
own_refs + inherited_refs
|
|
566
|
+
get_references_to(to_type) || EMPTY_ARRAY
|
|
528
567
|
end
|
|
529
568
|
else
|
|
530
569
|
# `@own_references_to` can be quite large for big schemas,
|
|
@@ -544,7 +583,7 @@ module GraphQL
|
|
|
544
583
|
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
|
545
584
|
end
|
|
546
585
|
|
|
547
|
-
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
|
|
586
|
+
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
|
|
548
587
|
parent_type = case type_or_name
|
|
549
588
|
when LateBoundType
|
|
550
589
|
get_type(type_or_name.name, context)
|
|
@@ -567,7 +606,7 @@ module GraphQL
|
|
|
567
606
|
end
|
|
568
607
|
end
|
|
569
608
|
|
|
570
|
-
def get_fields(type, context = GraphQL::Query::NullContext)
|
|
609
|
+
def get_fields(type, context = GraphQL::Query::NullContext.instance)
|
|
571
610
|
type.fields(context)
|
|
572
611
|
end
|
|
573
612
|
|
|
@@ -657,7 +696,7 @@ module GraphQL
|
|
|
657
696
|
else
|
|
658
697
|
string_or_document
|
|
659
698
|
end
|
|
660
|
-
query =
|
|
699
|
+
query = query_class.new(self, document: doc, context: context)
|
|
661
700
|
validator_opts = { schema: self }
|
|
662
701
|
rules && (validator_opts[:rules] = rules)
|
|
663
702
|
validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
|
|
@@ -665,6 +704,14 @@ module GraphQL
|
|
|
665
704
|
res[:errors]
|
|
666
705
|
end
|
|
667
706
|
|
|
707
|
+
def query_class(new_query_class = NOT_CONFIGURED)
|
|
708
|
+
if NOT_CONFIGURED.equal?(new_query_class)
|
|
709
|
+
@query_class || (superclass.respond_to?(:query_class) ? superclass.query_class : GraphQL::Query)
|
|
710
|
+
else
|
|
711
|
+
@query_class = new_query_class
|
|
712
|
+
end
|
|
713
|
+
end
|
|
714
|
+
|
|
668
715
|
attr_writer :validate_max_errors
|
|
669
716
|
|
|
670
717
|
def validate_max_errors(new_validate_max_errors = nil)
|
|
@@ -707,6 +754,7 @@ module GraphQL
|
|
|
707
754
|
|
|
708
755
|
def error_bubbling(new_error_bubbling = nil)
|
|
709
756
|
if !new_error_bubbling.nil?
|
|
757
|
+
warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
|
|
710
758
|
@error_bubbling = new_error_bubbling
|
|
711
759
|
else
|
|
712
760
|
@error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
|
|
@@ -717,9 +765,10 @@ module GraphQL
|
|
|
717
765
|
|
|
718
766
|
attr_writer :max_depth
|
|
719
767
|
|
|
720
|
-
def max_depth(new_max_depth = nil)
|
|
768
|
+
def max_depth(new_max_depth = nil, count_introspection_fields: true)
|
|
721
769
|
if new_max_depth
|
|
722
770
|
@max_depth = new_max_depth
|
|
771
|
+
@count_introspection_fields = count_introspection_fields
|
|
723
772
|
elsif defined?(@max_depth)
|
|
724
773
|
@max_depth
|
|
725
774
|
else
|
|
@@ -727,6 +776,14 @@ module GraphQL
|
|
|
727
776
|
end
|
|
728
777
|
end
|
|
729
778
|
|
|
779
|
+
def count_introspection_fields
|
|
780
|
+
if defined?(@count_introspection_fields)
|
|
781
|
+
@count_introspection_fields
|
|
782
|
+
else
|
|
783
|
+
find_inherited_value(:count_introspection_fields, true)
|
|
784
|
+
end
|
|
785
|
+
end
|
|
786
|
+
|
|
730
787
|
def disable_introspection_entry_points
|
|
731
788
|
@disable_introspection_entry_points = true
|
|
732
789
|
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
|
@@ -769,6 +826,26 @@ module GraphQL
|
|
|
769
826
|
end
|
|
770
827
|
end
|
|
771
828
|
|
|
829
|
+
# @param new_extra_types [Module] Type definitions to include in printing and introspection, even though they aren't referenced in the schema
|
|
830
|
+
# @return [Array<Module>] Type definitions added to this schema
|
|
831
|
+
def extra_types(*new_extra_types)
|
|
832
|
+
if new_extra_types.any?
|
|
833
|
+
new_extra_types = new_extra_types.flatten
|
|
834
|
+
@own_extra_types ||= []
|
|
835
|
+
@own_extra_types.concat(new_extra_types)
|
|
836
|
+
end
|
|
837
|
+
inherited_et = find_inherited_value(:extra_types, nil)
|
|
838
|
+
if inherited_et
|
|
839
|
+
if @own_extra_types
|
|
840
|
+
inherited_et + @own_extra_types
|
|
841
|
+
else
|
|
842
|
+
inherited_et
|
|
843
|
+
end
|
|
844
|
+
else
|
|
845
|
+
@own_extra_types || EMPTY_ARRAY
|
|
846
|
+
end
|
|
847
|
+
end
|
|
848
|
+
|
|
772
849
|
def orphan_types(*new_orphan_types)
|
|
773
850
|
if new_orphan_types.any?
|
|
774
851
|
new_orphan_types = new_orphan_types.flatten
|
|
@@ -776,7 +853,16 @@ module GraphQL
|
|
|
776
853
|
own_orphan_types.concat(new_orphan_types.flatten)
|
|
777
854
|
end
|
|
778
855
|
|
|
779
|
-
find_inherited_value(:orphan_types,
|
|
856
|
+
inherited_ot = find_inherited_value(:orphan_types, nil)
|
|
857
|
+
if inherited_ot
|
|
858
|
+
if own_orphan_types.any?
|
|
859
|
+
inherited_ot + own_orphan_types
|
|
860
|
+
else
|
|
861
|
+
inherited_ot
|
|
862
|
+
end
|
|
863
|
+
else
|
|
864
|
+
own_orphan_types
|
|
865
|
+
end
|
|
780
866
|
end
|
|
781
867
|
|
|
782
868
|
def default_execution_strategy
|
|
@@ -795,6 +881,26 @@ module GraphQL
|
|
|
795
881
|
end
|
|
796
882
|
end
|
|
797
883
|
|
|
884
|
+
def default_logger(new_default_logger = NOT_CONFIGURED)
|
|
885
|
+
if NOT_CONFIGURED.equal?(new_default_logger)
|
|
886
|
+
if defined?(@default_logger)
|
|
887
|
+
@default_logger
|
|
888
|
+
elsif superclass.respond_to?(:default_logger)
|
|
889
|
+
superclass.default_logger
|
|
890
|
+
elsif defined?(Rails) && Rails.respond_to?(:logger) && (rails_logger = Rails.logger)
|
|
891
|
+
rails_logger
|
|
892
|
+
else
|
|
893
|
+
def_logger = Logger.new($stdout)
|
|
894
|
+
def_logger.info! # It doesn't output debug info by default
|
|
895
|
+
def_logger
|
|
896
|
+
end
|
|
897
|
+
elsif new_default_logger == nil
|
|
898
|
+
@default_logger = Logger.new(IO::NULL)
|
|
899
|
+
else
|
|
900
|
+
@default_logger = new_default_logger
|
|
901
|
+
end
|
|
902
|
+
end
|
|
903
|
+
|
|
798
904
|
def context_class(new_context_class = nil)
|
|
799
905
|
if new_context_class
|
|
800
906
|
@context_class = new_context_class
|
|
@@ -870,17 +976,19 @@ module GraphQL
|
|
|
870
976
|
end
|
|
871
977
|
|
|
872
978
|
def resolve_type(type, obj, ctx)
|
|
873
|
-
|
|
874
|
-
type
|
|
875
|
-
else
|
|
876
|
-
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types or Interface types (tried to resolve: #{type.name})"
|
|
877
|
-
end
|
|
979
|
+
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types, Interface types, or `loads:` (tried to resolve: #{type.name})"
|
|
878
980
|
end
|
|
879
981
|
# rubocop:enable Lint/DuplicateMethods
|
|
880
982
|
|
|
881
983
|
def inherited(child_class)
|
|
882
984
|
if self == GraphQL::Schema
|
|
883
985
|
child_class.directives(default_directives.values)
|
|
986
|
+
child_class.extend(SubclassGetReferencesTo)
|
|
987
|
+
end
|
|
988
|
+
# Make sure the child class has these built out, so that
|
|
989
|
+
# subclasses can be modified by later calls to `trace_with`
|
|
990
|
+
own_trace_modes.each do |name, _class|
|
|
991
|
+
child_class.own_trace_modes[name] = child_class.build_trace_mode(name)
|
|
884
992
|
end
|
|
885
993
|
child_class.singleton_class.prepend(ResolveTypeWithType)
|
|
886
994
|
super
|
|
@@ -968,6 +1076,12 @@ module GraphQL
|
|
|
968
1076
|
end
|
|
969
1077
|
|
|
970
1078
|
def instrument(instrument_step, instrumenter, options = {})
|
|
1079
|
+
warn <<~WARN
|
|
1080
|
+
Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
|
|
1081
|
+
(From `#{self}.instrument(#{instrument_step}, #{instrumenter})` at #{caller(1, 1).first})
|
|
1082
|
+
|
|
1083
|
+
WARN
|
|
1084
|
+
trace_with(Tracing::LegacyHooksTrace)
|
|
971
1085
|
own_instrumenters[instrument_step] << instrumenter
|
|
972
1086
|
end
|
|
973
1087
|
|
|
@@ -978,7 +1092,12 @@ module GraphQL
|
|
|
978
1092
|
new_directives.flatten.each { |d| directive(d) }
|
|
979
1093
|
end
|
|
980
1094
|
|
|
981
|
-
find_inherited_value(:directives, default_directives)
|
|
1095
|
+
inherited_dirs = find_inherited_value(:directives, default_directives)
|
|
1096
|
+
if own_directives.any?
|
|
1097
|
+
inherited_dirs.merge(own_directives)
|
|
1098
|
+
else
|
|
1099
|
+
inherited_dirs
|
|
1100
|
+
end
|
|
982
1101
|
end
|
|
983
1102
|
|
|
984
1103
|
# Attach a single directive to this schema
|
|
@@ -994,11 +1113,13 @@ module GraphQL
|
|
|
994
1113
|
"skip" => GraphQL::Schema::Directive::Skip,
|
|
995
1114
|
"deprecated" => GraphQL::Schema::Directive::Deprecated,
|
|
996
1115
|
"oneOf" => GraphQL::Schema::Directive::OneOf,
|
|
1116
|
+
"specifiedBy" => GraphQL::Schema::Directive::SpecifiedBy,
|
|
997
1117
|
}.freeze
|
|
998
1118
|
end
|
|
999
1119
|
|
|
1000
1120
|
def tracer(new_tracer)
|
|
1001
|
-
|
|
1121
|
+
default_trace = trace_class_for(:default, build: true)
|
|
1122
|
+
if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
|
|
1002
1123
|
trace_with(GraphQL::Tracing::CallLegacyTracers)
|
|
1003
1124
|
end
|
|
1004
1125
|
|
|
@@ -1020,13 +1141,26 @@ module GraphQL
|
|
|
1020
1141
|
if mode.is_a?(Array)
|
|
1021
1142
|
mode.each { |m| trace_with(trace_mod, mode: m, **options) }
|
|
1022
1143
|
else
|
|
1023
|
-
tc =
|
|
1144
|
+
tc = own_trace_modes[mode] ||= build_trace_mode(mode)
|
|
1024
1145
|
tc.include(trace_mod)
|
|
1025
|
-
|
|
1026
|
-
|
|
1146
|
+
own_trace_modules[mode] << trace_mod
|
|
1147
|
+
add_trace_options_for(mode, options)
|
|
1148
|
+
if mode == :default
|
|
1149
|
+
# This module is being added as a default tracer. If any other mode classes
|
|
1150
|
+
# have already been created, but get their default behavior from a superclass,
|
|
1151
|
+
# Then mix this into this schema's subclass.
|
|
1152
|
+
# (But don't mix it into mode classes that aren't default-based.)
|
|
1153
|
+
own_trace_modes.each do |other_mode_name, other_mode_class|
|
|
1154
|
+
if other_mode_class < DefaultTraceClass
|
|
1155
|
+
# Don't add it back to the inheritance tree if it's already there
|
|
1156
|
+
if !(other_mode_class < trace_mod)
|
|
1157
|
+
other_mode_class.include(trace_mod)
|
|
1158
|
+
end
|
|
1159
|
+
# Add any options so they'll be available
|
|
1160
|
+
add_trace_options_for(other_mode_name, options)
|
|
1161
|
+
end
|
|
1162
|
+
end
|
|
1027
1163
|
end
|
|
1028
|
-
t_opts = trace_options_for(mode)
|
|
1029
|
-
t_opts.merge!(options)
|
|
1030
1164
|
end
|
|
1031
1165
|
nil
|
|
1032
1166
|
end
|
|
@@ -1036,16 +1170,22 @@ module GraphQL
|
|
|
1036
1170
|
def trace_options_for(mode)
|
|
1037
1171
|
@trace_options_for_mode ||= {}
|
|
1038
1172
|
@trace_options_for_mode[mode] ||= begin
|
|
1173
|
+
# It may be time to create an options hash for a mode that wasn't registered yet.
|
|
1174
|
+
# Mix in the default options in that case.
|
|
1175
|
+
default_options = mode == :default ? EMPTY_HASH : trace_options_for(:default)
|
|
1176
|
+
# Make sure this returns a new object so that other hashes aren't modified later
|
|
1039
1177
|
if superclass.respond_to?(:trace_options_for)
|
|
1040
|
-
superclass.trace_options_for(mode).
|
|
1178
|
+
superclass.trace_options_for(mode).merge(default_options)
|
|
1041
1179
|
else
|
|
1042
|
-
|
|
1180
|
+
default_options.dup
|
|
1043
1181
|
end
|
|
1044
1182
|
end
|
|
1045
1183
|
end
|
|
1046
1184
|
|
|
1047
1185
|
# Create a trace instance which will include the trace modules specified for the optional mode.
|
|
1048
1186
|
#
|
|
1187
|
+
# If no `mode:` is given, then {default_trace_mode} will be used.
|
|
1188
|
+
#
|
|
1049
1189
|
# @param mode [Symbol] Trace modules for this trade mode will be included
|
|
1050
1190
|
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
|
1051
1191
|
# @return [Tracing::Trace]
|
|
@@ -1056,14 +1196,21 @@ module GraphQL
|
|
|
1056
1196
|
trace_mode = if mode
|
|
1057
1197
|
mode
|
|
1058
1198
|
elsif target && target.context[:backtrace]
|
|
1059
|
-
:
|
|
1199
|
+
if default_trace_mode != :default
|
|
1200
|
+
raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
|
|
1201
|
+
else
|
|
1202
|
+
own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
|
|
1203
|
+
options_trace_mode = :default
|
|
1204
|
+
:default_backtrace
|
|
1205
|
+
end
|
|
1060
1206
|
else
|
|
1061
|
-
|
|
1207
|
+
default_trace_mode
|
|
1062
1208
|
end
|
|
1063
1209
|
|
|
1064
|
-
|
|
1210
|
+
options_trace_mode ||= trace_mode
|
|
1211
|
+
base_trace_options = trace_options_for(options_trace_mode)
|
|
1065
1212
|
trace_options = base_trace_options.merge(options)
|
|
1066
|
-
trace_class_for_mode = trace_class_for(trace_mode)
|
|
1213
|
+
trace_class_for_mode = trace_class_for(trace_mode, build: true)
|
|
1067
1214
|
trace_class_for_mode.new(**trace_options)
|
|
1068
1215
|
end
|
|
1069
1216
|
|
|
@@ -1217,6 +1364,12 @@ module GraphQL
|
|
|
1217
1364
|
|
|
1218
1365
|
private
|
|
1219
1366
|
|
|
1367
|
+
def add_trace_options_for(mode, new_options)
|
|
1368
|
+
t_opts = trace_options_for(mode)
|
|
1369
|
+
t_opts.merge!(new_options)
|
|
1370
|
+
nil
|
|
1371
|
+
end
|
|
1372
|
+
|
|
1220
1373
|
# @param t [Module, Array<Module>]
|
|
1221
1374
|
# @return [void]
|
|
1222
1375
|
def add_type_and_traverse(t, root:)
|
|
@@ -1278,7 +1431,7 @@ module GraphQL
|
|
|
1278
1431
|
else
|
|
1279
1432
|
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
|
1280
1433
|
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
|
1281
|
-
@lazy_methods.set(GraphQL::Dataloader::Request, :
|
|
1434
|
+
@lazy_methods.set(GraphQL::Dataloader::Request, :load_with_deprecation_warning)
|
|
1282
1435
|
end
|
|
1283
1436
|
end
|
|
1284
1437
|
@lazy_methods
|
|
@@ -1327,6 +1480,27 @@ module GraphQL
|
|
|
1327
1480
|
def own_multiplex_analyzers
|
|
1328
1481
|
@own_multiplex_analyzers ||= []
|
|
1329
1482
|
end
|
|
1483
|
+
|
|
1484
|
+
# This is overridden in subclasses to check the inheritance chain
|
|
1485
|
+
def get_references_to(type_name)
|
|
1486
|
+
@own_references_to[type_name]
|
|
1487
|
+
end
|
|
1488
|
+
end
|
|
1489
|
+
|
|
1490
|
+
module SubclassGetReferencesTo
|
|
1491
|
+
def get_references_to(type_name)
|
|
1492
|
+
own_refs = @own_references_to[type_name]
|
|
1493
|
+
inherited_refs = superclass.references_to(type_name)
|
|
1494
|
+
if inherited_refs&.any?
|
|
1495
|
+
if own_refs&.any?
|
|
1496
|
+
own_refs + inherited_refs
|
|
1497
|
+
else
|
|
1498
|
+
inherited_refs
|
|
1499
|
+
end
|
|
1500
|
+
else
|
|
1501
|
+
own_refs
|
|
1502
|
+
end
|
|
1503
|
+
end
|
|
1330
1504
|
end
|
|
1331
1505
|
|
|
1332
1506
|
# Install these here so that subclasses will also install it.
|
|
@@ -3,7 +3,7 @@ module GraphQL
|
|
|
3
3
|
module StaticValidation
|
|
4
4
|
# Default rules for {GraphQL::StaticValidation::Validator}
|
|
5
5
|
#
|
|
6
|
-
# Order is important here. Some validators
|
|
6
|
+
# Order is important here. Some validators skip later hooks.
|
|
7
7
|
# which stops the visit on that node. That way it doesn't try to find fields on types that
|
|
8
8
|
# don't exist, etc.
|
|
9
9
|
ALL_RULES = [
|
|
@@ -110,8 +110,8 @@ module GraphQL
|
|
|
110
110
|
# TODO - would be nice to use these to create an error message so the caller knows
|
|
111
111
|
# that required fields are missing
|
|
112
112
|
required_field_names = @warden.arguments(type)
|
|
113
|
-
.select { |argument| argument.type.kind.non_null? &&
|
|
114
|
-
.map(&:name)
|
|
113
|
+
.select { |argument| argument.type.kind.non_null? && !argument.default_value? }
|
|
114
|
+
.map!(&:name)
|
|
115
115
|
|
|
116
116
|
present_field_names = ast_node.arguments.map(&:name)
|
|
117
117
|
missing_required_field_names = required_field_names - present_field_names
|
|
@@ -122,7 +122,6 @@ module GraphQL
|
|
|
122
122
|
arg_type = @warden.get_argument(type, name).type
|
|
123
123
|
recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
|
|
124
124
|
end
|
|
125
|
-
|
|
126
125
|
if type.one_of? && ast_node.arguments.size != 1
|
|
127
126
|
results << Query::InputValidationResult.from_problem("`#{type.graphql_name}` is a OneOf type, so only one argument may be given (instead of #{ast_node.arguments.size})")
|
|
128
127
|
end
|
|
@@ -340,7 +340,7 @@ module GraphQL
|
|
|
340
340
|
selections.each do |node|
|
|
341
341
|
case node
|
|
342
342
|
when GraphQL::Language::Nodes::Field
|
|
343
|
-
definition = context.
|
|
343
|
+
definition = context.warden.get_field(owner_type, node.name)
|
|
344
344
|
fields << Field.new(node, definition, owner_type, parents)
|
|
345
345
|
when GraphQL::Language::Nodes::InlineFragment
|
|
346
346
|
fragment_type = node.type ? context.warden.get_type(node.type.name) : owner_type
|
|
@@ -21,7 +21,7 @@ module GraphQL
|
|
|
21
21
|
present_argument_names = ast_node.arguments.map(&:name)
|
|
22
22
|
required_argument_names = context.warden.arguments(defn)
|
|
23
23
|
.select { |a| a.type.kind.non_null? && !a.default_value? && context.warden.get_argument(defn, a.name) }
|
|
24
|
-
.map(&:name)
|
|
24
|
+
.map!(&:name)
|
|
25
25
|
|
|
26
26
|
missing_names = required_argument_names - present_argument_names
|
|
27
27
|
if missing_names.any?
|
|
@@ -35,8 +35,8 @@ module GraphQL
|
|
|
35
35
|
return unless parent_type && parent_type.kind.input_object?
|
|
36
36
|
|
|
37
37
|
required_fields = context.warden.arguments(parent_type)
|
|
38
|
-
.select{|arg| arg.type.kind.non_null?}
|
|
39
|
-
.map(&:graphql_name)
|
|
38
|
+
.select{ |arg| arg.type.kind.non_null? && !arg.default_value? }
|
|
39
|
+
.map!(&:graphql_name)
|
|
40
40
|
|
|
41
41
|
present_fields = ast_node.arguments.map(&:name)
|
|
42
42
|
missing_fields = required_fields - present_fields
|