graphql 2.0.13 → 2.3.10
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/generators/graphql/install/mutation_root_generator.rb +2 -2
- 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/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +18 -1
- 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 +8 -0
- 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/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/backtrace/table.rb +2 -2
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/backtrace.rb +2 -1
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +88 -0
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +89 -45
- data/lib/graphql/dataloader.rb +115 -142
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
- data/lib/graphql/execution/interpreter/runtime.rb +331 -455
- data/lib/graphql/execution/interpreter.rb +125 -61
- data/lib/graphql/execution/lazy.rb +6 -12
- data/lib/graphql/execution/lookahead.rb +124 -46
- data/lib/graphql/execution/multiplex.rb +3 -117
- data/lib/graphql/execution.rb +0 -1
- data/lib/graphql/introspection/directive_type.rb +3 -3
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/field_type.rb +2 -2
- data/lib/graphql/introspection/schema_type.rb +10 -13
- data/lib/graphql/introspection/type_type.rb +17 -10
- data/lib/graphql/introspection.rb +3 -2
- 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 +75 -59
- data/lib/graphql/language/lexer.rb +358 -1506
- data/lib/graphql/language/nodes.rb +166 -93
- data/lib/graphql/language/parser.rb +795 -1953
- data/lib/graphql/language/printer.rb +340 -160
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +61 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +33 -6
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +117 -112
- data/lib/graphql/query/null_context.rb +12 -25
- data/lib/graphql/query/validation_pipeline.rb +6 -5
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +86 -30
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +29 -11
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/schema/addition.rb +59 -23
- data/lib/graphql/schema/always_visible.rb +11 -0
- data/lib/graphql/schema/argument.rb +55 -26
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +56 -32
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +15 -3
- data/lib/graphql/schema/enum.rb +35 -24
- data/lib/graphql/schema/enum_value.rb +2 -3
- data/lib/graphql/schema/field/connection_extension.rb +2 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +147 -107
- data/lib/graphql/schema/field_extension.rb +1 -4
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/has_single_input_argument.rb +158 -0
- data/lib/graphql/schema/input_object.rb +47 -11
- data/lib/graphql/schema/interface.rb +15 -21
- data/lib/graphql/schema/introspection_system.rb +7 -17
- data/lib/graphql/schema/late_bound_type.rb +10 -0
- data/lib/graphql/schema/list.rb +2 -2
- data/lib/graphql/schema/loader.rb +2 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -14
- data/lib/graphql/schema/member/build_type.rb +11 -3
- data/lib/graphql/schema/member/has_arguments.rb +170 -130
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +100 -38
- data/lib/graphql/schema/member/has_interfaces.rb +65 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +16 -5
- data/lib/graphql/schema/printer.rb +11 -8
- data/lib/graphql/schema/relay_classic_mutation.rb +7 -129
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/resolver.rb +47 -32
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/subset.rb +397 -0
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +11 -2
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +60 -0
- data/lib/graphql/schema/validator.rb +4 -2
- data/lib/graphql/schema/warden.rb +238 -93
- data/lib/graphql/schema.rb +498 -103
- data/lib/graphql/static_validation/all_rules.rb +2 -1
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/literal_validator.rb +24 -7
- 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_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +10 -10
- 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/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- 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 +5 -5
- data/lib/graphql/static_validation/validator.rb +4 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +11 -4
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/event.rb +11 -10
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +20 -13
- data/lib/graphql/testing/helpers.rb +151 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +251 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/data_dog_trace.rb +183 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +9 -21
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
- data/lib/graphql/tracing/legacy_trace.rb +69 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +17 -3
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +76 -0
- data/lib/graphql/tracing.rb +20 -40
- data/lib/graphql/type_kinds.rb +7 -4
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +1 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +68 -6
- data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
- data/lib/graphql/types/relay/node_behaviors.rb +8 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -1
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +27 -20
- data/readme.md +13 -3
- metadata +96 -47
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- 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 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -269
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/language/lexer.rl +0 -280
- data/lib/graphql/language/parser.y +0 -554
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
- data/lib/graphql/types/relay/default_relay.rb +0 -21
data/lib/graphql/schema.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "logger"
|
2
3
|
require "graphql/schema/addition"
|
4
|
+
require "graphql/schema/always_visible"
|
3
5
|
require "graphql/schema/base_64_encoder"
|
4
6
|
require "graphql/schema/find_inherited_value"
|
5
7
|
require "graphql/schema/finder"
|
6
|
-
require "graphql/schema/invalid_type_error"
|
7
8
|
require "graphql/schema/introspection_system"
|
8
9
|
require "graphql/schema/late_bound_type"
|
9
10
|
require "graphql/schema/null_mask"
|
@@ -31,16 +32,20 @@ require "graphql/schema/union"
|
|
31
32
|
require "graphql/schema/directive"
|
32
33
|
require "graphql/schema/directive/deprecated"
|
33
34
|
require "graphql/schema/directive/include"
|
35
|
+
require "graphql/schema/directive/one_of"
|
34
36
|
require "graphql/schema/directive/skip"
|
35
37
|
require "graphql/schema/directive/feature"
|
36
38
|
require "graphql/schema/directive/flagged"
|
37
39
|
require "graphql/schema/directive/transform"
|
40
|
+
require "graphql/schema/directive/specified_by"
|
38
41
|
require "graphql/schema/type_membership"
|
39
42
|
|
40
43
|
require "graphql/schema/resolver"
|
41
44
|
require "graphql/schema/mutation"
|
45
|
+
require "graphql/schema/has_single_input_argument"
|
42
46
|
require "graphql/schema/relay_classic_mutation"
|
43
47
|
require "graphql/schema/subscription"
|
48
|
+
require "graphql/schema/subset"
|
44
49
|
|
45
50
|
module GraphQL
|
46
51
|
# A GraphQL schema which may be queried with {GraphQL::Query}.
|
@@ -58,10 +63,6 @@ module GraphQL
|
|
58
63
|
# Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
|
59
64
|
# (These configurations can be overridden by specific calls to {Schema#execute})
|
60
65
|
#
|
61
|
-
# Schemas can specify how queries should be executed against them.
|
62
|
-
# `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
|
63
|
-
# each apply to corresponding root types.
|
64
|
-
# #
|
65
66
|
# @example defining a schema
|
66
67
|
# class MySchema < GraphQL::Schema
|
67
68
|
# query QueryType
|
@@ -109,9 +110,10 @@ module GraphQL
|
|
109
110
|
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
110
111
|
# @return [Class] the schema described by `document`
|
111
112
|
def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
|
112
|
-
# If the file ends in `.graphql`, treat it like a filepath
|
113
|
-
if definition_or_path.end_with?(".graphql")
|
113
|
+
# If the file ends in `.graphql` or `.graphqls`, treat it like a filepath
|
114
|
+
if definition_or_path.end_with?(".graphql") || definition_or_path.end_with?(".graphqls")
|
114
115
|
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
116
|
+
self,
|
115
117
|
definition_or_path,
|
116
118
|
default_resolve: default_resolve,
|
117
119
|
parser: parser,
|
@@ -119,6 +121,7 @@ module GraphQL
|
|
119
121
|
)
|
120
122
|
else
|
121
123
|
GraphQL::Schema::BuildFromDefinition.from_definition(
|
124
|
+
self,
|
122
125
|
definition_or_path,
|
123
126
|
default_resolve: default_resolve,
|
124
127
|
parser: parser,
|
@@ -140,6 +143,119 @@ module GraphQL
|
|
140
143
|
@subscriptions = new_implementation
|
141
144
|
end
|
142
145
|
|
146
|
+
# @param new_mode [Symbol] If configured, this will be used when `context: { trace_mode: ... }` isn't set.
|
147
|
+
def default_trace_mode(new_mode = nil)
|
148
|
+
if new_mode
|
149
|
+
@default_trace_mode = new_mode
|
150
|
+
elsif defined?(@default_trace_mode)
|
151
|
+
@default_trace_mode
|
152
|
+
elsif superclass.respond_to?(:default_trace_mode)
|
153
|
+
superclass.default_trace_mode
|
154
|
+
else
|
155
|
+
:default
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def trace_class(new_class = nil)
|
160
|
+
if new_class
|
161
|
+
# If any modules were already added for `:default`,
|
162
|
+
# re-apply them here
|
163
|
+
mods = trace_modules_for(:default)
|
164
|
+
mods.each { |mod| new_class.include(mod) }
|
165
|
+
trace_mode(:default, new_class)
|
166
|
+
backtrace_class = Class.new(new_class)
|
167
|
+
backtrace_class.include(GraphQL::Backtrace::Trace)
|
168
|
+
trace_mode(:default_backtrace, backtrace_class)
|
169
|
+
end
|
170
|
+
trace_class_for(:default, build: true)
|
171
|
+
end
|
172
|
+
|
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.
|
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
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
|
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 receive 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
|
+
#
|
195
|
+
# @param mode_name [Symbol]
|
196
|
+
# @param trace_class [Class] subclass of GraphQL::Tracing::Trace
|
197
|
+
# @return void
|
198
|
+
def trace_mode(mode_name, trace_class)
|
199
|
+
own_trace_modes[mode_name] = trace_class
|
200
|
+
nil
|
201
|
+
end
|
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
|
+
|
245
|
+
def own_trace_modules
|
246
|
+
@own_trace_modules ||= Hash.new { |h, k| h[k] = [] }
|
247
|
+
end
|
248
|
+
|
249
|
+
# @return [Array<Module>] Modules added for tracing in `trace_mode`, including inherited ones
|
250
|
+
def trace_modules_for(trace_mode)
|
251
|
+
modules = own_trace_modules[trace_mode]
|
252
|
+
if superclass.respond_to?(:trace_modules_for)
|
253
|
+
modules += superclass.trace_modules_for(trace_mode)
|
254
|
+
end
|
255
|
+
modules
|
256
|
+
end
|
257
|
+
|
258
|
+
|
143
259
|
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
144
260
|
# @see {#as_json}
|
145
261
|
# @return [String]
|
@@ -151,18 +267,29 @@ module GraphQL
|
|
151
267
|
# @param context [Hash]
|
152
268
|
# @param only [<#call(member, ctx)>]
|
153
269
|
# @param except [<#call(member, ctx)>]
|
270
|
+
# @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
|
271
|
+
# @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
|
272
|
+
# @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
|
273
|
+
# @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
|
274
|
+
# @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
|
154
275
|
# @return [Hash] GraphQL result
|
155
|
-
def as_json(
|
156
|
-
|
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)
|
277
|
+
introspection_query = Introspection.query(
|
278
|
+
include_deprecated_args: include_deprecated_args,
|
279
|
+
include_schema_description: include_schema_description,
|
280
|
+
include_is_repeatable: include_is_repeatable,
|
281
|
+
include_is_one_of: include_is_one_of,
|
282
|
+
include_specified_by_url: include_specified_by_url,
|
283
|
+
)
|
284
|
+
|
285
|
+
execute(introspection_query, context: context).to_h
|
157
286
|
end
|
158
287
|
|
159
288
|
# Return the GraphQL IDL for the schema
|
160
289
|
# @param context [Hash]
|
161
|
-
# @param only [<#call(member, ctx)>]
|
162
|
-
# @param except [<#call(member, ctx)>]
|
163
290
|
# @return [String]
|
164
|
-
def to_definition(
|
165
|
-
GraphQL::Schema::Printer.print_schema(self,
|
291
|
+
def to_definition(context: {})
|
292
|
+
GraphQL::Schema::Printer.print_schema(self, context: context)
|
166
293
|
end
|
167
294
|
|
168
295
|
# Return the GraphQL::Language::Document IDL AST for the schema
|
@@ -190,18 +317,6 @@ module GraphQL
|
|
190
317
|
@find_cache[path] ||= @finder.find(path)
|
191
318
|
end
|
192
319
|
|
193
|
-
def default_filter
|
194
|
-
GraphQL::Filter.new(except: default_mask)
|
195
|
-
end
|
196
|
-
|
197
|
-
def default_mask(new_mask = nil)
|
198
|
-
if new_mask
|
199
|
-
@own_default_mask = new_mask
|
200
|
-
else
|
201
|
-
@own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
320
|
def static_validator
|
206
321
|
GraphQL::StaticValidation::Validator.new(schema: self)
|
207
322
|
end
|
@@ -222,7 +337,7 @@ module GraphQL
|
|
222
337
|
# Build a map of `{ name => type }` and return it
|
223
338
|
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
224
339
|
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
225
|
-
def types(context = GraphQL::Query::NullContext)
|
340
|
+
def types(context = GraphQL::Query::NullContext.instance)
|
226
341
|
all_types = non_introspection_types.merge(introspection_system.types)
|
227
342
|
visible_types = {}
|
228
343
|
all_types.each do |k, v|
|
@@ -249,26 +364,30 @@ module GraphQL
|
|
249
364
|
|
250
365
|
# @param type_name [String]
|
251
366
|
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
252
|
-
def get_type(type_name, context = GraphQL::Query::NullContext)
|
367
|
+
def get_type(type_name, context = GraphQL::Query::NullContext.instance)
|
253
368
|
local_entry = own_types[type_name]
|
254
369
|
type_defn = case local_entry
|
255
370
|
when nil
|
256
371
|
nil
|
257
372
|
when Array
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
373
|
+
if context.respond_to?(:types) && context.types.is_a?(GraphQL::Schema::Subset)
|
374
|
+
local_entry
|
375
|
+
else
|
376
|
+
visible_t = nil
|
377
|
+
warden = Warden.from_context(context)
|
378
|
+
local_entry.each do |t|
|
379
|
+
if warden.visible_type?(t, context)
|
380
|
+
if visible_t.nil?
|
381
|
+
visible_t = t
|
382
|
+
else
|
383
|
+
raise DuplicateNamesError.new(
|
384
|
+
duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
385
|
+
)
|
386
|
+
end
|
268
387
|
end
|
269
388
|
end
|
389
|
+
visible_t
|
270
390
|
end
|
271
|
-
visible_t
|
272
391
|
when Module
|
273
392
|
local_entry
|
274
393
|
else
|
@@ -280,6 +399,11 @@ module GraphQL
|
|
280
399
|
(superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
|
281
400
|
end
|
282
401
|
|
402
|
+
# @return [Boolean] Does this schema have _any_ definition for a type named `type_name`, regardless of visibility?
|
403
|
+
def has_defined_type?(type_name)
|
404
|
+
own_types.key?(type_name) || introspection_system.types.key?(type_name) || (superclass.respond_to?(:has_defined_type?) ? superclass.has_defined_type?(type_name) : false)
|
405
|
+
end
|
406
|
+
|
283
407
|
# @api private
|
284
408
|
attr_writer :connections
|
285
409
|
|
@@ -365,16 +489,50 @@ module GraphQL
|
|
365
489
|
@root_types
|
366
490
|
end
|
367
491
|
|
492
|
+
def warden_class
|
493
|
+
if defined?(@warden_class)
|
494
|
+
@warden_class
|
495
|
+
elsif superclass.respond_to?(:warden_class)
|
496
|
+
superclass.warden_class
|
497
|
+
else
|
498
|
+
GraphQL::Schema::Warden
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
attr_writer :warden_class
|
503
|
+
|
504
|
+
def subset_class
|
505
|
+
if defined?(@subset_class)
|
506
|
+
@subset_class
|
507
|
+
elsif superclass.respond_to?(:subset_class)
|
508
|
+
superclass.subset_class
|
509
|
+
else
|
510
|
+
GraphQL::Schema::Subset
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
attr_writer :subset_class, :use_schema_subset
|
515
|
+
|
516
|
+
def use_schema_subset?
|
517
|
+
if defined?(@use_schema_subset)
|
518
|
+
@use_schema_subset
|
519
|
+
elsif superclass.respond_to?(:use_schema_subset?)
|
520
|
+
superclass.use_schema_subset?
|
521
|
+
else
|
522
|
+
false
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
368
526
|
# @param type [Module] The type definition whose possible types you want to see
|
369
527
|
# @return [Hash<String, Module>] All possible types, if no `type` is given.
|
370
528
|
# @return [Array<Module>] Possible types for `type`, if it's given.
|
371
|
-
def possible_types(type = nil, context = GraphQL::Query::NullContext)
|
529
|
+
def possible_types(type = nil, context = GraphQL::Query::NullContext.instance)
|
372
530
|
if type
|
373
531
|
# TODO duck-typing `.possible_types` would probably be nicer here
|
374
532
|
if type.kind.union?
|
375
533
|
type.possible_types(context: context)
|
376
534
|
else
|
377
|
-
stored_possible_types = own_possible_types[type
|
535
|
+
stored_possible_types = own_possible_types[type]
|
378
536
|
visible_possible_types = if stored_possible_types && type.kind.interface?
|
379
537
|
stored_possible_types.select do |possible_type|
|
380
538
|
possible_type.interfaces(context).include?(type)
|
@@ -383,7 +541,7 @@ module GraphQL
|
|
383
541
|
stored_possible_types
|
384
542
|
end
|
385
543
|
visible_possible_types ||
|
386
|
-
introspection_system.possible_types[type
|
544
|
+
introspection_system.possible_types[type] ||
|
387
545
|
(
|
388
546
|
superclass.respond_to?(:possible_types) ?
|
389
547
|
superclass.possible_types(type, context) :
|
@@ -421,18 +579,12 @@ module GraphQL
|
|
421
579
|
attr_writer :dataloader_class
|
422
580
|
|
423
581
|
def references_to(to_type = nil, from: nil)
|
424
|
-
@own_references_to ||= Hash.new { |h, k| h[k] = [] }
|
425
582
|
if to_type
|
426
|
-
if !to_type.is_a?(String)
|
427
|
-
to_type = to_type.graphql_name
|
428
|
-
end
|
429
|
-
|
430
583
|
if from
|
431
|
-
|
584
|
+
refs = own_references_to[to_type] ||= []
|
585
|
+
refs << from
|
432
586
|
else
|
433
|
-
|
434
|
-
inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
|
435
|
-
own_refs + inherited_refs
|
587
|
+
get_references_to(to_type) || EMPTY_ARRAY
|
436
588
|
end
|
437
589
|
else
|
438
590
|
# `@own_references_to` can be quite large for big schemas,
|
@@ -440,19 +592,18 @@ module GraphQL
|
|
440
592
|
# So optimize the most common case -- don't create a duplicate Hash.
|
441
593
|
inherited_value = find_inherited_value(:references_to, EMPTY_HASH)
|
442
594
|
if inherited_value.any?
|
443
|
-
inherited_value.merge(
|
595
|
+
inherited_value.merge(own_references_to)
|
444
596
|
else
|
445
|
-
|
597
|
+
own_references_to
|
446
598
|
end
|
447
599
|
end
|
448
600
|
end
|
449
601
|
|
450
|
-
def type_from_ast(ast_node, context:
|
451
|
-
|
452
|
-
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
602
|
+
def type_from_ast(ast_node, context: self.query_class.new(self, "{ __typename }").context)
|
603
|
+
GraphQL::Schema::TypeExpression.build_type(context.query.types, ast_node)
|
453
604
|
end
|
454
605
|
|
455
|
-
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
|
606
|
+
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
|
456
607
|
parent_type = case type_or_name
|
457
608
|
when LateBoundType
|
458
609
|
get_type(type_or_name.name, context)
|
@@ -475,7 +626,7 @@ module GraphQL
|
|
475
626
|
end
|
476
627
|
end
|
477
628
|
|
478
|
-
def get_fields(type, context = GraphQL::Query::NullContext)
|
629
|
+
def get_fields(type, context = GraphQL::Query::NullContext.instance)
|
479
630
|
type.fields(context)
|
480
631
|
end
|
481
632
|
|
@@ -512,6 +663,17 @@ module GraphQL
|
|
512
663
|
end
|
513
664
|
end
|
514
665
|
|
666
|
+
# A limit on the number of tokens to accept on incoming query strings.
|
667
|
+
# Use this to prevent parsing maliciously-large query strings.
|
668
|
+
# @return [nil, Integer]
|
669
|
+
def max_query_string_tokens(new_max_tokens = NOT_CONFIGURED)
|
670
|
+
if NOT_CONFIGURED.equal?(new_max_tokens)
|
671
|
+
defined?(@max_query_string_tokens) ? @max_query_string_tokens : find_inherited_value(:max_query_string_tokens)
|
672
|
+
else
|
673
|
+
@max_query_string_tokens = new_max_tokens
|
674
|
+
end
|
675
|
+
end
|
676
|
+
|
515
677
|
def default_page_size(new_default_page_size = nil)
|
516
678
|
if new_default_page_size
|
517
679
|
@default_page_size = new_default_page_size
|
@@ -520,27 +682,39 @@ module GraphQL
|
|
520
682
|
end
|
521
683
|
end
|
522
684
|
|
523
|
-
def query_execution_strategy(new_query_execution_strategy = nil)
|
685
|
+
def query_execution_strategy(new_query_execution_strategy = nil, deprecation_warning: true)
|
686
|
+
if deprecation_warning
|
687
|
+
warn "GraphQL::Schema.query_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
|
688
|
+
warn " #{caller(1, 1).first}"
|
689
|
+
end
|
524
690
|
if new_query_execution_strategy
|
525
691
|
@query_execution_strategy = new_query_execution_strategy
|
526
692
|
else
|
527
|
-
@query_execution_strategy ||
|
693
|
+
@query_execution_strategy || (superclass.respond_to?(:query_execution_strategy) ? superclass.query_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
|
528
694
|
end
|
529
695
|
end
|
530
696
|
|
531
|
-
def mutation_execution_strategy(new_mutation_execution_strategy = nil)
|
697
|
+
def mutation_execution_strategy(new_mutation_execution_strategy = nil, deprecation_warning: true)
|
698
|
+
if deprecation_warning
|
699
|
+
warn "GraphQL::Schema.mutation_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
|
700
|
+
warn " #{caller(1, 1).first}"
|
701
|
+
end
|
532
702
|
if new_mutation_execution_strategy
|
533
703
|
@mutation_execution_strategy = new_mutation_execution_strategy
|
534
704
|
else
|
535
|
-
@mutation_execution_strategy ||
|
705
|
+
@mutation_execution_strategy || (superclass.respond_to?(:mutation_execution_strategy) ? superclass.mutation_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
|
536
706
|
end
|
537
707
|
end
|
538
708
|
|
539
|
-
def subscription_execution_strategy(new_subscription_execution_strategy = nil)
|
709
|
+
def subscription_execution_strategy(new_subscription_execution_strategy = nil, deprecation_warning: true)
|
710
|
+
if deprecation_warning
|
711
|
+
warn "GraphQL::Schema.subscription_execution_strategy is deprecated without replacement. Use `GraphQL::Query.new` directly to create and execute a custom query instead."
|
712
|
+
warn " #{caller(1, 1).first}"
|
713
|
+
end
|
540
714
|
if new_subscription_execution_strategy
|
541
715
|
@subscription_execution_strategy = new_subscription_execution_strategy
|
542
716
|
else
|
543
|
-
@subscription_execution_strategy ||
|
717
|
+
@subscription_execution_strategy || (superclass.respond_to?(:subscription_execution_strategy) ? superclass.subscription_execution_strategy(deprecation_warning: false) : self.default_execution_strategy)
|
544
718
|
end
|
545
719
|
end
|
546
720
|
|
@@ -565,7 +739,7 @@ module GraphQL
|
|
565
739
|
else
|
566
740
|
string_or_document
|
567
741
|
end
|
568
|
-
query =
|
742
|
+
query = query_class.new(self, document: doc, context: context)
|
569
743
|
validator_opts = { schema: self }
|
570
744
|
rules && (validator_opts[:rules] = rules)
|
571
745
|
validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
|
@@ -573,6 +747,14 @@ module GraphQL
|
|
573
747
|
res[:errors]
|
574
748
|
end
|
575
749
|
|
750
|
+
def query_class(new_query_class = NOT_CONFIGURED)
|
751
|
+
if NOT_CONFIGURED.equal?(new_query_class)
|
752
|
+
@query_class || (superclass.respond_to?(:query_class) ? superclass.query_class : GraphQL::Query)
|
753
|
+
else
|
754
|
+
@query_class = new_query_class
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
576
758
|
attr_writer :validate_max_errors
|
577
759
|
|
578
760
|
def validate_max_errors(new_validate_max_errors = nil)
|
@@ -587,9 +769,10 @@ module GraphQL
|
|
587
769
|
|
588
770
|
attr_writer :max_complexity
|
589
771
|
|
590
|
-
def max_complexity(max_complexity = nil)
|
772
|
+
def max_complexity(max_complexity = nil, count_introspection_fields: true)
|
591
773
|
if max_complexity
|
592
774
|
@max_complexity = max_complexity
|
775
|
+
@max_complexity_count_introspection_fields = count_introspection_fields
|
593
776
|
elsif defined?(@max_complexity)
|
594
777
|
@max_complexity
|
595
778
|
else
|
@@ -597,6 +780,14 @@ module GraphQL
|
|
597
780
|
end
|
598
781
|
end
|
599
782
|
|
783
|
+
def max_complexity_count_introspection_fields
|
784
|
+
if defined?(@max_complexity_count_introspection_fields)
|
785
|
+
@max_complexity_count_introspection_fields
|
786
|
+
else
|
787
|
+
find_inherited_value(:max_complexity_count_introspection_fields, true)
|
788
|
+
end
|
789
|
+
end
|
790
|
+
|
600
791
|
attr_writer :analysis_engine
|
601
792
|
|
602
793
|
def analysis_engine
|
@@ -615,6 +806,7 @@ module GraphQL
|
|
615
806
|
|
616
807
|
def error_bubbling(new_error_bubbling = nil)
|
617
808
|
if !new_error_bubbling.nil?
|
809
|
+
warn("error_bubbling(#{new_error_bubbling.inspect}) is deprecated; the default value of `false` will be the only option in GraphQL-Ruby 3.0")
|
618
810
|
@error_bubbling = new_error_bubbling
|
619
811
|
else
|
620
812
|
@error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
|
@@ -625,9 +817,10 @@ module GraphQL
|
|
625
817
|
|
626
818
|
attr_writer :max_depth
|
627
819
|
|
628
|
-
def max_depth(new_max_depth = nil)
|
820
|
+
def max_depth(new_max_depth = nil, count_introspection_fields: true)
|
629
821
|
if new_max_depth
|
630
822
|
@max_depth = new_max_depth
|
823
|
+
@count_introspection_fields = count_introspection_fields
|
631
824
|
elsif defined?(@max_depth)
|
632
825
|
@max_depth
|
633
826
|
else
|
@@ -635,6 +828,14 @@ module GraphQL
|
|
635
828
|
end
|
636
829
|
end
|
637
830
|
|
831
|
+
def count_introspection_fields
|
832
|
+
if defined?(@count_introspection_fields)
|
833
|
+
@count_introspection_fields
|
834
|
+
else
|
835
|
+
find_inherited_value(:count_introspection_fields, true)
|
836
|
+
end
|
837
|
+
end
|
838
|
+
|
638
839
|
def disable_introspection_entry_points
|
639
840
|
@disable_introspection_entry_points = true
|
640
841
|
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
@@ -677,14 +878,54 @@ module GraphQL
|
|
677
878
|
end
|
678
879
|
end
|
679
880
|
|
881
|
+
# @param new_extra_types [Module] Type definitions to include in printing and introspection, even though they aren't referenced in the schema
|
882
|
+
# @return [Array<Module>] Type definitions added to this schema
|
883
|
+
def extra_types(*new_extra_types)
|
884
|
+
if new_extra_types.any?
|
885
|
+
new_extra_types = new_extra_types.flatten
|
886
|
+
@own_extra_types ||= []
|
887
|
+
@own_extra_types.concat(new_extra_types)
|
888
|
+
end
|
889
|
+
inherited_et = find_inherited_value(:extra_types, nil)
|
890
|
+
if inherited_et
|
891
|
+
if @own_extra_types
|
892
|
+
inherited_et + @own_extra_types
|
893
|
+
else
|
894
|
+
inherited_et
|
895
|
+
end
|
896
|
+
else
|
897
|
+
@own_extra_types || EMPTY_ARRAY
|
898
|
+
end
|
899
|
+
end
|
900
|
+
|
680
901
|
def orphan_types(*new_orphan_types)
|
681
902
|
if new_orphan_types.any?
|
682
903
|
new_orphan_types = new_orphan_types.flatten
|
904
|
+
non_object_types = new_orphan_types.reject { |ot| ot.is_a?(Class) && ot < GraphQL::Schema::Object }
|
905
|
+
if non_object_types.any?
|
906
|
+
raise ArgumentError, <<~ERR
|
907
|
+
Only object type classes should be added as `orphan_types(...)`.
|
908
|
+
|
909
|
+
- Remove these no-op types from `orphan_types`: #{non_object_types.map { |t| "#{t.inspect} (#{t.kind.name})"}.join(", ")}
|
910
|
+
- See https://graphql-ruby.org/type_definitions/interfaces.html#orphan-types
|
911
|
+
|
912
|
+
To add other types to your schema, you might want `extra_types`: https://graphql-ruby.org/schema/definition.html#extra-types
|
913
|
+
ERR
|
914
|
+
end
|
683
915
|
add_type_and_traverse(new_orphan_types, root: false)
|
684
916
|
own_orphan_types.concat(new_orphan_types.flatten)
|
685
917
|
end
|
686
918
|
|
687
|
-
find_inherited_value(:orphan_types,
|
919
|
+
inherited_ot = find_inherited_value(:orphan_types, nil)
|
920
|
+
if inherited_ot
|
921
|
+
if own_orphan_types.any?
|
922
|
+
inherited_ot + own_orphan_types
|
923
|
+
else
|
924
|
+
inherited_ot
|
925
|
+
end
|
926
|
+
else
|
927
|
+
own_orphan_types
|
928
|
+
end
|
688
929
|
end
|
689
930
|
|
690
931
|
def default_execution_strategy
|
@@ -703,6 +944,26 @@ module GraphQL
|
|
703
944
|
end
|
704
945
|
end
|
705
946
|
|
947
|
+
def default_logger(new_default_logger = NOT_CONFIGURED)
|
948
|
+
if NOT_CONFIGURED.equal?(new_default_logger)
|
949
|
+
if defined?(@default_logger)
|
950
|
+
@default_logger
|
951
|
+
elsif superclass.respond_to?(:default_logger)
|
952
|
+
superclass.default_logger
|
953
|
+
elsif defined?(Rails) && Rails.respond_to?(:logger) && (rails_logger = Rails.logger)
|
954
|
+
rails_logger
|
955
|
+
else
|
956
|
+
def_logger = Logger.new($stdout)
|
957
|
+
def_logger.info! # It doesn't output debug info by default
|
958
|
+
def_logger
|
959
|
+
end
|
960
|
+
elsif new_default_logger == nil
|
961
|
+
@default_logger = Logger.new(IO::NULL)
|
962
|
+
else
|
963
|
+
@default_logger = new_default_logger
|
964
|
+
end
|
965
|
+
end
|
966
|
+
|
706
967
|
def context_class(new_context_class = nil)
|
707
968
|
if new_context_class
|
708
969
|
@context_class = new_context_class
|
@@ -737,11 +998,10 @@ module GraphQL
|
|
737
998
|
def handle_or_reraise(context, err)
|
738
999
|
handler = Execution::Errors.find_handler_for(self, err.class)
|
739
1000
|
if handler
|
740
|
-
|
741
|
-
|
742
|
-
args =
|
743
|
-
|
744
|
-
field = runtime_info[:current_field]
|
1001
|
+
obj = context[:current_object]
|
1002
|
+
args = context[:current_arguments]
|
1003
|
+
args = args && args.respond_to?(:keyword_arguments) ? args.keyword_arguments : nil
|
1004
|
+
field = context[:current_field]
|
745
1005
|
if obj.is_a?(GraphQL::Schema::Object)
|
746
1006
|
obj = obj.object
|
747
1007
|
end
|
@@ -770,11 +1030,7 @@ module GraphQL
|
|
770
1030
|
end
|
771
1031
|
|
772
1032
|
if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind))
|
773
|
-
|
774
|
-
[resolved_type, resolved_value]
|
775
|
-
else
|
776
|
-
resolved_type
|
777
|
-
end
|
1033
|
+
[resolved_type, resolved_value]
|
778
1034
|
else
|
779
1035
|
raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
|
780
1036
|
end
|
@@ -783,17 +1039,19 @@ module GraphQL
|
|
783
1039
|
end
|
784
1040
|
|
785
1041
|
def resolve_type(type, obj, ctx)
|
786
|
-
|
787
|
-
type
|
788
|
-
else
|
789
|
-
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})"
|
790
|
-
end
|
1042
|
+
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})"
|
791
1043
|
end
|
792
1044
|
# rubocop:enable Lint/DuplicateMethods
|
793
1045
|
|
794
1046
|
def inherited(child_class)
|
795
1047
|
if self == GraphQL::Schema
|
796
1048
|
child_class.directives(default_directives.values)
|
1049
|
+
child_class.extend(SubclassGetReferencesTo)
|
1050
|
+
end
|
1051
|
+
# Make sure the child class has these built out, so that
|
1052
|
+
# subclasses can be modified by later calls to `trace_with`
|
1053
|
+
own_trace_modes.each do |name, _class|
|
1054
|
+
child_class.own_trace_modes[name] = child_class.build_trace_mode(name)
|
797
1055
|
end
|
798
1056
|
child_class.singleton_class.prepend(ResolveTypeWithType)
|
799
1057
|
super
|
@@ -811,22 +1069,19 @@ module GraphQL
|
|
811
1069
|
member.visible?(ctx)
|
812
1070
|
end
|
813
1071
|
|
814
|
-
def
|
815
|
-
|
1072
|
+
def schema_directive(dir_class, **options)
|
1073
|
+
@own_schema_directives ||= []
|
1074
|
+
Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
|
816
1075
|
end
|
817
1076
|
|
818
|
-
|
819
|
-
|
820
|
-
#
|
821
|
-
# By default, an error is added to the response. Override this hook to
|
822
|
-
# track metrics or return a different error to the client.
|
823
|
-
#
|
824
|
-
# @param error [InaccessibleFieldsError] The analysis error for this check
|
825
|
-
# @return [AnalysisError, nil] Return an error to skip the query
|
826
|
-
def inaccessible_fields(error)
|
827
|
-
error
|
1077
|
+
def schema_directives
|
1078
|
+
Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
|
828
1079
|
end
|
829
1080
|
|
1081
|
+
# Called when a type is needed by name at runtime
|
1082
|
+
def load_type(type_name, ctx)
|
1083
|
+
get_type(type_name, ctx)
|
1084
|
+
end
|
830
1085
|
# This hook is called when an object fails an `authorized?` check.
|
831
1086
|
# You might report to your bug tracker here, so you can correct
|
832
1087
|
# the field resolvers not to return unauthorized objects.
|
@@ -876,7 +1131,7 @@ module GraphQL
|
|
876
1131
|
# A function to call when {#execute} receives an invalid query string
|
877
1132
|
#
|
878
1133
|
# The default is to add the error to `context.errors`
|
879
|
-
# @param
|
1134
|
+
# @param parse_err [GraphQL::ParseError] The error encountered during parsing
|
880
1135
|
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
881
1136
|
# @return void
|
882
1137
|
def parse_error(parse_err, ctx)
|
@@ -888,6 +1143,12 @@ module GraphQL
|
|
888
1143
|
end
|
889
1144
|
|
890
1145
|
def instrument(instrument_step, instrumenter, options = {})
|
1146
|
+
warn <<~WARN
|
1147
|
+
Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
|
1148
|
+
(From `#{self}.instrument(#{instrument_step}, #{instrumenter})` at #{caller(1, 1).first})
|
1149
|
+
|
1150
|
+
WARN
|
1151
|
+
trace_with(Tracing::LegacyHooksTrace)
|
891
1152
|
own_instrumenters[instrument_step] << instrumenter
|
892
1153
|
end
|
893
1154
|
|
@@ -898,7 +1159,12 @@ module GraphQL
|
|
898
1159
|
new_directives.flatten.each { |d| directive(d) }
|
899
1160
|
end
|
900
1161
|
|
901
|
-
find_inherited_value(:directives, default_directives)
|
1162
|
+
inherited_dirs = find_inherited_value(:directives, default_directives)
|
1163
|
+
if own_directives.any?
|
1164
|
+
inherited_dirs.merge(own_directives)
|
1165
|
+
else
|
1166
|
+
inherited_dirs
|
1167
|
+
end
|
902
1168
|
end
|
903
1169
|
|
904
1170
|
# Attach a single directive to this schema
|
@@ -913,10 +1179,21 @@ module GraphQL
|
|
913
1179
|
"include" => GraphQL::Schema::Directive::Include,
|
914
1180
|
"skip" => GraphQL::Schema::Directive::Skip,
|
915
1181
|
"deprecated" => GraphQL::Schema::Directive::Deprecated,
|
1182
|
+
"oneOf" => GraphQL::Schema::Directive::OneOf,
|
1183
|
+
"specifiedBy" => GraphQL::Schema::Directive::SpecifiedBy,
|
916
1184
|
}.freeze
|
917
1185
|
end
|
918
1186
|
|
919
|
-
def tracer(new_tracer)
|
1187
|
+
def tracer(new_tracer, silence_deprecation_warning: false)
|
1188
|
+
if !silence_deprecation_warning
|
1189
|
+
warn("`Schema.tracer(#{new_tracer.inspect})` is deprecated; use module-based `trace_with` instead. See: https://graphql-ruby.org/queries/tracing.html")
|
1190
|
+
warn " #{caller(1, 1).first}"
|
1191
|
+
end
|
1192
|
+
default_trace = trace_class_for(:default, build: true)
|
1193
|
+
if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
|
1194
|
+
trace_with(GraphQL::Tracing::CallLegacyTracers)
|
1195
|
+
end
|
1196
|
+
|
920
1197
|
own_tracers << new_tracer
|
921
1198
|
end
|
922
1199
|
|
@@ -924,6 +1201,90 @@ module GraphQL
|
|
924
1201
|
find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
|
925
1202
|
end
|
926
1203
|
|
1204
|
+
# Mix `trace_mod` into this schema's `Trace` class so that its methods
|
1205
|
+
# will be called at runtime.
|
1206
|
+
#
|
1207
|
+
# @param trace_mod [Module] A module that implements tracing methods
|
1208
|
+
# @param mode [Symbol] Trace module will only be used for this trade mode
|
1209
|
+
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
1210
|
+
# @return [void]
|
1211
|
+
def trace_with(trace_mod, mode: :default, **options)
|
1212
|
+
if mode.is_a?(Array)
|
1213
|
+
mode.each { |m| trace_with(trace_mod, mode: m, **options) }
|
1214
|
+
else
|
1215
|
+
tc = own_trace_modes[mode] ||= build_trace_mode(mode)
|
1216
|
+
tc.include(trace_mod)
|
1217
|
+
own_trace_modules[mode] << trace_mod
|
1218
|
+
add_trace_options_for(mode, options)
|
1219
|
+
if mode == :default
|
1220
|
+
# This module is being added as a default tracer. If any other mode classes
|
1221
|
+
# have already been created, but get their default behavior from a superclass,
|
1222
|
+
# Then mix this into this schema's subclass.
|
1223
|
+
# (But don't mix it into mode classes that aren't default-based.)
|
1224
|
+
own_trace_modes.each do |other_mode_name, other_mode_class|
|
1225
|
+
if other_mode_class < DefaultTraceClass
|
1226
|
+
# Don't add it back to the inheritance tree if it's already there
|
1227
|
+
if !(other_mode_class < trace_mod)
|
1228
|
+
other_mode_class.include(trace_mod)
|
1229
|
+
end
|
1230
|
+
# Add any options so they'll be available
|
1231
|
+
add_trace_options_for(other_mode_name, options)
|
1232
|
+
end
|
1233
|
+
end
|
1234
|
+
end
|
1235
|
+
end
|
1236
|
+
nil
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
# The options hash for this trace mode
|
1240
|
+
# @return [Hash]
|
1241
|
+
def trace_options_for(mode)
|
1242
|
+
@trace_options_for_mode ||= {}
|
1243
|
+
@trace_options_for_mode[mode] ||= begin
|
1244
|
+
# It may be time to create an options hash for a mode that wasn't registered yet.
|
1245
|
+
# Mix in the default options in that case.
|
1246
|
+
default_options = mode == :default ? EMPTY_HASH : trace_options_for(:default)
|
1247
|
+
# Make sure this returns a new object so that other hashes aren't modified later
|
1248
|
+
if superclass.respond_to?(:trace_options_for)
|
1249
|
+
superclass.trace_options_for(mode).merge(default_options)
|
1250
|
+
else
|
1251
|
+
default_options.dup
|
1252
|
+
end
|
1253
|
+
end
|
1254
|
+
end
|
1255
|
+
|
1256
|
+
# Create a trace instance which will include the trace modules specified for the optional mode.
|
1257
|
+
#
|
1258
|
+
# If no `mode:` is given, then {default_trace_mode} will be used.
|
1259
|
+
#
|
1260
|
+
# @param mode [Symbol] Trace modules for this trade mode will be included
|
1261
|
+
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
1262
|
+
# @return [Tracing::Trace]
|
1263
|
+
def new_trace(mode: nil, **options)
|
1264
|
+
target = options[:query] || options[:multiplex]
|
1265
|
+
mode ||= target && target.context[:trace_mode]
|
1266
|
+
|
1267
|
+
trace_mode = if mode
|
1268
|
+
mode
|
1269
|
+
elsif target && target.context[:backtrace]
|
1270
|
+
if default_trace_mode != :default
|
1271
|
+
raise ArgumentError, "Can't use `context[:backtrace]` with a custom default trace mode (`#{dm.inspect}`)"
|
1272
|
+
else
|
1273
|
+
own_trace_modes[:default_backtrace] ||= build_trace_mode(:default_backtrace)
|
1274
|
+
options_trace_mode = :default
|
1275
|
+
:default_backtrace
|
1276
|
+
end
|
1277
|
+
else
|
1278
|
+
default_trace_mode
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
options_trace_mode ||= trace_mode
|
1282
|
+
base_trace_options = trace_options_for(options_trace_mode)
|
1283
|
+
trace_options = base_trace_options.merge(options)
|
1284
|
+
trace_class_for_mode = trace_class_for(trace_mode, build: true)
|
1285
|
+
trace_class_for_mode.new(**trace_options)
|
1286
|
+
end
|
1287
|
+
|
927
1288
|
def query_analyzer(new_analyzer)
|
928
1289
|
own_query_analyzers << new_analyzer
|
929
1290
|
end
|
@@ -950,7 +1311,7 @@ module GraphQL
|
|
950
1311
|
|
951
1312
|
# Execute a query on itself.
|
952
1313
|
# @see {Query#initialize} for arguments.
|
953
|
-
# @return [
|
1314
|
+
# @return [GraphQL::Query::Result] query result, ready to be serialized as JSON
|
954
1315
|
def execute(query_str = nil, **kwargs)
|
955
1316
|
if query_str
|
956
1317
|
kwargs[:query] = query_str
|
@@ -960,7 +1321,9 @@ module GraphQL
|
|
960
1321
|
{
|
961
1322
|
backtrace: ctx[:backtrace],
|
962
1323
|
tracers: ctx[:tracers],
|
1324
|
+
trace: ctx[:trace],
|
963
1325
|
dataloader: ctx[:dataloader],
|
1326
|
+
trace_mode: ctx[:trace_mode],
|
964
1327
|
}
|
965
1328
|
else
|
966
1329
|
{}
|
@@ -988,9 +1351,9 @@ module GraphQL
|
|
988
1351
|
# @see {Execution::Multiplex#run_all} for multiplex keyword arguments
|
989
1352
|
# @param queries [Array<Hash>] Keyword arguments for each query
|
990
1353
|
# @param context [Hash] Multiplex-level context
|
991
|
-
# @return [Array<
|
1354
|
+
# @return [Array<GraphQL::Query::Result>] One result for each query in the input
|
992
1355
|
def multiplex(queries, **kwargs)
|
993
|
-
GraphQL::Execution::
|
1356
|
+
GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
|
994
1357
|
end
|
995
1358
|
|
996
1359
|
def instrumenters
|
@@ -1072,6 +1435,12 @@ module GraphQL
|
|
1072
1435
|
|
1073
1436
|
private
|
1074
1437
|
|
1438
|
+
def add_trace_options_for(mode, new_options)
|
1439
|
+
t_opts = trace_options_for(mode)
|
1440
|
+
t_opts.merge!(new_options)
|
1441
|
+
nil
|
1442
|
+
end
|
1443
|
+
|
1075
1444
|
# @param t [Module, Array<Module>]
|
1076
1445
|
# @return [void]
|
1077
1446
|
def add_type_and_traverse(t, root:)
|
@@ -1115,7 +1484,8 @@ module GraphQL
|
|
1115
1484
|
own_union_memberships.merge!(addition.union_memberships)
|
1116
1485
|
|
1117
1486
|
addition.references.each { |thing, pointers|
|
1118
|
-
|
1487
|
+
prev_refs = own_references_to[thing] || []
|
1488
|
+
own_references_to[thing] = prev_refs | pointers.to_a
|
1119
1489
|
}
|
1120
1490
|
|
1121
1491
|
addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
|
@@ -1133,7 +1503,7 @@ module GraphQL
|
|
1133
1503
|
else
|
1134
1504
|
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
1135
1505
|
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
1136
|
-
@lazy_methods.set(GraphQL::Dataloader::Request, :
|
1506
|
+
@lazy_methods.set(GraphQL::Dataloader::Request, :load_with_deprecation_warning)
|
1137
1507
|
end
|
1138
1508
|
end
|
1139
1509
|
@lazy_methods
|
@@ -1143,6 +1513,10 @@ module GraphQL
|
|
1143
1513
|
@own_types ||= {}
|
1144
1514
|
end
|
1145
1515
|
|
1516
|
+
def own_references_to
|
1517
|
+
@own_references_to ||= {}.tap(&:compare_by_identity)
|
1518
|
+
end
|
1519
|
+
|
1146
1520
|
def non_introspection_types
|
1147
1521
|
find_inherited_value(:non_introspection_types, EMPTY_HASH).merge(own_types)
|
1148
1522
|
end
|
@@ -1156,7 +1530,7 @@ module GraphQL
|
|
1156
1530
|
end
|
1157
1531
|
|
1158
1532
|
def own_possible_types
|
1159
|
-
@own_possible_types ||= {}
|
1533
|
+
@own_possible_types ||= {}.tap(&:compare_by_identity)
|
1160
1534
|
end
|
1161
1535
|
|
1162
1536
|
def own_union_memberships
|
@@ -1182,6 +1556,27 @@ module GraphQL
|
|
1182
1556
|
def own_multiplex_analyzers
|
1183
1557
|
@own_multiplex_analyzers ||= []
|
1184
1558
|
end
|
1559
|
+
|
1560
|
+
# This is overridden in subclasses to check the inheritance chain
|
1561
|
+
def get_references_to(type_defn)
|
1562
|
+
own_references_to[type_defn]
|
1563
|
+
end
|
1564
|
+
end
|
1565
|
+
|
1566
|
+
module SubclassGetReferencesTo
|
1567
|
+
def get_references_to(type_defn)
|
1568
|
+
own_refs = own_references_to[type_defn]
|
1569
|
+
inherited_refs = superclass.references_to(type_defn)
|
1570
|
+
if inherited_refs&.any?
|
1571
|
+
if own_refs&.any?
|
1572
|
+
own_refs + inherited_refs
|
1573
|
+
else
|
1574
|
+
inherited_refs
|
1575
|
+
end
|
1576
|
+
else
|
1577
|
+
own_refs
|
1578
|
+
end
|
1579
|
+
end
|
1185
1580
|
end
|
1186
1581
|
|
1187
1582
|
# Install these here so that subclasses will also install it.
|