graphql 2.0.31 → 2.5.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +49 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +8 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +5 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +263 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +95 -1
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +161 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +112 -0
- data/lib/graphql/dataloader/null_dataloader.rb +51 -10
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +35 -12
- data/lib/graphql/dataloader.rb +224 -149
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +23 -25
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
- data/lib/graphql/execution/interpreter/runtime.rb +363 -434
- data/lib/graphql/execution/interpreter.rb +91 -164
- data/lib/graphql/execution/lookahead.rb +105 -31
- data/lib/graphql/execution/multiplex.rb +6 -5
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +8 -11
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +20 -17
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +90 -61
- data/lib/graphql/language/lexer.rb +319 -193
- data/lib/graphql/language/nodes.rb +139 -77
- data/lib/graphql/language/parser.rb +807 -1985
- data/lib/graphql/language/printer.rb +324 -151
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +171 -0
- data/lib/graphql/language/visitor.rb +62 -119
- data/lib/graphql/language.rb +71 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +28 -1
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +81 -144
- data/lib/graphql/query/null_context.rb +7 -16
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +4 -4
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +126 -81
- data/lib/graphql/railtie.rb +16 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +26 -13
- data/lib/graphql/schema/always_visible.rb +7 -2
- data/lib/graphql/schema/argument.rb +73 -14
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +123 -66
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive.rb +55 -3
- data/lib/graphql/schema/enum.rb +110 -27
- data/lib/graphql/schema/enum_value.rb +11 -3
- data/lib/graphql/schema/field/connection_extension.rb +2 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +173 -119
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +123 -65
- data/lib/graphql/schema/interface.rb +34 -16
- data/lib/graphql/schema/introspection_system.rb +8 -17
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/list.rb +3 -3
- data/lib/graphql/schema/loader.rb +3 -4
- data/lib/graphql/schema/member/base_dsl_methods.rb +17 -1
- data/lib/graphql/schema/member/has_arguments.rb +132 -100
- data/lib/graphql/schema/member/has_dataloader.rb +62 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +5 -5
- data/lib/graphql/schema/member/has_fields.rb +111 -16
- data/lib/graphql/schema/member/has_interfaces.rb +27 -13
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +18 -5
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +33 -8
- data/lib/graphql/schema/printer.rb +9 -7
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
- data/lib/graphql/schema/resolver.rb +45 -31
- data/lib/graphql/schema/scalar.rb +4 -9
- data/lib/graphql/schema/subscription.rb +63 -10
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/union.rb +2 -2
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +92 -11
- data/lib/graphql/schema/validator.rb +3 -1
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +275 -103
- data/lib/graphql/schema.rb +924 -210
- data/lib/graphql/static_validation/all_rules.rb +3 -3
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/literal_validator.rb +6 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +21 -5
- data/lib/graphql/static_validation/validator.rb +9 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +21 -4
- data/lib/graphql/subscriptions/serialize.rb +3 -1
- data/lib/graphql/subscriptions.rb +21 -17
- data/lib/graphql/testing/helpers.rb +161 -0
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +3 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +11 -3
- data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
- data/lib/graphql/tracing/appsignal_trace.rb +32 -55
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +46 -158
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +141 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +184 -34
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +818 -0
- data/lib/graphql/tracing/platform_trace.rb +5 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
- data/lib/graphql/tracing/prometheus_trace.rb +72 -68
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -55
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +82 -0
- data/lib/graphql/tracing/statsd_trace.rb +33 -41
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +112 -1
- data/lib/graphql/tracing.rb +31 -28
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +43 -3
- data/lib/graphql/types/relay/edge_behaviors.rb +18 -1
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/types.rb +18 -10
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +68 -54
- data/readme.md +12 -2
- metadata +220 -40
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/trace.rb +0 -96
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
|
@@ -19,7 +19,15 @@ module GraphQL
|
|
|
19
19
|
attr_reader :items
|
|
20
20
|
|
|
21
21
|
# @return [GraphQL::Query::Context]
|
|
22
|
-
|
|
22
|
+
attr_reader :context
|
|
23
|
+
|
|
24
|
+
def context=(new_ctx)
|
|
25
|
+
@context = new_ctx
|
|
26
|
+
if @was_authorized_by_scope_items.nil?
|
|
27
|
+
@was_authorized_by_scope_items = detect_was_authorized_by_scope_items
|
|
28
|
+
end
|
|
29
|
+
@context
|
|
30
|
+
end
|
|
23
31
|
|
|
24
32
|
# @return [Object] the object this collection belongs to
|
|
25
33
|
attr_accessor :parent
|
|
@@ -83,6 +91,11 @@ module GraphQL
|
|
|
83
91
|
else
|
|
84
92
|
default_page_size
|
|
85
93
|
end
|
|
94
|
+
@was_authorized_by_scope_items = detect_was_authorized_by_scope_items
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def was_authorized_by_scope_items?
|
|
98
|
+
@was_authorized_by_scope_items
|
|
86
99
|
end
|
|
87
100
|
|
|
88
101
|
def max_page_size=(new_value)
|
|
@@ -208,6 +221,16 @@ module GraphQL
|
|
|
208
221
|
|
|
209
222
|
private
|
|
210
223
|
|
|
224
|
+
def detect_was_authorized_by_scope_items
|
|
225
|
+
if @context &&
|
|
226
|
+
(current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
227
|
+
(query_runtime_state = current_runtime_state[@context.query])
|
|
228
|
+
query_runtime_state.was_authorized_by_scope_items
|
|
229
|
+
else
|
|
230
|
+
nil
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
211
234
|
# @param argument [nil, Integer] `first` or `last`, as provided by the client
|
|
212
235
|
# @param max_page_size [nil, Integer]
|
|
213
236
|
# @return [nil, Integer] `nil` if the input was `nil`, otherwise a value between `0` and `max_page_size`
|
|
@@ -247,6 +270,10 @@ module GraphQL
|
|
|
247
270
|
def cursor
|
|
248
271
|
@cursor ||= @connection.cursor_for(@node)
|
|
249
272
|
end
|
|
273
|
+
|
|
274
|
+
def was_authorized_by_scope_items?
|
|
275
|
+
@connection.was_authorized_by_scope_items?
|
|
276
|
+
end
|
|
250
277
|
end
|
|
251
278
|
end
|
|
252
279
|
end
|
|
@@ -13,8 +13,7 @@ module GraphQL
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def relation_count(relation)
|
|
16
|
-
|
|
17
|
-
relation.to_a.count
|
|
16
|
+
relation.all.count(relation.options.slice(:limit, :skip))
|
|
18
17
|
end
|
|
19
18
|
|
|
20
19
|
def null_relation(relation)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
class Query
|
|
4
|
+
class Context
|
|
5
|
+
class ScopedContext
|
|
6
|
+
def initialize(query_context)
|
|
7
|
+
@query_context = query_context
|
|
8
|
+
@scoped_contexts = nil
|
|
9
|
+
@all_keys = nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def merged_context
|
|
13
|
+
if @scoped_contexts.nil?
|
|
14
|
+
GraphQL::EmptyObjects::EMPTY_HASH
|
|
15
|
+
else
|
|
16
|
+
merged_ctx = {}
|
|
17
|
+
each_present_path_ctx do |path_ctx|
|
|
18
|
+
merged_ctx = path_ctx.merge(merged_ctx)
|
|
19
|
+
end
|
|
20
|
+
merged_ctx
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def merge!(hash, at: current_path)
|
|
25
|
+
@all_keys ||= Set.new
|
|
26
|
+
@all_keys.merge(hash.keys)
|
|
27
|
+
ctx = @scoped_contexts ||= {}
|
|
28
|
+
at.each do |path_part|
|
|
29
|
+
ctx = ctx[path_part] ||= { parent: ctx }
|
|
30
|
+
end
|
|
31
|
+
this_scoped_ctx = ctx[:scoped_context] ||= {}
|
|
32
|
+
this_scoped_ctx.merge!(hash)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def key?(key)
|
|
36
|
+
if @all_keys && @all_keys.include?(key)
|
|
37
|
+
each_present_path_ctx do |path_ctx|
|
|
38
|
+
if path_ctx.key?(key)
|
|
39
|
+
return true
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def [](key)
|
|
47
|
+
each_present_path_ctx do |path_ctx|
|
|
48
|
+
if path_ctx.key?(key)
|
|
49
|
+
return path_ctx[key]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def current_path
|
|
56
|
+
@query_context.current_path || GraphQL::EmptyObjects::EMPTY_ARRAY
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def dig(key, *other_keys)
|
|
60
|
+
each_present_path_ctx do |path_ctx|
|
|
61
|
+
if path_ctx.key?(key)
|
|
62
|
+
found_value = path_ctx[key]
|
|
63
|
+
if !other_keys.empty?
|
|
64
|
+
return found_value.dig(*other_keys)
|
|
65
|
+
else
|
|
66
|
+
return found_value
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
# Start at the current location,
|
|
76
|
+
# but look up the tree for previously-assigned scoped values
|
|
77
|
+
def each_present_path_ctx
|
|
78
|
+
ctx = @scoped_contexts
|
|
79
|
+
if ctx.nil?
|
|
80
|
+
# no-op
|
|
81
|
+
else
|
|
82
|
+
current_path.each do |path_part|
|
|
83
|
+
if ctx.key?(path_part)
|
|
84
|
+
ctx = ctx[path_part]
|
|
85
|
+
else
|
|
86
|
+
break
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
while ctx
|
|
91
|
+
if (scoped_ctx = ctx[:scoped_context])
|
|
92
|
+
yield(scoped_ctx)
|
|
93
|
+
end
|
|
94
|
+
ctx = ctx[:parent]
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -1,39 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module GraphQL
|
|
3
4
|
class Query
|
|
4
5
|
# Expose some query-specific info to field resolve functions.
|
|
5
6
|
# It delegates `[]` to the hash that's passed to `GraphQL::Query#initialize`.
|
|
6
7
|
class Context
|
|
7
|
-
module SharedMethods
|
|
8
|
-
# Return this value to tell the runtime
|
|
9
|
-
# to exclude this field from the response altogether
|
|
10
|
-
def skip
|
|
11
|
-
GraphQL::Execution::SKIP
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# Add error at query-level.
|
|
15
|
-
# @param error [GraphQL::ExecutionError] an execution error
|
|
16
|
-
# @return [void]
|
|
17
|
-
def add_error(error)
|
|
18
|
-
if !error.is_a?(ExecutionError)
|
|
19
|
-
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
|
20
|
-
end
|
|
21
|
-
errors << error
|
|
22
|
-
nil
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# @example Print the GraphQL backtrace during field resolution
|
|
26
|
-
# puts ctx.backtrace
|
|
27
|
-
#
|
|
28
|
-
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
|
29
|
-
def backtrace
|
|
30
|
-
GraphQL::Backtrace.new(self)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def execution_errors
|
|
34
|
-
@execution_errors ||= ExecutionErrors.new(self)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
8
|
|
|
38
9
|
class ExecutionErrors
|
|
39
10
|
def initialize(ctx)
|
|
@@ -57,7 +28,6 @@ module GraphQL
|
|
|
57
28
|
alias :push :add
|
|
58
29
|
end
|
|
59
30
|
|
|
60
|
-
include SharedMethods
|
|
61
31
|
extend Forwardable
|
|
62
32
|
|
|
63
33
|
# @return [Array<GraphQL::ExecutionError>] errors returned during execution
|
|
@@ -69,125 +39,21 @@ module GraphQL
|
|
|
69
39
|
# @return [GraphQL::Schema]
|
|
70
40
|
attr_reader :schema
|
|
71
41
|
|
|
72
|
-
# @return [Array<String, Integer>] The current position in the result
|
|
73
|
-
attr_reader :path
|
|
74
|
-
|
|
75
42
|
# Make a new context which delegates key lookup to `values`
|
|
76
43
|
# @param query [GraphQL::Query] the query who owns this context
|
|
77
44
|
# @param values [Hash] A hash of arbitrary values which will be accessible at query-time
|
|
78
|
-
def initialize(query:, schema: query.schema, values
|
|
45
|
+
def initialize(query:, schema: query.schema, values:)
|
|
79
46
|
@query = query
|
|
80
47
|
@schema = schema
|
|
81
48
|
@provided_values = values || {}
|
|
82
|
-
@object = object
|
|
83
49
|
# Namespaced storage, where user-provided values are in `nil` namespace:
|
|
84
50
|
@storage = Hash.new { |h, k| h[k] = {} }
|
|
85
51
|
@storage[nil] = @provided_values
|
|
86
52
|
@errors = []
|
|
87
|
-
@path = []
|
|
88
|
-
@value = nil
|
|
89
|
-
@context = self # for SharedMethods TODO delete sharedmethods
|
|
90
53
|
@scoped_context = ScopedContext.new(self)
|
|
91
54
|
end
|
|
92
55
|
|
|
93
|
-
|
|
94
|
-
NO_PATH = GraphQL::EmptyObjects::EMPTY_ARRAY
|
|
95
|
-
NO_CONTEXT = GraphQL::EmptyObjects::EMPTY_HASH
|
|
96
|
-
|
|
97
|
-
def initialize(query_context)
|
|
98
|
-
@query_context = query_context
|
|
99
|
-
@scoped_contexts = nil
|
|
100
|
-
@all_keys = nil
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def merged_context
|
|
104
|
-
if @scoped_contexts.nil?
|
|
105
|
-
NO_CONTEXT
|
|
106
|
-
else
|
|
107
|
-
merged_ctx = {}
|
|
108
|
-
each_present_path_ctx do |path_ctx|
|
|
109
|
-
merged_ctx = path_ctx.merge(merged_ctx)
|
|
110
|
-
end
|
|
111
|
-
merged_ctx
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def merge!(hash)
|
|
116
|
-
@all_keys ||= Set.new
|
|
117
|
-
@all_keys.merge(hash.keys)
|
|
118
|
-
ctx = @scoped_contexts ||= {}
|
|
119
|
-
current_path.each do |path_part|
|
|
120
|
-
ctx = ctx[path_part] ||= { parent: ctx }
|
|
121
|
-
end
|
|
122
|
-
this_scoped_ctx = ctx[:scoped_context] ||= {}
|
|
123
|
-
this_scoped_ctx.merge!(hash)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def key?(key)
|
|
127
|
-
if @all_keys && @all_keys.include?(key)
|
|
128
|
-
each_present_path_ctx do |path_ctx|
|
|
129
|
-
if path_ctx.key?(key)
|
|
130
|
-
return true
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
false
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def [](key)
|
|
138
|
-
each_present_path_ctx do |path_ctx|
|
|
139
|
-
if path_ctx.key?(key)
|
|
140
|
-
return path_ctx[key]
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
nil
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def current_path
|
|
147
|
-
@query_context.current_path || NO_PATH
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def dig(key, *other_keys)
|
|
151
|
-
each_present_path_ctx do |path_ctx|
|
|
152
|
-
if path_ctx.key?(key)
|
|
153
|
-
found_value = path_ctx[key]
|
|
154
|
-
if other_keys.any?
|
|
155
|
-
return found_value.dig(*other_keys)
|
|
156
|
-
else
|
|
157
|
-
return found_value
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
nil
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
private
|
|
165
|
-
|
|
166
|
-
# Start at the current location,
|
|
167
|
-
# but look up the tree for previously-assigned scoped values
|
|
168
|
-
def each_present_path_ctx
|
|
169
|
-
ctx = @scoped_contexts
|
|
170
|
-
if ctx.nil?
|
|
171
|
-
# no-op
|
|
172
|
-
else
|
|
173
|
-
current_path.each do |path_part|
|
|
174
|
-
if ctx.key?(path_part)
|
|
175
|
-
ctx = ctx[path_part]
|
|
176
|
-
else
|
|
177
|
-
break
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
while ctx
|
|
182
|
-
if (scoped_ctx = ctx[:scoped_context])
|
|
183
|
-
yield(scoped_ctx)
|
|
184
|
-
end
|
|
185
|
-
ctx = ctx[:parent]
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
56
|
+
# Modify this hash to return extensions to client.
|
|
191
57
|
# @return [Hash] A hash that will be added verbatim to the result hash, as `"extensions" => { ... }`
|
|
192
58
|
def response_extensions
|
|
193
59
|
namespace(:__query_result_extensions__)
|
|
@@ -210,9 +76,15 @@ module GraphQL
|
|
|
210
76
|
@provided_values[key] = value
|
|
211
77
|
end
|
|
212
78
|
|
|
213
|
-
def_delegators :@query, :trace
|
|
79
|
+
def_delegators :@query, :trace
|
|
80
|
+
|
|
81
|
+
def types
|
|
82
|
+
@types ||= @query.types
|
|
83
|
+
end
|
|
214
84
|
|
|
215
|
-
|
|
85
|
+
attr_writer :types
|
|
86
|
+
|
|
87
|
+
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path]).freeze
|
|
216
88
|
# @!method []=(key, value)
|
|
217
89
|
# Reassign `key` to the hash passed to {Schema#execute} as `context:`
|
|
218
90
|
|
|
@@ -226,7 +98,7 @@ module GraphQL
|
|
|
226
98
|
if key == :current_path
|
|
227
99
|
current_path
|
|
228
100
|
else
|
|
229
|
-
(current_runtime_state =
|
|
101
|
+
(current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
230
102
|
(query_runtime_state = current_runtime_state[@query]) &&
|
|
231
103
|
(query_runtime_state.public_send(key))
|
|
232
104
|
end
|
|
@@ -236,8 +108,37 @@ module GraphQL
|
|
|
236
108
|
end
|
|
237
109
|
end
|
|
238
110
|
|
|
111
|
+
# Return this value to tell the runtime
|
|
112
|
+
# to exclude this field from the response altogether
|
|
113
|
+
def skip
|
|
114
|
+
GraphQL::Execution::SKIP
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Add error at query-level.
|
|
118
|
+
# @param error [GraphQL::ExecutionError] an execution error
|
|
119
|
+
# @return [void]
|
|
120
|
+
def add_error(error)
|
|
121
|
+
if !error.is_a?(ExecutionError)
|
|
122
|
+
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
|
123
|
+
end
|
|
124
|
+
errors << error
|
|
125
|
+
nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# @example Print the GraphQL backtrace during field resolution
|
|
129
|
+
# puts ctx.backtrace
|
|
130
|
+
#
|
|
131
|
+
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
|
132
|
+
def backtrace
|
|
133
|
+
GraphQL::Backtrace.new(self)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def execution_errors
|
|
137
|
+
@execution_errors ||= ExecutionErrors.new(self)
|
|
138
|
+
end
|
|
139
|
+
|
|
239
140
|
def current_path
|
|
240
|
-
current_runtime_state =
|
|
141
|
+
current_runtime_state = Fiber[:__graphql_runtime_info]
|
|
241
142
|
query_runtime_state = current_runtime_state && current_runtime_state[@query]
|
|
242
143
|
|
|
243
144
|
path = query_runtime_state &&
|
|
@@ -262,7 +163,7 @@ module GraphQL
|
|
|
262
163
|
|
|
263
164
|
def fetch(key, default = UNSPECIFIED_FETCH_DEFAULT)
|
|
264
165
|
if RUNTIME_METADATA_KEYS.include?(key)
|
|
265
|
-
(runtime =
|
|
166
|
+
(runtime = Fiber[:__graphql_runtime_info]) &&
|
|
266
167
|
(query_runtime_state = runtime[@query]) &&
|
|
267
168
|
(query_runtime_state.public_send(key))
|
|
268
169
|
elsif @scoped_context.key?(key)
|
|
@@ -280,7 +181,7 @@ module GraphQL
|
|
|
280
181
|
|
|
281
182
|
def dig(key, *other_keys)
|
|
282
183
|
if RUNTIME_METADATA_KEYS.include?(key)
|
|
283
|
-
(current_runtime_state =
|
|
184
|
+
(current_runtime_state = Fiber[:__graphql_runtime_info]) &&
|
|
284
185
|
(query_runtime_state = current_runtime_state[@query]) &&
|
|
285
186
|
(obj = query_runtime_state.public_send(key)) &&
|
|
286
187
|
if other_keys.empty?
|
|
@@ -333,8 +234,12 @@ module GraphQL
|
|
|
333
234
|
@storage.key?(ns)
|
|
334
235
|
end
|
|
335
236
|
|
|
237
|
+
def logger
|
|
238
|
+
@query && @query.logger
|
|
239
|
+
end
|
|
240
|
+
|
|
336
241
|
def inspect
|
|
337
|
-
"
|
|
242
|
+
"#<#{self.class} ...>"
|
|
338
243
|
end
|
|
339
244
|
|
|
340
245
|
def scoped_merge!(hash)
|
|
@@ -345,6 +250,38 @@ module GraphQL
|
|
|
345
250
|
scoped_merge!(key => value)
|
|
346
251
|
nil
|
|
347
252
|
end
|
|
253
|
+
|
|
254
|
+
# Use this when you need to do a scoped set _inside_ a lazy-loaded (or batch-loaded)
|
|
255
|
+
# block of code.
|
|
256
|
+
#
|
|
257
|
+
# @example using scoped context inside a promise
|
|
258
|
+
# scoped_ctx = context.scoped
|
|
259
|
+
# SomeBatchLoader.load(...).then do |thing|
|
|
260
|
+
# # use a scoped_ctx which was created _before_ dataloading:
|
|
261
|
+
# scoped_ctx.set!(:thing, thing)
|
|
262
|
+
# end
|
|
263
|
+
# @return [Context::Scoped]
|
|
264
|
+
def scoped
|
|
265
|
+
Scoped.new(@scoped_context, current_path)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
class Scoped
|
|
269
|
+
def initialize(scoped_context, path)
|
|
270
|
+
@path = path
|
|
271
|
+
@scoped_context = scoped_context
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def merge!(hash)
|
|
275
|
+
@scoped_context.merge!(hash, at: @path)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def set!(key, value)
|
|
279
|
+
@scoped_context.merge!({ key => value }, at: @path)
|
|
280
|
+
nil
|
|
281
|
+
end
|
|
282
|
+
end
|
|
348
283
|
end
|
|
349
284
|
end
|
|
350
285
|
end
|
|
286
|
+
|
|
287
|
+
require "graphql/query/context/scoped_context"
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
require "graphql/query/context"
|
|
2
3
|
module GraphQL
|
|
3
4
|
class Query
|
|
4
5
|
# This object can be `ctx` in places where there is no query
|
|
5
|
-
class NullContext
|
|
6
|
+
class NullContext < Context
|
|
7
|
+
include Singleton
|
|
8
|
+
|
|
6
9
|
class NullQuery
|
|
7
10
|
def after_lazy(value)
|
|
8
11
|
yield(value)
|
|
@@ -15,27 +18,15 @@ module GraphQL
|
|
|
15
18
|
extend Forwardable
|
|
16
19
|
|
|
17
20
|
attr_reader :schema, :query, :warden, :dataloader
|
|
18
|
-
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key
|
|
21
|
+
def_delegators GraphQL::EmptyObjects::EMPTY_HASH, :[], :fetch, :dig, :key?, :to_h
|
|
19
22
|
|
|
20
23
|
def initialize
|
|
21
24
|
@query = NullQuery.new
|
|
22
25
|
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
|
23
26
|
@schema = NullSchema
|
|
24
27
|
@warden = Schema::Warden::NullWarden.new(context: self, schema: @schema)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def interpreter?
|
|
28
|
-
true
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
class << self
|
|
32
|
-
extend Forwardable
|
|
33
|
-
|
|
34
|
-
def instance
|
|
35
|
-
@instance ||= self.new
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader, :[], :fetch, :dig, :key?
|
|
28
|
+
@types = @warden.visibility_profile
|
|
29
|
+
freeze
|
|
39
30
|
end
|
|
40
31
|
end
|
|
41
32
|
end
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
class Query
|
|
4
|
+
# This class is _like_ a {GraphQL::Query}, except it can run on an arbitrary path within a query string.
|
|
5
|
+
#
|
|
6
|
+
# It depends on a "parent" {Query}.
|
|
7
|
+
#
|
|
8
|
+
# During execution, it calls query-related tracing hooks but passes itself as `query:`.
|
|
9
|
+
#
|
|
10
|
+
# The {Partial} will use your {Schema.resolve_type} hook to find the right GraphQL type to use for
|
|
11
|
+
# `object` in some cases.
|
|
12
|
+
#
|
|
13
|
+
# @see Query#run_partials Run via {Query#run_partials}
|
|
14
|
+
class Partial
|
|
15
|
+
include Query::Runnable
|
|
16
|
+
|
|
17
|
+
# @param path [Array<String, Integer>] A path in `query.query_string` to start executing from
|
|
18
|
+
# @param object [Object] A starting object for execution
|
|
19
|
+
# @param query [GraphQL::Query] A full query instance that this partial is based on. Caches are shared.
|
|
20
|
+
# @param context [Hash] Extra context values to merge into `query.context`, if provided
|
|
21
|
+
# @param fragment_node [GraphQL::Language::Nodes::InlineFragment, GraphQL::Language::Nodes::FragmentDefinition]
|
|
22
|
+
def initialize(path: nil, object:, query:, context: nil, fragment_node: nil, type: nil)
|
|
23
|
+
@path = path
|
|
24
|
+
@object = object
|
|
25
|
+
@query = query
|
|
26
|
+
@schema = query.schema
|
|
27
|
+
context_vals = @query.context.to_h
|
|
28
|
+
if context
|
|
29
|
+
context_vals = context_vals.merge(context)
|
|
30
|
+
end
|
|
31
|
+
@context = GraphQL::Query::Context.new(query: self, schema: @query.schema, values: context_vals)
|
|
32
|
+
@multiplex = nil
|
|
33
|
+
@result_values = nil
|
|
34
|
+
@result = nil
|
|
35
|
+
|
|
36
|
+
if fragment_node
|
|
37
|
+
@ast_nodes = [fragment_node]
|
|
38
|
+
@root_type = type || raise(ArgumentError, "Pass `type:` when using `node:`")
|
|
39
|
+
# This is only used when `@leaf`
|
|
40
|
+
@field_definition = nil
|
|
41
|
+
elsif path.nil?
|
|
42
|
+
raise ArgumentError, "`path:` is required if `node:` is not given; add `path:`"
|
|
43
|
+
else
|
|
44
|
+
set_type_info_from_path
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
@leaf = @root_type.unwrap.kind.leaf?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def leaf?
|
|
51
|
+
@leaf
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
attr_reader :context, :query, :ast_nodes, :root_type, :object, :field_definition, :path, :schema
|
|
55
|
+
|
|
56
|
+
attr_accessor :multiplex, :result_values
|
|
57
|
+
|
|
58
|
+
class Result < GraphQL::Query::Result
|
|
59
|
+
def path
|
|
60
|
+
@query.path
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [GraphQL::Query::Partial]
|
|
64
|
+
def partial
|
|
65
|
+
@query
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def result
|
|
70
|
+
@result ||= Result.new(query: self, values: result_values)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def current_trace
|
|
74
|
+
@query.current_trace
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def types
|
|
78
|
+
@query.types
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def resolve_type(...)
|
|
82
|
+
@query.resolve_type(...)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def variables
|
|
86
|
+
@query.variables
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def fragments
|
|
90
|
+
@query.fragments
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def valid?
|
|
94
|
+
@query.valid?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def analyzers
|
|
98
|
+
EmptyObjects::EMPTY_ARRAY
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def analysis_errors=(_ignored)
|
|
102
|
+
# pass
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def subscription?
|
|
106
|
+
@query.subscription?
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def selected_operation
|
|
110
|
+
ast_nodes.first
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def static_errors
|
|
114
|
+
@query.static_errors
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def selected_operation_name
|
|
118
|
+
@query.selected_operation_name
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
def set_type_info_from_path
|
|
124
|
+
selections = [@query.selected_operation]
|
|
125
|
+
type = @query.root_type
|
|
126
|
+
parent_type = nil
|
|
127
|
+
field_defn = nil
|
|
128
|
+
|
|
129
|
+
@path.each do |name_in_doc|
|
|
130
|
+
if name_in_doc.is_a?(Integer)
|
|
131
|
+
if type.list?
|
|
132
|
+
type = type.unwrap
|
|
133
|
+
next
|
|
134
|
+
else
|
|
135
|
+
raise ArgumentError, "Received path with index `#{name_in_doc}`, but type wasn't a list. Type: #{type.to_type_signature}, path: #{@path}"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
next_selections = []
|
|
140
|
+
selections.each do |selection|
|
|
141
|
+
selections_to_check = []
|
|
142
|
+
selections_to_check.concat(selection.selections)
|
|
143
|
+
while (sel = selections_to_check.shift)
|
|
144
|
+
case sel
|
|
145
|
+
when GraphQL::Language::Nodes::InlineFragment
|
|
146
|
+
selections_to_check.concat(sel.selections)
|
|
147
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
|
148
|
+
fragment = @query.fragments[sel.name]
|
|
149
|
+
selections_to_check.concat(fragment.selections)
|
|
150
|
+
when GraphQL::Language::Nodes::Field
|
|
151
|
+
if sel.alias == name_in_doc || sel.name == name_in_doc
|
|
152
|
+
next_selections << sel
|
|
153
|
+
end
|
|
154
|
+
else
|
|
155
|
+
raise "Unexpected selection in partial path: #{sel.class}, #{sel.inspect}"
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
if next_selections.empty?
|
|
161
|
+
raise ArgumentError, "Path `#{@path.inspect}` is not present in this query. `#{name_in_doc.inspect}` was not found. Try a different path or rewrite the query to include it."
|
|
162
|
+
end
|
|
163
|
+
field_name = next_selections.first.name
|
|
164
|
+
field_defn = @schema.get_field(type, field_name, @query.context) || raise("Invariant: no field called #{field_name} on #{type.graphql_name}")
|
|
165
|
+
parent_type = type
|
|
166
|
+
type = field_defn.type
|
|
167
|
+
if type.non_null?
|
|
168
|
+
type = type.of_type
|
|
169
|
+
end
|
|
170
|
+
selections = next_selections
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
@ast_nodes = selections
|
|
174
|
+
@root_type = type
|
|
175
|
+
@field_definition = field_defn
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|