graphql 1.13.24 → 2.5.11
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 +50 -1
- data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/relay.rb +21 -18
- 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 +8 -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 +65 -28
- data/lib/graphql/analysis/max_query_complexity.rb +11 -17
- data/lib/graphql/analysis/max_query_depth.rb +13 -19
- data/lib/graphql/analysis/query_complexity.rb +236 -61
- data/lib/graphql/analysis/query_depth.rb +38 -23
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +93 -6
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -73
- data/lib/graphql/backtrace.rb +2 -25
- 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 +23 -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 +158 -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 +101 -0
- data/lib/graphql/dataloader/null_dataloader.rb +11 -2
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +103 -47
- data/lib/graphql/dataloader.rb +174 -148
- data/lib/graphql/dig.rb +3 -2
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/errors.rb +12 -82
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +30 -35
- data/lib/graphql/execution/interpreter/resolve.rb +32 -2
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +215 -0
- data/lib/graphql/execution/interpreter/runtime.rb +525 -502
- data/lib/graphql/execution/interpreter.rb +127 -81
- data/lib/graphql/execution/lazy.rb +7 -21
- data/lib/graphql/execution/lookahead.rb +133 -55
- data/lib/graphql/execution/multiplex.rb +6 -176
- data/lib/graphql/execution.rb +11 -4
- 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 +3 -8
- data/lib/graphql/introspection/entry_points.rb +10 -17
- 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 +13 -6
- data/lib/graphql/introspection.rb +4 -3
- 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 +114 -80
- data/lib/graphql/language/lexer.rb +375 -1489
- data/lib/graphql/language/nodes.rb +189 -104
- data/lib/graphql/language/parser.rb +807 -1941
- data/lib/graphql/language/printer.rb +366 -163
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +171 -0
- data/lib/graphql/language/visitor.rb +189 -138
- data/lib/graphql/language.rb +62 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +8 -6
- data/lib/graphql/pagination/connection.rb +61 -7
- data/lib/graphql/pagination/connections.rb +3 -28
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +2 -0
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +131 -225
- data/lib/graphql/query/input_validation_result.rb +1 -1
- data/lib/graphql/query/null_context.rb +11 -33
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +14 -37
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +6 -19
- data/lib/graphql/query.rb +162 -98
- data/lib/graphql/railtie.rb +15 -109
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +30 -11
- data/lib/graphql/relay/range_add.rb +9 -20
- data/lib/graphql/relay.rb +0 -15
- 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 +70 -33
- data/lib/graphql/schema/always_visible.rb +15 -0
- data/lib/graphql/schema/argument.rb +104 -59
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +154 -74
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +47 -24
- data/lib/graphql/schema/enum.rb +137 -65
- data/lib/graphql/schema/enum_value.rb +11 -26
- data/lib/graphql/schema/field/connection_extension.rb +6 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +399 -404
- data/lib/graphql/schema/field_extension.rb +2 -5
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +144 -99
- data/lib/graphql/schema/interface.rb +34 -51
- data/lib/graphql/schema/introspection_system.rb +12 -26
- data/lib/graphql/schema/late_bound_type.rb +12 -2
- data/lib/graphql/schema/list.rb +3 -9
- data/lib/graphql/schema/loader.rb +4 -6
- data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
- data/lib/graphql/schema/member/build_type.rb +15 -9
- data/lib/graphql/schema/member/has_arguments.rb +192 -96
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_dataloader.rb +62 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +18 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +119 -39
- data/lib/graphql/schema/member/has_interfaces.rb +66 -23
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +32 -2
- data/lib/graphql/schema/member/validates_input.rb +4 -4
- data/lib/graphql/schema/member.rb +1 -6
- data/lib/graphql/schema/mutation.rb +7 -9
- data/lib/graphql/schema/non_null.rb +1 -7
- data/lib/graphql/schema/object.rb +42 -49
- data/lib/graphql/schema/printer.rb +12 -8
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +12 -124
- data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
- data/lib/graphql/schema/resolver.rb +96 -81
- data/lib/graphql/schema/scalar.rb +10 -30
- data/lib/graphql/schema/subscription.rb +60 -14
- data/lib/graphql/schema/timeout.rb +44 -31
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +12 -19
- 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 +60 -10
- data/lib/graphql/schema/validator.rb +5 -3
- 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 +318 -94
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +1148 -1085
- data/lib/graphql/static_validation/all_rules.rb +4 -3
- data/lib/graphql/static_validation/base_visitor.rb +11 -27
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/error.rb +2 -2
- data/lib/graphql/static_validation/literal_validator.rb +24 -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 +13 -7
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -12
- 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 +48 -6
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +90 -27
- 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/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +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 +19 -9
- 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 +12 -26
- data/lib/graphql/static_validation.rb +0 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +14 -6
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
- data/lib/graphql/subscriptions/event.rb +24 -12
- data/lib/graphql/subscriptions/serialize.rb +3 -1
- data/lib/graphql/subscriptions.rb +48 -32
- data/lib/graphql/testing/helpers.rb +158 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +27 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +259 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
- data/lib/graphql/tracing/appsignal_trace.rb +54 -0
- 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 +71 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +3 -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 +93 -0
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
- data/lib/graphql/tracing/legacy_trace.rb +12 -0
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +68 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +195 -0
- 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 +734 -0
- data/lib/graphql/tracing/platform_trace.rb +123 -0
- data/lib/graphql/tracing/platform_tracing.rb +28 -41
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
- data/lib/graphql/tracing/prometheus_trace.rb +93 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
- data/lib/graphql/tracing/scout_trace.rb +49 -0
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +80 -0
- data/lib/graphql/tracing/statsd_trace.rb +48 -0
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +186 -0
- data/lib/graphql/tracing.rb +32 -52
- data/lib/graphql/type_kinds.rb +8 -4
- data/lib/graphql/types/iso_8601_date.rb +4 -1
- data/lib/graphql/types/iso_8601_date_time.rb +4 -0
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +65 -23
- data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +1 -1
- 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 +76 -123
- data/readme.md +13 -3
- metadata +225 -142
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -55
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
- 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 -56
- data/lib/graphql/analysis/ast/visitor.rb +0 -269
- data/lib/graphql/analysis/ast.rb +0 -91
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backtrace/tracer.rb +0 -81
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -232
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -255
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -55
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -107
- data/lib/graphql/enum_type.rb +0 -133
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -260
- data/lib/graphql/language/parser.y +0 -550
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -54
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -39
- data/lib/graphql/relay/global_id_resolve.rb +0 -17
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/member/accepts_definition.rb +0 -164
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/instrumentation.rb +0 -79
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/default_relay.rb +0 -31
- data/lib/graphql/types/relay/node_field.rb +0 -24
- data/lib/graphql/types/relay/nodes_field.rb +0 -43
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
@@ -35,7 +35,7 @@ module GraphQL
|
|
35
35
|
# }
|
36
36
|
#
|
37
37
|
# result = MySchema.execute(
|
38
|
-
# query
|
38
|
+
# query,
|
39
39
|
# context: context,
|
40
40
|
# variables: variables,
|
41
41
|
# operation_name: operation_name
|
@@ -91,7 +91,13 @@ module GraphQL
|
|
91
91
|
# A per-process map of subscriptions to deliver.
|
92
92
|
# This is provided by Rails, so let's use it
|
93
93
|
@subscriptions = Concurrent::Map.new
|
94
|
-
@events = Concurrent::Map.new
|
94
|
+
@events = Concurrent::Map.new do |h, k|
|
95
|
+
h.compute_if_absent(k) do
|
96
|
+
Concurrent::Map.new do |h2, k2|
|
97
|
+
h2.compute_if_absent(k2) { Concurrent::Array.new }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
95
101
|
@action_cable = action_cable
|
96
102
|
@action_cable_coder = action_cable_coder
|
97
103
|
@serializer = serializer
|
@@ -101,7 +107,7 @@ module GraphQL
|
|
101
107
|
when 2
|
102
108
|
true
|
103
109
|
else
|
104
|
-
raise ArgumentError, "#{@serializer} must
|
110
|
+
raise ArgumentError, "#{@serializer} must respond to `.load` accepting one or two arguments"
|
105
111
|
end
|
106
112
|
@transmit_ns = namespace
|
107
113
|
super
|
@@ -118,7 +124,8 @@ module GraphQL
|
|
118
124
|
# This subscription was re-evaluated.
|
119
125
|
# Send it to the specific stream where this client was waiting.
|
120
126
|
def deliver(subscription_id, result)
|
121
|
-
|
127
|
+
has_more = !result.context.namespace(:subscriptions)[:final_update]
|
128
|
+
payload = { result: result.to_h, more: has_more }
|
122
129
|
@action_cable.server.broadcast(stream_subscription_name(subscription_id), payload)
|
123
130
|
end
|
124
131
|
|
@@ -159,11 +166,12 @@ module GraphQL
|
|
159
166
|
#
|
160
167
|
def setup_stream(channel, initial_event)
|
161
168
|
topic = initial_event.topic
|
162
|
-
|
169
|
+
event_stream = stream_event_name(initial_event)
|
170
|
+
channel.stream_from(event_stream, coder: @action_cable_coder) do |message|
|
163
171
|
events_by_fingerprint = @events[topic]
|
164
172
|
object = nil
|
165
173
|
events_by_fingerprint.each do |_fingerprint, events|
|
166
|
-
if events.
|
174
|
+
if !events.empty? && events.first == initial_event
|
167
175
|
# The fingerprint has told us that this response should be shared by all subscribers,
|
168
176
|
# so just run it once, then deliver the result to every subscriber
|
169
177
|
first_event = events.first
|
@@ -9,7 +9,7 @@ module GraphQL
|
|
9
9
|
# Assign the result to `context.namespace(:subscriptions)[:subscription_broadcastable]`
|
10
10
|
# @api private
|
11
11
|
# @see Subscriptions#broadcastable? for a public API
|
12
|
-
class BroadcastAnalyzer < GraphQL::Analysis::
|
12
|
+
class BroadcastAnalyzer < GraphQL::Analysis::Analyzer
|
13
13
|
def initialize(subject)
|
14
14
|
super
|
15
15
|
@default_broadcastable = subject.schema.subscriptions.default_broadcastable
|
@@ -28,9 +28,8 @@ module GraphQL
|
|
28
28
|
end
|
29
29
|
|
30
30
|
current_field = visitor.field_definition
|
31
|
-
apply_broadcastable(current_field)
|
32
|
-
|
33
31
|
current_type = visitor.parent_type_definition
|
32
|
+
apply_broadcastable(current_type, current_field)
|
34
33
|
if current_type.kind.interface?
|
35
34
|
pt = @query.possible_types(current_type)
|
36
35
|
pt.each do |object_type|
|
@@ -38,7 +37,7 @@ module GraphQL
|
|
38
37
|
# Inherited fields would be exactly the same object;
|
39
38
|
# only check fields that are overrides of the inherited one
|
40
39
|
if ot_field && ot_field != current_field
|
41
|
-
apply_broadcastable(ot_field)
|
40
|
+
apply_broadcastable(object_type, ot_field)
|
42
41
|
end
|
43
42
|
end
|
44
43
|
end
|
@@ -55,10 +54,16 @@ module GraphQL
|
|
55
54
|
private
|
56
55
|
|
57
56
|
# Modify `@subscription_broadcastable` based on `field_defn`'s configuration (and/or the default value)
|
58
|
-
def apply_broadcastable(field_defn)
|
57
|
+
def apply_broadcastable(owner_type, field_defn)
|
59
58
|
current_field_broadcastable = field_defn.introspection? || field_defn.broadcastable?
|
59
|
+
|
60
|
+
if current_field_broadcastable.nil? && owner_type.respond_to?(:default_broadcastable?)
|
61
|
+
current_field_broadcastable = owner_type.default_broadcastable?
|
62
|
+
end
|
63
|
+
|
60
64
|
case current_field_broadcastable
|
61
65
|
when nil
|
66
|
+
query.logger.debug { "`broadcastable: nil` for field: #{field_defn.path}" }
|
62
67
|
# If the value wasn't set, mix in the default value:
|
63
68
|
# - If the default is false and the current value is true, make it false
|
64
69
|
# - If the default is true and the current value is true, it stays true
|
@@ -66,6 +71,7 @@ module GraphQL
|
|
66
71
|
# - If the default is true and the current value is false, keep it false
|
67
72
|
@subscription_broadcastable = @subscription_broadcastable && @default_broadcastable
|
68
73
|
when false
|
74
|
+
query.logger.debug { "`broadcastable: false` for field: #{field_defn.path}" }
|
69
75
|
# One non-broadcastable field is enough to make the whole subscription non-broadcastable
|
70
76
|
@subscription_broadcastable = false
|
71
77
|
when true
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
class Subscriptions
|
4
|
-
class DefaultSubscriptionResolveExtension < GraphQL::
|
4
|
+
class DefaultSubscriptionResolveExtension < GraphQL::Schema::FieldExtension
|
5
5
|
def resolve(context:, object:, arguments:)
|
6
6
|
has_override_implementation = @field.resolver ||
|
7
7
|
object.respond_to?(@field.resolver_method)
|
@@ -16,6 +16,45 @@ module GraphQL
|
|
16
16
|
yield(object, arguments)
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
def after_resolve(value:, context:, object:, arguments:, **rest)
|
21
|
+
if value.is_a?(GraphQL::ExecutionError)
|
22
|
+
value
|
23
|
+
elsif @field.resolver&.method_defined?(:subscription_written?) &&
|
24
|
+
(subscription_namespace = context.namespace(:subscriptions)) &&
|
25
|
+
(subscriptions_by_path = subscription_namespace[:subscriptions])
|
26
|
+
(subscription_instance = subscriptions_by_path[context.current_path])
|
27
|
+
# If it was already written, don't append this event to be written later
|
28
|
+
if !subscription_instance.subscription_written?
|
29
|
+
events = context.namespace(:subscriptions)[:events]
|
30
|
+
events << subscription_instance.event
|
31
|
+
end
|
32
|
+
value
|
33
|
+
elsif (events = context.namespace(:subscriptions)[:events])
|
34
|
+
# This is the first execution, so gather an Event
|
35
|
+
# for the backend to register:
|
36
|
+
event = Subscriptions::Event.new(
|
37
|
+
name: field.name,
|
38
|
+
arguments: arguments,
|
39
|
+
context: context,
|
40
|
+
field: field,
|
41
|
+
)
|
42
|
+
events << event
|
43
|
+
value
|
44
|
+
elsif context.query.subscription_topic == Subscriptions::Event.serialize(
|
45
|
+
field.name,
|
46
|
+
arguments,
|
47
|
+
field,
|
48
|
+
scope: (field.subscription_scope ? context[field.subscription_scope] : nil),
|
49
|
+
)
|
50
|
+
# This is a subscription update. The resolver returned `skip` if it should be skipped,
|
51
|
+
# or else it returned an object to resolve the update.
|
52
|
+
value
|
53
|
+
else
|
54
|
+
# This is a subscription update, but this event wasn't triggered.
|
55
|
+
context.skip
|
56
|
+
end
|
57
|
+
end
|
19
58
|
end
|
20
59
|
end
|
21
60
|
end
|
@@ -9,7 +9,7 @@ module GraphQL
|
|
9
9
|
# @return [String] Corresponds to the Subscription root field name
|
10
10
|
attr_reader :name
|
11
11
|
|
12
|
-
# @return [GraphQL::
|
12
|
+
# @return [GraphQL::Execution::Interpreter::Arguments]
|
13
13
|
attr_reader :arguments
|
14
14
|
|
15
15
|
# @return [GraphQL::Query::Context]
|
@@ -20,7 +20,7 @@ module GraphQL
|
|
20
20
|
|
21
21
|
def initialize(name:, arguments:, field: nil, context: nil, scope: nil)
|
22
22
|
@name = name
|
23
|
-
@arguments = arguments
|
23
|
+
@arguments = self.class.arguments_without_field_extras(arguments: arguments, field: field)
|
24
24
|
@context = context
|
25
25
|
field ||= context.field
|
26
26
|
scope_key = field.subscription_scope
|
@@ -37,8 +37,9 @@ module GraphQL
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# @return [String] an identifier for this unit of subscription
|
40
|
-
def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext)
|
40
|
+
def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext.instance)
|
41
41
|
subscription = field.resolver || GraphQL::Schema::Subscription
|
42
|
+
arguments = arguments_without_field_extras(field: field, arguments: arguments)
|
42
43
|
normalized_args = stringify_args(field, arguments.to_h, context)
|
43
44
|
subscription.topic_for(arguments: normalized_args, field: field, scope: scope)
|
44
45
|
end
|
@@ -60,6 +61,16 @@ module GraphQL
|
|
60
61
|
end
|
61
62
|
|
62
63
|
class << self
|
64
|
+
def arguments_without_field_extras(arguments:, field:)
|
65
|
+
if !field.extras.empty?
|
66
|
+
arguments = arguments.dup
|
67
|
+
field.extras.each do |extra_key|
|
68
|
+
arguments.delete(extra_key)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
arguments
|
72
|
+
end
|
73
|
+
|
63
74
|
private
|
64
75
|
|
65
76
|
# This method does not support cyclic references in the Hash,
|
@@ -100,13 +111,8 @@ module GraphQL
|
|
100
111
|
arg_name = k.to_s
|
101
112
|
camelized_arg_name = GraphQL::Schema::Member::BuildType.camelize(arg_name)
|
102
113
|
arg_defn = get_arg_definition(arg_owner, camelized_arg_name, context)
|
103
|
-
|
104
|
-
|
105
|
-
normalized_arg_name = camelized_arg_name
|
106
|
-
else
|
107
|
-
normalized_arg_name = arg_name
|
108
|
-
arg_defn = get_arg_definition(arg_owner, normalized_arg_name, context)
|
109
|
-
end
|
114
|
+
arg_defn ||= get_arg_definition(arg_owner, arg_name, context)
|
115
|
+
normalized_arg_name = arg_defn.graphql_name
|
110
116
|
arg_base_type = arg_defn.type.unwrap
|
111
117
|
# In the case where the value being emitted is seen as a "JSON"
|
112
118
|
# type, treat the value as one atomic unit of serialization
|
@@ -131,12 +137,18 @@ module GraphQL
|
|
131
137
|
when GraphQL::Schema::InputObject
|
132
138
|
stringify_args(arg_owner, args.to_h, context)
|
133
139
|
else
|
134
|
-
|
140
|
+
if arg_owner.is_a?(Class) && arg_owner < GraphQL::Schema::Enum
|
141
|
+
# `prepare:` may have made the value something other than
|
142
|
+
# a defined value of this enum -- use _that_ in this case.
|
143
|
+
arg_owner.coerce_isolated_input(args) || args
|
144
|
+
else
|
145
|
+
args
|
146
|
+
end
|
135
147
|
end
|
136
148
|
end
|
137
149
|
|
138
150
|
def get_arg_definition(arg_owner, arg_name, context)
|
139
|
-
|
151
|
+
context.types.argument(arg_owner, arg_name) || context.types.arguments(arg_owner).find { |v| v.keyword.to_s == arg_name }
|
140
152
|
end
|
141
153
|
end
|
142
154
|
end
|
@@ -146,8 +146,10 @@ module GraphQL
|
|
146
146
|
elsif obj.is_a?(Date) || obj.is_a?(Time)
|
147
147
|
# DateTime extends Date; for TimeWithZone, call `.utc` first.
|
148
148
|
{ TIMESTAMP_KEY => [obj.class.name, obj.strftime(TIMESTAMP_FORMAT)] }
|
149
|
-
elsif obj.is_a?(OpenStruct)
|
149
|
+
elsif defined?(OpenStruct) && obj.is_a?(OpenStruct)
|
150
150
|
{ OPEN_STRUCT_KEY => dump_value(obj.to_h) }
|
151
|
+
elsif defined?(ActiveRecord::Relation) && obj.is_a?(ActiveRecord::Relation)
|
152
|
+
dump_value(obj.to_a)
|
151
153
|
else
|
152
154
|
obj
|
153
155
|
end
|
@@ -2,10 +2,8 @@
|
|
2
2
|
require "securerandom"
|
3
3
|
require "graphql/subscriptions/broadcast_analyzer"
|
4
4
|
require "graphql/subscriptions/event"
|
5
|
-
require "graphql/subscriptions/instrumentation"
|
6
5
|
require "graphql/subscriptions/serialize"
|
7
6
|
require "graphql/subscriptions/action_cable_subscriptions"
|
8
|
-
require "graphql/subscriptions/subscription_root"
|
9
7
|
require "graphql/subscriptions/default_subscription_resolve_extension"
|
10
8
|
|
11
9
|
module GraphQL
|
@@ -27,15 +25,10 @@ module GraphQL
|
|
27
25
|
def self.use(defn, options = {})
|
28
26
|
schema = defn.is_a?(Class) ? defn : defn.target
|
29
27
|
|
30
|
-
if schema.subscriptions
|
28
|
+
if schema.subscriptions(inherited: false)
|
31
29
|
raise ArgumentError, "Can't reinstall subscriptions. #{schema} is using #{schema.subscriptions}, can't also add #{self}"
|
32
30
|
end
|
33
31
|
|
34
|
-
instrumentation = Subscriptions::Instrumentation.new(schema: schema)
|
35
|
-
defn.instrument(:query, instrumentation)
|
36
|
-
if !schema.is_a?(Class)
|
37
|
-
defn.instrument(:field, instrumentation)
|
38
|
-
end
|
39
32
|
options[:schema] = schema
|
40
33
|
schema.subscriptions = self.new(**options)
|
41
34
|
schema.add_subscription_extension_if_necessary
|
@@ -43,15 +36,14 @@ module GraphQL
|
|
43
36
|
end
|
44
37
|
|
45
38
|
# @param schema [Class] the GraphQL schema this manager belongs to
|
46
|
-
|
39
|
+
# @param validate_update [Boolean] If false, then validation is skipped when executing updates
|
40
|
+
def initialize(schema:, validate_update: true, broadcast: false, default_broadcastable: false, **rest)
|
47
41
|
if broadcast
|
48
|
-
if !schema.using_ast_analysis?
|
49
|
-
raise ArgumentError, "`broadcast: true` requires AST analysis, add `using GraphQL::Analysis::AST` to your schema or see https://graphql-ruby.org/queries/ast_analysis.html."
|
50
|
-
end
|
51
42
|
schema.query_analyzer(Subscriptions::BroadcastAnalyzer)
|
52
43
|
end
|
53
44
|
@default_broadcastable = default_broadcastable
|
54
45
|
@schema = schema
|
46
|
+
@validate_update = validate_update
|
55
47
|
end
|
56
48
|
|
57
49
|
# @return [Boolean] Used when fields don't have `broadcastable:` explicitly set
|
@@ -63,17 +55,21 @@ module GraphQL
|
|
63
55
|
# @param args [Hash<String, Symbol => Object]
|
64
56
|
# @param object [Object]
|
65
57
|
# @param scope [Symbol, String]
|
58
|
+
# @param context [Hash]
|
66
59
|
# @return [void]
|
67
|
-
def trigger(event_name, args, object, scope: nil)
|
60
|
+
def trigger(event_name, args, object, scope: nil, context: {})
|
61
|
+
# Make something as context-like as possible, even though there isn't a current query:
|
62
|
+
dummy_query = @schema.query_class.new(@schema, "{ __typename }", validate: false, context: context)
|
63
|
+
context = dummy_query.context
|
68
64
|
event_name = event_name.to_s
|
69
65
|
|
70
66
|
# Try with the verbatim input first:
|
71
|
-
field =
|
67
|
+
field = dummy_query.types.field(@schema.subscription, event_name) # rubocop:disable Development/ContextIsPassedCop
|
72
68
|
|
73
69
|
if field.nil?
|
74
70
|
# And if it wasn't found, normalize it:
|
75
71
|
normalized_event_name = normalize_name(event_name)
|
76
|
-
field =
|
72
|
+
field = dummy_query.types.field(@schema.subscription, normalized_event_name) # rubocop:disable Development/ContextIsPassedCop
|
77
73
|
if field.nil?
|
78
74
|
raise InvalidTriggerError, "No subscription matching trigger: #{event_name} (looked for #{@schema.subscription.graphql_name}.#{normalized_event_name})"
|
79
75
|
end
|
@@ -84,13 +80,14 @@ module GraphQL
|
|
84
80
|
|
85
81
|
# Normalize symbol-keyed args to strings, try camelizing them
|
86
82
|
# Should this accept a real context somehow?
|
87
|
-
normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext)
|
83
|
+
normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext.instance)
|
88
84
|
|
89
85
|
event = Subscriptions::Event.new(
|
90
86
|
name: normalized_event_name,
|
91
87
|
arguments: normalized_args,
|
92
88
|
field: field,
|
93
89
|
scope: scope,
|
90
|
+
context: context,
|
94
91
|
)
|
95
92
|
execute_all(event, object)
|
96
93
|
end
|
@@ -117,24 +114,28 @@ module GraphQL
|
|
117
114
|
variables = query_data.fetch(:variables)
|
118
115
|
context = query_data.fetch(:context)
|
119
116
|
operation_name = query_data.fetch(:operation_name)
|
120
|
-
|
117
|
+
execute_options = {
|
121
118
|
query: query_string,
|
122
119
|
context: context,
|
123
120
|
subscription_topic: event.topic,
|
124
121
|
operation_name: operation_name,
|
125
122
|
variables: variables,
|
126
123
|
root_value: object,
|
127
|
-
|
124
|
+
}
|
125
|
+
|
126
|
+
# merge event's and query's context together
|
127
|
+
context.merge!(event.context) unless event.context.nil? || context.nil?
|
128
|
+
|
129
|
+
execute_options[:validate] = validate_update?(**execute_options)
|
130
|
+
result = @schema.execute(**execute_options)
|
128
131
|
subscriptions_context = result.context.namespace(:subscriptions)
|
129
132
|
if subscriptions_context[:no_update]
|
130
133
|
result = nil
|
131
134
|
end
|
132
135
|
|
133
|
-
unsubscribed
|
134
|
-
|
135
|
-
if unsubscribed
|
136
|
+
if subscriptions_context[:unsubscribed] && !subscriptions_context[:final_update]
|
136
137
|
# `unsubscribe` was called, clean up on our side
|
137
|
-
#
|
138
|
+
# The transport should also send `{more: false}` to client
|
138
139
|
delete_subscription(subscription_id)
|
139
140
|
result = nil
|
140
141
|
end
|
@@ -142,6 +143,14 @@ module GraphQL
|
|
142
143
|
result
|
143
144
|
end
|
144
145
|
|
146
|
+
# Define this method to customize whether to validate
|
147
|
+
# this subscription when executing an update.
|
148
|
+
#
|
149
|
+
# @return [Boolean] defaults to `true`, or false if `validate: false` is provided.
|
150
|
+
def validate_update?(query:, context:, root_value:, subscription_topic:, operation_name:, variables:)
|
151
|
+
@validate_update
|
152
|
+
end
|
153
|
+
|
145
154
|
# Run the update query for this subscription and deliver it
|
146
155
|
# @see {#execute_update}
|
147
156
|
# @see {#deliver}
|
@@ -150,7 +159,14 @@ module GraphQL
|
|
150
159
|
res = execute_update(subscription_id, event, object)
|
151
160
|
if !res.nil?
|
152
161
|
deliver(subscription_id, res)
|
162
|
+
|
163
|
+
if res.context.namespace(:subscriptions)[:unsubscribed]
|
164
|
+
# `unsubscribe` was called, clean up on our side
|
165
|
+
# The transport should also send `{more: false}` to client
|
166
|
+
delete_subscription(subscription_id)
|
167
|
+
end
|
153
168
|
end
|
169
|
+
|
154
170
|
end
|
155
171
|
|
156
172
|
# Event `event` occurred on `object`,
|
@@ -215,11 +231,11 @@ module GraphQL
|
|
215
231
|
|
216
232
|
# @return [Boolean] if true, then a query like this one would be broadcasted
|
217
233
|
def broadcastable?(query_str, **query_options)
|
218
|
-
query =
|
234
|
+
query = @schema.query_class.new(@schema, query_str, **query_options)
|
219
235
|
if !query.valid?
|
220
236
|
raise "Invalid query: #{query.validation_errors.map(&:to_h).inspect}"
|
221
237
|
end
|
222
|
-
GraphQL::Analysis
|
238
|
+
GraphQL::Analysis.analyze_query(query, @schema.query_analyzers)
|
223
239
|
query.context.namespace(:subscriptions)[:subscription_broadcastable]
|
224
240
|
end
|
225
241
|
|
@@ -233,7 +249,9 @@ module GraphQL
|
|
233
249
|
# @return [Any] normalized arguments value
|
234
250
|
def normalize_arguments(event_name, arg_owner, args, context)
|
235
251
|
case arg_owner
|
236
|
-
when GraphQL::
|
252
|
+
when GraphQL::Schema::Field, Class
|
253
|
+
return args if args.nil?
|
254
|
+
|
237
255
|
if arg_owner.is_a?(Class) && !arg_owner.kind.input_object?
|
238
256
|
# it's a type, but not an input object
|
239
257
|
return args
|
@@ -273,10 +291,8 @@ module GraphQL
|
|
273
291
|
end
|
274
292
|
end
|
275
293
|
|
276
|
-
if missing_arg_names.
|
277
|
-
arg_owner_name = if arg_owner.is_a?(GraphQL::Field)
|
278
|
-
"Subscription.#{arg_owner.name}"
|
279
|
-
elsif arg_owner.is_a?(GraphQL::Schema::Field)
|
294
|
+
if !missing_arg_names.empty?
|
295
|
+
arg_owner_name = if arg_owner.is_a?(GraphQL::Schema::Field)
|
280
296
|
arg_owner.path
|
281
297
|
elsif arg_owner.is_a?(Class)
|
282
298
|
arg_owner.graphql_name
|
@@ -287,9 +303,9 @@ module GraphQL
|
|
287
303
|
end
|
288
304
|
|
289
305
|
normalized_args
|
290
|
-
when GraphQL::
|
291
|
-
args
|
292
|
-
when GraphQL::
|
306
|
+
when GraphQL::Schema::List
|
307
|
+
args&.map { |a| normalize_arguments(event_name, arg_owner.of_type, a, context) }
|
308
|
+
when GraphQL::Schema::NonNull
|
293
309
|
normalize_arguments(event_name, arg_owner.of_type, args, context)
|
294
310
|
else
|
295
311
|
args
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module Testing
|
4
|
+
module Helpers
|
5
|
+
# @param schema_class [Class<GraphQL::Schema>]
|
6
|
+
# @return [Module] A helpers module which always uses the given schema
|
7
|
+
def self.for(schema_class)
|
8
|
+
SchemaHelpers.for(schema_class)
|
9
|
+
end
|
10
|
+
|
11
|
+
class Error < GraphQL::Error
|
12
|
+
end
|
13
|
+
|
14
|
+
class TypeNotVisibleError < Error
|
15
|
+
def initialize(type_name:)
|
16
|
+
message = "`#{type_name}` should be `visible?` this field resolution and `context`, but it was not"
|
17
|
+
super(message)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class FieldNotVisibleError < Error
|
22
|
+
def initialize(type_name:, field_name:)
|
23
|
+
message = "`#{type_name}.#{field_name}` should be `visible?` for this resolution, but it was not"
|
24
|
+
super(message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class TypeNotDefinedError < Error
|
29
|
+
def initialize(type_name:)
|
30
|
+
message = "No type named `#{type_name}` is defined; choose another type name or define this type."
|
31
|
+
super(message)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class FieldNotDefinedError < Error
|
36
|
+
def initialize(type_name:, field_name:)
|
37
|
+
message = "`#{type_name}` has no field named `#{field_name}`; pick another name or define this field."
|
38
|
+
super(message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def run_graphql_field(schema, field_path, object, arguments: {}, context: {}, ast_node: nil, lookahead: nil)
|
43
|
+
type_name, *field_names = field_path.split(".")
|
44
|
+
dummy_query = GraphQL::Query.new(schema, "{ __typename }", context: context)
|
45
|
+
query_context = dummy_query.context
|
46
|
+
dataloader = query_context.dataloader
|
47
|
+
object_type = dummy_query.types.type(type_name) # rubocop:disable Development/ContextIsPassedCop
|
48
|
+
if object_type
|
49
|
+
graphql_result = object
|
50
|
+
field_names.each do |field_name|
|
51
|
+
inner_object = graphql_result
|
52
|
+
dataloader.run_isolated {
|
53
|
+
graphql_result = object_type.wrap(inner_object, query_context)
|
54
|
+
}
|
55
|
+
if graphql_result.nil?
|
56
|
+
return nil
|
57
|
+
end
|
58
|
+
visible_field = dummy_query.types.field(object_type, field_name) # rubocop:disable Development/ContextIsPassedCop
|
59
|
+
if visible_field
|
60
|
+
dataloader.run_isolated {
|
61
|
+
query_context[:current_field] = visible_field
|
62
|
+
field_args = visible_field.coerce_arguments(graphql_result, arguments, query_context)
|
63
|
+
field_args = schema.sync_lazy(field_args)
|
64
|
+
if !visible_field.extras.empty?
|
65
|
+
extra_args = {}
|
66
|
+
visible_field.extras.each do |extra|
|
67
|
+
extra_args[extra] = case extra
|
68
|
+
when :ast_node
|
69
|
+
ast_node ||= GraphQL::Language::Nodes::Field.new(name: visible_field.graphql_name)
|
70
|
+
when :lookahead
|
71
|
+
lookahead ||= begin
|
72
|
+
ast_node ||= GraphQL::Language::Nodes::Field.new(name: visible_field.graphql_name)
|
73
|
+
Execution::Lookahead.new(
|
74
|
+
query: dummy_query,
|
75
|
+
ast_nodes: [ast_node],
|
76
|
+
field: visible_field,
|
77
|
+
)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
raise ArgumentError, "This extra isn't supported in `run_graphql_field` yet: `#{extra.inspect}`. Open an issue on GitHub to request it: https://github.com/rmosolgo/graphql-ruby/issues/new"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
field_args = field_args.merge_extras(extra_args)
|
85
|
+
end
|
86
|
+
graphql_result = visible_field.resolve(graphql_result, field_args.keyword_arguments, query_context)
|
87
|
+
graphql_result = schema.sync_lazy(graphql_result)
|
88
|
+
}
|
89
|
+
object_type = visible_field.type.unwrap
|
90
|
+
elsif object_type.all_field_definitions.any? { |f| f.graphql_name == field_name }
|
91
|
+
raise FieldNotVisibleError.new(field_name: field_name, type_name: type_name)
|
92
|
+
else
|
93
|
+
raise FieldNotDefinedError.new(type_name: type_name, field_name: field_name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
graphql_result
|
97
|
+
else
|
98
|
+
unfiltered_type = schema.use_visibility_profile? ? schema.visibility.get_type(type_name) : schema.get_type(type_name) # rubocop:disable Development/ContextIsPassedCop
|
99
|
+
if unfiltered_type
|
100
|
+
raise TypeNotVisibleError.new(type_name: type_name)
|
101
|
+
else
|
102
|
+
raise TypeNotDefinedError.new(type_name: type_name)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def with_resolution_context(schema, type:, object:, context:{})
|
108
|
+
resolution_context = ResolutionAssertionContext.new(
|
109
|
+
self,
|
110
|
+
schema: schema,
|
111
|
+
type_name: type,
|
112
|
+
object: object,
|
113
|
+
context: context
|
114
|
+
)
|
115
|
+
yield(resolution_context)
|
116
|
+
end
|
117
|
+
|
118
|
+
class ResolutionAssertionContext
|
119
|
+
def initialize(test, type_name:, object:, schema:, context:)
|
120
|
+
@test = test
|
121
|
+
@type_name = type_name
|
122
|
+
@object = object
|
123
|
+
@schema = schema
|
124
|
+
@context = context
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
def run_graphql_field(field_name, arguments: {})
|
129
|
+
if @schema
|
130
|
+
@test.run_graphql_field(@schema, "#{@type_name}.#{field_name}", @object, arguments: arguments, context: @context)
|
131
|
+
else
|
132
|
+
@test.run_graphql_field("#{@type_name}.#{field_name}", @object, arguments: arguments, context: @context)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
module SchemaHelpers
|
138
|
+
include Helpers
|
139
|
+
|
140
|
+
def run_graphql_field(field_path, object, arguments: {}, context: {})
|
141
|
+
super(@@schema_class_for_helpers, field_path, object, arguments: arguments, context: context)
|
142
|
+
end
|
143
|
+
|
144
|
+
def with_resolution_context(*args, **kwargs, &block)
|
145
|
+
# schema will be added later
|
146
|
+
super(nil, *args, **kwargs, &block)
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.for(schema_class)
|
150
|
+
Module.new do
|
151
|
+
include SchemaHelpers
|
152
|
+
@@schema_class_for_helpers = schema_class
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "graphql/tracing/notifications_trace"
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
module Tracing
|
7
|
+
# This implementation forwards events to ActiveSupport::Notifications with a `graphql` suffix.
|
8
|
+
#
|
9
|
+
# @example Sending execution events to ActiveSupport::Notifications
|
10
|
+
# class MySchema < GraphQL::Schema
|
11
|
+
# trace_with(GraphQL::Tracing::ActiveSupportNotificationsTrace)
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @example Subscribing to GraphQL events with ActiveSupport::Notifications
|
15
|
+
# ActiveSupport::Notifications.subscribe(/graphql/) do |event|
|
16
|
+
# pp event.name
|
17
|
+
# pp event.payload
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
module ActiveSupportNotificationsTrace
|
21
|
+
include NotificationsTrace
|
22
|
+
def initialize(engine: ActiveSupport::Notifications, **rest)
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|