graphql 1.9.17 → 1.11.7
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/core.rb +18 -2
- data/lib/generators/graphql/install_generator.rb +27 -0
- data/lib/generators/graphql/object_generator.rb +52 -8
- data/lib/generators/graphql/templates/base_argument.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_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -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/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +14 -10
- data/lib/generators/graphql/templates/interface.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/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +10 -0
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/graphql/analysis/ast/field_usage.rb +1 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +178 -67
- data/lib/graphql/analysis/ast/visitor.rb +3 -3
- data/lib/graphql/analysis/ast.rb +12 -11
- data/lib/graphql/argument.rb +10 -38
- data/lib/graphql/backtrace/table.rb +10 -2
- data/lib/graphql/backtrace/tracer.rb +2 -1
- data/lib/graphql/base_type.rb +4 -0
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
- data/lib/graphql/define/assign_enum_value.rb +1 -1
- data/lib/graphql/define/assign_global_id_field.rb +2 -2
- data/lib/graphql/define/assign_object_field.rb +3 -3
- data/lib/graphql/define/defined_object_proxy.rb +3 -0
- data/lib/graphql/define/instance_definable.rb +18 -108
- data/lib/graphql/directive/deprecated_directive.rb +1 -12
- data/lib/graphql/directive.rb +8 -1
- data/lib/graphql/enum_type.rb +5 -71
- data/lib/graphql/execution/directive_checks.rb +2 -2
- data/lib/graphql/execution/errors.rb +2 -3
- data/lib/graphql/execution/execute.rb +1 -1
- data/lib/graphql/execution/instrumentation.rb +1 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +51 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +79 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +25 -0
- data/lib/graphql/execution/interpreter/runtime.rb +227 -254
- data/lib/graphql/execution/interpreter.rb +34 -11
- data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
- data/lib/graphql/execution/lookahead.rb +39 -114
- data/lib/graphql/execution/multiplex.rb +14 -5
- data/lib/graphql/field.rb +14 -118
- data/lib/graphql/filter.rb +1 -1
- data/lib/graphql/function.rb +1 -30
- data/lib/graphql/input_object_type.rb +6 -24
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/interface_type.rb +7 -23
- data/lib/graphql/internal_representation/scope.rb +2 -2
- data/lib/graphql/internal_representation/visit.rb +2 -2
- data/lib/graphql/introspection/base_object.rb +2 -5
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +7 -7
- data/lib/graphql/introspection/field_type.rb +7 -3
- data/lib/graphql/introspection/input_value_type.rb +33 -9
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +4 -9
- data/lib/graphql/introspection/type_type.rb +11 -7
- data/lib/graphql/introspection.rb +96 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +24 -5
- data/lib/graphql/language/definition_slice.rb +21 -10
- data/lib/graphql/language/document_from_schema_definition.rb +89 -64
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/lexer.rl +7 -3
- data/lib/graphql/language/nodes.rb +52 -91
- data/lib/graphql/language/parser.rb +719 -717
- data/lib/graphql/language/parser.y +104 -98
- data/lib/graphql/language/printer.rb +1 -1
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/visitor.rb +2 -2
- data/lib/graphql/language.rb +2 -1
- data/lib/graphql/name_validator.rb +6 -7
- data/lib/graphql/non_null_type.rb +0 -10
- data/lib/graphql/object_type.rb +45 -56
- data/lib/graphql/pagination/active_record_relation_connection.rb +41 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +208 -0
- data/lib/graphql/pagination/connections.rb +145 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +185 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/query/arguments.rb +4 -2
- data/lib/graphql/query/context.rb +36 -9
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +23 -6
- data/lib/graphql/query/literal_input.rb +30 -10
- data/lib/graphql/query/null_context.rb +5 -1
- data/lib/graphql/query/validation_pipeline.rb +4 -1
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +16 -7
- data/lib/graphql/query.rb +64 -15
- data/lib/graphql/rake_task/validate.rb +3 -0
- data/lib/graphql/rake_task.rb +9 -9
- data/lib/graphql/relay/array_connection.rb +10 -12
- data/lib/graphql/relay/base_connection.rb +23 -13
- data/lib/graphql/relay/connection_type.rb +2 -1
- data/lib/graphql/relay/edge_type.rb +1 -0
- data/lib/graphql/relay/edges_instrumentation.rb +1 -1
- data/lib/graphql/relay/mutation.rb +1 -86
- data/lib/graphql/relay/node.rb +2 -2
- data/lib/graphql/relay/range_add.rb +14 -5
- data/lib/graphql/relay/relation_connection.rb +8 -10
- data/lib/graphql/scalar_type.rb +15 -59
- data/lib/graphql/schema/argument.rb +113 -11
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
- data/lib/graphql/schema/build_from_definition.rb +212 -190
- data/lib/graphql/schema/built_in_types.rb +5 -5
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive.rb +34 -3
- data/lib/graphql/schema/enum.rb +52 -4
- data/lib/graphql/schema/enum_value.rb +6 -1
- data/lib/graphql/schema/field/connection_extension.rb +44 -20
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +200 -129
- data/lib/graphql/schema/find_inherited_value.rb +13 -0
- data/lib/graphql/schema/finder.rb +13 -11
- data/lib/graphql/schema/input_object.rb +131 -22
- data/lib/graphql/schema/interface.rb +26 -8
- data/lib/graphql/schema/introspection_system.rb +108 -37
- data/lib/graphql/schema/late_bound_type.rb +3 -2
- data/lib/graphql/schema/list.rb +47 -0
- data/lib/graphql/schema/loader.rb +134 -96
- data/lib/graphql/schema/member/base_dsl_methods.rb +29 -12
- data/lib/graphql/schema/member/build_type.rb +19 -5
- data/lib/graphql/schema/member/cached_graphql_definition.rb +5 -0
- data/lib/graphql/schema/member/has_arguments.rb +105 -5
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- data/lib/graphql/schema/member/has_fields.rb +20 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +5 -1
- data/lib/graphql/schema/non_null.rb +30 -0
- data/lib/graphql/schema/object.rb +65 -12
- data/lib/graphql/schema/possible_types.rb +9 -4
- data/lib/graphql/schema/printer.rb +0 -15
- data/lib/graphql/schema/relay_classic_mutation.rb +5 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +5 -2
- data/lib/graphql/schema/resolver.rb +26 -18
- data/lib/graphql/schema/scalar.rb +27 -3
- data/lib/graphql/schema/subscription.rb +8 -18
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/traversal.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +21 -13
- data/lib/graphql/schema/type_membership.rb +2 -2
- data/lib/graphql/schema/union.rb +37 -3
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +10 -2
- data/lib/graphql/schema/warden.rb +115 -29
- data/lib/graphql/schema.rb +903 -195
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +10 -6
- data/lib/graphql/static_validation/literal_validator.rb +52 -27
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +43 -83
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +17 -5
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +33 -25
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +29 -21
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -5
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -6
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
- data/lib/graphql/static_validation/type_stack.rb +2 -2
- data/lib/graphql/static_validation/validation_context.rb +1 -1
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +30 -8
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +89 -19
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
- data/lib/graphql/subscriptions/event.rb +23 -5
- data/lib/graphql/subscriptions/instrumentation.rb +10 -5
- data/lib/graphql/subscriptions/serialize.rb +22 -4
- data/lib/graphql/subscriptions/subscription_root.rb +15 -5
- data/lib/graphql/subscriptions.rb +108 -35
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +14 -10
- data/lib/graphql/tracing/appoptics_tracing.rb +171 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +8 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +8 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
- data/lib/graphql/tracing/platform_tracing.rb +53 -9
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
- data/lib/graphql/tracing/scout_tracing.rb +19 -0
- data/lib/graphql/tracing/skylight_tracing.rb +8 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +14 -34
- data/lib/graphql/types/big_int.rb +1 -1
- data/lib/graphql/types/int.rb +9 -2
- data/lib/graphql/types/iso_8601_date.rb +3 -3
- data/lib/graphql/types/iso_8601_date_time.rb +25 -10
- data/lib/graphql/types/relay/base_connection.rb +11 -7
- data/lib/graphql/types/relay/base_edge.rb +2 -1
- data/lib/graphql/types/string.rb +7 -1
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/union_type.rb +13 -28
- data/lib/graphql/unresolved_type_error.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +31 -6
- data/readme.md +1 -1
- metadata +34 -9
- data/lib/graphql/literal_validation_error.rb +0 -6
data/lib/graphql/schema.rb
CHANGED
@@ -36,6 +36,7 @@ require "graphql/schema/scalar"
|
|
36
36
|
require "graphql/schema/object"
|
37
37
|
require "graphql/schema/union"
|
38
38
|
require "graphql/schema/directive"
|
39
|
+
require "graphql/schema/directive/deprecated"
|
39
40
|
require "graphql/schema/directive/include"
|
40
41
|
require "graphql/schema/directive/skip"
|
41
42
|
require "graphql/schema/directive/feature"
|
@@ -55,7 +56,6 @@ module GraphQL
|
|
55
56
|
# - types for exposing your application
|
56
57
|
# - query analyzers for assessing incoming queries (including max depth & max complexity restrictions)
|
57
58
|
# - execution strategies for running incoming queries
|
58
|
-
# - middleware for interacting with execution
|
59
59
|
#
|
60
60
|
# Schemas start with root types, {Schema#query}, {Schema#mutation} and {Schema#subscription}.
|
61
61
|
# The schema will traverse the tree of fields & types, using those as starting points.
|
@@ -67,14 +67,10 @@ module GraphQL
|
|
67
67
|
# Schemas can specify how queries should be executed against them.
|
68
68
|
# `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
|
69
69
|
# each apply to corresponding root types.
|
70
|
-
#
|
71
|
-
# A schema accepts a `Relay::GlobalNodeIdentification` instance for use with Relay IDs.
|
72
|
-
#
|
70
|
+
# #
|
73
71
|
# @example defining a schema
|
74
|
-
# MySchema
|
72
|
+
# class MySchema < GraphQL::Schema
|
75
73
|
# query QueryType
|
76
|
-
# middleware PermissionMiddleware
|
77
|
-
# rescue_from(ActiveRecord::RecordNotFound) { "Not found" }
|
78
74
|
# # If types are only connected by way of interfaces, they must be added here
|
79
75
|
# orphan_types ImageType, AudioType
|
80
76
|
# end
|
@@ -82,12 +78,86 @@ module GraphQL
|
|
82
78
|
class Schema
|
83
79
|
extend Forwardable
|
84
80
|
extend GraphQL::Schema::Member::AcceptsDefinition
|
81
|
+
extend GraphQL::Schema::Member::HasAstNode
|
85
82
|
include GraphQL::Define::InstanceDefinable
|
86
83
|
extend GraphQL::Schema::FindInheritedValue
|
87
84
|
|
85
|
+
class DuplicateTypeNamesError < GraphQL::Error
|
86
|
+
def initialize(type_name:, first_definition:, second_definition:, path:)
|
87
|
+
super("Multiple definitions for `#{type_name}`. Previously found #{first_definition.inspect} (#{first_definition.class}), then found #{second_definition.inspect} (#{second_definition.class}) at #{path.join(".")}")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class UnresolvedLateBoundTypeError < GraphQL::Error
|
92
|
+
attr_reader :type
|
93
|
+
def initialize(type:)
|
94
|
+
@type = type
|
95
|
+
super("Late bound type was never found: #{type.inspect}")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
module LazyHandlingMethods
|
100
|
+
# Call the given block at the right time, either:
|
101
|
+
# - Right away, if `value` is not registered with `lazy_resolve`
|
102
|
+
# - After resolving `value`, if it's registered with `lazy_resolve` (eg, `Promise`)
|
103
|
+
# @api private
|
104
|
+
def after_lazy(value, &block)
|
105
|
+
if lazy?(value)
|
106
|
+
GraphQL::Execution::Lazy.new do
|
107
|
+
result = sync_lazy(value)
|
108
|
+
# The returned result might also be lazy, so check it, too
|
109
|
+
after_lazy(result, &block)
|
110
|
+
end
|
111
|
+
else
|
112
|
+
yield(value) if block_given?
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Override this method to handle lazy objects in a custom way.
|
117
|
+
# @param value [Object] an instance of a class registered with {.lazy_resolve}
|
118
|
+
# @return [Object] A GraphQL-ready (non-lazy) object
|
119
|
+
# @api private
|
120
|
+
def sync_lazy(value)
|
121
|
+
lazy_method = lazy_method_name(value)
|
122
|
+
if lazy_method
|
123
|
+
synced_value = value.public_send(lazy_method)
|
124
|
+
sync_lazy(synced_value)
|
125
|
+
else
|
126
|
+
value
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered with {#lazy_resolve}.
|
131
|
+
def lazy_method_name(obj)
|
132
|
+
lazy_methods.get(obj)
|
133
|
+
end
|
134
|
+
|
135
|
+
# @return [Boolean] True if this object should be lazily resolved
|
136
|
+
def lazy?(obj)
|
137
|
+
!!lazy_method_name(obj)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Return a lazy if any of `maybe_lazies` are lazy,
|
141
|
+
# otherwise, call the block eagerly and return the result.
|
142
|
+
# @param maybe_lazies [Array]
|
143
|
+
# @api private
|
144
|
+
def after_any_lazies(maybe_lazies)
|
145
|
+
if maybe_lazies.any? { |l| lazy?(l) }
|
146
|
+
GraphQL::Execution::Lazy.all(maybe_lazies).then do |result|
|
147
|
+
yield result
|
148
|
+
end
|
149
|
+
else
|
150
|
+
yield maybe_lazies
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
include LazyHandlingMethods
|
156
|
+
extend LazyHandlingMethods
|
157
|
+
|
88
158
|
accepts_definitions \
|
89
159
|
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
90
|
-
:max_depth, :max_complexity, :default_max_page_size,
|
160
|
+
:validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
|
91
161
|
:orphan_types, :resolve_type, :type_error, :parse_error,
|
92
162
|
:error_bubbling,
|
93
163
|
:raise_definition_error,
|
@@ -99,7 +169,9 @@ module GraphQL
|
|
99
169
|
mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
100
170
|
subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
|
101
171
|
disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
|
102
|
-
|
172
|
+
disable_schema_introspection_entry_point: ->(schema) { schema.disable_schema_introspection_entry_point = true },
|
173
|
+
disable_type_introspection_entry_point: ->(schema) { schema.disable_type_introspection_entry_point = true },
|
174
|
+
directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.graphql_name] = d; m } },
|
103
175
|
directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
|
104
176
|
instrument: ->(schema, type, instrumenter, after_built_ins: false) {
|
105
177
|
if type == :field && after_built_ins
|
@@ -124,7 +196,7 @@ module GraphQL
|
|
124
196
|
attr_accessor \
|
125
197
|
:query, :mutation, :subscription,
|
126
198
|
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
127
|
-
:max_depth, :max_complexity, :default_max_page_size,
|
199
|
+
:validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
|
128
200
|
:orphan_types, :directives,
|
129
201
|
:query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
|
130
202
|
:cursor_encoder,
|
@@ -154,6 +226,24 @@ module GraphQL
|
|
154
226
|
# [Boolean] True if this object disables the introspection entry point fields
|
155
227
|
attr_accessor :disable_introspection_entry_points
|
156
228
|
|
229
|
+
def disable_introspection_entry_points?
|
230
|
+
!!@disable_introspection_entry_points
|
231
|
+
end
|
232
|
+
|
233
|
+
# [Boolean] True if this object disables the __schema introspection entry point field
|
234
|
+
attr_accessor :disable_schema_introspection_entry_point
|
235
|
+
|
236
|
+
def disable_schema_introspection_entry_point?
|
237
|
+
!!@disable_schema_introspection_entry_point
|
238
|
+
end
|
239
|
+
|
240
|
+
# [Boolean] True if this object disables the __type introspection entry point field
|
241
|
+
attr_accessor :disable_type_introspection_entry_point
|
242
|
+
|
243
|
+
def disable_type_introspection_entry_point?
|
244
|
+
!!@disable_type_introspection_entry_point
|
245
|
+
end
|
246
|
+
|
157
247
|
class << self
|
158
248
|
attr_writer :default_execution_strategy
|
159
249
|
end
|
@@ -167,8 +257,6 @@ module GraphQL
|
|
167
257
|
attr_reader :tracers
|
168
258
|
|
169
259
|
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
|
170
|
-
EMPTY_ARRAY = [].freeze
|
171
|
-
EMPTY_HASH = {}.freeze
|
172
260
|
|
173
261
|
attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
|
174
262
|
|
@@ -176,7 +264,10 @@ module GraphQL
|
|
176
264
|
@tracers = []
|
177
265
|
@definition_error = nil
|
178
266
|
@orphan_types = []
|
179
|
-
@directives =
|
267
|
+
@directives = {}
|
268
|
+
self.class.default_directives.each do |name, dir|
|
269
|
+
@directives[name] = dir.graphql_definition
|
270
|
+
end
|
180
271
|
@static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
|
181
272
|
@middleware = MiddlewareChain.new(final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
182
273
|
@query_analyzers = []
|
@@ -203,6 +294,8 @@ module GraphQL
|
|
203
294
|
@interpreter = false
|
204
295
|
@error_bubbling = false
|
205
296
|
@disable_introspection_entry_points = false
|
297
|
+
@disable_schema_introspection_entry_point = false
|
298
|
+
@disable_type_introspection_entry_point = false
|
206
299
|
end
|
207
300
|
|
208
301
|
# @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
|
@@ -272,8 +365,8 @@ module GraphQL
|
|
272
365
|
query = GraphQL::Query.new(self, document: doc, context: context)
|
273
366
|
validator_opts = { schema: self }
|
274
367
|
rules && (validator_opts[:rules] = rules)
|
275
|
-
validator = GraphQL::StaticValidation::Validator.new(validator_opts)
|
276
|
-
res = validator.validate(query)
|
368
|
+
validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
|
369
|
+
res = validator.validate(query, timeout: validate_timeout)
|
277
370
|
res[:errors]
|
278
371
|
end
|
279
372
|
|
@@ -325,6 +418,10 @@ module GraphQL
|
|
325
418
|
end
|
326
419
|
end
|
327
420
|
|
421
|
+
def get_type(type_name)
|
422
|
+
@types[type_name]
|
423
|
+
end
|
424
|
+
|
328
425
|
# @api private
|
329
426
|
def introspection_system
|
330
427
|
@introspection_system ||= begin
|
@@ -336,9 +433,13 @@ module GraphQL
|
|
336
433
|
# Returns a list of Arguments and Fields referencing a certain type
|
337
434
|
# @param type_name [String]
|
338
435
|
# @return [Hash]
|
339
|
-
def references_to(type_name)
|
436
|
+
def references_to(type_name = nil)
|
340
437
|
rebuild_artifacts unless defined?(@type_reference_map)
|
341
|
-
|
438
|
+
if type_name
|
439
|
+
@type_reference_map.fetch(type_name, [])
|
440
|
+
else
|
441
|
+
@type_reference_map
|
442
|
+
end
|
342
443
|
end
|
343
444
|
|
344
445
|
# Returns a list of Union types in which a type is a member
|
@@ -416,8 +517,8 @@ module GraphQL
|
|
416
517
|
def get_field(parent_type, field_name)
|
417
518
|
with_definition_error_check do
|
418
519
|
parent_type_name = case parent_type
|
419
|
-
when GraphQL::BaseType
|
420
|
-
parent_type.
|
520
|
+
when GraphQL::BaseType, Class, Module
|
521
|
+
parent_type.graphql_name
|
421
522
|
when String
|
422
523
|
parent_type
|
423
524
|
else
|
@@ -443,8 +544,8 @@ module GraphQL
|
|
443
544
|
@instrumented_field_map[type.graphql_name]
|
444
545
|
end
|
445
546
|
|
446
|
-
def type_from_ast(ast_node)
|
447
|
-
GraphQL::Schema::TypeExpression.build_type(self
|
547
|
+
def type_from_ast(ast_node, context:)
|
548
|
+
GraphQL::Schema::TypeExpression.build_type(self, ast_node)
|
448
549
|
end
|
449
550
|
|
450
551
|
# @see [GraphQL::Schema::Warden] Restricted access to members of a schema
|
@@ -452,8 +553,17 @@ module GraphQL
|
|
452
553
|
# @param context [GraphQL::Query::Context] The context for the current query
|
453
554
|
# @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
|
454
555
|
def possible_types(type_defn, context = GraphQL::Query::NullContext)
|
455
|
-
|
456
|
-
|
556
|
+
if context == GraphQL::Query::NullContext
|
557
|
+
@possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
|
558
|
+
@possible_types.possible_types(type_defn, context)
|
559
|
+
else
|
560
|
+
# Use the incoming context to cache this instance --
|
561
|
+
# if it were cached on the schema, we'd have a memory leak
|
562
|
+
# https://github.com/rmosolgo/graphql-ruby/issues/2878
|
563
|
+
ns = context.namespace(:possible_types)
|
564
|
+
per_query_possible_types = ns[:possible_types] ||= GraphQL::Schema::PossibleTypes.new(self)
|
565
|
+
per_query_possible_types.possible_types(type_defn, context)
|
566
|
+
end
|
457
567
|
end
|
458
568
|
|
459
569
|
# @see [GraphQL::Schema::Warden] Resticted access to root types
|
@@ -597,10 +707,41 @@ module GraphQL
|
|
597
707
|
|
598
708
|
# Can't delegate to `class`
|
599
709
|
alias :_schema_class :class
|
600
|
-
def_delegators :_schema_class, :
|
710
|
+
def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
|
601
711
|
def_delegators :_schema_class, :directive
|
602
712
|
def_delegators :_schema_class, :error_handler
|
603
713
|
|
714
|
+
|
715
|
+
# Given this schema member, find the class-based definition object
|
716
|
+
# whose `method_name` should be treated as an application hook
|
717
|
+
# @see {.visible?}
|
718
|
+
# @see {.accessible?}
|
719
|
+
def call_on_type_class(member, method_name, context, default:)
|
720
|
+
member = if member.respond_to?(:type_class)
|
721
|
+
member.type_class
|
722
|
+
else
|
723
|
+
member
|
724
|
+
end
|
725
|
+
|
726
|
+
if member.respond_to?(:relay_node_type) && (t = member.relay_node_type)
|
727
|
+
member = t
|
728
|
+
end
|
729
|
+
|
730
|
+
if member.respond_to?(method_name)
|
731
|
+
member.public_send(method_name, context)
|
732
|
+
else
|
733
|
+
default
|
734
|
+
end
|
735
|
+
end
|
736
|
+
|
737
|
+
def visible?(member, context)
|
738
|
+
call_on_type_class(member, :visible?, context, default: true)
|
739
|
+
end
|
740
|
+
|
741
|
+
def accessible?(member, context)
|
742
|
+
call_on_type_class(member, :accessible?, context, default: true)
|
743
|
+
end
|
744
|
+
|
604
745
|
# A function to call when {#execute} receives an invalid query string
|
605
746
|
#
|
606
747
|
# @see {DefaultParseError} is the default behavior.
|
@@ -645,30 +786,33 @@ module GraphQL
|
|
645
786
|
# @param definition_or_path [String] A schema definition string, or a path to a file containing the definition
|
646
787
|
# @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
|
647
788
|
# @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
|
648
|
-
# @
|
649
|
-
|
789
|
+
# @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
|
790
|
+
# @param interpreter [Boolean] If false, the legacy {Execution::Execute} runtime will be used
|
791
|
+
# @return [Class] the schema described by `document`
|
792
|
+
def self.from_definition(definition_or_path, default_resolve: nil, interpreter: true, parser: GraphQL.default_parser, using: {})
|
650
793
|
# If the file ends in `.graphql`, treat it like a filepath
|
651
|
-
|
652
|
-
|
794
|
+
if definition_or_path.end_with?(".graphql")
|
795
|
+
GraphQL::Schema::BuildFromDefinition.from_definition_path(
|
796
|
+
definition_or_path,
|
797
|
+
default_resolve: default_resolve,
|
798
|
+
parser: parser,
|
799
|
+
using: using,
|
800
|
+
interpreter: interpreter,
|
801
|
+
)
|
653
802
|
else
|
654
|
-
|
803
|
+
GraphQL::Schema::BuildFromDefinition.from_definition(
|
804
|
+
definition_or_path,
|
805
|
+
default_resolve: default_resolve,
|
806
|
+
parser: parser,
|
807
|
+
using: using,
|
808
|
+
interpreter: interpreter,
|
809
|
+
)
|
655
810
|
end
|
656
|
-
GraphQL::Schema::BuildFromDefinition.from_definition(definition, default_resolve: default_resolve, parser: parser)
|
657
811
|
end
|
658
812
|
|
659
813
|
# Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
|
660
814
|
class InvalidDocumentError < Error; end;
|
661
815
|
|
662
|
-
# @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
|
663
|
-
def lazy_method_name(obj)
|
664
|
-
@lazy_methods.get(obj)
|
665
|
-
end
|
666
|
-
|
667
|
-
# @return [Boolean] True if this object should be lazily resolved
|
668
|
-
def lazy?(obj)
|
669
|
-
!!lazy_method_name(obj)
|
670
|
-
end
|
671
|
-
|
672
816
|
# Return the GraphQL IDL for the schema
|
673
817
|
# @param context [Hash]
|
674
818
|
# @param only [<#call(member, ctx)>]
|
@@ -679,9 +823,12 @@ module GraphQL
|
|
679
823
|
end
|
680
824
|
|
681
825
|
# Return the GraphQL::Language::Document IDL AST for the schema
|
826
|
+
# @param context [Hash]
|
827
|
+
# @param only [<#call(member, ctx)>]
|
828
|
+
# @param except [<#call(member, ctx)>]
|
682
829
|
# @return [GraphQL::Language::Document]
|
683
|
-
def to_document
|
684
|
-
GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
|
830
|
+
def to_document(only: nil, except: nil, context: {})
|
831
|
+
GraphQL::Language::DocumentFromSchemaDefinition.new(self, only: only, except: except, context: context).document
|
685
832
|
end
|
686
833
|
|
687
834
|
# Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
|
@@ -690,7 +837,7 @@ module GraphQL
|
|
690
837
|
# @param except [<#call(member, ctx)>]
|
691
838
|
# @return [Hash] GraphQL result
|
692
839
|
def as_json(only: nil, except: nil, context: {})
|
693
|
-
execute(Introspection
|
840
|
+
execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
|
694
841
|
end
|
695
842
|
|
696
843
|
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
@@ -700,6 +847,12 @@ module GraphQL
|
|
700
847
|
JSON.pretty_generate(as_json(*args))
|
701
848
|
end
|
702
849
|
|
850
|
+
def new_connections?
|
851
|
+
!!connections
|
852
|
+
end
|
853
|
+
|
854
|
+
attr_accessor :connections
|
855
|
+
|
703
856
|
class << self
|
704
857
|
extend Forwardable
|
705
858
|
# For compatibility, these methods all:
|
@@ -707,39 +860,84 @@ module GraphQL
|
|
707
860
|
# - Delegate to that instance
|
708
861
|
# Eventually, the methods will be moved into this class, removing the need for the singleton.
|
709
862
|
def_delegators :graphql_definition,
|
710
|
-
# Schema structure
|
711
|
-
:as_json, :to_json, :to_document, :to_definition, :ast_node,
|
712
863
|
# Execution
|
713
|
-
:execute, :multiplex,
|
714
|
-
:static_validator, :introspection_system,
|
715
|
-
:query_analyzers, :tracers, :instrumenters,
|
716
864
|
:execution_strategy_for_operation,
|
717
|
-
:validate,
|
865
|
+
:validate,
|
718
866
|
# Configuration
|
719
|
-
:
|
720
|
-
:max_complexity=, :max_depth=,
|
721
|
-
:error_bubbling=,
|
722
|
-
:metadata,
|
723
|
-
:default_mask,
|
724
|
-
:default_filter, :redefine,
|
867
|
+
:metadata, :redefine,
|
725
868
|
:id_from_object_proc, :object_from_id_proc,
|
726
869
|
:id_from_object=, :object_from_id=,
|
727
|
-
:remove_handler
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
870
|
+
:remove_handler
|
871
|
+
|
872
|
+
# @return [GraphQL::Subscriptions]
|
873
|
+
attr_accessor :subscriptions
|
874
|
+
|
875
|
+
# Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
|
876
|
+
# @see {#as_json}
|
877
|
+
# @return [String]
|
878
|
+
def to_json(**args)
|
879
|
+
JSON.pretty_generate(as_json(**args))
|
880
|
+
end
|
881
|
+
|
882
|
+
# Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
|
883
|
+
# @param context [Hash]
|
884
|
+
# @param only [<#call(member, ctx)>]
|
885
|
+
# @param except [<#call(member, ctx)>]
|
886
|
+
# @return [Hash] GraphQL result
|
887
|
+
def as_json(only: nil, except: nil, context: {})
|
888
|
+
execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
|
889
|
+
end
|
890
|
+
|
891
|
+
# Return the GraphQL IDL for the schema
|
892
|
+
# @param context [Hash]
|
893
|
+
# @param only [<#call(member, ctx)>]
|
894
|
+
# @param except [<#call(member, ctx)>]
|
895
|
+
# @return [String]
|
896
|
+
def to_definition(only: nil, except: nil, context: {})
|
897
|
+
GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
|
898
|
+
end
|
899
|
+
|
900
|
+
# Return the GraphQL::Language::Document IDL AST for the schema
|
901
|
+
# @return [GraphQL::Language::Document]
|
902
|
+
def to_document
|
903
|
+
GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
|
904
|
+
end
|
905
|
+
|
906
|
+
def find(path)
|
907
|
+
if !@finder
|
908
|
+
@find_cache = {}
|
909
|
+
@finder ||= GraphQL::Schema::Finder.new(self)
|
910
|
+
end
|
911
|
+
@find_cache[path] ||= @finder.find(path)
|
912
|
+
end
|
736
913
|
|
737
914
|
def graphql_definition
|
738
915
|
@graphql_definition ||= to_graphql
|
739
916
|
end
|
740
917
|
|
741
|
-
def
|
742
|
-
|
918
|
+
def default_filter
|
919
|
+
GraphQL::Filter.new(except: default_mask)
|
920
|
+
end
|
921
|
+
|
922
|
+
def default_mask(new_mask = nil)
|
923
|
+
if new_mask
|
924
|
+
@own_default_mask = new_mask
|
925
|
+
else
|
926
|
+
@own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
|
927
|
+
end
|
928
|
+
end
|
929
|
+
|
930
|
+
def static_validator
|
931
|
+
GraphQL::StaticValidation::Validator.new(schema: self)
|
932
|
+
end
|
933
|
+
|
934
|
+
def use(plugin, **kwargs)
|
935
|
+
if kwargs.any?
|
936
|
+
plugin.use(self, **kwargs)
|
937
|
+
else
|
938
|
+
plugin.use(self)
|
939
|
+
end
|
940
|
+
own_plugins << [plugin, kwargs]
|
743
941
|
end
|
744
942
|
|
745
943
|
def plugins
|
@@ -749,15 +947,18 @@ module GraphQL
|
|
749
947
|
def to_graphql
|
750
948
|
schema_defn = self.new
|
751
949
|
schema_defn.raise_definition_error = true
|
752
|
-
schema_defn.query = query
|
753
|
-
schema_defn.mutation = mutation
|
754
|
-
schema_defn.subscription = subscription
|
950
|
+
schema_defn.query = query && query.graphql_definition
|
951
|
+
schema_defn.mutation = mutation && mutation.graphql_definition
|
952
|
+
schema_defn.subscription = subscription && subscription.graphql_definition
|
953
|
+
schema_defn.validate_timeout = validate_timeout
|
755
954
|
schema_defn.max_complexity = max_complexity
|
756
955
|
schema_defn.error_bubbling = error_bubbling
|
757
956
|
schema_defn.max_depth = max_depth
|
758
957
|
schema_defn.default_max_page_size = default_max_page_size
|
759
|
-
schema_defn.orphan_types = orphan_types
|
958
|
+
schema_defn.orphan_types = orphan_types.map(&:graphql_definition)
|
760
959
|
schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
|
960
|
+
schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
|
961
|
+
schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
|
761
962
|
|
762
963
|
prepped_dirs = {}
|
763
964
|
directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
|
@@ -771,81 +972,268 @@ module GraphQL
|
|
771
972
|
schema_defn.cursor_encoder = cursor_encoder
|
772
973
|
schema_defn.tracers.concat(tracers)
|
773
974
|
schema_defn.query_analyzers.concat(query_analyzers)
|
975
|
+
schema_defn.analysis_engine = analysis_engine
|
774
976
|
|
775
977
|
schema_defn.middleware.concat(all_middleware)
|
776
978
|
schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
|
777
979
|
schema_defn.query_execution_strategy = query_execution_strategy
|
778
980
|
schema_defn.mutation_execution_strategy = mutation_execution_strategy
|
779
981
|
schema_defn.subscription_execution_strategy = subscription_execution_strategy
|
780
|
-
|
982
|
+
schema_defn.default_mask = default_mask
|
983
|
+
instrumenters.each do |step, insts|
|
781
984
|
insts.each do |inst|
|
782
985
|
schema_defn.instrumenters[step] << inst
|
783
986
|
end
|
784
987
|
end
|
785
|
-
|
988
|
+
|
989
|
+
lazy_methods.each do |lazy_class, value_method|
|
786
990
|
schema_defn.lazy_methods.set(lazy_class, value_method)
|
787
991
|
end
|
992
|
+
|
788
993
|
rescues.each do |err_class, handler|
|
789
994
|
schema_defn.rescue_from(err_class, &handler)
|
790
995
|
end
|
791
996
|
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
schema_defn = schema_defn.redefine do
|
796
|
-
schema_plugins.each do |plugin, options|
|
797
|
-
if options.any?
|
798
|
-
use(plugin, **options)
|
799
|
-
else
|
800
|
-
use(plugin)
|
801
|
-
end
|
802
|
-
end
|
803
|
-
end
|
804
|
-
end
|
805
|
-
# Do this after `plugins` since Interpreter is a plugin
|
806
|
-
if schema_defn.query_execution_strategy != GraphQL::Execution::Interpreter
|
997
|
+
schema_defn.subscriptions ||= self.subscriptions
|
998
|
+
|
999
|
+
if !schema_defn.interpreter?
|
807
1000
|
schema_defn.instrumenters[:query] << GraphQL::Schema::Member::Instrumentation
|
808
1001
|
end
|
1002
|
+
|
1003
|
+
if new_connections?
|
1004
|
+
schema_defn.connections = self.connections
|
1005
|
+
end
|
1006
|
+
|
809
1007
|
schema_defn.send(:rebuild_artifacts)
|
810
1008
|
|
811
1009
|
schema_defn
|
812
1010
|
end
|
813
1011
|
|
1012
|
+
# Build a map of `{ name => type }` and return it
|
1013
|
+
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
1014
|
+
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
1015
|
+
def types
|
1016
|
+
non_introspection_types.merge(introspection_system.types)
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
# @param type_name [String]
|
1020
|
+
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
1021
|
+
def get_type(type_name)
|
1022
|
+
own_types[type_name] ||
|
1023
|
+
introspection_system.types[type_name] ||
|
1024
|
+
find_inherited_value(:types, EMPTY_HASH)[type_name]
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
# @api private
|
1028
|
+
attr_writer :connections
|
1029
|
+
|
1030
|
+
# @return [GraphQL::Pagination::Connections] if installed
|
1031
|
+
def connections
|
1032
|
+
if defined?(@connections)
|
1033
|
+
@connections
|
1034
|
+
else
|
1035
|
+
inherited_connections = find_inherited_value(:connections, nil)
|
1036
|
+
# This schema is part of an inheritance chain which is using new connections,
|
1037
|
+
# make a new instance, so we don't pollute the upstream one.
|
1038
|
+
if inherited_connections
|
1039
|
+
@connections = Pagination::Connections.new(schema: self)
|
1040
|
+
else
|
1041
|
+
nil
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
def new_connections?
|
1047
|
+
!!connections
|
1048
|
+
end
|
1049
|
+
|
814
1050
|
def query(new_query_object = nil)
|
815
1051
|
if new_query_object
|
816
|
-
@query_object
|
1052
|
+
if @query_object
|
1053
|
+
raise GraphQL::Error, "Second definition of `query(...)` (#{new_query_object.inspect}) is invalid, already configured with #{@query_object.inspect}"
|
1054
|
+
else
|
1055
|
+
@query_object = new_query_object
|
1056
|
+
add_type_and_traverse(new_query_object, root: true)
|
1057
|
+
nil
|
1058
|
+
end
|
817
1059
|
else
|
818
|
-
|
819
|
-
query_object.respond_to?(:graphql_definition) ? query_object.graphql_definition : query_object
|
1060
|
+
@query_object || find_inherited_value(:query)
|
820
1061
|
end
|
821
1062
|
end
|
822
1063
|
|
823
1064
|
def mutation(new_mutation_object = nil)
|
824
1065
|
if new_mutation_object
|
825
|
-
@mutation_object
|
1066
|
+
if @mutation_object
|
1067
|
+
raise GraphQL::Error, "Second definition of `mutation(...)` (#{new_mutation_object.inspect}) is invalid, already configured with #{@mutation_object.inspect}"
|
1068
|
+
else
|
1069
|
+
@mutation_object = new_mutation_object
|
1070
|
+
add_type_and_traverse(new_mutation_object, root: true)
|
1071
|
+
nil
|
1072
|
+
end
|
826
1073
|
else
|
827
|
-
|
828
|
-
mutation_object.respond_to?(:graphql_definition) ? mutation_object.graphql_definition : mutation_object
|
1074
|
+
@mutation_object || find_inherited_value(:mutation)
|
829
1075
|
end
|
830
1076
|
end
|
831
1077
|
|
832
1078
|
def subscription(new_subscription_object = nil)
|
833
1079
|
if new_subscription_object
|
834
|
-
@subscription_object
|
1080
|
+
if @subscription_object
|
1081
|
+
raise GraphQL::Error, "Second definition of `subscription(...)` (#{new_subscription_object.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
|
1082
|
+
else
|
1083
|
+
@subscription_object = new_subscription_object
|
1084
|
+
add_subscription_extension_if_necessary
|
1085
|
+
add_type_and_traverse(new_subscription_object, root: true)
|
1086
|
+
nil
|
1087
|
+
end
|
1088
|
+
else
|
1089
|
+
@subscription_object || find_inherited_value(:subscription)
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
|
1093
|
+
# @see [GraphQL::Schema::Warden] Resticted access to root types
|
1094
|
+
# @return [GraphQL::ObjectType, nil]
|
1095
|
+
def root_type_for_operation(operation)
|
1096
|
+
case operation
|
1097
|
+
when "query"
|
1098
|
+
query
|
1099
|
+
when "mutation"
|
1100
|
+
mutation
|
1101
|
+
when "subscription"
|
1102
|
+
subscription
|
1103
|
+
else
|
1104
|
+
raise ArgumentError, "unknown operation type: #{operation}"
|
1105
|
+
end
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
def root_types
|
1109
|
+
@root_types
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
# @param type [Module] The type definition whose possible types you want to see
|
1113
|
+
# @return [Hash<String, Module>] All possible types, if no `type` is given.
|
1114
|
+
# @return [Array<Module>] Possible types for `type`, if it's given.
|
1115
|
+
def possible_types(type = nil, context = GraphQL::Query::NullContext)
|
1116
|
+
if type
|
1117
|
+
# TODO duck-typing `.possible_types` would probably be nicer here
|
1118
|
+
if type.kind.union?
|
1119
|
+
type.possible_types(context: context)
|
1120
|
+
else
|
1121
|
+
stored_possible_types = own_possible_types[type.graphql_name]
|
1122
|
+
visible_possible_types = stored_possible_types.select do |possible_type|
|
1123
|
+
next true unless type.kind.interface?
|
1124
|
+
next true unless possible_type.kind.object?
|
1125
|
+
|
1126
|
+
# Use `.graphql_name` comparison to match legacy vs class-based types.
|
1127
|
+
# When we don't need to support legacy `.define` types, use `.include?(type)` instead.
|
1128
|
+
possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
|
1129
|
+
end if stored_possible_types
|
1130
|
+
visible_possible_types ||
|
1131
|
+
introspection_system.possible_types[type.graphql_name] ||
|
1132
|
+
(
|
1133
|
+
superclass.respond_to?(:possible_types) ?
|
1134
|
+
superclass.possible_types(type, context) :
|
1135
|
+
EMPTY_ARRAY
|
1136
|
+
)
|
1137
|
+
end
|
1138
|
+
else
|
1139
|
+
find_inherited_value(:possible_types, EMPTY_HASH)
|
1140
|
+
.merge(own_possible_types)
|
1141
|
+
.merge(introspection_system.possible_types)
|
1142
|
+
end
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
def union_memberships(type = nil)
|
1146
|
+
if type
|
1147
|
+
own_um = own_union_memberships.fetch(type.graphql_name, EMPTY_ARRAY)
|
1148
|
+
inherited_um = find_inherited_value(:union_memberships, EMPTY_HASH).fetch(type.graphql_name, EMPTY_ARRAY)
|
1149
|
+
own_um + inherited_um
|
1150
|
+
else
|
1151
|
+
joined_um = own_union_memberships.dup
|
1152
|
+
find_inherited_value(:union_memberhips, EMPTY_HASH).each do |k, v|
|
1153
|
+
um = joined_um[k] ||= []
|
1154
|
+
um.concat(v)
|
1155
|
+
end
|
1156
|
+
joined_um
|
1157
|
+
end
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
def references_to(to_type = nil, from: nil)
|
1161
|
+
@own_references_to ||= Hash.new { |h, k| h[k] = [] }
|
1162
|
+
if to_type
|
1163
|
+
if !to_type.is_a?(String)
|
1164
|
+
to_type = to_type.graphql_name
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
if from
|
1168
|
+
@own_references_to[to_type] << from
|
1169
|
+
else
|
1170
|
+
own_refs = @own_references_to[to_type]
|
1171
|
+
inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
|
1172
|
+
own_refs + inherited_refs
|
1173
|
+
end
|
1174
|
+
else
|
1175
|
+
# `@own_references_to` can be quite large for big schemas,
|
1176
|
+
# and generally speaking, we won't inherit any values.
|
1177
|
+
# So optimize the most common case -- don't create a duplicate Hash.
|
1178
|
+
inherited_value = find_inherited_value(:references_to, EMPTY_HASH)
|
1179
|
+
if inherited_value.any?
|
1180
|
+
inherited_value.merge(@own_references_to)
|
1181
|
+
else
|
1182
|
+
@own_references_to
|
1183
|
+
end
|
1184
|
+
end
|
1185
|
+
end
|
1186
|
+
|
1187
|
+
def type_from_ast(ast_node, context: nil)
|
1188
|
+
type_owner = context ? context.warden : self
|
1189
|
+
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
def get_field(type_or_name, field_name)
|
1193
|
+
parent_type = case type_or_name
|
1194
|
+
when LateBoundType
|
1195
|
+
get_type(type_or_name.name)
|
1196
|
+
when String
|
1197
|
+
get_type(type_or_name)
|
1198
|
+
when Module
|
1199
|
+
type_or_name
|
1200
|
+
else
|
1201
|
+
raise ArgumentError, "unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
|
1202
|
+
end
|
1203
|
+
|
1204
|
+
if parent_type.kind.fields? && (field = parent_type.get_field(field_name))
|
1205
|
+
field
|
1206
|
+
elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
|
1207
|
+
entry_point_field
|
1208
|
+
elsif (dynamic_field = introspection_system.dynamic_field(name: field_name))
|
1209
|
+
dynamic_field
|
835
1210
|
else
|
836
|
-
|
837
|
-
subscription_object.respond_to?(:graphql_definition) ? subscription_object.graphql_definition : subscription_object
|
1211
|
+
nil
|
838
1212
|
end
|
839
1213
|
end
|
840
1214
|
|
1215
|
+
def get_fields(type)
|
1216
|
+
type.fields
|
1217
|
+
end
|
1218
|
+
|
841
1219
|
def introspection(new_introspection_namespace = nil)
|
842
1220
|
if new_introspection_namespace
|
843
1221
|
@introspection = new_introspection_namespace
|
1222
|
+
# reset this cached value:
|
1223
|
+
@introspection_system = nil
|
844
1224
|
else
|
845
1225
|
@introspection || find_inherited_value(:introspection)
|
846
1226
|
end
|
847
1227
|
end
|
848
1228
|
|
1229
|
+
def introspection_system
|
1230
|
+
if !@introspection_system
|
1231
|
+
@introspection_system = Schema::IntrospectionSystem.new(self)
|
1232
|
+
@introspection_system.resolve_late_bindings
|
1233
|
+
end
|
1234
|
+
@introspection_system
|
1235
|
+
end
|
1236
|
+
|
849
1237
|
def cursor_encoder(new_encoder = nil)
|
850
1238
|
if new_encoder
|
851
1239
|
@cursor_encoder = new_encoder
|
@@ -885,14 +1273,50 @@ module GraphQL
|
|
885
1273
|
end
|
886
1274
|
end
|
887
1275
|
|
1276
|
+
attr_writer :validate_timeout
|
1277
|
+
|
1278
|
+
def validate_timeout(new_validate_timeout = nil)
|
1279
|
+
if new_validate_timeout
|
1280
|
+
@validate_timeout = new_validate_timeout
|
1281
|
+
elsif defined?(@validate_timeout)
|
1282
|
+
@validate_timeout
|
1283
|
+
else
|
1284
|
+
find_inherited_value(:validate_timeout)
|
1285
|
+
end
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
attr_writer :max_complexity
|
1289
|
+
|
888
1290
|
def max_complexity(max_complexity = nil)
|
889
1291
|
if max_complexity
|
890
1292
|
@max_complexity = max_complexity
|
1293
|
+
elsif defined?(@max_complexity)
|
1294
|
+
@max_complexity
|
891
1295
|
else
|
892
|
-
|
1296
|
+
find_inherited_value(:max_complexity)
|
893
1297
|
end
|
894
1298
|
end
|
895
1299
|
|
1300
|
+
attr_writer :analysis_engine
|
1301
|
+
|
1302
|
+
def analysis_engine
|
1303
|
+
@analysis_engine || find_inherited_value(:analysis_engine, GraphQL::Analysis)
|
1304
|
+
end
|
1305
|
+
|
1306
|
+
def using_ast_analysis?
|
1307
|
+
analysis_engine == GraphQL::Analysis::AST
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
def interpreter?
|
1311
|
+
if defined?(@interpreter)
|
1312
|
+
@interpreter
|
1313
|
+
else
|
1314
|
+
find_inherited_value(:interpreter?, false)
|
1315
|
+
end
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
attr_writer :interpreter
|
1319
|
+
|
896
1320
|
def error_bubbling(new_error_bubbling = nil)
|
897
1321
|
if !new_error_bubbling.nil?
|
898
1322
|
@error_bubbling = new_error_bubbling
|
@@ -901,16 +1325,36 @@ module GraphQL
|
|
901
1325
|
end
|
902
1326
|
end
|
903
1327
|
|
1328
|
+
attr_writer :error_bubbling
|
1329
|
+
|
1330
|
+
attr_writer :max_depth
|
1331
|
+
|
904
1332
|
def max_depth(new_max_depth = nil)
|
905
1333
|
if new_max_depth
|
906
1334
|
@max_depth = new_max_depth
|
1335
|
+
elsif defined?(@max_depth)
|
1336
|
+
@max_depth
|
907
1337
|
else
|
908
|
-
|
1338
|
+
find_inherited_value(:max_depth)
|
909
1339
|
end
|
910
1340
|
end
|
911
1341
|
|
912
1342
|
def disable_introspection_entry_points
|
913
1343
|
@disable_introspection_entry_points = true
|
1344
|
+
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
1345
|
+
@introspection_system = nil
|
1346
|
+
end
|
1347
|
+
|
1348
|
+
def disable_schema_introspection_entry_point
|
1349
|
+
@disable_schema_introspection_entry_point = true
|
1350
|
+
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
1351
|
+
@introspection_system = nil
|
1352
|
+
end
|
1353
|
+
|
1354
|
+
def disable_type_introspection_entry_point
|
1355
|
+
@disable_type_introspection_entry_point = true
|
1356
|
+
# TODO: this clears the cache made in `def types`. But this is not a great solution.
|
1357
|
+
@introspection_system = nil
|
914
1358
|
end
|
915
1359
|
|
916
1360
|
def disable_introspection_entry_points?
|
@@ -921,8 +1365,27 @@ module GraphQL
|
|
921
1365
|
end
|
922
1366
|
end
|
923
1367
|
|
1368
|
+
def disable_schema_introspection_entry_point?
|
1369
|
+
if instance_variable_defined?(:@disable_schema_introspection_entry_point)
|
1370
|
+
@disable_schema_introspection_entry_point
|
1371
|
+
else
|
1372
|
+
find_inherited_value(:disable_schema_introspection_entry_point?, false)
|
1373
|
+
end
|
1374
|
+
end
|
1375
|
+
|
1376
|
+
def disable_type_introspection_entry_point?
|
1377
|
+
if instance_variable_defined?(:@disable_type_introspection_entry_point)
|
1378
|
+
@disable_type_introspection_entry_point
|
1379
|
+
else
|
1380
|
+
find_inherited_value(:disable_type_introspection_entry_point?, false)
|
1381
|
+
end
|
1382
|
+
end
|
1383
|
+
|
924
1384
|
def orphan_types(*new_orphan_types)
|
925
1385
|
if new_orphan_types.any?
|
1386
|
+
new_orphan_types = new_orphan_types.flatten
|
1387
|
+
add_type_and_traverse(new_orphan_types, root: false)
|
1388
|
+
@orphan_types = new_orphan_types
|
926
1389
|
own_orphan_types.concat(new_orphan_types.flatten)
|
927
1390
|
end
|
928
1391
|
|
@@ -951,8 +1414,27 @@ module GraphQL
|
|
951
1414
|
end
|
952
1415
|
end
|
953
1416
|
|
954
|
-
|
955
|
-
|
1417
|
+
# rubocop:disable Lint/DuplicateMethods
|
1418
|
+
module ResolveTypeWithType
|
1419
|
+
def resolve_type(type, obj, ctx)
|
1420
|
+
first_resolved_type, resolved_value = if type.is_a?(Module) && type.respond_to?(:resolve_type)
|
1421
|
+
type.resolve_type(obj, ctx)
|
1422
|
+
else
|
1423
|
+
super
|
1424
|
+
end
|
1425
|
+
|
1426
|
+
after_lazy(first_resolved_type) do |resolved_type|
|
1427
|
+
if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind)) || resolved_type.is_a?(GraphQL::BaseType)
|
1428
|
+
if resolved_value
|
1429
|
+
[resolved_type, resolved_value]
|
1430
|
+
else
|
1431
|
+
resolved_type
|
1432
|
+
end
|
1433
|
+
else
|
1434
|
+
raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
|
1435
|
+
end
|
1436
|
+
end
|
1437
|
+
end
|
956
1438
|
end
|
957
1439
|
|
958
1440
|
def resolve_type(type, obj, ctx)
|
@@ -962,6 +1444,19 @@ module GraphQL
|
|
962
1444
|
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})"
|
963
1445
|
end
|
964
1446
|
end
|
1447
|
+
# rubocop:enable Lint/DuplicateMethods
|
1448
|
+
|
1449
|
+
def inherited(child_class)
|
1450
|
+
if self == GraphQL::Schema
|
1451
|
+
child_class.directives(default_directives.values)
|
1452
|
+
end
|
1453
|
+
child_class.singleton_class.prepend(ResolveTypeWithType)
|
1454
|
+
super
|
1455
|
+
end
|
1456
|
+
|
1457
|
+
def rescues
|
1458
|
+
find_inherited_value(:rescues, EMPTY_HASH).merge(own_rescues)
|
1459
|
+
end
|
965
1460
|
|
966
1461
|
def object_from_id(node_id, ctx)
|
967
1462
|
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(node_id, ctx) must be implemented to load by ID (tried to load from id `#{node_id}`)"
|
@@ -971,12 +1466,12 @@ module GraphQL
|
|
971
1466
|
raise GraphQL::RequiredImplementationMissingError, "#{self.name}.id_from_object(object, type, ctx) must be implemented to create global ids (tried to create an id for `#{object.inspect}`)"
|
972
1467
|
end
|
973
1468
|
|
974
|
-
def visible?(member,
|
975
|
-
|
1469
|
+
def visible?(member, ctx)
|
1470
|
+
member.type_class.visible?(ctx)
|
976
1471
|
end
|
977
1472
|
|
978
|
-
def accessible?(member,
|
979
|
-
|
1473
|
+
def accessible?(member, ctx)
|
1474
|
+
member.type_class.accessible?(ctx)
|
980
1475
|
end
|
981
1476
|
|
982
1477
|
# This hook is called when a client tries to access one or more
|
@@ -1030,15 +1525,28 @@ module GraphQL
|
|
1030
1525
|
DefaultTypeError.call(type_err, ctx)
|
1031
1526
|
end
|
1032
1527
|
|
1528
|
+
# A function to call when {#execute} receives an invalid query string
|
1529
|
+
#
|
1530
|
+
# The default is to add the error to `context.errors`
|
1531
|
+
# @param err [GraphQL::ParseError] The error encountered during parsing
|
1532
|
+
# @param ctx [GraphQL::Query::Context] The context for the query where the error occurred
|
1533
|
+
# @return void
|
1534
|
+
def parse_error(parse_err, ctx)
|
1535
|
+
ctx.errors.push(parse_err)
|
1536
|
+
end
|
1033
1537
|
attr_writer :error_handler
|
1034
1538
|
|
1035
1539
|
# @return [GraphQL::Execution::Errors, Class<GraphQL::Execution::Errors::NullErrorHandler>]
|
1036
1540
|
def error_handler
|
1037
|
-
@error_handler
|
1541
|
+
if defined?(@error_handler)
|
1542
|
+
@error_handler
|
1543
|
+
else
|
1544
|
+
find_inherited_value(:error_handler, GraphQL::Execution::Errors::NullErrorHandler)
|
1545
|
+
end
|
1038
1546
|
end
|
1039
1547
|
|
1040
1548
|
def lazy_resolve(lazy_class, value_method)
|
1041
|
-
|
1549
|
+
lazy_methods.set(lazy_class, value_method)
|
1042
1550
|
end
|
1043
1551
|
|
1044
1552
|
def instrument(instrument_step, instrumenter, options = {})
|
@@ -1051,24 +1559,29 @@ module GraphQL
|
|
1051
1559
|
own_instrumenters[step] << instrumenter
|
1052
1560
|
end
|
1053
1561
|
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1562
|
+
# Add several directives at once
|
1563
|
+
# @param new_directives [Class]
|
1564
|
+
def directives(*new_directives)
|
1565
|
+
if new_directives.any?
|
1566
|
+
new_directives.flatten.each { |d| directive(d) }
|
1057
1567
|
end
|
1058
1568
|
|
1059
1569
|
find_inherited_value(:directives, default_directives).merge(own_directives)
|
1060
1570
|
end
|
1061
1571
|
|
1572
|
+
# Attach a single directive to this schema
|
1573
|
+
# @param new_directive [Class]
|
1062
1574
|
def directive(new_directive)
|
1575
|
+
add_type_and_traverse(new_directive, root: false)
|
1063
1576
|
own_directives[new_directive.graphql_name] = new_directive
|
1064
1577
|
end
|
1065
1578
|
|
1066
1579
|
def default_directives
|
1067
|
-
{
|
1068
|
-
"include" => GraphQL::Directive::
|
1069
|
-
"skip" => GraphQL::Directive::
|
1070
|
-
"deprecated" => GraphQL::Directive::
|
1071
|
-
}
|
1580
|
+
@default_directives ||= {
|
1581
|
+
"include" => GraphQL::Schema::Directive::Include,
|
1582
|
+
"skip" => GraphQL::Schema::Directive::Skip,
|
1583
|
+
"deprecated" => GraphQL::Schema::Directive::Deprecated,
|
1584
|
+
}.freeze
|
1072
1585
|
end
|
1073
1586
|
|
1074
1587
|
def tracer(new_tracer)
|
@@ -1094,7 +1607,8 @@ module GraphQL
|
|
1094
1607
|
if new_middleware
|
1095
1608
|
own_middleware << new_middleware
|
1096
1609
|
else
|
1097
|
-
|
1610
|
+
# TODO make sure this is cached when running a query
|
1611
|
+
MiddlewareChain.new(steps: all_middleware, final_step: GraphQL::Execution::Execute::FieldResolveStep)
|
1098
1612
|
end
|
1099
1613
|
end
|
1100
1614
|
|
@@ -1106,10 +1620,101 @@ module GraphQL
|
|
1106
1620
|
find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
|
1107
1621
|
end
|
1108
1622
|
|
1623
|
+
# Execute a query on itself.
|
1624
|
+
# @see {Query#initialize} for arguments.
|
1625
|
+
# @return [Hash] query result, ready to be serialized as JSON
|
1626
|
+
def execute(query_str = nil, **kwargs)
|
1627
|
+
if query_str
|
1628
|
+
kwargs[:query] = query_str
|
1629
|
+
end
|
1630
|
+
# Some of the query context _should_ be passed to the multiplex, too
|
1631
|
+
multiplex_context = if (ctx = kwargs[:context])
|
1632
|
+
{
|
1633
|
+
backtrace: ctx[:backtrace],
|
1634
|
+
tracers: ctx[:tracers],
|
1635
|
+
}
|
1636
|
+
else
|
1637
|
+
{}
|
1638
|
+
end
|
1639
|
+
# Since we're running one query, don't run a multiplex-level complexity analyzer
|
1640
|
+
all_results = multiplex([kwargs], max_complexity: nil, context: multiplex_context)
|
1641
|
+
all_results[0]
|
1642
|
+
end
|
1643
|
+
|
1644
|
+
# Execute several queries on itself, concurrently.
|
1645
|
+
#
|
1646
|
+
# @example Run several queries at once
|
1647
|
+
# context = { ... }
|
1648
|
+
# queries = [
|
1649
|
+
# { query: params[:query_1], variables: params[:variables_1], context: context },
|
1650
|
+
# { query: params[:query_2], variables: params[:variables_2], context: context },
|
1651
|
+
# ]
|
1652
|
+
# results = MySchema.multiplex(queries)
|
1653
|
+
# render json: {
|
1654
|
+
# result_1: results[0],
|
1655
|
+
# result_2: results[1],
|
1656
|
+
# }
|
1657
|
+
#
|
1658
|
+
# @see {Query#initialize} for query keyword arguments
|
1659
|
+
# @see {Execution::Multiplex#run_queries} for multiplex keyword arguments
|
1660
|
+
# @param queries [Array<Hash>] Keyword arguments for each query
|
1661
|
+
# @param context [Hash] Multiplex-level context
|
1662
|
+
# @return [Array<Hash>] One result for each query in the input
|
1663
|
+
def multiplex(queries, **kwargs)
|
1664
|
+
schema = if interpreter?
|
1665
|
+
self
|
1666
|
+
else
|
1667
|
+
graphql_definition
|
1668
|
+
end
|
1669
|
+
GraphQL::Execution::Multiplex.run_all(schema, queries, **kwargs)
|
1670
|
+
end
|
1671
|
+
|
1672
|
+
def instrumenters
|
1673
|
+
inherited_instrumenters = find_inherited_value(:instrumenters) || Hash.new { |h,k| h[k] = [] }
|
1674
|
+
inherited_instrumenters.merge(own_instrumenters) do |_step, inherited, own|
|
1675
|
+
inherited + own
|
1676
|
+
end
|
1677
|
+
end
|
1678
|
+
|
1679
|
+
# @api private
|
1680
|
+
def add_subscription_extension_if_necessary
|
1681
|
+
if interpreter? && !defined?(@subscription_extension_added) && subscription && self.subscriptions
|
1682
|
+
@subscription_extension_added = true
|
1683
|
+
if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
|
1684
|
+
warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
|
1685
|
+
else
|
1686
|
+
subscription.fields.each do |name, field|
|
1687
|
+
field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
|
1688
|
+
end
|
1689
|
+
end
|
1690
|
+
end
|
1691
|
+
end
|
1692
|
+
|
1693
|
+
def query_stack_error(query, err)
|
1694
|
+
query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
|
1695
|
+
end
|
1696
|
+
|
1109
1697
|
private
|
1110
1698
|
|
1111
|
-
def
|
1112
|
-
@
|
1699
|
+
def lazy_methods
|
1700
|
+
if !defined?(@lazy_methods)
|
1701
|
+
if inherited_map = find_inherited_value(:lazy_methods)
|
1702
|
+
# this isn't _completely_ inherited :S (Things added after `dup` won't work)
|
1703
|
+
@lazy_methods = inherited_map.dup
|
1704
|
+
else
|
1705
|
+
@lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
|
1706
|
+
@lazy_methods.set(GraphQL::Execution::Lazy, :value)
|
1707
|
+
end
|
1708
|
+
end
|
1709
|
+
@lazy_methods
|
1710
|
+
end
|
1711
|
+
|
1712
|
+
def own_types
|
1713
|
+
@own_types ||= {}
|
1714
|
+
end
|
1715
|
+
|
1716
|
+
def non_introspection_types
|
1717
|
+
find_inherited_value(:non_introspection_types, EMPTY_HASH).merge(own_types)
|
1113
1718
|
end
|
1114
1719
|
|
1115
1720
|
def own_plugins
|
@@ -1124,15 +1729,16 @@ module GraphQL
|
|
1124
1729
|
@own_orphan_types ||= []
|
1125
1730
|
end
|
1126
1731
|
|
1127
|
-
def
|
1128
|
-
@
|
1732
|
+
def own_possible_types
|
1733
|
+
@own_possible_types ||= {}
|
1129
1734
|
end
|
1130
1735
|
|
1131
|
-
def
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1736
|
+
def own_union_memberships
|
1737
|
+
@own_union_memberships ||= {}
|
1738
|
+
end
|
1739
|
+
|
1740
|
+
def own_directives
|
1741
|
+
@own_directives ||= {}
|
1136
1742
|
end
|
1137
1743
|
|
1138
1744
|
def own_instrumenters
|
@@ -1159,91 +1765,193 @@ module GraphQL
|
|
1159
1765
|
@own_multiplex_analyzers ||= []
|
1160
1766
|
end
|
1161
1767
|
|
1162
|
-
#
|
1163
|
-
#
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
member = if member.respond_to?(:metadata) && member.metadata
|
1169
|
-
member.metadata[:type_class] || member
|
1170
|
-
else
|
1171
|
-
member
|
1172
|
-
end
|
1173
|
-
|
1174
|
-
if member.respond_to?(:relay_node_type) && (t = member.relay_node_type)
|
1175
|
-
member = t
|
1768
|
+
# @param t [Module, Array<Module>]
|
1769
|
+
# @return [void]
|
1770
|
+
def add_type_and_traverse(t, root:)
|
1771
|
+
if root
|
1772
|
+
@root_types ||= []
|
1773
|
+
@root_types << t
|
1176
1774
|
end
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1775
|
+
late_types = []
|
1776
|
+
new_types = Array(t)
|
1777
|
+
new_types.each { |t| add_type(t, owner: nil, late_types: late_types, path: [t.graphql_name]) }
|
1778
|
+
missed_late_types = 0
|
1779
|
+
while (late_type_vals = late_types.shift)
|
1780
|
+
type_owner, lt = late_type_vals
|
1781
|
+
if lt.is_a?(String)
|
1782
|
+
type = Member::BuildType.constantize(lt)
|
1783
|
+
# Reset the counter, since we might succeed next go-round
|
1784
|
+
missed_late_types = 0
|
1785
|
+
update_type_owner(type_owner, type)
|
1786
|
+
add_type(type, owner: type_owner, late_types: late_types, path: [type.graphql_name])
|
1787
|
+
elsif lt.is_a?(LateBoundType)
|
1788
|
+
if (type = get_type(lt.graphql_name))
|
1789
|
+
# Reset the counter, since we might succeed next go-round
|
1790
|
+
missed_late_types = 0
|
1791
|
+
update_type_owner(type_owner, type)
|
1792
|
+
add_type(type, owner: type_owner, late_types: late_types, path: [type.graphql_name])
|
1793
|
+
else
|
1794
|
+
missed_late_types += 1
|
1795
|
+
# Add it back to the list, maybe we'll be able to resolve it later.
|
1796
|
+
late_types << [type_owner, lt]
|
1797
|
+
if missed_late_types == late_types.size
|
1798
|
+
# We've looked at all of them and haven't resolved one.
|
1799
|
+
raise UnresolvedLateBoundTypeError.new(type: lt)
|
1800
|
+
else
|
1801
|
+
# Try the next one
|
1802
|
+
end
|
1803
|
+
end
|
1804
|
+
else
|
1805
|
+
raise ArgumentError, "Unexpected late type: #{lt.inspect}"
|
1806
|
+
end
|
1182
1807
|
end
|
1808
|
+
nil
|
1183
1809
|
end
|
1184
|
-
end
|
1185
|
-
|
1186
1810
|
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1811
|
+
def update_type_owner(owner, type)
|
1812
|
+
case owner
|
1813
|
+
when Class
|
1814
|
+
if owner.kind.union?
|
1815
|
+
# It's a union with possible_types
|
1816
|
+
# Replace the item by class name
|
1817
|
+
owner.assign_type_membership_object_type(type)
|
1818
|
+
own_possible_types[owner.graphql_name] = owner.possible_types
|
1819
|
+
elsif type.kind.interface? && owner.kind.object?
|
1820
|
+
new_interfaces = []
|
1821
|
+
owner.interfaces.each do |int_t|
|
1822
|
+
if int_t.is_a?(String) && int_t == type.graphql_name
|
1823
|
+
new_interfaces << type
|
1824
|
+
elsif int_t.is_a?(LateBoundType) && int_t.graphql_name == type.graphql_name
|
1825
|
+
new_interfaces << type
|
1826
|
+
else
|
1827
|
+
# Don't re-add proper interface definitions,
|
1828
|
+
# they were probably already added, maybe with options.
|
1829
|
+
end
|
1830
|
+
end
|
1831
|
+
owner.implements(*new_interfaces)
|
1832
|
+
new_interfaces.each do |int|
|
1833
|
+
pt = own_possible_types[int.graphql_name] ||= []
|
1834
|
+
if !pt.include?(owner)
|
1835
|
+
pt << owner
|
1836
|
+
end
|
1837
|
+
end
|
1838
|
+
end
|
1192
1839
|
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1840
|
+
when nil
|
1841
|
+
# It's a root type
|
1842
|
+
own_types[type.graphql_name] = type
|
1843
|
+
when GraphQL::Schema::Field, GraphQL::Schema::Argument
|
1844
|
+
orig_type = owner.type
|
1845
|
+
# Apply list/non-null wrapper as needed
|
1846
|
+
if orig_type.respond_to?(:of_type)
|
1847
|
+
transforms = []
|
1848
|
+
while (orig_type.respond_to?(:of_type))
|
1849
|
+
if orig_type.kind.non_null?
|
1850
|
+
transforms << :to_non_null_type
|
1851
|
+
elsif orig_type.kind.list?
|
1852
|
+
transforms << :to_list_type
|
1853
|
+
else
|
1854
|
+
raise "Invariant: :of_type isn't non-null or list"
|
1855
|
+
end
|
1856
|
+
orig_type = orig_type.of_type
|
1857
|
+
end
|
1858
|
+
transforms.reverse_each { |t| type = type.public_send(t) }
|
1859
|
+
end
|
1860
|
+
owner.type = type
|
1861
|
+
else
|
1862
|
+
raise "Unexpected update: #{owner.inspect} #{type.inspect}"
|
1198
1863
|
end
|
1199
1864
|
end
|
1200
|
-
end
|
1201
1865
|
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
result = sync_lazy(value)
|
1210
|
-
# The returned result might also be lazy, so check it, too
|
1211
|
-
after_lazy(result) do |final_result|
|
1212
|
-
yield(final_result) if block_given?
|
1866
|
+
def add_type(type, owner:, late_types:, path:)
|
1867
|
+
if type.respond_to?(:metadata) && type.metadata.is_a?(Hash)
|
1868
|
+
type_class = type.metadata[:type_class]
|
1869
|
+
if type_class.nil?
|
1870
|
+
raise ArgumentError, "Can't add legacy type: #{type} (#{type.class})"
|
1871
|
+
else
|
1872
|
+
type = type_class
|
1213
1873
|
end
|
1874
|
+
elsif type.is_a?(String) || type.is_a?(GraphQL::Schema::LateBoundType)
|
1875
|
+
late_types << [owner, type]
|
1876
|
+
return
|
1214
1877
|
end
|
1215
|
-
else
|
1216
|
-
yield(value) if block_given?
|
1217
|
-
end
|
1218
|
-
end
|
1219
1878
|
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
def self.sync_lazy(value)
|
1225
|
-
if block_given?
|
1226
|
-
# This was already hit by the instance, just give it back
|
1227
|
-
yield(value)
|
1228
|
-
else
|
1229
|
-
# This was called directly on the class, hit the instance
|
1230
|
-
# which has the lazy method map
|
1231
|
-
self.graphql_definition.sync_lazy(value)
|
1232
|
-
end
|
1233
|
-
end
|
1879
|
+
if owner.is_a?(Class) && owner < GraphQL::Schema::Union
|
1880
|
+
um = own_union_memberships[type.graphql_name] ||= []
|
1881
|
+
um << owner
|
1882
|
+
end
|
1234
1883
|
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1884
|
+
if (prev_type = own_types[type.graphql_name])
|
1885
|
+
if prev_type != type
|
1886
|
+
raise DuplicateTypeNamesError.new(
|
1887
|
+
type_name: type.graphql_name,
|
1888
|
+
first_definition: prev_type,
|
1889
|
+
second_definition: type,
|
1890
|
+
path: path,
|
1891
|
+
)
|
1892
|
+
else
|
1893
|
+
# This type was already added
|
1894
|
+
end
|
1895
|
+
elsif type.is_a?(Class) && type < GraphQL::Schema::Directive
|
1896
|
+
type.arguments.each do |name, arg|
|
1897
|
+
arg_type = arg.type.unwrap
|
1898
|
+
references_to(arg_type, from: arg)
|
1899
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path + [name])
|
1900
|
+
end
|
1243
1901
|
else
|
1244
|
-
|
1902
|
+
own_types[type.graphql_name] = type
|
1903
|
+
if type.kind.fields?
|
1904
|
+
type.fields.each do |name, field|
|
1905
|
+
field_type = field.type.unwrap
|
1906
|
+
references_to(field_type, from: field)
|
1907
|
+
field_path = path + [name]
|
1908
|
+
add_type(field_type, owner: field, late_types: late_types, path: field_path)
|
1909
|
+
field.arguments.each do |arg_name, arg|
|
1910
|
+
arg_type = arg.type.unwrap
|
1911
|
+
references_to(arg_type, from: arg)
|
1912
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: field_path + [arg_name])
|
1913
|
+
end
|
1914
|
+
end
|
1915
|
+
end
|
1916
|
+
if type.kind.input_object?
|
1917
|
+
type.arguments.each do |arg_name, arg|
|
1918
|
+
arg_type = arg.type.unwrap
|
1919
|
+
references_to(arg_type, from: arg)
|
1920
|
+
add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg_name])
|
1921
|
+
end
|
1922
|
+
end
|
1923
|
+
if type.kind.union?
|
1924
|
+
own_possible_types[type.graphql_name] = type.possible_types
|
1925
|
+
type.possible_types.each do |t|
|
1926
|
+
add_type(t, owner: type, late_types: late_types, path: path + ["possible_types"])
|
1927
|
+
end
|
1928
|
+
end
|
1929
|
+
if type.kind.interface?
|
1930
|
+
type.orphan_types.each do |t|
|
1931
|
+
add_type(t, owner: type, late_types: late_types, path: path + ["orphan_types"])
|
1932
|
+
end
|
1933
|
+
end
|
1934
|
+
if type.kind.object?
|
1935
|
+
own_possible_types[type.graphql_name] = [type]
|
1936
|
+
type.interface_type_memberships.each do |interface_type_membership|
|
1937
|
+
case interface_type_membership
|
1938
|
+
when Schema::TypeMembership
|
1939
|
+
interface_type = interface_type_membership.abstract_type
|
1940
|
+
# We can get these now; we'll have to get late-bound types later
|
1941
|
+
if interface_type.is_a?(Module)
|
1942
|
+
implementers = own_possible_types[interface_type.graphql_name] ||= []
|
1943
|
+
implementers << type
|
1944
|
+
end
|
1945
|
+
when String, Schema::LateBoundType
|
1946
|
+
interface_type = interface_type_membership
|
1947
|
+
else
|
1948
|
+
raise ArgumentError, "Invariant: unexpected type membership for #{type.graphql_name}: #{interface_type_membership.class} (#{interface_type_membership.inspect})"
|
1949
|
+
end
|
1950
|
+
add_type(interface_type, owner: type, late_types: late_types, path: path + ["implements"])
|
1951
|
+
end
|
1952
|
+
end
|
1245
1953
|
end
|
1246
|
-
|
1954
|
+
end
|
1247
1955
|
end
|
1248
1956
|
|
1249
1957
|
protected
|