graphql 2.0.32 → 2.5.22
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/detailed_trace_generator.rb +77 -0
- 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/create_graphql_detailed_traces.erb +10 -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/application_controller.rb +41 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/landings_controller.rb +9 -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/statics_controller.rb +31 -0
- data/lib/graphql/dashboard/subscriptions.rb +97 -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 +96 -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 +55 -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 +7 -6
- data/lib/graphql/execution/next/field_resolve_step.rb +711 -0
- data/lib/graphql/execution/next/load_argument_step.rb +60 -0
- data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
- data/lib/graphql/execution/next/runner.rb +389 -0
- data/lib/graphql/execution/next/selections_step.rb +37 -0
- data/lib/graphql/execution/next.rb +70 -0
- data/lib/graphql/execution.rb +1 -0
- data/lib/graphql/execution_error.rb +13 -10
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +7 -3
- data/lib/graphql/introspection/dynamic_fields.rb +5 -1
- data/lib/graphql/introspection/entry_points.rb +20 -6
- data/lib/graphql/introspection/enum_value_type.rb +5 -5
- data/lib/graphql/introspection/field_type.rb +13 -5
- data/lib/graphql/introspection/input_value_type.rb +21 -13
- data/lib/graphql/introspection/schema_type.rb +8 -11
- data/lib/graphql/introspection/type_type.rb +64 -28
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +26 -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 +136 -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 +23 -83
- 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 +30 -1
- data/lib/graphql/pagination/connections.rb +32 -0
- 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 +82 -144
- data/lib/graphql/query/null_context.rb +15 -18
- 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 +75 -9
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +123 -60
- 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 +54 -2
- data/lib/graphql/schema/enum.rb +110 -27
- data/lib/graphql/schema/enum_value.rb +10 -2
- data/lib/graphql/schema/field/connection_extension.rb +15 -49
- data/lib/graphql/schema/field/scope_extension.rb +23 -7
- data/lib/graphql/schema/field.rb +245 -118
- data/lib/graphql/schema/field_extension.rb +34 -1
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +116 -60
- 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 +18 -2
- data/lib/graphql/schema/member/has_arguments.rb +132 -100
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +99 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +115 -15
- data/lib/graphql/schema/member/has_interfaces.rb +26 -12
- 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 +17 -4
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +34 -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 +90 -32
- 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 +950 -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 +7 -3
- data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
- data/lib/graphql/tracing/appsignal_trace.rb +32 -59
- 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 -162
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -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 +156 -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 +183 -37
- 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 +864 -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 +73 -73
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -58
- 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 -45
- 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 +44 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +18 -0
- data/lib/graphql/types/relay/has_node_field.rb +13 -8
- data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
- data/lib/graphql/types/relay/node_behaviors.rb +13 -2
- 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/unauthorized_error.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +71 -54
- data/readme.md +12 -2
- metadata +233 -37
- 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
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require "graphql/types/string"
|
|
3
2
|
|
|
4
3
|
module GraphQL
|
|
5
4
|
class Schema
|
|
@@ -21,6 +20,10 @@ module GraphQL
|
|
|
21
20
|
# @see {GraphQL::Schema::Mutation} for an example, it's basically the same.
|
|
22
21
|
#
|
|
23
22
|
class RelayClassicMutation < GraphQL::Schema::Mutation
|
|
23
|
+
include GraphQL::Schema::HasSingleInputArgument
|
|
24
|
+
|
|
25
|
+
argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
|
|
26
|
+
|
|
24
27
|
# The payload should always include this field
|
|
25
28
|
field(:client_mutation_id, String, "A unique identifier for the client performing the mutation.")
|
|
26
29
|
# Relay classic default:
|
|
@@ -31,34 +34,14 @@ module GraphQL
|
|
|
31
34
|
def resolve_with_support(**inputs)
|
|
32
35
|
input = inputs[:input].to_kwargs
|
|
33
36
|
|
|
34
|
-
new_extras = field ? field.extras : []
|
|
35
|
-
all_extras = self.class.extras + new_extras
|
|
36
|
-
|
|
37
|
-
# Transfer these from the top-level hash to the
|
|
38
|
-
# shortcutted `input:` object
|
|
39
|
-
all_extras.each do |ext|
|
|
40
|
-
# It's possible that the `extra` was not passed along by this point,
|
|
41
|
-
# don't re-add it if it wasn't given here.
|
|
42
|
-
if inputs.key?(ext)
|
|
43
|
-
input[ext] = inputs[ext]
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
37
|
if input
|
|
48
38
|
# This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
|
|
49
39
|
input_kwargs = input.to_h
|
|
50
40
|
client_mutation_id = input_kwargs.delete(:client_mutation_id)
|
|
51
|
-
|
|
52
|
-
# Relay Classic Mutations with no `argument`s
|
|
53
|
-
# don't require `input:`
|
|
54
|
-
input_kwargs = {}
|
|
41
|
+
inputs[:input] = input_kwargs
|
|
55
42
|
end
|
|
56
43
|
|
|
57
|
-
return_value =
|
|
58
|
-
super(**input_kwargs)
|
|
59
|
-
else
|
|
60
|
-
super()
|
|
61
|
-
end
|
|
44
|
+
return_value = super(**inputs)
|
|
62
45
|
|
|
63
46
|
context.query.after_lazy(return_value) do |return_hash|
|
|
64
47
|
# It might be an error
|
|
@@ -68,112 +51,6 @@ module GraphQL
|
|
|
68
51
|
return_hash
|
|
69
52
|
end
|
|
70
53
|
end
|
|
71
|
-
|
|
72
|
-
class << self
|
|
73
|
-
def dummy
|
|
74
|
-
@dummy ||= begin
|
|
75
|
-
d = Class.new(GraphQL::Schema::Resolver)
|
|
76
|
-
d.argument_class(self.argument_class)
|
|
77
|
-
# TODO make this lazier?
|
|
78
|
-
d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
|
|
79
|
-
d
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def field_arguments(context = GraphQL::Query::NullContext)
|
|
84
|
-
dummy.arguments(context)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def get_field_argument(name, context = GraphQL::Query::NullContext)
|
|
88
|
-
dummy.get_argument(name, context)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def own_field_arguments
|
|
92
|
-
dummy.own_arguments
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def all_field_argument_definitions
|
|
96
|
-
dummy.all_argument_definitions
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Also apply this argument to the input type:
|
|
100
|
-
def argument(*args, own_argument: false, **kwargs, &block)
|
|
101
|
-
it = input_type # make sure any inherited arguments are already added to it
|
|
102
|
-
arg = super(*args, **kwargs, &block)
|
|
103
|
-
|
|
104
|
-
# This definition might be overriding something inherited;
|
|
105
|
-
# if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
|
|
106
|
-
prev_args = it.own_arguments[arg.graphql_name]
|
|
107
|
-
case prev_args
|
|
108
|
-
when GraphQL::Schema::Argument
|
|
109
|
-
if prev_args.owner != self
|
|
110
|
-
it.own_arguments.delete(arg.graphql_name)
|
|
111
|
-
end
|
|
112
|
-
when Array
|
|
113
|
-
prev_args.reject! { |a| a.owner != self }
|
|
114
|
-
if prev_args.empty?
|
|
115
|
-
it.own_arguments.delete(arg.graphql_name)
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it.add_argument(arg)
|
|
120
|
-
arg
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# The base class for generated input object types
|
|
124
|
-
# @param new_class [Class] The base class to use for generating input object definitions
|
|
125
|
-
# @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})
|
|
126
|
-
def input_object_class(new_class = nil)
|
|
127
|
-
if new_class
|
|
128
|
-
@input_object_class = new_class
|
|
129
|
-
end
|
|
130
|
-
@input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# @param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
|
|
134
|
-
# @return [Class] The generated {Schema::InputObject} class for this mutation's `input`
|
|
135
|
-
def input_type(new_input_type = nil)
|
|
136
|
-
if new_input_type
|
|
137
|
-
@input_type = new_input_type
|
|
138
|
-
end
|
|
139
|
-
@input_type ||= generate_input_type
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
private
|
|
143
|
-
|
|
144
|
-
# Generate the input type for the `input:` argument
|
|
145
|
-
# To customize how input objects are generated, override this method
|
|
146
|
-
# @return [Class] a subclass of {.input_object_class}
|
|
147
|
-
def generate_input_type
|
|
148
|
-
mutation_args = all_argument_definitions
|
|
149
|
-
mutation_class = self
|
|
150
|
-
Class.new(input_object_class) do
|
|
151
|
-
class << self
|
|
152
|
-
def default_graphql_name
|
|
153
|
-
"#{self.mutation.graphql_name}Input"
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def description(new_desc = nil)
|
|
157
|
-
super || "Autogenerated input type of #{self.mutation.graphql_name}"
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
mutation(mutation_class)
|
|
161
|
-
# these might be inherited:
|
|
162
|
-
mutation_args.each do |arg|
|
|
163
|
-
add_argument(arg)
|
|
164
|
-
end
|
|
165
|
-
argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
private
|
|
171
|
-
|
|
172
|
-
def authorize_arguments(args, values)
|
|
173
|
-
# remove the `input` wrapper to match values
|
|
174
|
-
input_args = args["input"].type.unwrap.arguments(context)
|
|
175
|
-
super(input_args, values)
|
|
176
|
-
end
|
|
177
54
|
end
|
|
178
55
|
end
|
|
179
56
|
end
|
|
@@ -8,6 +8,7 @@ module GraphQL
|
|
|
8
8
|
# - Arguments, via `.argument(...)` helper, which will be applied to the field.
|
|
9
9
|
# - Return type, via `.type(..., null: ...)`, which will be applied to the field.
|
|
10
10
|
# - Description, via `.description(...)`, which will be applied to the field
|
|
11
|
+
# - Comment, via `.comment(...)`, which will be applied to the field
|
|
11
12
|
# - Resolution, via `#resolve(**args)` method, which will be called to resolve the field.
|
|
12
13
|
# - `#object` and `#context` accessors for use during `#resolve`.
|
|
13
14
|
#
|
|
@@ -19,12 +20,16 @@ module GraphQL
|
|
|
19
20
|
# @see {GraphQL::Function} `Resolver` is a replacement for `GraphQL::Function`
|
|
20
21
|
class Resolver
|
|
21
22
|
include Schema::Member::GraphQLTypeNames
|
|
22
|
-
# Really we only need description from here, but:
|
|
23
|
+
# Really we only need description & comment from here, but:
|
|
23
24
|
extend Schema::Member::BaseDSLMethods
|
|
24
25
|
extend GraphQL::Schema::Member::HasArguments
|
|
26
|
+
extend GraphQL::Schema::Member::HasAuthorization
|
|
25
27
|
extend GraphQL::Schema::Member::HasValidators
|
|
26
28
|
include Schema::Member::HasPath
|
|
27
29
|
extend Schema::Member::HasPath
|
|
30
|
+
extend Schema::Member::HasDirectives
|
|
31
|
+
include Schema::Member::HasDataloader
|
|
32
|
+
extend Schema::Member::HasDeprecationReason
|
|
28
33
|
|
|
29
34
|
# @param object [Object] The application object that this field is being resolved on
|
|
30
35
|
# @param context [GraphQL::Query::Context]
|
|
@@ -35,26 +40,64 @@ module GraphQL
|
|
|
35
40
|
@field = field
|
|
36
41
|
# Since this hash is constantly rebuilt, cache it for this call
|
|
37
42
|
@arguments_by_keyword = {}
|
|
38
|
-
|
|
43
|
+
context.types.arguments(self.class).each do |arg|
|
|
39
44
|
@arguments_by_keyword[arg.keyword] = arg
|
|
40
45
|
end
|
|
41
46
|
@prepared_arguments = nil
|
|
42
47
|
end
|
|
43
48
|
|
|
49
|
+
attr_accessor :exec_result, :exec_index, :field_resolve_step
|
|
50
|
+
|
|
44
51
|
# @return [Object] The application object this field is being resolved on
|
|
45
|
-
|
|
52
|
+
attr_accessor :object
|
|
46
53
|
|
|
47
54
|
# @return [GraphQL::Query::Context]
|
|
48
55
|
attr_reader :context
|
|
49
56
|
|
|
50
|
-
# @return [GraphQL::Dataloader]
|
|
51
|
-
def dataloader
|
|
52
|
-
context.dataloader
|
|
53
|
-
end
|
|
54
|
-
|
|
55
57
|
# @return [GraphQL::Schema::Field]
|
|
56
58
|
attr_reader :field
|
|
57
59
|
|
|
60
|
+
attr_writer :prepared_arguments
|
|
61
|
+
|
|
62
|
+
def call
|
|
63
|
+
if self.class < Schema::HasSingleInputArgument
|
|
64
|
+
@prepared_arguments = @prepared_arguments[:input]
|
|
65
|
+
end
|
|
66
|
+
q = context.query
|
|
67
|
+
trace_objs = [object]
|
|
68
|
+
q.current_trace.begin_execute_field(field, @prepared_arguments, trace_objs, q)
|
|
69
|
+
is_authed, new_return_value = authorized?(**@prepared_arguments)
|
|
70
|
+
|
|
71
|
+
if (runner = @field_resolve_step.runner).resolves_lazies && runner.schema.lazy?(is_authed)
|
|
72
|
+
is_authed, new_return_value = runner.schema.sync_lazy(is_authed)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
result = if is_authed
|
|
76
|
+
Schema::Validator.validate!(self.class.validators, object, context, @prepared_arguments, as: @field)
|
|
77
|
+
call_resolve(@prepared_arguments)
|
|
78
|
+
else
|
|
79
|
+
new_return_value
|
|
80
|
+
end
|
|
81
|
+
q = context.query
|
|
82
|
+
q.current_trace.end_execute_field(field, @prepared_arguments, trace_objs, q, [result])
|
|
83
|
+
|
|
84
|
+
exec_result[exec_index] = result
|
|
85
|
+
rescue RuntimeError => err
|
|
86
|
+
exec_result[exec_index] = err
|
|
87
|
+
rescue StandardError => stderr
|
|
88
|
+
exec_result[exec_index] = begin
|
|
89
|
+
context.query.handle_or_reraise(stderr)
|
|
90
|
+
rescue GraphQL::ExecutionError => ex_err
|
|
91
|
+
ex_err
|
|
92
|
+
end
|
|
93
|
+
ensure
|
|
94
|
+
field_pending_steps = field_resolve_step.pending_steps
|
|
95
|
+
field_pending_steps.delete(self)
|
|
96
|
+
if field_pending_steps.size == 0 && field_resolve_step.field_results
|
|
97
|
+
field_resolve_step.runner.add_step(field_resolve_step)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
58
101
|
def arguments
|
|
59
102
|
@prepared_arguments || raise("Arguments have not been prepared yet, still waiting for #load_arguments to resolve. (Call `.arguments` later in the code.)")
|
|
60
103
|
end
|
|
@@ -65,7 +108,7 @@ module GraphQL
|
|
|
65
108
|
# @api private
|
|
66
109
|
def resolve_with_support(**args)
|
|
67
110
|
# First call the ready? hook which may raise
|
|
68
|
-
raw_ready_val = if args.
|
|
111
|
+
raw_ready_val = if !args.empty?
|
|
69
112
|
ready?(**args)
|
|
70
113
|
else
|
|
71
114
|
ready?
|
|
@@ -86,7 +129,7 @@ module GraphQL
|
|
|
86
129
|
@prepared_arguments = loaded_args
|
|
87
130
|
Schema::Validator.validate!(self.class.validators, object, context, loaded_args, as: @field)
|
|
88
131
|
# Then call `authorized?`, which may raise or may return a lazy object
|
|
89
|
-
raw_authorized_val = if loaded_args.
|
|
132
|
+
raw_authorized_val = if !loaded_args.empty?
|
|
90
133
|
authorized?(**loaded_args)
|
|
91
134
|
else
|
|
92
135
|
authorized?
|
|
@@ -103,11 +146,7 @@ module GraphQL
|
|
|
103
146
|
end
|
|
104
147
|
elsif authorized_val
|
|
105
148
|
# Finally, all the hooks have passed, so resolve it
|
|
106
|
-
|
|
107
|
-
public_send(self.class.resolve_method, **loaded_args)
|
|
108
|
-
else
|
|
109
|
-
public_send(self.class.resolve_method)
|
|
110
|
-
end
|
|
149
|
+
call_resolve(loaded_args)
|
|
111
150
|
else
|
|
112
151
|
raise GraphQL::UnauthorizedFieldError.new(context: context, object: object, type: field.owner, field: field)
|
|
113
152
|
end
|
|
@@ -117,6 +156,15 @@ module GraphQL
|
|
|
117
156
|
end
|
|
118
157
|
end
|
|
119
158
|
|
|
159
|
+
# @api private {GraphQL::Schema::Mutation} uses this to clear the dataloader cache
|
|
160
|
+
def call_resolve(args_hash)
|
|
161
|
+
if !args_hash.empty?
|
|
162
|
+
public_send(self.class.resolve_method, **args_hash)
|
|
163
|
+
else
|
|
164
|
+
public_send(self.class.resolve_method)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
120
168
|
# Do the work. Everything happens here.
|
|
121
169
|
# @return [Object] An object corresponding to the return type
|
|
122
170
|
def resolve(**args)
|
|
@@ -146,7 +194,7 @@ module GraphQL
|
|
|
146
194
|
# @return [Boolean, early_return_data] If `false`, execution will stop (and `early_return_data` will be returned instead, if present.)
|
|
147
195
|
def authorized?(**inputs)
|
|
148
196
|
arg_owner = @field # || self.class
|
|
149
|
-
args =
|
|
197
|
+
args = context.types.arguments(arg_owner)
|
|
150
198
|
authorize_arguments(args, inputs)
|
|
151
199
|
end
|
|
152
200
|
|
|
@@ -163,19 +211,22 @@ module GraphQL
|
|
|
163
211
|
private
|
|
164
212
|
|
|
165
213
|
def authorize_arguments(args, inputs)
|
|
166
|
-
args.
|
|
214
|
+
args.each do |argument|
|
|
167
215
|
arg_keyword = argument.keyword
|
|
168
216
|
if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
|
|
169
|
-
|
|
170
|
-
if
|
|
171
|
-
return
|
|
172
|
-
|
|
173
|
-
|
|
217
|
+
auth_result = argument.authorized?(self, arg_value, context)
|
|
218
|
+
if auth_result.is_a?(Array)
|
|
219
|
+
# only return this second value if the application returned a second value
|
|
220
|
+
arg_auth, err = auth_result
|
|
221
|
+
if !arg_auth
|
|
222
|
+
return arg_auth, err
|
|
223
|
+
end
|
|
224
|
+
elsif auth_result == false
|
|
225
|
+
return auth_result
|
|
174
226
|
end
|
|
175
|
-
else
|
|
176
|
-
true
|
|
177
227
|
end
|
|
178
228
|
end
|
|
229
|
+
true
|
|
179
230
|
end
|
|
180
231
|
|
|
181
232
|
def load_arguments(args)
|
|
@@ -198,23 +249,27 @@ module GraphQL
|
|
|
198
249
|
end
|
|
199
250
|
|
|
200
251
|
# Avoid returning a lazy if none are needed
|
|
201
|
-
if prepare_lazies.
|
|
252
|
+
if !prepare_lazies.empty?
|
|
202
253
|
GraphQL::Execution::Lazy.all(prepare_lazies).then { prepared_args }
|
|
203
254
|
else
|
|
204
255
|
prepared_args
|
|
205
256
|
end
|
|
206
257
|
end
|
|
207
258
|
|
|
208
|
-
def get_argument(name, context = GraphQL::Query::NullContext)
|
|
259
|
+
def get_argument(name, context = GraphQL::Query::NullContext.instance)
|
|
209
260
|
self.class.get_argument(name, context)
|
|
210
261
|
end
|
|
211
262
|
|
|
212
263
|
class << self
|
|
213
|
-
def field_arguments(context = GraphQL::Query::NullContext)
|
|
264
|
+
def field_arguments(context = GraphQL::Query::NullContext.instance)
|
|
214
265
|
arguments(context)
|
|
215
266
|
end
|
|
216
267
|
|
|
217
|
-
def
|
|
268
|
+
def any_field_arguments?
|
|
269
|
+
any_arguments?
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
|
|
218
273
|
get_argument(name, context)
|
|
219
274
|
end
|
|
220
275
|
|
|
@@ -380,7 +435,7 @@ module GraphQL
|
|
|
380
435
|
if superclass.respond_to?(:extensions)
|
|
381
436
|
s_exts = superclass.extensions
|
|
382
437
|
if own_exts
|
|
383
|
-
if s_exts.
|
|
438
|
+
if !s_exts.empty?
|
|
384
439
|
own_exts + s_exts
|
|
385
440
|
else
|
|
386
441
|
own_exts
|
|
@@ -393,11 +448,14 @@ module GraphQL
|
|
|
393
448
|
end
|
|
394
449
|
end
|
|
395
450
|
|
|
451
|
+
def inherited(child_class)
|
|
452
|
+
child_class.description(description)
|
|
453
|
+
super
|
|
454
|
+
end
|
|
455
|
+
|
|
396
456
|
private
|
|
397
457
|
|
|
398
|
-
|
|
399
|
-
@own_extensions
|
|
400
|
-
end
|
|
458
|
+
attr_reader :own_extensions
|
|
401
459
|
end
|
|
402
460
|
end
|
|
403
461
|
end
|
|
@@ -19,9 +19,9 @@ module GraphQL
|
|
|
19
19
|
|
|
20
20
|
def specified_by_url(new_url = nil)
|
|
21
21
|
if new_url
|
|
22
|
-
|
|
23
|
-
elsif
|
|
24
|
-
|
|
22
|
+
directive(GraphQL::Schema::Directive::SpecifiedBy, url: new_url)
|
|
23
|
+
elsif (directive = directives.find { |dir| dir.graphql_name == "specifiedBy" })
|
|
24
|
+
directive.arguments[:url] # rubocop:disable Development/ContextIsPassedCop
|
|
25
25
|
elsif superclass.respond_to?(:specified_by_url)
|
|
26
26
|
superclass.specified_by_url
|
|
27
27
|
else
|
|
@@ -50,12 +50,7 @@ module GraphQL
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
if coerced_result.nil?
|
|
53
|
-
|
|
54
|
-
""
|
|
55
|
-
else
|
|
56
|
-
" #{GraphQL::Language.serialize(value)}"
|
|
57
|
-
end
|
|
58
|
-
Query::InputValidationResult.from_problem("Could not coerce value#{str_value} to #{graphql_name}")
|
|
53
|
+
Query::InputValidationResult.from_problem("Could not coerce value #{GraphQL::Language.serialize(value)} to #{graphql_name}")
|
|
59
54
|
elsif coerced_result.is_a?(GraphQL::CoercionError)
|
|
60
55
|
Query::InputValidationResult.from_problem(coerced_result.message, message: coerced_result.message, extensions: coerced_result.extensions)
|
|
61
56
|
else
|
|
@@ -19,29 +19,45 @@ module GraphQL
|
|
|
19
19
|
# propagate null.
|
|
20
20
|
null false
|
|
21
21
|
|
|
22
|
+
# @api private
|
|
22
23
|
def initialize(object:, context:, field:)
|
|
23
24
|
super
|
|
24
25
|
# Figure out whether this is an update or an initial subscription
|
|
25
26
|
@mode = context.query.subscription_update? ? :update : :subscribe
|
|
27
|
+
@subscription_written = false
|
|
28
|
+
@original_arguments = nil
|
|
29
|
+
if (subs_ns = context.namespace(:subscriptions)) &&
|
|
30
|
+
(sub_insts = subs_ns[:subscriptions])
|
|
31
|
+
sub_insts[context.current_path] = self
|
|
32
|
+
end
|
|
26
33
|
end
|
|
27
34
|
|
|
35
|
+
# @api private
|
|
28
36
|
def resolve_with_support(**args)
|
|
37
|
+
@original_arguments = args # before `loads:` have been run
|
|
29
38
|
result = nil
|
|
30
39
|
unsubscribed = true
|
|
31
|
-
catch :graphql_subscription_unsubscribed do
|
|
40
|
+
unsubscribed_result = catch :graphql_subscription_unsubscribed do
|
|
32
41
|
result = super
|
|
33
42
|
unsubscribed = false
|
|
34
43
|
end
|
|
35
44
|
|
|
36
45
|
|
|
37
46
|
if unsubscribed
|
|
38
|
-
|
|
47
|
+
if unsubscribed_result
|
|
48
|
+
context.namespace(:subscriptions)[:final_update] = true
|
|
49
|
+
unsubscribed_result
|
|
50
|
+
else
|
|
51
|
+
context.skip
|
|
52
|
+
end
|
|
39
53
|
else
|
|
40
54
|
result
|
|
41
55
|
end
|
|
42
56
|
end
|
|
43
57
|
|
|
44
|
-
# Implement the {Resolve} API
|
|
58
|
+
# Implement the {Resolve} API.
|
|
59
|
+
# You can implement this if you want code to run for _both_ the initial subscription
|
|
60
|
+
# and for later updates. Or, implement {#subscribe} and {#update}
|
|
45
61
|
def resolve(**args)
|
|
46
62
|
# Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
|
|
47
63
|
# have an unexpected `@mode`
|
|
@@ -49,8 +65,9 @@ module GraphQL
|
|
|
49
65
|
end
|
|
50
66
|
|
|
51
67
|
# Wrap the user-defined `#subscribe` hook
|
|
68
|
+
# @api private
|
|
52
69
|
def resolve_subscribe(**args)
|
|
53
|
-
ret_val = args.
|
|
70
|
+
ret_val = !args.empty? ? subscribe(**args) : subscribe
|
|
54
71
|
if ret_val == :no_response
|
|
55
72
|
context.skip
|
|
56
73
|
else
|
|
@@ -66,8 +83,9 @@ module GraphQL
|
|
|
66
83
|
end
|
|
67
84
|
|
|
68
85
|
# Wrap the user-provided `#update` hook
|
|
86
|
+
# @api private
|
|
69
87
|
def resolve_update(**args)
|
|
70
|
-
ret_val = args.
|
|
88
|
+
ret_val = !args.empty? ? update(**args) : update
|
|
71
89
|
if ret_val == NO_UPDATE
|
|
72
90
|
context.namespace(:subscriptions)[:no_update] = true
|
|
73
91
|
context.skip
|
|
@@ -94,19 +112,20 @@ module GraphQL
|
|
|
94
112
|
end
|
|
95
113
|
|
|
96
114
|
# Call this to halt execution and remove this subscription from the system
|
|
97
|
-
|
|
115
|
+
# @param update_value [Object] if present, deliver this update before unsubscribing
|
|
116
|
+
# @return [void]
|
|
117
|
+
def unsubscribe(update_value = nil)
|
|
98
118
|
context.namespace(:subscriptions)[:unsubscribed] = true
|
|
99
|
-
throw :graphql_subscription_unsubscribed
|
|
119
|
+
throw :graphql_subscription_unsubscribed, update_value
|
|
100
120
|
end
|
|
101
121
|
|
|
102
|
-
READING_SCOPE = ::Object.new
|
|
103
122
|
# Call this method to provide a new subscription_scope; OR
|
|
104
123
|
# call it without an argument to get the subscription_scope
|
|
105
124
|
# @param new_scope [Symbol]
|
|
106
125
|
# @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription.
|
|
107
126
|
# @return [Symbol]
|
|
108
|
-
def self.subscription_scope(new_scope =
|
|
109
|
-
if new_scope !=
|
|
127
|
+
def self.subscription_scope(new_scope = NOT_CONFIGURED, optional: false)
|
|
128
|
+
if new_scope != NOT_CONFIGURED
|
|
110
129
|
@subscription_scope = new_scope
|
|
111
130
|
@subscription_scope_optional = optional
|
|
112
131
|
elsif defined?(@subscription_scope)
|
|
@@ -143,6 +162,40 @@ module GraphQL
|
|
|
143
162
|
def self.topic_for(arguments:, field:, scope:)
|
|
144
163
|
Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
|
|
145
164
|
end
|
|
165
|
+
|
|
166
|
+
# Calls through to `schema.subscriptions` to register this subscription with the backend.
|
|
167
|
+
# This is automatically called by GraphQL-Ruby after a query finishes successfully,
|
|
168
|
+
# but if you need to commit the subscription during `#subscribe`, you can call it there.
|
|
169
|
+
# (This method also sets a flag showing that this subscription was already written.)
|
|
170
|
+
#
|
|
171
|
+
# If you call this method yourself, you may also need to {#unsubscribe}
|
|
172
|
+
# or call `subscriptions.delete_subscription` to clean up the database if the query crashes with an error
|
|
173
|
+
# later in execution.
|
|
174
|
+
# @return [void]
|
|
175
|
+
def write_subscription
|
|
176
|
+
if subscription_written?
|
|
177
|
+
raise GraphQL::Error, "`write_subscription` was called but `#{self.class}#subscription_written?` is already true. Remove a call to `write subscription`."
|
|
178
|
+
else
|
|
179
|
+
@subscription_written = true
|
|
180
|
+
context.schema.subscriptions.write_subscription(context.query, [event])
|
|
181
|
+
end
|
|
182
|
+
nil
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# @return [Boolean] `true` if {#write_subscription} was called already
|
|
186
|
+
def subscription_written?
|
|
187
|
+
@subscription_written
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# @return [Subscriptions::Event] This object is used as a representation of this subscription for the backend
|
|
191
|
+
def event
|
|
192
|
+
@event ||= Subscriptions::Event.new(
|
|
193
|
+
name: field.name,
|
|
194
|
+
arguments: @original_arguments,
|
|
195
|
+
context: context,
|
|
196
|
+
field: field,
|
|
197
|
+
)
|
|
198
|
+
end
|
|
146
199
|
end
|
|
147
200
|
end
|
|
148
201
|
end
|
|
@@ -71,15 +71,23 @@ module GraphQL
|
|
|
71
71
|
def execute_field(query:, field:, **_rest)
|
|
72
72
|
timeout_state = query.context.namespace(@timeout).fetch(:state)
|
|
73
73
|
# If the `:state` is `false`, then `max_seconds(query)` opted out of timeout for this query.
|
|
74
|
-
if timeout_state
|
|
74
|
+
if timeout_state == false
|
|
75
|
+
super
|
|
76
|
+
elsif Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) > timeout_state.fetch(:timeout_at)
|
|
75
77
|
error = GraphQL::Schema::Timeout::TimeoutError.new(field)
|
|
76
78
|
# Only invoke the timeout callback for the first timeout
|
|
77
79
|
if !timeout_state[:timed_out]
|
|
78
80
|
timeout_state[:timed_out] = true
|
|
79
81
|
@timeout.handle_timeout(error, query)
|
|
82
|
+
timeout_state = query.context.namespace(@timeout).fetch(:state)
|
|
80
83
|
end
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
# `handle_timeout` may have set this to be `false`
|
|
86
|
+
if timeout_state != false
|
|
87
|
+
error
|
|
88
|
+
else
|
|
89
|
+
super
|
|
90
|
+
end
|
|
83
91
|
else
|
|
84
92
|
super
|
|
85
93
|
end
|
|
@@ -102,6 +110,15 @@ module GraphQL
|
|
|
102
110
|
# override to do something interesting
|
|
103
111
|
end
|
|
104
112
|
|
|
113
|
+
# Call this method (eg, from {#handle_timeout}) to disable timeout tracking
|
|
114
|
+
# for the given query.
|
|
115
|
+
# @param query [GraphQL::Query]
|
|
116
|
+
# @return [void]
|
|
117
|
+
def disable_timeout(query)
|
|
118
|
+
query.context.namespace(self)[:state] = false
|
|
119
|
+
nil
|
|
120
|
+
end
|
|
121
|
+
|
|
105
122
|
# This error is raised when a query exceeds `max_seconds`.
|
|
106
123
|
# Since it's a child of {GraphQL::ExecutionError},
|
|
107
124
|
# its message will be added to the response's `errors` key.
|
|
@@ -5,13 +5,13 @@ module GraphQL
|
|
|
5
5
|
module TypeExpression
|
|
6
6
|
# Fetch a type from a type map by its AST specification.
|
|
7
7
|
# Return `nil` if not found.
|
|
8
|
-
# @param type_owner [#
|
|
8
|
+
# @param type_owner [#type] A thing for looking up types by name
|
|
9
9
|
# @param ast_node [GraphQL::Language::Nodes::AbstractNode]
|
|
10
10
|
# @return [Class, GraphQL::Schema::NonNull, GraphQL::Schema:List]
|
|
11
11
|
def self.build_type(type_owner, ast_node)
|
|
12
12
|
case ast_node
|
|
13
13
|
when GraphQL::Language::Nodes::TypeName
|
|
14
|
-
type_owner.
|
|
14
|
+
type_owner.type(ast_node.name) # rubocop:disable Development/ContextIsPassedCop -- this is a `context` or `warden`, it's already query-aware
|
|
15
15
|
when GraphQL::Language::Nodes::NonNullType
|
|
16
16
|
ast_inner_type = ast_node.of_type
|
|
17
17
|
inner_type = build_type(type_owner, ast_inner_type)
|
data/lib/graphql/schema/union.rb
CHANGED
|
@@ -10,8 +10,8 @@ module GraphQL
|
|
|
10
10
|
super
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def possible_types(*types, context: GraphQL::Query::NullContext, **options)
|
|
14
|
-
if types.
|
|
13
|
+
def possible_types(*types, context: GraphQL::Query::NullContext.instance, **options)
|
|
14
|
+
if !types.empty?
|
|
15
15
|
types.each do |t|
|
|
16
16
|
assert_valid_union_member(t)
|
|
17
17
|
type_memberships << type_membership_class.new(self, t, **options)
|