graphql 1.13.12 → 2.0.21
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_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +3 -17
- data/lib/generators/graphql/templates/schema.erb +3 -0
- data/lib/graphql/analysis/ast/field_usage.rb +3 -1
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
- data/lib/graphql/analysis/ast/query_depth.rb +0 -1
- data/lib/graphql/analysis/ast/visitor.rb +43 -36
- data/lib/graphql/analysis/ast.rb +2 -12
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/table.rb +2 -20
- data/lib/graphql/backtrace/trace.rb +96 -0
- data/lib/graphql/backtrace/tracer.rb +2 -3
- data/lib/graphql/backtrace.rb +7 -8
- data/lib/graphql/dataloader/null_dataloader.rb +3 -1
- data/lib/graphql/dataloader/source.rb +9 -0
- data/lib/graphql/dataloader.rb +4 -1
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/execution/errors.rb +12 -82
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -3
- data/lib/graphql/execution/interpreter/resolve.rb +26 -0
- data/lib/graphql/execution/interpreter/runtime.rb +300 -222
- data/lib/graphql/execution/interpreter.rb +187 -78
- data/lib/graphql/execution/lazy.rb +7 -21
- data/lib/graphql/execution/lookahead.rb +44 -40
- data/lib/graphql/execution/multiplex.rb +3 -174
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/filter.rb +7 -2
- data/lib/graphql/introspection/directive_type.rb +2 -2
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +2 -15
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +2 -2
- data/lib/graphql/introspection/type_type.rb +13 -6
- data/lib/graphql/introspection.rb +4 -3
- data/lib/graphql/language/document_from_schema_definition.rb +43 -44
- data/lib/graphql/language/lexer.rb +216 -1488
- data/lib/graphql/language/nodes.rb +66 -40
- data/lib/graphql/language/parser.rb +539 -510
- data/lib/graphql/language/parser.y +53 -44
- data/lib/graphql/language/printer.rb +37 -21
- data/lib/graphql/language/visitor.rb +191 -83
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +4 -2
- data/lib/graphql/pagination/connection.rb +33 -6
- data/lib/graphql/pagination/connections.rb +3 -28
- data/lib/graphql/pagination/relation_connection.rb +2 -0
- data/lib/graphql/query/context.rb +156 -196
- data/lib/graphql/query/input_validation_result.rb +10 -1
- data/lib/graphql/query/null_context.rb +1 -4
- data/lib/graphql/query/validation_pipeline.rb +12 -37
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +35 -21
- data/lib/graphql/query.rb +39 -46
- data/lib/graphql/railtie.rb +0 -104
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +29 -1
- data/lib/graphql/relay/range_add.rb +9 -20
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/schema/addition.rb +7 -9
- data/lib/graphql/schema/argument.rb +38 -47
- data/lib/graphql/schema/build_from_definition.rb +47 -21
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +12 -23
- data/lib/graphql/schema/enum.rb +29 -41
- data/lib/graphql/schema/enum_value.rb +2 -25
- data/lib/graphql/schema/field/connection_extension.rb +4 -0
- data/lib/graphql/schema/field.rb +256 -349
- data/lib/graphql/schema/field_extension.rb +1 -4
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/input_object.rb +57 -69
- data/lib/graphql/schema/interface.rb +0 -35
- data/lib/graphql/schema/introspection_system.rb +3 -8
- data/lib/graphql/schema/late_bound_type.rb +8 -2
- data/lib/graphql/schema/list.rb +18 -9
- data/lib/graphql/schema/loader.rb +1 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +17 -19
- data/lib/graphql/schema/member/build_type.rb +5 -7
- data/lib/graphql/schema/member/has_arguments.rb +147 -56
- 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 +97 -40
- data/lib/graphql/schema/member/has_interfaces.rb +49 -10
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +0 -6
- data/lib/graphql/schema/mutation.rb +0 -9
- data/lib/graphql/schema/non_null.rb +3 -9
- data/lib/graphql/schema/object.rb +15 -52
- data/lib/graphql/schema/relay_classic_mutation.rb +53 -42
- data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
- data/lib/graphql/schema/resolver.rb +43 -44
- data/lib/graphql/schema/scalar.rb +8 -23
- data/lib/graphql/schema/subscription.rb +0 -7
- data/lib/graphql/schema/timeout.rb +24 -28
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +10 -17
- data/lib/graphql/schema/validator.rb +1 -1
- data/lib/graphql/schema/warden.rb +37 -9
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +265 -968
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +4 -21
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/error.rb +2 -2
- data/lib/graphql/static_validation/literal_validator.rb +19 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +12 -12
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +2 -2
- 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/unique_directives_per_location.rb +12 -6
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +3 -25
- data/lib/graphql/static_validation.rb +0 -2
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
- data/lib/graphql/subscriptions/event.rb +3 -8
- data/lib/graphql/subscriptions/instrumentation.rb +0 -51
- data/lib/graphql/subscriptions.rb +32 -20
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +21 -2
- data/lib/graphql/tracing/legacy_trace.rb +65 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +42 -0
- data/lib/graphql/tracing/platform_trace.rb +109 -0
- data/lib/graphql/tracing/platform_tracing.rb +33 -43
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +1 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +75 -0
- data/lib/graphql/tracing.rb +16 -40
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/iso_8601_date.rb +4 -1
- data/lib/graphql/types/iso_8601_date_time.rb +4 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +29 -27
- data/lib/graphql/types/relay/edge_behaviors.rb +16 -5
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +17 -74
- metadata +33 -133
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -232
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -255
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -55
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -107
- data/lib/graphql/enum_type.rb +0 -133
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/instrumentation.rb +0 -92
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -260
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -54
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -39
- data/lib/graphql/relay/global_id_resolve.rb +0 -17
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/member/accepts_definition.rb +0 -164
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/default_relay.rb +0 -31
- data/lib/graphql/types/relay/node_field.rb +0 -24
- data/lib/graphql/types/relay/nodes_field.rb +0 -43
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
data/lib/graphql/schema.rb
CHANGED
@@ -1,24 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "graphql/schema/addition"
|
3
3
|
require "graphql/schema/base_64_encoder"
|
4
|
-
require "graphql/schema/catchall_middleware"
|
5
|
-
require "graphql/schema/default_parse_error"
|
6
|
-
require "graphql/schema/default_type_error"
|
7
4
|
require "graphql/schema/find_inherited_value"
|
8
5
|
require "graphql/schema/finder"
|
9
6
|
require "graphql/schema/invalid_type_error"
|
10
7
|
require "graphql/schema/introspection_system"
|
11
8
|
require "graphql/schema/late_bound_type"
|
12
|
-
require "graphql/schema/middleware_chain"
|
13
9
|
require "graphql/schema/null_mask"
|
14
|
-
require "graphql/schema/possible_types"
|
15
|
-
require "graphql/schema/rescue_middleware"
|
16
10
|
require "graphql/schema/timeout"
|
17
|
-
require "graphql/schema/timeout_middleware"
|
18
|
-
require "graphql/schema/traversal"
|
19
11
|
require "graphql/schema/type_expression"
|
20
12
|
require "graphql/schema/unique_within_type"
|
21
|
-
require "graphql/schema/validation"
|
22
13
|
require "graphql/schema/warden"
|
23
14
|
require "graphql/schema/build_from_definition"
|
24
15
|
|
@@ -40,6 +31,7 @@ require "graphql/schema/union"
|
|
40
31
|
require "graphql/schema/directive"
|
41
32
|
require "graphql/schema/directive/deprecated"
|
42
33
|
require "graphql/schema/directive/include"
|
34
|
+
require "graphql/schema/directive/one_of"
|
43
35
|
require "graphql/schema/directive/skip"
|
44
36
|
require "graphql/schema/directive/feature"
|
45
37
|
require "graphql/schema/directive/flagged"
|
@@ -70,7 +62,7 @@ module GraphQL
|
|
70
62
|
# Schemas can specify how queries should be executed against them.
|
71
63
|
# `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
|
72
64
|
# each apply to corresponding root types.
|
73
|
-
#
|
65
|
+
#
|
74
66
|
# @example defining a schema
|
75
67
|
# class MySchema < GraphQL::Schema
|
76
68
|
# query QueryType
|
@@ -79,21 +71,19 @@ module GraphQL
|
|
79
71
|
# end
|
80
72
|
#
|
81
73
|
class Schema
|
82
|
-
extend Forwardable
|
83
|
-
extend GraphQL::Schema::Member::AcceptsDefinition
|
84
74
|
extend GraphQL::Schema::Member::HasAstNode
|
85
|
-
include GraphQL::Define::InstanceDefinable
|
86
|
-
extend GraphQL::Define::InstanceDefinable::DeprecatedDefine
|
87
75
|
extend GraphQL::Schema::FindInheritedValue
|
88
76
|
|
89
|
-
class
|
90
|
-
|
91
|
-
|
77
|
+
class DuplicateNamesError < GraphQL::Error
|
78
|
+
attr_reader :duplicated_name
|
79
|
+
def initialize(duplicated_name:, duplicated_definition_1:, duplicated_definition_2:)
|
80
|
+
@duplicated_name = duplicated_name
|
81
|
+
super(
|
82
|
+
"Found two visible definitions for `#{duplicated_name}`: #{duplicated_definition_1}, #{duplicated_definition_2}"
|
83
|
+
)
|
92
84
|
end
|
93
85
|
end
|
94
86
|
|
95
|
-
class DuplicateNamesError < GraphQL::Error; end
|
96
|
-
|
97
87
|
class UnresolvedLateBoundTypeError < GraphQL::Error
|
98
88
|
attr_reader :type
|
99
89
|
def initialize(type:)
|
@@ -102,764 +92,93 @@ module GraphQL
|
|
102
92
|
end
|
103
93
|
end
|
104
94
|
|
105
|
-
|
106
|
-
|
107
|
-
# - Right away, if `value` is not registered with `lazy_resolve`
|
108
|
-
# - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
|
109
|
-
# @api private
|
110
|
-
def after_lazy(value, &block)
|
111
|
-
if lazy?(value)
|
112
|
-
GraphQL::Execution::Lazy.new do
|
113
|
-
result = sync_lazy(value)
|
114
|
-
# The returned result might also be lazy, so check it, too
|
115
|
-
after_lazy(result, &block)
|
116
|
-
end
|
117
|
-
else
|
118
|
-
yield(value) if block_given?
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# Override this method to handle lazy objects in a custom way.
|
123
|
-
# @param value [Object] an instance of a class registered with {.lazy_resolve}
|
124
|
-
# @return [Object] A GraphQL-ready (non-lazy) object
|
125
|
-
# @api private
|
126
|
-
def sync_lazy(value)
|
127
|
-
lazy_method = lazy_method_name(value)
|
128
|
-
if lazy_method
|
129
|
-
synced_value = value.public_send(lazy_method)
|
130
|
-
sync_lazy(synced_value)
|
131
|
-
else
|
132
|
-
value
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
|
137
|
-
def lazy_method_name(obj)
|
138
|
-
lazy_methods.get(obj)
|
139
|
-
end
|
140
|
-
|
141
|
-
# @return [Boolean] True if this object should be lazily resolved
|
142
|
-
def lazy?(obj)
|
143
|
-
!!lazy_method_name(obj)
|
144
|
-
end
|
145
|
-
|
146
|
-
# Return a lazy if any of `maybe_lazies` are lazy,
|
147
|
-
# otherwise, call the block eagerly and return the result.
|
148
|
-
# @param maybe_lazies [Array]
|
149
|
-
# @api private
|
150
|
-
def after_any_lazies(maybe_lazies)
|
151
|
-
if maybe_lazies.any? { |l| lazy?(l) }
|
152
|
-
GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
|
153
|
-
yield result
|
154
|
-
end
|
155
|
-
else
|
156
|
-
yield maybe_lazies
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
include LazyHandlingMethods
|
162
|
-
extend LazyHandlingMethods
|
163
|
-
|
164
|
-
deprecated_accepts_definitions \
|
165
|
-
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
166
|
-
:validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
|
167
|
-
:orphan_types, :resolve_type, :type_error, :parse_error,
|
168
|
-
:error_bubbling,
|
169
|
-
:raise_definition_error,
|
170
|
-
:object_from_id, :id_from_object,
|
171
|
-
:default_mask,
|
172
|
-
:cursor_encoder,
|
173
|
-
# If these are given as classes, normalize them. Accept `nil` when building from string.
|
174
|
-
query: ->(schema, t) { schema.query = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
175
|
-
mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
176
|
-
subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
177
|
-
disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
|
178
|
-
disable_schema_introspection_entry_point: ->(schema) { schema.disable_schema_introspection_entry_point = true },
|
179
|
-
disable_type_introspection_entry_point: ->(schema) { schema.disable_type_introspection_entry_point = true },
|
180
|
-
directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.graphql_name] = d; m } },
|
181
|
-
directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
|
182
|
-
instrument: ->(schema, type, instrumenter, after_built_ins: false) {
|
183
|
-
if type == :field && after_built_ins
|
184
|
-
type = :field_after_built_ins
|
185
|
-
end
|
186
|
-
schema.instrumenters[type] << instrumenter
|
187
|
-
},
|
188
|
-
query_analyzer: ->(schema, analyzer) {
|
189
|
-
if analyzer == GraphQL::Authorization::Analyzer
|
190
|
-
GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
|
191
|
-
end
|
192
|
-
schema.query_analyzers << analyzer
|
193
|
-
},
|
194
|
-
multiplex_analyzer: ->(schema, analyzer) { schema.multiplex_analyzers << analyzer },
|
195
|
-
middleware: ->(schema, middleware) { schema.middleware << middleware },
|
196
|
-
lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
|
197
|
-
rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block) },
|
198
|
-
tracer: ->(schema, tracer) { schema.tracers.push(tracer) }
|
199
|
-
|
200
|
-
ensure_defined :introspection_system
|
201
|
-
|
202
|
-
attr_accessor \
|
203
|
-
:query, :mutation, :subscription,
|
204
|
-
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
205
|
-
:validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
|
206
|
-
:orphan_types, :directives,
|
207
|
-
:query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
|
208
|
-
:cursor_encoder,
|
209
|
-
:ast_node,
|
210
|
-
:raise_definition_error,
|
211
|
-
:introspection_namespace,
|
212
|
-
:analysis_engine
|
213
|
-
|
214
|
-
# [Boolean] True if this object bubbles validation errors up from a field into its parent InputObject, if there is one.
|
215
|
-
attr_accessor :error_bubbling
|
216
|
-
|
217
|
-
# Single, long-lived instance of the provided subscriptions class, if there is one.
|
218
|
-
# @return [GraphQL::Subscriptions]
|
219
|
-
attr_accessor :subscriptions
|
220
|
-
|
221
|
-
# @return [MiddlewareChain] MiddlewareChain which is applied to fields during execution
|
222
|
-
attr_accessor :middleware
|
223
|
-
|
224
|
-
# @return [<#call(member, ctx)>] A callable for filtering members of the schema
|
225
|
-
# @see {Query.new} for query-specific filters with `except:`
|
226
|
-
attr_accessor :default_mask
|
227
|
-
|
228
|
-
# @see {GraphQL::Query::Context} The parent class of these classes
|
229
|
-
# @return [Class] Instantiated for each query
|
230
|
-
attr_accessor :context_class
|
231
|
-
|
232
|
-
# [Boolean] True if this object disables the introspection entry point fields
|
233
|
-
attr_accessor :disable_introspection_entry_points
|
234
|
-
|
235
|
-
def disable_introspection_entry_points?
|
236
|
-
!!@disable_introspection_entry_points
|
237
|
-
end
|
238
|
-
|
239
|
-
# [Boolean] True if this object disables the __schema introspection entry point field
|
240
|
-
attr_accessor :disable_schema_introspection_entry_point
|
241
|
-
|
242
|
-
def disable_schema_introspection_entry_point?
|
243
|
-
!!@disable_schema_introspection_entry_point
|
244
|
-
end
|
245
|
-
|
246
|
-
# [Boolean] True if this object disables the __type introspection entry point field
|
247
|
-
attr_accessor :disable_type_introspection_entry_point
|
248
|
-
|
249
|
-
def disable_type_introspection_entry_point?
|
250
|
-
!!@disable_type_introspection_entry_point
|
251
|
-
end
|
95
|
+
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
96
|
+
class InvalidDocumentError < Error; end;
|
252
97
|
|
253
98
|
class << self
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
278
|
-
@middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
279
|
-
@query_analyzers = []
|
280
|
-
@multiplex_analyzers = []
|
281
|
-
@resolve_type_proc = nil
|
282
|
-
@object_from_id_proc = nil
|
283
|
-
@id_from_object_proc = nil
|
284
|
-
@type_error_proc = DefaultTypeError
|
285
|
-
@parse_error_proc = DefaultParseError
|
286
|
-
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
287
|
-
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
288
|
-
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
289
|
-
@cursor_encoder = Base64Encoder
|
290
|
-
# For schema instances, default to legacy runtime modules
|
291
|
-
@analysis_engine = GraphQL::Analysis
|
292
|
-
@query_execution_strategy = GraphQL::Execution::Execute
|
293
|
-
@mutation_execution_strategy = GraphQL::Execution::Execute
|
294
|
-
@subscription_execution_strategy = GraphQL::Execution::Execute
|
295
|
-
@default_mask = GraphQL::Schema::NullMask
|
296
|
-
@rebuilding_artifacts = false
|
297
|
-
@context_class = GraphQL::Query::Context
|
298
|
-
@introspection_namespace = nil
|
299
|
-
@introspection_system = nil
|
300
|
-
@interpreter = false
|
301
|
-
@error_bubbling = false
|
302
|
-
@disable_introspection_entry_points = false
|
303
|
-
@disable_schema_introspection_entry_point = false
|
304
|
-
@disable_type_introspection_entry_point = false
|
305
|
-
end
|
306
|
-
|
307
|
-
# @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
|
308
|
-
def interpreter?
|
309
|
-
query_execution_strategy == GraphQL::Execution::Interpreter &&
|
310
|
-
mutation_execution_strategy == GraphQL::Execution::Interpreter &&
|
311
|
-
subscription_execution_strategy == GraphQL::Execution::Interpreter
|
312
|
-
end
|
313
|
-
|
314
|
-
def inspect
|
315
|
-
"#<#{self.class.name} ...>"
|
316
|
-
end
|
317
|
-
|
318
|
-
def initialize_copy(other)
|
319
|
-
super
|
320
|
-
@orphan_types = other.orphan_types.dup
|
321
|
-
@directives = other.directives.dup
|
322
|
-
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
323
|
-
@middleware = other.middleware.dup
|
324
|
-
@query_analyzers = other.query_analyzers.dup
|
325
|
-
@multiplex_analyzers = other.multiplex_analyzers.dup
|
326
|
-
@tracers = other.tracers.dup
|
327
|
-
@possible_types = GraphQL::Schema::PossibleTypes.new(self)
|
328
|
-
|
329
|
-
@lazy_methods = other.lazy_methods.dup
|
330
|
-
|
331
|
-
@instrumenters = Hash.new { |h, k| h[k] = [] }
|
332
|
-
other.instrumenters.each do |key, insts|
|
333
|
-
@instrumenters[key].concat(insts)
|
334
|
-
end
|
335
|
-
|
336
|
-
if other.rescues?
|
337
|
-
@rescue_middleware = other.rescue_middleware
|
338
|
-
end
|
339
|
-
|
340
|
-
# This will be rebuilt when it's requested
|
341
|
-
# or during a later `define` call
|
342
|
-
@types = nil
|
343
|
-
@introspection_system = nil
|
344
|
-
end
|
345
|
-
|
346
|
-
def rescue_from(*args, &block)
|
347
|
-
rescue_middleware.rescue_from(*args, &block)
|
348
|
-
end
|
349
|
-
|
350
|
-
def remove_handler(*args, &block)
|
351
|
-
rescue_middleware.remove_handler(*args, &block)
|
352
|
-
end
|
353
|
-
|
354
|
-
def using_ast_analysis?
|
355
|
-
@analysis_engine == GraphQL::Analysis::AST
|
356
|
-
end
|
357
|
-
|
358
|
-
# For forwards-compatibility with Schema classes
|
359
|
-
alias :graphql_definition :itself
|
360
|
-
|
361
|
-
def deprecated_define(**kwargs, &block)
|
362
|
-
super
|
363
|
-
ensure_defined
|
364
|
-
# Assert that all necessary configs are present:
|
365
|
-
validation_error = Validation.validate(self)
|
366
|
-
validation_error && raise(GraphQL::RequiredImplementationMissingError, validation_error)
|
367
|
-
rebuild_artifacts
|
368
|
-
|
369
|
-
@definition_error = nil
|
370
|
-
nil
|
371
|
-
rescue StandardError => err
|
372
|
-
if @raise_definition_error || err.is_a?(CyclicalDefinitionError) || err.is_a?(GraphQL::RequiredImplementationMissingError)
|
373
|
-
raise
|
374
|
-
else
|
375
|
-
# Raise this error _later_ to avoid messing with Rails constant loading
|
376
|
-
@definition_error = err
|
377
|
-
end
|
378
|
-
nil
|
379
|
-
end
|
380
|
-
|
381
|
-
# Attach `instrumenter` to this schema for instrumenting events of `instrumentation_type`.
|
382
|
-
# @param instrumentation_type [Symbol]
|
383
|
-
# @param instrumenter
|
384
|
-
# @return [void]
|
385
|
-
def instrument(instrumentation_type, instrumenter)
|
386
|
-
@instrumenters[instrumentation_type] << instrumenter
|
387
|
-
if instrumentation_type == :field
|
388
|
-
rebuild_artifacts
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
# @return [Array<GraphQL::BaseType>] The root types of this schema
|
393
|
-
def root_types
|
394
|
-
@root_types ||= begin
|
395
|
-
rebuild_artifacts
|
396
|
-
@root_types
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
401
|
-
# @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
|
402
|
-
def types
|
403
|
-
@types ||= begin
|
404
|
-
rebuild_artifacts
|
405
|
-
@types
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
def get_type(type_name)
|
410
|
-
@types[type_name]
|
411
|
-
end
|
412
|
-
|
413
|
-
# @api private
|
414
|
-
def introspection_system
|
415
|
-
@introspection_system ||= begin
|
416
|
-
rebuild_artifacts
|
417
|
-
@introspection_system
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
# Returns a list of Arguments and Fields referencing a certain type
|
422
|
-
# @param type_name [String]
|
423
|
-
# @return [Hash]
|
424
|
-
def references_to(type_name = nil)
|
425
|
-
rebuild_artifacts unless defined?(@type_reference_map)
|
426
|
-
if type_name
|
427
|
-
@type_reference_map.fetch(type_name, [])
|
428
|
-
else
|
429
|
-
@type_reference_map
|
430
|
-
end
|
431
|
-
end
|
432
|
-
|
433
|
-
# Returns a list of Union types in which a type is a member
|
434
|
-
# @param type [GraphQL::ObjectType]
|
435
|
-
# @return [Array<GraphQL::UnionType>] list of union types of which the type is a member
|
436
|
-
def union_memberships(type)
|
437
|
-
rebuild_artifacts unless defined?(@union_memberships)
|
438
|
-
@union_memberships.fetch(type.name, [])
|
439
|
-
end
|
440
|
-
|
441
|
-
# Execute a query on itself. Raises an error if the schema definition is invalid.
|
442
|
-
# @see {Query#initialize} for arguments.
|
443
|
-
# @return [Hash] query result, ready to be serialized as JSON
|
444
|
-
def execute(query_str = nil, **kwargs)
|
445
|
-
if query_str
|
446
|
-
kwargs[:query] = query_str
|
447
|
-
end
|
448
|
-
# Some of the query context _should_ be passed to the multiplex, too
|
449
|
-
multiplex_context = if (ctx = kwargs[:context])
|
450
|
-
{
|
451
|
-
backtrace: ctx[:backtrace],
|
452
|
-
tracers: ctx[:tracers],
|
453
|
-
}
|
454
|
-
else
|
455
|
-
{}
|
456
|
-
end
|
457
|
-
# Since we're running one query, don't run a multiplex-level complexity analyzer
|
458
|
-
all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
|
459
|
-
all_results[0]
|
460
|
-
end
|
461
|
-
|
462
|
-
# Execute several queries on itself. Raises an error if the schema definition is invalid.
|
463
|
-
# @example Run several queries at once
|
464
|
-
# context = { ... }
|
465
|
-
# queries = [
|
466
|
-
# { query: params[:query_1], variables: params[:variables_1], context: context },
|
467
|
-
# { query: params[:query_2], variables: params[:variables_2], context: context },
|
468
|
-
# ]
|
469
|
-
# results = MySchema.multiplex(queries)
|
470
|
-
# render json: {
|
471
|
-
# result_1: results[0],
|
472
|
-
# result_2: results[1],
|
473
|
-
# }
|
474
|
-
#
|
475
|
-
# @see {Query#initialize} for query keyword arguments
|
476
|
-
# @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
|
477
|
-
# @param queries [Array<Hash>] Keyword arguments for each query
|
478
|
-
# @param context [Hash] Multiplex-level context
|
479
|
-
# @return [Array<Hash>] One result for each query in the input
|
480
|
-
def multiplex(queries, **kwargs)
|
481
|
-
with_definition_error_check {
|
482
|
-
GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
|
483
|
-
}
|
484
|
-
end
|
485
|
-
|
486
|
-
# Search for a schema member using a string path
|
487
|
-
# @example Finding a Field
|
488
|
-
# Schema.find("Ensemble.musicians")
|
489
|
-
#
|
490
|
-
# @see {GraphQL::Schema::Finder} for more examples
|
491
|
-
# @param path [String] A dot-separated path to the member
|
492
|
-
# @raise [Schema::Finder::MemberNotFoundError] if path could not be found
|
493
|
-
# @return [GraphQL::BaseType, GraphQL::Field, GraphQL::Argument, GraphQL::Directive] A GraphQL Schema Member
|
494
|
-
def find(path)
|
495
|
-
rebuild_artifacts unless defined?(@finder)
|
496
|
-
@find_cache[path] ||= @finder.find(path)
|
497
|
-
end
|
498
|
-
|
499
|
-
# Resolve field named `field_name` for type `parent_type`.
|
500
|
-
# Handles dynamic fields `__typename`, `__type` and `__schema`, too
|
501
|
-
# @param parent_type [String, GraphQL::BaseType]
|
502
|
-
# @param field_name [String]
|
503
|
-
# @return [GraphQL::Field, nil] The field named `field_name` on `parent_type`
|
504
|
-
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
505
|
-
def get_field(parent_type, field_name)
|
506
|
-
with_definition_error_check do
|
507
|
-
parent_type_name = case parent_type
|
508
|
-
when GraphQL::BaseType, Class, Module
|
509
|
-
parent_type.graphql_name
|
510
|
-
when String
|
511
|
-
parent_type
|
99
|
+
# Create schema with the result of an introspection query.
|
100
|
+
# @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
|
101
|
+
# @return [Class<GraphQL::Schema>] the schema described by `input`
|
102
|
+
def from_introspection(introspection_result)
|
103
|
+
GraphQL::Schema::Loader.load(introspection_result)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Create schema from an IDL schema or file containing an IDL definition.
|
107
|
+
# @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
|
108
|
+
# @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
|
109
|
+
# @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
|
110
|
+
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
111
|
+
# @return [Class] the schema described by `document`
|
112
|
+
def from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
|
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")
|
115
|
+
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
116
|
+
self,
|
117
|
+
definition_or_path,
|
118
|
+
default_resolve: default_resolve,
|
119
|
+
parser: parser,
|
120
|
+
using: using,
|
121
|
+
)
|
512
122
|
else
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
entry_point_field
|
521
|
-
elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
|
522
|
-
dynamic_field
|
523
|
-
else
|
524
|
-
nil
|
123
|
+
GraphQL::Schema::BuildFromDefinition.from_definition(
|
124
|
+
self,
|
125
|
+
definition_or_path,
|
126
|
+
default_resolve: default_resolve,
|
127
|
+
parser: parser,
|
128
|
+
using: using,
|
129
|
+
)
|
525
130
|
end
|
526
131
|
end
|
527
|
-
end
|
528
|
-
|
529
|
-
# Fields for this type, after instrumentation is applied
|
530
|
-
# @return [Hash<String, GraphQL::Field>]
|
531
|
-
def get_fields(type)
|
532
|
-
@instrumented_field_map[type.graphql_name]
|
533
|
-
end
|
534
132
|
|
535
|
-
|
536
|
-
|
537
|
-
end
|
538
|
-
|
539
|
-
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
540
|
-
# @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
|
541
|
-
# @param context [GraphQL::Query::Context] The context for the current query
|
542
|
-
# @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
|
543
|
-
def possible_types(type_defn, context = GraphQL::Query::NullContext)
|
544
|
-
if context == GraphQL::Query::NullContext
|
545
|
-
@possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
|
546
|
-
@possible_types.possible_types(type_defn, context)
|
547
|
-
else
|
548
|
-
# Use the incoming context to cache this instance --
|
549
|
-
# if it were cached on the schema, we'd have a memory leak
|
550
|
-
# https://github.com/rmosolgo/graphql-ruby/issues/2878
|
551
|
-
ns = context.namespace(:possible_types)
|
552
|
-
per_query_possible_types = ns[:possible_types] ||= GraphQL::Schema::PossibleTypes.new(self)
|
553
|
-
per_query_possible_types.possible_types(type_defn, context)
|
133
|
+
def deprecated_graphql_definition
|
134
|
+
graphql_definition(silence_deprecation_warning: true)
|
554
135
|
end
|
555
|
-
end
|
556
136
|
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
case operation
|
561
|
-
when "query"
|
562
|
-
query
|
563
|
-
when "mutation"
|
564
|
-
mutation
|
565
|
-
when "subscription"
|
566
|
-
subscription
|
567
|
-
else
|
568
|
-
raise ArgumentError, "unknown operation type: #{operation}"
|
137
|
+
# @return [GraphQL::Subscriptions]
|
138
|
+
def subscriptions(inherited: true)
|
139
|
+
defined?(@subscriptions) ? @subscriptions : (inherited ? find_inherited_value(:subscriptions, nil) : nil)
|
569
140
|
end
|
570
|
-
end
|
571
141
|
|
572
|
-
|
573
|
-
|
574
|
-
when "query"
|
575
|
-
query_execution_strategy
|
576
|
-
when "mutation"
|
577
|
-
mutation_execution_strategy
|
578
|
-
when "subscription"
|
579
|
-
subscription_execution_strategy
|
580
|
-
else
|
581
|
-
raise ArgumentError, "unknown operation type: #{operation}"
|
142
|
+
def subscriptions=(new_implementation)
|
143
|
+
@subscriptions = new_implementation
|
582
144
|
end
|
583
|
-
end
|
584
145
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
# @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
|
592
|
-
def resolve_type(type, object, ctx = :__undefined__)
|
593
|
-
check_resolved_type(type, object, ctx) do |ok_type, ok_object, ok_ctx|
|
594
|
-
if @resolve_type_proc.nil?
|
595
|
-
raise(GraphQL::RequiredImplementationMissingError, "Can't determine GraphQL type for: #{ok_object.inspect}, define `resolve_type (type, obj, ctx) -> { ... }` inside `Schema.define`.")
|
146
|
+
def trace_class(new_class = nil)
|
147
|
+
if new_class
|
148
|
+
trace_mode(:default, new_class)
|
149
|
+
backtrace_class = Class.new(new_class)
|
150
|
+
backtrace_class.include(GraphQL::Backtrace::Trace)
|
151
|
+
trace_mode(:default_backtrace, backtrace_class)
|
596
152
|
end
|
597
|
-
|
598
|
-
end
|
599
|
-
end
|
600
|
-
|
601
|
-
# This is a compatibility hack so that instance-level and class-level
|
602
|
-
# methods can get correctness checks without calling one another
|
603
|
-
# @api private
|
604
|
-
def check_resolved_type(type, object, ctx = :__undefined__)
|
605
|
-
if ctx == :__undefined__
|
606
|
-
# Old method signature
|
607
|
-
ctx = object
|
608
|
-
object = type
|
609
|
-
type = nil
|
153
|
+
trace_class_for(:default)
|
610
154
|
end
|
611
155
|
|
612
|
-
if
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
# Prefer a type-local function; fall back to the schema-level function
|
621
|
-
type_proc = type && type.resolve_type_proc
|
622
|
-
type_result = if type_proc
|
623
|
-
type_proc.call(object, ctx)
|
624
|
-
else
|
625
|
-
yield(type, object, ctx)
|
626
|
-
end
|
627
|
-
|
628
|
-
if type_result.nil?
|
629
|
-
nil
|
630
|
-
else
|
631
|
-
after_lazy(type_result) do |resolved_type_result|
|
632
|
-
if resolved_type_result.respond_to?(:graphql_definition)
|
633
|
-
resolved_type_result = resolved_type_result.graphql_definition
|
634
|
-
end
|
635
|
-
if !resolved_type_result.is_a?(GraphQL::BaseType)
|
636
|
-
type_str = "#{resolved_type_result} (#{resolved_type_result.class.name})"
|
637
|
-
raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
|
156
|
+
# @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.
|
157
|
+
def trace_class_for(mode)
|
158
|
+
@trace_modes ||= {}
|
159
|
+
@trace_modes[mode] ||= begin
|
160
|
+
base_class = if superclass.respond_to?(:trace_class_for)
|
161
|
+
superclass.trace_class_for(mode)
|
162
|
+
elsif mode == :default_backtrace
|
163
|
+
GraphQL::Backtrace::DefaultBacktraceTrace
|
638
164
|
else
|
639
|
-
|
165
|
+
GraphQL::Tracing::Trace
|
640
166
|
end
|
167
|
+
Class.new(base_class)
|
641
168
|
end
|
642
169
|
end
|
643
|
-
end
|
644
|
-
|
645
|
-
def resolve_type=(new_resolve_type_proc)
|
646
|
-
callable = GraphQL::BackwardsCompatibility.wrap_arity(new_resolve_type_proc, from: 2, to: 3, last: true, name: "Schema#resolve_type(type, obj, ctx)")
|
647
|
-
@resolve_type_proc = callable
|
648
|
-
end
|
649
|
-
|
650
|
-
# Fetch an application object by its unique id
|
651
|
-
# @param id [String] A unique identifier, provided previously by this GraphQL schema
|
652
|
-
# @param ctx [GraphQL::Query::Context] The context for the current query
|
653
|
-
# @return [Any] The application object identified by `id`
|
654
|
-
def object_from_id(id, ctx)
|
655
|
-
if @object_from_id_proc.nil?
|
656
|
-
raise(GraphQL::RequiredImplementationMissingError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
|
657
|
-
else
|
658
|
-
@object_from_id_proc.call(id, ctx)
|
659
|
-
end
|
660
|
-
end
|
661
|
-
|
662
|
-
# @param new_proc [#call] A new callable for fetching objects by ID
|
663
|
-
def object_from_id=(new_proc)
|
664
|
-
@object_from_id_proc = new_proc
|
665
|
-
end
|
666
|
-
|
667
|
-
# When we encounter a type error during query execution, we call this hook.
|
668
|
-
#
|
669
|
-
# You can use this hook to write a log entry,
|
670
|
-
# add a {GraphQL::ExecutionError} to the response (with `ctx.add_error`)
|
671
|
-
# or raise an exception and halt query execution.
|
672
|
-
#
|
673
|
-
# @example A `nil` is encountered by a non-null field
|
674
|
-
# type_error ->(err, query_ctx) {
|
675
|
-
# err.is_a?(GraphQL::InvalidNullError) # => true
|
676
|
-
# }
|
677
|
-
#
|
678
|
-
# @example An object doesn't resolve to one of a {UnionType}'s members
|
679
|
-
# type_error ->(err, query_ctx) {
|
680
|
-
# err.is_a?(GraphQL::UnresolvedTypeError) # => true
|
681
|
-
# }
|
682
|
-
#
|
683
|
-
# @see {DefaultTypeError} is the default behavior.
|
684
|
-
# @param err [GraphQL::TypeError] The error encountered during execution
|
685
|
-
# @param ctx [GraphQL::Query::Context] The context for the field where the error occurred
|
686
|
-
# @return void
|
687
|
-
def type_error(err, ctx)
|
688
|
-
@type_error_proc.call(err, ctx)
|
689
|
-
end
|
690
|
-
|
691
|
-
# @param new_proc [#call] A new callable for handling type errors during execution
|
692
|
-
def type_error=(new_proc)
|
693
|
-
@type_error_proc = new_proc
|
694
|
-
end
|
695
|
-
|
696
|
-
# Can't delegate to `class`
|
697
|
-
alias :_schema_class :class
|
698
|
-
def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
|
699
|
-
def_delegators :_schema_class, :directive
|
700
|
-
def_delegators :_schema_class, :error_handler
|
701
|
-
def_delegators :_schema_class, :validate
|
702
|
-
|
703
|
-
|
704
|
-
# Given this schema member, find the class-based definition object
|
705
|
-
# whose `method_name` should be treated as an application hook
|
706
|
-
# @see {.visible?}
|
707
|
-
# @see {.accessible?}
|
708
|
-
def call_on_type_class(member, method_name, context, default:)
|
709
|
-
member = if member.respond_to?(:type_class)
|
710
|
-
member.type_class
|
711
|
-
else
|
712
|
-
member
|
713
|
-
end
|
714
|
-
|
715
|
-
if member.respond_to?(:relay_node_type) && (t = member.relay_node_type)
|
716
|
-
member = t
|
717
|
-
end
|
718
|
-
|
719
|
-
if member.respond_to?(method_name)
|
720
|
-
member.public_send(method_name, context)
|
721
|
-
else
|
722
|
-
default
|
723
|
-
end
|
724
|
-
end
|
725
|
-
|
726
|
-
def visible?(member, context)
|
727
|
-
call_on_type_class(member, :visible?, context, default: true)
|
728
|
-
end
|
729
|
-
|
730
|
-
def accessible?(member, context)
|
731
|
-
call_on_type_class(member, :accessible?, context, default: true)
|
732
|
-
end
|
733
|
-
|
734
|
-
# A function to call when {#execute} receives an invalid query string
|
735
|
-
#
|
736
|
-
# @see {DefaultParseError} is the default behavior.
|
737
|
-
# @param err [GraphQL::ParseError] The error encountered during parsing
|
738
|
-
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
739
|
-
# @return void
|
740
|
-
def parse_error(err, ctx)
|
741
|
-
@parse_error_proc.call(err, ctx)
|
742
|
-
end
|
743
|
-
|
744
|
-
# @param new_proc [#call] A new callable for handling parse errors during execution
|
745
|
-
def parse_error=(new_proc)
|
746
|
-
@parse_error_proc = new_proc
|
747
|
-
end
|
748
|
-
|
749
|
-
# Get a unique identifier from this object
|
750
|
-
# @param object [Any] An application object
|
751
|
-
# @param type [GraphQL::BaseType] The current type definition
|
752
|
-
# @param ctx [GraphQL::Query::Context] the context for the current query
|
753
|
-
# @return [String] a unique identifier for `object` which clients can use to refetch it
|
754
|
-
def id_from_object(object, type, ctx)
|
755
|
-
if @id_from_object_proc.nil?
|
756
|
-
raise(GraphQL::RequiredImplementationMissingError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
|
757
|
-
else
|
758
|
-
@id_from_object_proc.call(object, type, ctx)
|
759
|
-
end
|
760
|
-
end
|
761
|
-
|
762
|
-
# @param new_proc [#call] A new callable for generating unique IDs
|
763
|
-
def id_from_object=(new_proc)
|
764
|
-
@id_from_object_proc = new_proc
|
765
|
-
end
|
766
|
-
|
767
|
-
# Create schema with the result of an introspection query.
|
768
|
-
# @param introspection_result [Hash] A response from {GraphQL::Introspection::INTROSPECTION_QUERY}
|
769
|
-
# @return [GraphQL::Schema] the schema described by `input`
|
770
|
-
def self.from_introspection(introspection_result)
|
771
|
-
GraphQL::Schema::Loader.load(introspection_result)
|
772
|
-
end
|
773
|
-
|
774
|
-
# Create schema from an IDL schema or file containing an IDL definition.
|
775
|
-
# @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
|
776
|
-
# @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
|
777
|
-
# @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
|
778
|
-
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
779
|
-
# @return [Class] the schema described by `document`
|
780
|
-
def self.from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
|
781
|
-
# If the file ends in `.graphql`, treat it like a filepath
|
782
|
-
if definition_or_path.end_with?(".graphql")
|
783
|
-
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
784
|
-
definition_or_path,
|
785
|
-
default_resolve: default_resolve,
|
786
|
-
parser: parser,
|
787
|
-
using: using,
|
788
|
-
)
|
789
|
-
else
|
790
|
-
GraphQL::Schema::BuildFromDefinition.from_definition(
|
791
|
-
definition_or_path,
|
792
|
-
default_resolve: default_resolve,
|
793
|
-
parser: parser,
|
794
|
-
using: using,
|
795
|
-
)
|
796
|
-
end
|
797
|
-
end
|
798
|
-
|
799
|
-
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
800
|
-
class InvalidDocumentError < Error; end;
|
801
|
-
|
802
|
-
# Return the GraphQL IDL for the schema
|
803
|
-
# @param context [Hash]
|
804
|
-
# @param only [<#call(member, ctx)>]
|
805
|
-
# @param except [<#call(member, ctx)>]
|
806
|
-
# @return [String]
|
807
|
-
def to_definition(only: nil, except: nil, context: {})
|
808
|
-
GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
|
809
|
-
end
|
810
|
-
|
811
|
-
# Return the GraphQL::Language::Document IDL AST for the schema
|
812
|
-
# @param context [Hash]
|
813
|
-
# @param only [<#call(member, ctx)>]
|
814
|
-
# @param except [<#call(member, ctx)>]
|
815
|
-
# @return [GraphQL::Language::Document]
|
816
|
-
def to_document(only: nil, except: nil, context: {})
|
817
|
-
GraphQL::Language::DocumentFromSchemaDefinition.new(self, only: only, except: except, context: context).document
|
818
|
-
end
|
819
|
-
|
820
|
-
# Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
|
821
|
-
# @param context [Hash]
|
822
|
-
# @param only [<#call(member, ctx)>]
|
823
|
-
# @param except [<#call(member, ctx)>]
|
824
|
-
# @return [Hash] GraphQL result
|
825
|
-
def as_json(only: nil, except: nil, context: {})
|
826
|
-
execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
|
827
|
-
end
|
828
|
-
|
829
|
-
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
830
|
-
# @see {#as_json}
|
831
|
-
# @return [String]
|
832
|
-
def to_json(*args)
|
833
|
-
JSON.pretty_generate(as_json(*args))
|
834
|
-
end
|
835
|
-
|
836
|
-
def new_connections?
|
837
|
-
!!connections
|
838
|
-
end
|
839
|
-
|
840
|
-
attr_accessor :connections
|
841
170
|
|
842
|
-
|
843
|
-
|
844
|
-
#
|
845
|
-
#
|
846
|
-
#
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
# Configuration
|
852
|
-
:metadata, :redefine,
|
853
|
-
:id_from_object_proc, :object_from_id_proc,
|
854
|
-
:id_from_object=, :object_from_id=,
|
855
|
-
:remove_handler
|
856
|
-
|
857
|
-
def deprecated_graphql_definition
|
858
|
-
graphql_definition(silence_deprecation_warning: true)
|
171
|
+
# Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
|
172
|
+
# `:default` is used when no `trace_mode: ...` is requested.
|
173
|
+
# @param mode_name [Symbol]
|
174
|
+
# @param trace_class [Class] subclass of GraphQL::Tracing::Trace
|
175
|
+
# @return void
|
176
|
+
def trace_mode(mode_name, trace_class)
|
177
|
+
@trace_modes ||= {}
|
178
|
+
@trace_modes[mode_name] = trace_class
|
179
|
+
nil
|
859
180
|
end
|
860
181
|
|
861
|
-
# @return [GraphQL::Subscriptions]
|
862
|
-
attr_accessor :subscriptions
|
863
182
|
|
864
183
|
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
865
184
|
# @see {#as_json}
|
@@ -872,9 +191,22 @@ module GraphQL
|
|
872
191
|
# @param context [Hash]
|
873
192
|
# @param only [<#call(member, ctx)>]
|
874
193
|
# @param except [<#call(member, ctx)>]
|
194
|
+
# @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
|
195
|
+
# @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
|
196
|
+
# @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
|
197
|
+
# @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
|
198
|
+
# @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
|
875
199
|
# @return [Hash] GraphQL result
|
876
|
-
def as_json(only: nil, except: nil, context: {})
|
877
|
-
|
200
|
+
def as_json(only: nil, except: nil, context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
|
201
|
+
introspection_query = Introspection.query(
|
202
|
+
include_deprecated_args: include_deprecated_args,
|
203
|
+
include_schema_description: include_schema_description,
|
204
|
+
include_is_repeatable: include_is_repeatable,
|
205
|
+
include_is_one_of: include_is_one_of,
|
206
|
+
include_specified_by_url: include_specified_by_url,
|
207
|
+
)
|
208
|
+
|
209
|
+
execute(introspection_query, only: only, except: except, context: context).to_h
|
878
210
|
end
|
879
211
|
|
880
212
|
# Return the GraphQL IDL for the schema
|
@@ -911,19 +243,8 @@ module GraphQL
|
|
911
243
|
@find_cache[path] ||= @finder.find(path)
|
912
244
|
end
|
913
245
|
|
914
|
-
def graphql_definition(silence_deprecation_warning: false)
|
915
|
-
@graphql_definition ||= begin
|
916
|
-
unless silence_deprecation_warning
|
917
|
-
message = "Legacy `.graphql_definition` objects are deprecated and will be removed in GraphQL-Ruby 2.0. Use a class-based definition instead."
|
918
|
-
caller_message = "\n\nCalled on #{self.inspect} from:\n #{caller(1, 25).map { |l| " #{l}" }.join("\n")}"
|
919
|
-
GraphQL::Deprecation.warn(message + caller_message)
|
920
|
-
end
|
921
|
-
to_graphql(silence_deprecation_warning: silence_deprecation_warning)
|
922
|
-
end
|
923
|
-
end
|
924
|
-
|
925
246
|
def default_filter
|
926
|
-
GraphQL::Filter.new(except: default_mask)
|
247
|
+
GraphQL::Filter.new(except: default_mask, silence_deprecation_warning: true)
|
927
248
|
end
|
928
249
|
|
929
250
|
def default_mask(new_mask = nil)
|
@@ -951,73 +272,6 @@ module GraphQL
|
|
951
272
|
find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
|
952
273
|
end
|
953
274
|
|
954
|
-
prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
|
955
|
-
def to_graphql
|
956
|
-
schema_defn = self.new
|
957
|
-
schema_defn.raise_definition_error = true
|
958
|
-
schema_defn.query = query && query.graphql_definition(silence_deprecation_warning: true)
|
959
|
-
schema_defn.mutation = mutation && mutation.graphql_definition(silence_deprecation_warning: true)
|
960
|
-
schema_defn.subscription = subscription && subscription.graphql_definition(silence_deprecation_warning: true)
|
961
|
-
schema_defn.validate_timeout = validate_timeout
|
962
|
-
schema_defn.validate_max_errors = validate_max_errors
|
963
|
-
schema_defn.max_complexity = max_complexity
|
964
|
-
schema_defn.error_bubbling = error_bubbling
|
965
|
-
schema_defn.max_depth = max_depth
|
966
|
-
schema_defn.default_max_page_size = default_max_page_size
|
967
|
-
schema_defn.orphan_types = orphan_types.map { |t| t.graphql_definition(silence_deprecation_warning: true) }
|
968
|
-
schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
|
969
|
-
schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
|
970
|
-
schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
|
971
|
-
|
972
|
-
prepped_dirs = {}
|
973
|
-
directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
|
974
|
-
schema_defn.directives = prepped_dirs
|
975
|
-
schema_defn.introspection_namespace = introspection
|
976
|
-
schema_defn.resolve_type = method(:resolve_type)
|
977
|
-
schema_defn.object_from_id = method(:object_from_id)
|
978
|
-
schema_defn.id_from_object = method(:id_from_object)
|
979
|
-
schema_defn.type_error = method(:type_error)
|
980
|
-
schema_defn.context_class = context_class
|
981
|
-
schema_defn.cursor_encoder = cursor_encoder
|
982
|
-
schema_defn.tracers.concat(tracers)
|
983
|
-
schema_defn.query_analyzers.concat(query_analyzers)
|
984
|
-
schema_defn.analysis_engine = analysis_engine
|
985
|
-
|
986
|
-
schema_defn.middleware.concat(all_middleware)
|
987
|
-
schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
|
988
|
-
schema_defn.query_execution_strategy = query_execution_strategy
|
989
|
-
schema_defn.mutation_execution_strategy = mutation_execution_strategy
|
990
|
-
schema_defn.subscription_execution_strategy = subscription_execution_strategy
|
991
|
-
schema_defn.default_mask = default_mask
|
992
|
-
instrumenters.each do |step, insts|
|
993
|
-
insts.each do |inst|
|
994
|
-
schema_defn.instrumenters[step] << inst
|
995
|
-
end
|
996
|
-
end
|
997
|
-
|
998
|
-
lazy_methods.each do |lazy_class, value_method|
|
999
|
-
schema_defn.lazy_methods.set(lazy_class, value_method)
|
1000
|
-
end
|
1001
|
-
|
1002
|
-
error_handler.each_rescue do |err_class, handler|
|
1003
|
-
schema_defn.rescue_from(err_class, &handler)
|
1004
|
-
end
|
1005
|
-
|
1006
|
-
schema_defn.subscriptions ||= self.subscriptions
|
1007
|
-
|
1008
|
-
if !schema_defn.interpreter?
|
1009
|
-
schema_defn.instrumenters[:query] << GraphQL::Schema::Member::Instrumentation
|
1010
|
-
end
|
1011
|
-
|
1012
|
-
if new_connections?
|
1013
|
-
schema_defn.connections = self.connections
|
1014
|
-
end
|
1015
|
-
|
1016
|
-
schema_defn.send(:rebuild_artifacts)
|
1017
|
-
|
1018
|
-
schema_defn
|
1019
|
-
end
|
1020
|
-
|
1021
275
|
# Build a map of `{ name => type }` and return it
|
1022
276
|
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
1023
277
|
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
@@ -1032,7 +286,9 @@ module GraphQL
|
|
1032
286
|
if visible_t.nil?
|
1033
287
|
visible_t = t
|
1034
288
|
else
|
1035
|
-
raise DuplicateNamesError
|
289
|
+
raise DuplicateNamesError.new(
|
290
|
+
duplicated_name: k, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
291
|
+
)
|
1036
292
|
end
|
1037
293
|
end
|
1038
294
|
end
|
@@ -1059,7 +315,9 @@ module GraphQL
|
|
1059
315
|
if visible_t.nil?
|
1060
316
|
visible_t = t
|
1061
317
|
else
|
1062
|
-
raise DuplicateNamesError
|
318
|
+
raise DuplicateNamesError.new(
|
319
|
+
duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
|
320
|
+
)
|
1063
321
|
end
|
1064
322
|
end
|
1065
323
|
end
|
@@ -1172,9 +430,7 @@ module GraphQL
|
|
1172
430
|
stored_possible_types = own_possible_types[type.graphql_name]
|
1173
431
|
visible_possible_types = if stored_possible_types && type.kind.interface?
|
1174
432
|
stored_possible_types.select do |possible_type|
|
1175
|
-
|
1176
|
-
# When we don't need to support legacy `.define` types, use `.include?(type)` instead.
|
1177
|
-
possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
|
433
|
+
possible_type.interfaces(context).include?(type)
|
1178
434
|
end
|
1179
435
|
else
|
1180
436
|
stored_possible_types
|
@@ -1309,6 +565,14 @@ module GraphQL
|
|
1309
565
|
end
|
1310
566
|
end
|
1311
567
|
|
568
|
+
def default_page_size(new_default_page_size = nil)
|
569
|
+
if new_default_page_size
|
570
|
+
@default_page_size = new_default_page_size
|
571
|
+
else
|
572
|
+
@default_page_size || find_inherited_value(:default_page_size)
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
1312
576
|
def query_execution_strategy(new_query_execution_strategy = nil)
|
1313
577
|
if new_query_execution_strategy
|
1314
578
|
@query_execution_strategy = new_query_execution_strategy
|
@@ -1393,13 +657,11 @@ module GraphQL
|
|
1393
657
|
end
|
1394
658
|
|
1395
659
|
def using_ast_analysis?
|
1396
|
-
|
660
|
+
true
|
1397
661
|
end
|
1398
662
|
|
1399
663
|
def interpreter?
|
1400
|
-
|
1401
|
-
mutation_execution_strategy == GraphQL::Execution::Interpreter &&
|
1402
|
-
subscription_execution_strategy == GraphQL::Execution::Interpreter
|
664
|
+
true
|
1403
665
|
end
|
1404
666
|
|
1405
667
|
attr_writer :interpreter
|
@@ -1504,26 +766,63 @@ module GraphQL
|
|
1504
766
|
|
1505
767
|
def rescue_from(*err_classes, &handler_block)
|
1506
768
|
err_classes.each do |err_class|
|
1507
|
-
|
769
|
+
Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
|
770
|
+
end
|
771
|
+
end
|
772
|
+
|
773
|
+
NEW_HANDLER_HASH = ->(h, k) {
|
774
|
+
h[k] = {
|
775
|
+
class: k,
|
776
|
+
handler: nil,
|
777
|
+
subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
|
778
|
+
}
|
779
|
+
}
|
780
|
+
|
781
|
+
def error_handlers
|
782
|
+
@error_handlers ||= {
|
783
|
+
class: nil,
|
784
|
+
handler: nil,
|
785
|
+
subclass_handlers: Hash.new(&NEW_HANDLER_HASH),
|
786
|
+
}
|
787
|
+
end
|
788
|
+
|
789
|
+
# @api private
|
790
|
+
def handle_or_reraise(context, err)
|
791
|
+
handler = Execution::Errors.find_handler_for(self, err.class)
|
792
|
+
if handler
|
793
|
+
obj = context[:current_object]
|
794
|
+
args = context[:current_arguments]
|
795
|
+
args = args && args.respond_to?(:keyword_arguments) ? args.keyword_arguments : nil
|
796
|
+
field = context[:current_field]
|
797
|
+
if obj.is_a?(GraphQL::Schema::Object)
|
798
|
+
obj = obj.object
|
799
|
+
end
|
800
|
+
handler[:handler].call(err, obj, args, context, field)
|
801
|
+
else
|
802
|
+
raise err
|
1508
803
|
end
|
1509
804
|
end
|
1510
805
|
|
1511
806
|
# rubocop:disable Lint/DuplicateMethods
|
1512
807
|
module ResolveTypeWithType
|
1513
808
|
def resolve_type(type, obj, ctx)
|
1514
|
-
|
809
|
+
maybe_lazy_resolve_type_result = if type.is_a?(Module) && type.respond_to?(:resolve_type)
|
1515
810
|
type.resolve_type(obj, ctx)
|
1516
811
|
else
|
1517
812
|
super
|
1518
813
|
end
|
1519
814
|
|
1520
|
-
after_lazy(
|
1521
|
-
if
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
815
|
+
after_lazy(maybe_lazy_resolve_type_result) do |resolve_type_result|
|
816
|
+
if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
|
817
|
+
resolved_type = resolve_type_result[0]
|
818
|
+
resolved_value = resolve_type_result[1]
|
819
|
+
else
|
820
|
+
resolved_type = resolve_type_result
|
821
|
+
resolved_value = obj
|
822
|
+
end
|
823
|
+
|
824
|
+
if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind))
|
825
|
+
[resolved_type, resolved_value]
|
1527
826
|
else
|
1528
827
|
raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
|
1529
828
|
end
|
@@ -1557,23 +856,16 @@ module GraphQL
|
|
1557
856
|
end
|
1558
857
|
|
1559
858
|
def visible?(member, ctx)
|
1560
|
-
member.
|
859
|
+
member.visible?(ctx)
|
1561
860
|
end
|
1562
861
|
|
1563
|
-
def
|
1564
|
-
|
862
|
+
def schema_directive(dir_class, **options)
|
863
|
+
@own_schema_directives ||= []
|
864
|
+
Member::HasDirectives.add_directive(self, @own_schema_directives, dir_class, options)
|
1565
865
|
end
|
1566
866
|
|
1567
|
-
|
1568
|
-
|
1569
|
-
#
|
1570
|
-
# By default, an error is added to the response. Override this hook to
|
1571
|
-
# track metrics or return a different error to the client.
|
1572
|
-
#
|
1573
|
-
# @param error [InaccessibleFieldsError] The analysis error for this check
|
1574
|
-
# @return [AnalysisError, nil] Return an error to skip the query
|
1575
|
-
def inaccessible_fields(error)
|
1576
|
-
error
|
867
|
+
def schema_directives
|
868
|
+
Member::HasDirectives.get_directives(self, @own_schema_directives, :schema_directives)
|
1577
869
|
end
|
1578
870
|
|
1579
871
|
# This hook is called when an object fails an `authorized?` check.
|
@@ -1611,41 +903,33 @@ module GraphQL
|
|
1611
903
|
unauthorized_object(unauthorized_error)
|
1612
904
|
end
|
1613
905
|
|
1614
|
-
def type_error(
|
1615
|
-
|
906
|
+
def type_error(type_error, ctx)
|
907
|
+
case type_error
|
908
|
+
when GraphQL::InvalidNullError
|
909
|
+
ctx.errors << type_error
|
910
|
+
when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
|
911
|
+
raise type_error
|
912
|
+
when GraphQL::IntegerDecodingError
|
913
|
+
nil
|
914
|
+
end
|
1616
915
|
end
|
1617
916
|
|
1618
917
|
# A function to call when {#execute} receives an invalid query string
|
1619
918
|
#
|
1620
919
|
# The default is to add the error to `context.errors`
|
1621
|
-
# @param
|
920
|
+
# @param parse_err [GraphQL::ParseError] The error encountered during parsing
|
1622
921
|
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
1623
922
|
# @return void
|
1624
923
|
def parse_error(parse_err, ctx)
|
1625
924
|
ctx.errors.push(parse_err)
|
1626
925
|
end
|
1627
926
|
|
1628
|
-
# @return [GraphQL::Execution::Errors]
|
1629
|
-
def error_handler
|
1630
|
-
@error_handler ||= GraphQL::Execution::Errors.new(self)
|
1631
|
-
end
|
1632
|
-
|
1633
927
|
def lazy_resolve(lazy_class, value_method)
|
1634
928
|
lazy_methods.set(lazy_class, value_method)
|
1635
929
|
end
|
1636
930
|
|
1637
931
|
def instrument(instrument_step, instrumenter, options = {})
|
1638
|
-
|
1639
|
-
GraphQL::Deprecation.warn "Field instrumentation (#{instrumenter.inspect}) will be removed in GraphQL-Ruby 2.0, please upgrade to field extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
|
1640
|
-
end
|
1641
|
-
|
1642
|
-
step = if instrument_step == :field && options[:after_built_ins]
|
1643
|
-
:field_after_built_ins
|
1644
|
-
else
|
1645
|
-
instrument_step
|
1646
|
-
end
|
1647
|
-
|
1648
|
-
own_instrumenters[step] << instrumenter
|
932
|
+
own_instrumenters[instrument_step] << instrumenter
|
1649
933
|
end
|
1650
934
|
|
1651
935
|
# Add several directives at once
|
@@ -1670,10 +954,17 @@ module GraphQL
|
|
1670
954
|
"include" => GraphQL::Schema::Directive::Include,
|
1671
955
|
"skip" => GraphQL::Schema::Directive::Skip,
|
1672
956
|
"deprecated" => GraphQL::Schema::Directive::Deprecated,
|
957
|
+
"oneOf" => GraphQL::Schema::Directive::OneOf,
|
1673
958
|
}.freeze
|
1674
959
|
end
|
1675
960
|
|
1676
961
|
def tracer(new_tracer)
|
962
|
+
if defined?(@trace_modes) && !(trace_class_for(:default) < GraphQL::Tracing::LegacyTrace)
|
963
|
+
raise ArgumentError, "Can't add tracer after configuring a `trace_class`, use GraphQL::Tracing::LegacyTrace to merge legacy tracers into a trace class instead."
|
964
|
+
else
|
965
|
+
trace_mode(:default, Class.new(GraphQL::Tracing::LegacyTrace))
|
966
|
+
end
|
967
|
+
|
1677
968
|
own_tracers << new_tracer
|
1678
969
|
end
|
1679
970
|
|
@@ -1681,25 +972,40 @@ module GraphQL
|
|
1681
972
|
find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
|
1682
973
|
end
|
1683
974
|
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1688
|
-
|
975
|
+
# Mix `trace_mod` into this schema's `Trace` class so that its methods
|
976
|
+
# will be called at runtime.
|
977
|
+
#
|
978
|
+
# @param trace_mod [Module] A module that implements tracing methods
|
979
|
+
# @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
|
980
|
+
# @return [void]
|
981
|
+
def trace_with(trace_mod, **options)
|
982
|
+
trace_options.merge!(options)
|
983
|
+
trace_class.include(trace_mod)
|
1689
984
|
end
|
1690
985
|
|
1691
|
-
def
|
1692
|
-
|
986
|
+
def trace_options
|
987
|
+
@trace_options ||= superclass.respond_to?(:trace_options) ? superclass.trace_options.dup : {}
|
1693
988
|
end
|
1694
989
|
|
1695
|
-
def
|
1696
|
-
if
|
1697
|
-
|
1698
|
-
|
990
|
+
def new_trace(**options)
|
991
|
+
if defined?(@trace_options)
|
992
|
+
options = trace_options.merge(options)
|
993
|
+
end
|
994
|
+
trace_mode = if (target = options[:query] || options[:multiplex]) && target.context[:backtrace]
|
995
|
+
:default_backtrace
|
1699
996
|
else
|
1700
|
-
|
1701
|
-
MiddlewareChain.new(steps: all_middleware, final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
997
|
+
:default
|
1702
998
|
end
|
999
|
+
trace = trace_class_for(trace_mode).new(**options)
|
1000
|
+
trace
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
def query_analyzer(new_analyzer)
|
1004
|
+
own_query_analyzers << new_analyzer
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
def query_analyzers
|
1008
|
+
find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
|
1703
1009
|
end
|
1704
1010
|
|
1705
1011
|
def multiplex_analyzer(new_analyzer)
|
@@ -1755,17 +1061,12 @@ module GraphQL
|
|
1755
1061
|
# }
|
1756
1062
|
#
|
1757
1063
|
# @see {Query#initialize} for query keyword arguments
|
1758
|
-
# @see {Execution::Multiplex#
|
1064
|
+
# @see {Execution::Multiplex#run_all} for multiplex keyword arguments
|
1759
1065
|
# @param queries [Array<Hash>] Keyword arguments for each query
|
1760
1066
|
# @param context [Hash] Multiplex-level context
|
1761
1067
|
# @return [Array<Hash>] One result for each query in the input
|
1762
1068
|
def multiplex(queries, **kwargs)
|
1763
|
-
|
1764
|
-
self
|
1765
|
-
else
|
1766
|
-
graphql_definition
|
1767
|
-
end
|
1768
|
-
GraphQL::Execution::Multiplex.run_all(schema, queries, **kwargs)
|
1069
|
+
GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
|
1769
1070
|
end
|
1770
1071
|
|
1771
1072
|
def instrumenters
|
@@ -1777,12 +1078,10 @@ module GraphQL
|
|
1777
1078
|
|
1778
1079
|
# @api private
|
1779
1080
|
def add_subscription_extension_if_necessary
|
1780
|
-
if
|
1081
|
+
if !defined?(@subscription_extension_added) && subscription && self.subscriptions
|
1781
1082
|
@subscription_extension_added = true
|
1782
|
-
|
1783
|
-
|
1784
|
-
else
|
1785
|
-
subscription.all_field_definitions.each do |field|
|
1083
|
+
subscription.all_field_definitions.each do |field|
|
1084
|
+
if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
|
1786
1085
|
field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
|
1787
1086
|
end
|
1788
1087
|
end
|
@@ -1793,6 +1092,60 @@ module GraphQL
|
|
1793
1092
|
query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
|
1794
1093
|
end
|
1795
1094
|
|
1095
|
+
# Call the given block at the right time, either:
|
1096
|
+
# - Right away, if `value` is not registered with `lazy_resolve`
|
1097
|
+
# - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
|
1098
|
+
# @api private
|
1099
|
+
def after_lazy(value, &block)
|
1100
|
+
if lazy?(value)
|
1101
|
+
GraphQL::Execution::Lazy.new do
|
1102
|
+
result = sync_lazy(value)
|
1103
|
+
# The returned result might also be lazy, so check it, too
|
1104
|
+
after_lazy(result, &block)
|
1105
|
+
end
|
1106
|
+
else
|
1107
|
+
yield(value) if block_given?
|
1108
|
+
end
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
# Override this method to handle lazy objects in a custom way.
|
1112
|
+
# @param value [Object] an instance of a class registered with {.lazy_resolve}
|
1113
|
+
# @return [Object] A GraphQL-ready (non-lazy) object
|
1114
|
+
# @api private
|
1115
|
+
def sync_lazy(value)
|
1116
|
+
lazy_method = lazy_method_name(value)
|
1117
|
+
if lazy_method
|
1118
|
+
synced_value = value.public_send(lazy_method)
|
1119
|
+
sync_lazy(synced_value)
|
1120
|
+
else
|
1121
|
+
value
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
|
1126
|
+
def lazy_method_name(obj)
|
1127
|
+
lazy_methods.get(obj)
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
# @return [Boolean] True if this object should be lazily resolved
|
1131
|
+
def lazy?(obj)
|
1132
|
+
!!lazy_method_name(obj)
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
# Return a lazy if any of `maybe_lazies` are lazy,
|
1136
|
+
# otherwise, call the block eagerly and return the result.
|
1137
|
+
# @param maybe_lazies [Array]
|
1138
|
+
# @api private
|
1139
|
+
def after_any_lazies(maybe_lazies)
|
1140
|
+
if maybe_lazies.any? { |l| lazy?(l) }
|
1141
|
+
GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
|
1142
|
+
yield result
|
1143
|
+
end
|
1144
|
+
else
|
1145
|
+
yield maybe_lazies
|
1146
|
+
end
|
1147
|
+
end
|
1148
|
+
|
1796
1149
|
private
|
1797
1150
|
|
1798
1151
|
# @param t [Module, Array<Module>]
|
@@ -1902,68 +1255,12 @@ module GraphQL
|
|
1902
1255
|
@defined_query_analyzers ||= []
|
1903
1256
|
end
|
1904
1257
|
|
1905
|
-
def all_middleware
|
1906
|
-
find_inherited_value(:all_middleware, EMPTY_ARRAY) + own_middleware
|
1907
|
-
end
|
1908
|
-
|
1909
|
-
def own_middleware
|
1910
|
-
@own_middleware ||= []
|
1911
|
-
end
|
1912
|
-
|
1913
1258
|
def own_multiplex_analyzers
|
1914
1259
|
@own_multiplex_analyzers ||= []
|
1915
1260
|
end
|
1916
1261
|
end
|
1917
1262
|
|
1918
|
-
def dataloader_class
|
1919
|
-
self.class.dataloader_class
|
1920
|
-
end
|
1921
|
-
|
1922
1263
|
# Install these here so that subclasses will also install it.
|
1923
|
-
|
1924
|
-
|
1925
|
-
protected
|
1926
|
-
|
1927
|
-
def rescues?
|
1928
|
-
!!@rescue_middleware
|
1929
|
-
end
|
1930
|
-
|
1931
|
-
# Lazily create a middleware and add it to the schema
|
1932
|
-
# (Don't add it if it's not used)
|
1933
|
-
def rescue_middleware
|
1934
|
-
@rescue_middleware ||= GraphQL::Schema::RescueMiddleware.new.tap { |m| middleware.insert(0, m) }
|
1935
|
-
end
|
1936
|
-
|
1937
|
-
private
|
1938
|
-
|
1939
|
-
def rebuild_artifacts
|
1940
|
-
if @rebuilding_artifacts
|
1941
|
-
raise CyclicalDefinitionError, "Part of the schema build process re-triggered the schema build process, causing an infinite loop. Avoid using Schema#types, Schema#possible_types, and Schema#get_field during schema build."
|
1942
|
-
else
|
1943
|
-
@rebuilding_artifacts = true
|
1944
|
-
@introspection_system = Schema::IntrospectionSystem.new(self)
|
1945
|
-
traversal = Traversal.new(self)
|
1946
|
-
@types = traversal.type_map
|
1947
|
-
@root_types = [query, mutation, subscription]
|
1948
|
-
@instrumented_field_map = traversal.instrumented_field_map
|
1949
|
-
@type_reference_map = traversal.type_reference_map
|
1950
|
-
@union_memberships = traversal.union_memberships
|
1951
|
-
@find_cache = {}
|
1952
|
-
@finder = Finder.new(self)
|
1953
|
-
end
|
1954
|
-
ensure
|
1955
|
-
@rebuilding_artifacts = false
|
1956
|
-
end
|
1957
|
-
|
1958
|
-
class CyclicalDefinitionError < GraphQL::Error
|
1959
|
-
end
|
1960
|
-
|
1961
|
-
def with_definition_error_check
|
1962
|
-
if @definition_error
|
1963
|
-
raise @definition_error
|
1964
|
-
else
|
1965
|
-
yield
|
1966
|
-
end
|
1967
|
-
end
|
1264
|
+
self.connections = GraphQL::Pagination::Connections.new(schema: self)
|
1968
1265
|
end
|
1969
1266
|
end
|