graphql 1.10.2 → 2.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +21 -10
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
- data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +45 -8
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/loader_generator.rb +1 -0
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +6 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +28 -12
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +49 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +8 -0
- data/lib/generators/graphql/templates/base_edge.erb +8 -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_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +7 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +6 -2
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +3 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +7 -3
- data/lib/generators/graphql/templates/query_type.erb +3 -3
- data/lib/generators/graphql/templates/scalar.erb +5 -1
- data/lib/generators/graphql/templates/schema.erb +24 -33
- data/lib/generators/graphql/templates/union.erb +6 -2
- data/lib/generators/graphql/type_generator.rb +47 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/ast/field_usage.rb +30 -1
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +125 -117
- data/lib/graphql/analysis/ast/query_depth.rb +0 -1
- data/lib/graphql/analysis/ast/visitor.rb +52 -36
- data/lib/graphql/analysis/ast.rb +7 -8
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/inspect_result.rb +0 -1
- data/lib/graphql/backtrace/table.rb +31 -18
- data/lib/graphql/backtrace/trace.rb +96 -0
- data/lib/graphql/backtrace/traced_error.rb +0 -1
- data/lib/graphql/backtrace/tracer.rb +39 -9
- data/lib/graphql/backtrace.rb +26 -18
- data/lib/graphql/dataloader/null_dataloader.rb +24 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +164 -0
- data/lib/graphql/dataloader.rb +311 -0
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/execution/errors.rb +77 -44
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +88 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +104 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
- data/lib/graphql/execution/interpreter/resolve.rb +62 -24
- data/lib/graphql/execution/interpreter/runtime.rb +826 -464
- data/lib/graphql/execution/interpreter.rb +206 -68
- data/lib/graphql/execution/lazy.rb +11 -21
- data/lib/graphql/execution/lookahead.rb +55 -136
- data/lib/graphql/execution/multiplex.rb +6 -162
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/filter.rb +7 -2
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +11 -5
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +4 -17
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +9 -5
- data/lib/graphql/introspection/input_value_type.rb +15 -3
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/schema_type.rb +11 -6
- data/lib/graphql/introspection/type_type.rb +31 -14
- data/lib/graphql/introspection.rb +100 -0
- data/lib/graphql/invalid_null_error.rb +18 -0
- data/lib/graphql/language/block_string.rb +20 -5
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/document_from_schema_definition.rb +96 -44
- data/lib/graphql/language/lexer.rb +216 -1462
- data/lib/graphql/language/nodes.rb +126 -129
- data/lib/graphql/language/parser.rb +997 -933
- data/lib/graphql/language/parser.y +148 -118
- data/lib/graphql/language/printer.rb +48 -23
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/language/visitor.rb +192 -84
- data/lib/graphql/language.rb +2 -0
- data/lib/graphql/name_validator.rb +2 -7
- data/lib/graphql/pagination/active_record_relation_connection.rb +45 -3
- data/lib/graphql/pagination/array_connection.rb +6 -4
- data/lib/graphql/pagination/connection.rb +105 -23
- data/lib/graphql/pagination/connections.rb +62 -35
- data/lib/graphql/pagination/relation_connection.rb +88 -36
- data/lib/graphql/parse_error.rb +0 -1
- data/lib/graphql/query/context.rb +203 -198
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +33 -7
- data/lib/graphql/query/null_context.rb +22 -9
- data/lib/graphql/query/validation_pipeline.rb +16 -38
- data/lib/graphql/query/variable_validation_error.rb +3 -3
- data/lib/graphql/query/variables.rb +36 -12
- data/lib/graphql/query.rb +92 -44
- data/lib/graphql/railtie.rb +6 -102
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +41 -10
- data/lib/graphql/relay/range_add.rb +17 -10
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/schema/addition.rb +245 -0
- data/lib/graphql/schema/argument.rb +250 -46
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
- data/lib/graphql/schema/build_from_definition.rb +243 -89
- data/lib/graphql/schema/directive/deprecated.rb +1 -1
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/transform.rb +14 -2
- data/lib/graphql/schema/directive.rb +108 -20
- data/lib/graphql/schema/enum.rb +105 -44
- data/lib/graphql/schema/enum_value.rb +15 -25
- data/lib/graphql/schema/field/connection_extension.rb +50 -30
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +476 -331
- data/lib/graphql/schema/field_extension.rb +86 -2
- data/lib/graphql/schema/find_inherited_value.rb +6 -8
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/input_object.rb +133 -121
- data/lib/graphql/schema/interface.rb +17 -45
- data/lib/graphql/schema/introspection_system.rb +3 -8
- data/lib/graphql/schema/late_bound_type.rb +8 -2
- data/lib/graphql/schema/list.rb +25 -8
- data/lib/graphql/schema/loader.rb +139 -103
- data/lib/graphql/schema/member/base_dsl_methods.rb +29 -35
- data/lib/graphql/schema/member/build_type.rb +19 -14
- data/lib/graphql/schema/member/has_arguments.rb +310 -26
- data/lib/graphql/schema/member/has_ast_node.rb +16 -1
- data/lib/graphql/schema/member/has_deprecation_reason.rb +24 -0
- data/lib/graphql/schema/member/has_directives.rb +118 -0
- data/lib/graphql/schema/member/has_fields.rb +164 -42
- data/lib/graphql/schema/member/has_interfaces.rb +129 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/has_validators.rb +57 -0
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/type_system_helpers.rb +20 -3
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +6 -6
- data/lib/graphql/schema/mutation.rb +4 -9
- data/lib/graphql/schema/non_null.rb +12 -7
- data/lib/graphql/schema/object.rb +35 -69
- data/lib/graphql/schema/printer.rb +16 -34
- data/lib/graphql/schema/relay_classic_mutation.rb +90 -43
- data/lib/graphql/schema/resolver/has_payload_type.rb +51 -11
- data/lib/graphql/schema/resolver.rb +144 -79
- data/lib/graphql/schema/scalar.rb +27 -18
- data/lib/graphql/schema/subscription.rb +55 -26
- data/lib/graphql/schema/timeout.rb +45 -35
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +21 -4
- data/lib/graphql/schema/union.rb +48 -13
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/format_validator.rb +48 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
- data/lib/graphql/schema/validator/length_validator.rb +59 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
- data/lib/graphql/schema/validator/required_validator.rb +82 -0
- data/lib/graphql/schema/validator.rb +171 -0
- data/lib/graphql/schema/warden.rb +185 -32
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +471 -1116
- data/lib/graphql/static_validation/all_rules.rb +3 -0
- data/lib/graphql/static_validation/base_visitor.rb +13 -27
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +69 -26
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +44 -87
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +28 -22
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -6
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +13 -13
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +92 -49
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/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 +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +6 -7
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +9 -10
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
- data/lib/graphql/static_validation/validation_context.rb +13 -3
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +32 -20
- data/lib/graphql/static_validation.rb +1 -2
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +126 -19
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
- data/lib/graphql/subscriptions/event.rb +81 -35
- data/lib/graphql/subscriptions/instrumentation.rb +0 -52
- data/lib/graphql/subscriptions/serialize.rb +53 -6
- data/lib/graphql/subscriptions.rb +113 -58
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -21
- data/lib/graphql/tracing/appoptics_trace.rb +231 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
- data/lib/graphql/tracing/data_dog_trace.rb +148 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +26 -2
- data/lib/graphql/tracing/legacy_trace.rb +65 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
- data/lib/graphql/tracing/notifications_trace.rb +42 -0
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_trace.rb +109 -0
- data/lib/graphql/tracing/platform_tracing.rb +64 -43
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +5 -2
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/scout_tracing.rb +11 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing/trace.rb +75 -0
- data/lib/graphql/tracing.rb +23 -71
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +10 -3
- data/lib/graphql/types/iso_8601_date.rb +20 -9
- data/lib/graphql/types/iso_8601_date_time.rb +36 -10
- data/lib/graphql/types/relay/base_connection.rb +18 -92
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +176 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +75 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +2 -4
- data/lib/graphql/types/relay/node_behaviors.rb +25 -0
- data/lib/graphql/types/relay/page_info.rb +2 -14
- data/lib/graphql/types/relay/page_info_behaviors.rb +30 -0
- data/lib/graphql/types/relay.rb +10 -5
- data/lib/graphql/types/string.rb +8 -2
- data/lib/graphql/unauthorized_error.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +54 -65
- data/readme.md +3 -6
- metadata +116 -236
- data/lib/graphql/analysis/analyze_query.rb +0 -91
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backwards_compatibility.rb +0 -60
- data/lib/graphql/base_type.rb +0 -230
- 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 -435
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -213
- 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 -264
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -680
- 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 -210
- 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 -42
- 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 -127
- data/lib/graphql/execution/execute.rb +0 -326
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/instrumentation.rb +0 -92
- data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
- 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 -222
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -124
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -132
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -65
- 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 -258
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/literal_validation_error.rb +0 -6
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -121
- data/lib/graphql/query/arguments.rb +0 -188
- data/lib/graphql/query/arguments_cache.rb +0 -25
- data/lib/graphql/query/executor.rb +0 -53
- 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 -39
- data/lib/graphql/relay/array_connection.rb +0 -85
- data/lib/graphql/relay/base_connection.rb +0 -176
- 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 -41
- 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 -40
- data/lib/graphql/relay/global_id_resolve.rb +0 -18
- 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 -105
- data/lib/graphql/relay/node.rb +0 -36
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -190
- data/lib/graphql/relay/type_extensions.rb +0 -30
- data/lib/graphql/scalar_type.rb +0 -76
- 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 -15
- data/lib/graphql/schema/member/accepts_definition.rb +0 -152
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
- data/lib/graphql/schema/member/instrumentation.rb +0 -132
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -39
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -86
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -303
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/subscription_root.rb +0 -65
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/base_field.rb +0 -22
- data/lib/graphql/types/relay/base_interface.rb +0 -29
- data/lib/graphql/types/relay/base_object.rb +0 -26
- data/lib/graphql/types/relay/node_field.rb +0 -43
- data/lib/graphql/types/relay/nodes_field.rb +0 -45
- data/lib/graphql/union_type.rb +0 -113
- data/lib/graphql/upgrader/member.rb +0 -936
- data/lib/graphql/upgrader/schema.rb +0 -37
@@ -1,17 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../subscriptions.rb
|
3
2
|
module GraphQL
|
4
3
|
class Subscriptions
|
5
4
|
# This thing can be:
|
6
5
|
# - Subscribed to by `subscription { ... }`
|
7
6
|
# - Triggered by `MySchema.subscriber.trigger(name, arguments, obj)`
|
8
7
|
#
|
9
|
-
# An array of `Event`s are passed to `store.register(query, events)`.
|
10
8
|
class Event
|
11
9
|
# @return [String] Corresponds to the Subscription root field name
|
12
10
|
attr_reader :name
|
13
11
|
|
14
|
-
# @return [GraphQL::
|
12
|
+
# @return [GraphQL::Execution::Interpreter::Arguments]
|
15
13
|
attr_reader :arguments
|
16
14
|
|
17
15
|
# @return [GraphQL::Query::Context]
|
@@ -25,67 +23,115 @@ module GraphQL
|
|
25
23
|
@arguments = arguments
|
26
24
|
@context = context
|
27
25
|
field ||= context.field
|
28
|
-
|
26
|
+
scope_key = field.subscription_scope
|
27
|
+
scope_val = scope || (context && scope_key && context[scope_key])
|
28
|
+
if scope_key &&
|
29
|
+
(subscription = field.resolver) &&
|
30
|
+
(subscription.respond_to?(:subscription_scope_optional?)) &&
|
31
|
+
!subscription.subscription_scope_optional? &&
|
32
|
+
scope_val.nil?
|
33
|
+
raise Subscriptions::SubscriptionScopeMissingError, "#{field.path} (#{subscription}) requires a `scope:` value to trigger updates (Set `subscription_scope ..., optional: true` to disable this requirement)"
|
34
|
+
end
|
29
35
|
|
30
|
-
@topic = self.class.serialize(name, arguments, field, scope: scope_val)
|
36
|
+
@topic = self.class.serialize(name, arguments, field, scope: scope_val, context: context)
|
31
37
|
end
|
32
38
|
|
33
39
|
# @return [String] an identifier for this unit of subscription
|
34
|
-
def self.serialize(
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext)
|
41
|
+
subscription = field.resolver || GraphQL::Schema::Subscription
|
42
|
+
normalized_args = stringify_args(field, arguments.to_h, context)
|
43
|
+
subscription.topic_for(arguments: normalized_args, field: field, scope: scope)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [String] a logical identifier for this event. (Stable when the query is broadcastable.)
|
47
|
+
def fingerprint
|
48
|
+
@fingerprint ||= begin
|
49
|
+
# When this query has been flagged as broadcastable,
|
50
|
+
# use a generalized, stable fingerprint so that
|
51
|
+
# duplicate subscriptions can be evaluated and distributed in bulk.
|
52
|
+
# (`@topic` includes field, args, and subscription scope already.)
|
53
|
+
if @context.namespace(:subscriptions)[:subscription_broadcastable]
|
54
|
+
"#{@topic}/#{@context.query.fingerprint}"
|
41
55
|
else
|
42
|
-
|
43
|
-
|
44
|
-
field,
|
45
|
-
nil,
|
46
|
-
)
|
56
|
+
# not broadcastable, build a unique ID for this event
|
57
|
+
@context.schema.subscriptions.build_id
|
47
58
|
end
|
48
|
-
else
|
49
|
-
raise ArgumentError, "Unexpected arguments: #{arguments}, must be Hash or GraphQL::Arguments"
|
50
59
|
end
|
51
|
-
|
52
|
-
sorted_h = stringify_args(field, normalized_args.to_h)
|
53
|
-
Serialize.dump_recursive([scope, name, sorted_h])
|
54
60
|
end
|
55
61
|
|
56
62
|
class << self
|
57
63
|
private
|
58
|
-
|
64
|
+
|
65
|
+
# This method does not support cyclic references in the Hash,
|
66
|
+
# nor does it support Hashes whose keys are not sortable
|
67
|
+
# with respect to their peers ( cases where a <=> b might throw an error )
|
68
|
+
def deep_sort_hash_keys(hash_to_sort)
|
69
|
+
raise ArgumentError.new("Argument must be a Hash") unless hash_to_sort.is_a?(Hash)
|
70
|
+
hash_to_sort.keys.sort.map do |k|
|
71
|
+
if hash_to_sort[k].is_a?(Hash)
|
72
|
+
[k, deep_sort_hash_keys(hash_to_sort[k])]
|
73
|
+
elsif hash_to_sort[k].is_a?(Array)
|
74
|
+
[k, deep_sort_array_hashes(hash_to_sort[k])]
|
75
|
+
else
|
76
|
+
[k, hash_to_sort[k]]
|
77
|
+
end
|
78
|
+
end.to_h
|
79
|
+
end
|
80
|
+
|
81
|
+
def deep_sort_array_hashes(array_to_inspect)
|
82
|
+
raise ArgumentError.new("Argument must be an Array") unless array_to_inspect.is_a?(Array)
|
83
|
+
array_to_inspect.map do |v|
|
84
|
+
if v.is_a?(Hash)
|
85
|
+
deep_sort_hash_keys(v)
|
86
|
+
elsif v.is_a?(Array)
|
87
|
+
deep_sort_array_hashes(v)
|
88
|
+
else
|
89
|
+
v
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def stringify_args(arg_owner, args, context)
|
95
|
+
arg_owner = arg_owner.respond_to?(:unwrap) ? arg_owner.unwrap : arg_owner # remove list and non-null wrappers
|
59
96
|
case args
|
60
97
|
when Hash
|
61
98
|
next_args = {}
|
62
99
|
args.each do |k, v|
|
63
100
|
arg_name = k.to_s
|
64
101
|
camelized_arg_name = GraphQL::Schema::Member::BuildType.camelize(arg_name)
|
65
|
-
arg_defn = get_arg_definition(arg_owner, camelized_arg_name)
|
66
|
-
|
67
|
-
|
68
|
-
|
102
|
+
arg_defn = get_arg_definition(arg_owner, camelized_arg_name, context)
|
103
|
+
arg_defn ||= get_arg_definition(arg_owner, arg_name, context)
|
104
|
+
normalized_arg_name = arg_defn.graphql_name
|
105
|
+
arg_base_type = arg_defn.type.unwrap
|
106
|
+
# In the case where the value being emitted is seen as a "JSON"
|
107
|
+
# type, treat the value as one atomic unit of serialization
|
108
|
+
is_json_definition = arg_base_type && arg_base_type <= GraphQL::Types::JSON
|
109
|
+
if is_json_definition
|
110
|
+
sorted_value = if v.is_a?(Hash)
|
111
|
+
deep_sort_hash_keys(v)
|
112
|
+
elsif v.is_a?(Array)
|
113
|
+
deep_sort_array_hashes(v)
|
114
|
+
else
|
115
|
+
v
|
116
|
+
end
|
117
|
+
next_args[normalized_arg_name] = sorted_value.respond_to?(:to_json) ? sorted_value.to_json : sorted_value
|
69
118
|
else
|
70
|
-
normalized_arg_name =
|
71
|
-
arg_defn = get_arg_definition(arg_owner, normalized_arg_name)
|
119
|
+
next_args[normalized_arg_name] = stringify_args(arg_base_type, v, context)
|
72
120
|
end
|
73
|
-
|
74
|
-
next_args[normalized_arg_name] = stringify_args(arg_defn.type, v)
|
75
121
|
end
|
76
122
|
# Make sure they're deeply sorted
|
77
123
|
next_args.sort.to_h
|
78
124
|
when Array
|
79
|
-
args.map { |a| stringify_args(arg_owner, a) }
|
125
|
+
args.map { |a| stringify_args(arg_owner, a, context) }
|
80
126
|
when GraphQL::Schema::InputObject
|
81
|
-
stringify_args(arg_owner, args.to_h)
|
127
|
+
stringify_args(arg_owner, args.to_h, context)
|
82
128
|
else
|
83
129
|
args
|
84
130
|
end
|
85
131
|
end
|
86
132
|
|
87
|
-
def get_arg_definition(arg_owner, arg_name)
|
88
|
-
arg_owner.
|
133
|
+
def get_arg_definition(arg_owner, arg_name, context)
|
134
|
+
arg_owner.get_argument(arg_name, context) || arg_owner.arguments(context).each_value.find { |v| v.keyword.to_s == arg_name }
|
89
135
|
end
|
90
136
|
end
|
91
137
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../subscriptions.rb
|
3
2
|
module GraphQL
|
4
3
|
class Subscriptions
|
5
4
|
# Wrap the root fields of the subscription type with special logic for:
|
@@ -10,16 +9,6 @@ module GraphQL
|
|
10
9
|
@schema = schema
|
11
10
|
end
|
12
11
|
|
13
|
-
def instrument(type, field)
|
14
|
-
if type == @schema.subscription.graphql_definition
|
15
|
-
# This is a root field of `subscription`
|
16
|
-
subscribing_resolve_proc = SubscriptionRegistrationResolve.new(field.resolve_proc)
|
17
|
-
field.redefine(resolve: subscribing_resolve_proc)
|
18
|
-
else
|
19
|
-
field
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
12
|
# If needed, prepare to gather events which this query subscribes to
|
24
13
|
def before_query(query)
|
25
14
|
if query.subscription? && !query.subscription_update?
|
@@ -34,47 +23,6 @@ module GraphQL
|
|
34
23
|
@schema.subscriptions.write_subscription(query, events)
|
35
24
|
end
|
36
25
|
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
class SubscriptionRegistrationResolve
|
41
|
-
def initialize(inner_proc)
|
42
|
-
@inner_proc = inner_proc
|
43
|
-
end
|
44
|
-
|
45
|
-
# Wrap the proc with subscription registration logic
|
46
|
-
def call(obj, args, ctx)
|
47
|
-
result = nil
|
48
|
-
if @inner_proc && !@inner_proc.is_a?(GraphQL::Field::Resolve::BuiltInResolve)
|
49
|
-
result = @inner_proc.call(obj, args, ctx)
|
50
|
-
end
|
51
|
-
|
52
|
-
events = ctx.namespace(:subscriptions)[:events]
|
53
|
-
|
54
|
-
if events
|
55
|
-
# This is the first execution, so gather an Event
|
56
|
-
# for the backend to register:
|
57
|
-
events << Subscriptions::Event.new(
|
58
|
-
name: ctx.field.name,
|
59
|
-
arguments: args,
|
60
|
-
context: ctx,
|
61
|
-
)
|
62
|
-
result
|
63
|
-
elsif ctx.irep_node.subscription_topic == ctx.query.subscription_topic
|
64
|
-
if !result.nil?
|
65
|
-
result
|
66
|
-
elsif obj.is_a?(GraphQL::Schema::Object)
|
67
|
-
# The root object is _already_ the subscription update:
|
68
|
-
obj.object
|
69
|
-
else
|
70
|
-
obj
|
71
|
-
end
|
72
|
-
else
|
73
|
-
# This is a subscription update, but this event wasn't triggered.
|
74
|
-
ctx.skip
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
26
|
end
|
79
27
|
end
|
80
28
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# test_via: ../subscriptions.rb
|
3
2
|
require "set"
|
4
3
|
module GraphQL
|
5
4
|
class Subscriptions
|
@@ -9,6 +8,9 @@ module GraphQL
|
|
9
8
|
GLOBALID_KEY = "__gid__"
|
10
9
|
SYMBOL_KEY = "__sym__"
|
11
10
|
SYMBOL_KEYS_KEY = "__sym_keys__"
|
11
|
+
TIMESTAMP_KEY = "__timestamp__"
|
12
|
+
TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S.%N%z" # eg '2020-01-01 23:59:59.123456789+05:00'
|
13
|
+
OPEN_STRUCT_KEY = "__ostruct__"
|
12
14
|
|
13
15
|
module_function
|
14
16
|
|
@@ -53,12 +55,40 @@ module GraphQL
|
|
53
55
|
# @return [Object] An object that load Global::Identification recursive
|
54
56
|
def load_value(value)
|
55
57
|
if value.is_a?(Array)
|
56
|
-
value.
|
58
|
+
is_gids = (v1 = value[0]).is_a?(Hash) && v1.size == 1 && v1[GLOBALID_KEY]
|
59
|
+
if is_gids
|
60
|
+
# Assume it's an array of global IDs
|
61
|
+
ids = value.map { |v| v[GLOBALID_KEY] }
|
62
|
+
GlobalID::Locator.locate_many(ids)
|
63
|
+
else
|
64
|
+
value.map { |item| load_value(item) }
|
65
|
+
end
|
57
66
|
elsif value.is_a?(Hash)
|
58
|
-
if value.size == 1
|
59
|
-
|
60
|
-
|
61
|
-
|
67
|
+
if value.size == 1
|
68
|
+
case value.keys.first # there's only 1 key
|
69
|
+
when GLOBALID_KEY
|
70
|
+
GlobalID::Locator.locate(value[GLOBALID_KEY])
|
71
|
+
when SYMBOL_KEY
|
72
|
+
value[SYMBOL_KEY].to_sym
|
73
|
+
when TIMESTAMP_KEY
|
74
|
+
timestamp_class_name, *timestamp_args = value[TIMESTAMP_KEY]
|
75
|
+
timestamp_class = Object.const_get(timestamp_class_name)
|
76
|
+
if defined?(ActiveSupport::TimeWithZone) && timestamp_class <= ActiveSupport::TimeWithZone
|
77
|
+
zone_name, timestamp_s = timestamp_args
|
78
|
+
zone = ActiveSupport::TimeZone[zone_name]
|
79
|
+
raise "Zone #{zone_name} not found, unable to deserialize" unless zone
|
80
|
+
zone.strptime(timestamp_s, TIMESTAMP_FORMAT)
|
81
|
+
else
|
82
|
+
timestamp_s = timestamp_args.first
|
83
|
+
timestamp_class.strptime(timestamp_s, TIMESTAMP_FORMAT)
|
84
|
+
end
|
85
|
+
when OPEN_STRUCT_KEY
|
86
|
+
ostruct_values = load_value(value[OPEN_STRUCT_KEY])
|
87
|
+
OpenStruct.new(ostruct_values)
|
88
|
+
else
|
89
|
+
key = value.keys.first
|
90
|
+
{ key => load_value(value[key]) }
|
91
|
+
end
|
62
92
|
else
|
63
93
|
loaded_h = {}
|
64
94
|
sym_keys = value.fetch(SYMBOL_KEYS_KEY, [])
|
@@ -101,6 +131,23 @@ module GraphQL
|
|
101
131
|
{ SYMBOL_KEY => obj.to_s }
|
102
132
|
elsif obj.respond_to?(:to_gid_param)
|
103
133
|
{GLOBALID_KEY => obj.to_gid_param}
|
134
|
+
elsif defined?(ActiveSupport::TimeWithZone) && obj.is_a?(ActiveSupport::TimeWithZone) && obj.class.name != Time.name
|
135
|
+
# This handles a case where Rails prior to 7 would
|
136
|
+
# make the class ActiveSupport::TimeWithZone return "Time" for
|
137
|
+
# its name. In Rails 7, it will now return "ActiveSupport::TimeWithZone",
|
138
|
+
# which happens to be incompatible with expectations we have
|
139
|
+
# with what a Time class supports ( notably, strptime in `load_value` ).
|
140
|
+
#
|
141
|
+
# This now passes along the name of the zone, such that a future deserialization
|
142
|
+
# of this string will use the correct time zone from the ActiveSupport TimeZone
|
143
|
+
# list to produce the time.
|
144
|
+
#
|
145
|
+
{ TIMESTAMP_KEY => [obj.class.name, obj.time_zone.name, obj.strftime(TIMESTAMP_FORMAT)] }
|
146
|
+
elsif obj.is_a?(Date) || obj.is_a?(Time)
|
147
|
+
# DateTime extends Date; for TimeWithZone, call `.utc` first.
|
148
|
+
{ TIMESTAMP_KEY => [obj.class.name, obj.strftime(TIMESTAMP_FORMAT)] }
|
149
|
+
elsif obj.is_a?(OpenStruct)
|
150
|
+
{ OPEN_STRUCT_KEY => dump_value(obj.to_h) }
|
104
151
|
else
|
105
152
|
obj
|
106
153
|
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "securerandom"
|
3
|
+
require "graphql/subscriptions/broadcast_analyzer"
|
3
4
|
require "graphql/subscriptions/event"
|
4
5
|
require "graphql/subscriptions/instrumentation"
|
5
6
|
require "graphql/subscriptions/serialize"
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
require "graphql/subscriptions/subscription_root"
|
7
|
+
require "graphql/subscriptions/action_cable_subscriptions"
|
8
|
+
require "graphql/subscriptions/default_subscription_resolve_extension"
|
10
9
|
|
11
10
|
module GraphQL
|
12
11
|
class Subscriptions
|
@@ -16,44 +15,64 @@ module GraphQL
|
|
16
15
|
class InvalidTriggerError < GraphQL::Error
|
17
16
|
end
|
18
17
|
|
18
|
+
# Raised when either:
|
19
|
+
# - An initial subscription didn't have a value for `context[subscription_scope]`
|
20
|
+
# - Or, an update didn't pass `.trigger(..., scope:)`
|
21
|
+
# When raised, the initial subscription or update fails completely.
|
22
|
+
class SubscriptionScopeMissingError < GraphQL::Error
|
23
|
+
end
|
24
|
+
|
19
25
|
# @see {Subscriptions#initialize} for options, concrete implementations may add options.
|
20
26
|
def self.use(defn, options = {})
|
21
27
|
schema = defn.is_a?(Class) ? defn : defn.target
|
22
28
|
|
23
|
-
if schema.subscriptions
|
29
|
+
if schema.subscriptions(inherited: false)
|
24
30
|
raise ArgumentError, "Can't reinstall subscriptions. #{schema} is using #{schema.subscriptions}, can't also add #{self}"
|
25
31
|
end
|
26
32
|
|
27
33
|
instrumentation = Subscriptions::Instrumentation.new(schema: schema)
|
28
34
|
defn.instrument(:query, instrumentation)
|
29
|
-
defn.instrument(:field, instrumentation)
|
30
35
|
options[:schema] = schema
|
31
36
|
schema.subscriptions = self.new(**options)
|
37
|
+
schema.add_subscription_extension_if_necessary
|
32
38
|
nil
|
33
39
|
end
|
34
40
|
|
35
41
|
# @param schema [Class] the GraphQL schema this manager belongs to
|
36
|
-
|
42
|
+
# @param validate_update [Boolean] If false, then validation is skipped when executing updates
|
43
|
+
def initialize(schema:, validate_update: true, broadcast: false, default_broadcastable: false, **rest)
|
44
|
+
if broadcast
|
45
|
+
schema.query_analyzer(Subscriptions::BroadcastAnalyzer)
|
46
|
+
end
|
47
|
+
@default_broadcastable = default_broadcastable
|
37
48
|
@schema = schema
|
49
|
+
@validate_update = validate_update
|
38
50
|
end
|
39
51
|
|
52
|
+
# @return [Boolean] Used when fields don't have `broadcastable:` explicitly set
|
53
|
+
attr_reader :default_broadcastable
|
54
|
+
|
40
55
|
# Fetch subscriptions matching this field + arguments pair
|
41
56
|
# And pass them off to the queue.
|
42
57
|
# @param event_name [String]
|
43
58
|
# @param args [Hash<String, Symbol => Object]
|
44
59
|
# @param object [Object]
|
45
60
|
# @param scope [Symbol, String]
|
61
|
+
# @param context [Hash]
|
46
62
|
# @return [void]
|
47
|
-
def trigger(event_name, args, object, scope: nil)
|
63
|
+
def trigger(event_name, args, object, scope: nil, context: {})
|
64
|
+
# Make something as context-like as possible, even though there isn't a current query:
|
65
|
+
dummy_query = GraphQL::Query.new(@schema, "", validate: false, context: context)
|
66
|
+
context = dummy_query.context
|
48
67
|
event_name = event_name.to_s
|
49
68
|
|
50
69
|
# Try with the verbatim input first:
|
51
|
-
field = @schema.get_field(@schema.subscription, event_name)
|
70
|
+
field = @schema.get_field(@schema.subscription, event_name, context)
|
52
71
|
|
53
72
|
if field.nil?
|
54
73
|
# And if it wasn't found, normalize it:
|
55
74
|
normalized_event_name = normalize_name(event_name)
|
56
|
-
field = @schema.get_field(@schema.subscription, normalized_event_name)
|
75
|
+
field = @schema.get_field(@schema.subscription, normalized_event_name, context)
|
57
76
|
if field.nil?
|
58
77
|
raise InvalidTriggerError, "No subscription matching trigger: #{event_name} (looked for #{@schema.subscription.graphql_name}.#{normalized_event_name})"
|
59
78
|
end
|
@@ -63,13 +82,15 @@ module GraphQL
|
|
63
82
|
end
|
64
83
|
|
65
84
|
# Normalize symbol-keyed args to strings, try camelizing them
|
66
|
-
|
85
|
+
# Should this accept a real context somehow?
|
86
|
+
normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext)
|
67
87
|
|
68
88
|
event = Subscriptions::Event.new(
|
69
89
|
name: normalized_event_name,
|
70
90
|
arguments: normalized_args,
|
71
91
|
field: field,
|
72
92
|
scope: scope,
|
93
|
+
context: context,
|
73
94
|
)
|
74
95
|
execute_all(event, object)
|
75
96
|
end
|
@@ -77,40 +98,73 @@ module GraphQL
|
|
77
98
|
# `event` was triggered on `object`, and `subscription_id` was subscribed,
|
78
99
|
# so it should be updated.
|
79
100
|
#
|
80
|
-
# Load `subscription_id`'s GraphQL data, re-evaluate the query
|
81
|
-
#
|
82
|
-
# This is where a queue may be inserted to push updates in the background.
|
101
|
+
# Load `subscription_id`'s GraphQL data, re-evaluate the query and return the result.
|
83
102
|
#
|
84
103
|
# @param subscription_id [String]
|
85
104
|
# @param event [GraphQL::Subscriptions::Event] The event which was triggered
|
86
105
|
# @param object [Object] The value for the subscription field
|
87
|
-
# @return [
|
88
|
-
def
|
106
|
+
# @return [GraphQL::Query::Result]
|
107
|
+
def execute_update(subscription_id, event, object)
|
89
108
|
# Lookup the saved data for this subscription
|
90
109
|
query_data = read_subscription(subscription_id)
|
110
|
+
if query_data.nil?
|
111
|
+
delete_subscription(subscription_id)
|
112
|
+
return nil
|
113
|
+
end
|
114
|
+
|
91
115
|
# Fetch the required keys from the saved data
|
92
116
|
query_string = query_data.fetch(:query_string)
|
93
117
|
variables = query_data.fetch(:variables)
|
94
118
|
context = query_data.fetch(:context)
|
95
119
|
operation_name = query_data.fetch(:operation_name)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
120
|
+
execute_options = {
|
121
|
+
query: query_string,
|
122
|
+
context: context,
|
123
|
+
subscription_topic: event.topic,
|
124
|
+
operation_name: operation_name,
|
125
|
+
variables: variables,
|
126
|
+
root_value: object,
|
127
|
+
}
|
128
|
+
|
129
|
+
# merge event's and query's context together
|
130
|
+
context.merge!(event.context) unless event.context.nil? || context.nil?
|
131
|
+
|
132
|
+
execute_options[:validate] = validate_update?(**execute_options)
|
133
|
+
result = @schema.execute(**execute_options)
|
134
|
+
subscriptions_context = result.context.namespace(:subscriptions)
|
135
|
+
if subscriptions_context[:no_update]
|
136
|
+
result = nil
|
137
|
+
end
|
138
|
+
|
139
|
+
unsubscribed = subscriptions_context[:unsubscribed]
|
140
|
+
|
141
|
+
if unsubscribed
|
142
|
+
# `unsubscribe` was called, clean up on our side
|
143
|
+
# TODO also send `{more: false}` to client?
|
144
|
+
delete_subscription(subscription_id)
|
145
|
+
result = nil
|
146
|
+
end
|
147
|
+
|
148
|
+
result
|
149
|
+
end
|
150
|
+
|
151
|
+
# Define this method to customize whether to validate
|
152
|
+
# this subscription when executing an update.
|
153
|
+
#
|
154
|
+
# @return [Boolean] defaults to `true`, or false if `validate: false` is provided.
|
155
|
+
def validate_update?(query:, context:, root_value:, subscription_topic:, operation_name:, variables:)
|
156
|
+
@validate_update
|
157
|
+
end
|
158
|
+
|
159
|
+
# Run the update query for this subscription and deliver it
|
160
|
+
# @see {#execute_update}
|
161
|
+
# @see {#deliver}
|
162
|
+
# @return [void]
|
163
|
+
def execute(subscription_id, event, object)
|
164
|
+
res = execute_update(subscription_id, event, object)
|
165
|
+
if !res.nil?
|
166
|
+
deliver(subscription_id, res)
|
167
|
+
end
|
114
168
|
end
|
115
169
|
|
116
170
|
# Event `event` occurred on `object`,
|
@@ -119,16 +173,6 @@ module GraphQL
|
|
119
173
|
# @param object [Object]
|
120
174
|
# @return [void]
|
121
175
|
def execute_all(event, object)
|
122
|
-
each_subscription_id(event) do |subscription_id|
|
123
|
-
execute(subscription_id, event, object)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# Get each `subscription_id` subscribed to `event.topic` and yield them
|
128
|
-
# @param event [GraphQL::Subscriptions::Event]
|
129
|
-
# @yieldparam subscription_id [String]
|
130
|
-
# @return [void]
|
131
|
-
def each_subscription_id(event)
|
132
176
|
raise GraphQL::RequiredImplementationMissingError
|
133
177
|
end
|
134
178
|
|
@@ -183,6 +227,16 @@ module GraphQL
|
|
183
227
|
Schema::Member::BuildType.camelize(event_or_arg_name.to_s)
|
184
228
|
end
|
185
229
|
|
230
|
+
# @return [Boolean] if true, then a query like this one would be broadcasted
|
231
|
+
def broadcastable?(query_str, **query_options)
|
232
|
+
query = GraphQL::Query.new(@schema, query_str, **query_options)
|
233
|
+
if !query.valid?
|
234
|
+
raise "Invalid query: #{query.validation_errors.map(&:to_h).inspect}"
|
235
|
+
end
|
236
|
+
GraphQL::Analysis::AST.analyze_query(query, @schema.query_analyzers)
|
237
|
+
query.context.namespace(:subscriptions)[:subscription_broadcastable]
|
238
|
+
end
|
239
|
+
|
186
240
|
private
|
187
241
|
|
188
242
|
# Recursively normalize `args` as belonging to `arg_owner`:
|
@@ -191,9 +245,9 @@ module GraphQL
|
|
191
245
|
# @param arg_owner [GraphQL::Field, GraphQL::BaseType]
|
192
246
|
# @param args [Hash, Array, Any] some GraphQL input value to coerce as `arg_owner`
|
193
247
|
# @return [Any] normalized arguments value
|
194
|
-
def normalize_arguments(event_name, arg_owner, args)
|
248
|
+
def normalize_arguments(event_name, arg_owner, args, context)
|
195
249
|
case arg_owner
|
196
|
-
when GraphQL::
|
250
|
+
when GraphQL::Schema::Field, Class
|
197
251
|
if arg_owner.is_a?(Class) && !arg_owner.kind.input_object?
|
198
252
|
# it's a type, but not an input object
|
199
253
|
return args
|
@@ -202,19 +256,19 @@ module GraphQL
|
|
202
256
|
missing_arg_names = []
|
203
257
|
args.each do |k, v|
|
204
258
|
arg_name = k.to_s
|
205
|
-
arg_defn = arg_owner.
|
259
|
+
arg_defn = arg_owner.get_argument(arg_name, context)
|
206
260
|
if arg_defn
|
207
261
|
normalized_arg_name = arg_name
|
208
262
|
else
|
209
263
|
normalized_arg_name = normalize_name(arg_name)
|
210
|
-
arg_defn = arg_owner.
|
264
|
+
arg_defn = arg_owner.get_argument(normalized_arg_name, context)
|
211
265
|
end
|
212
266
|
|
213
267
|
if arg_defn
|
214
268
|
if arg_defn.loads
|
215
269
|
normalized_arg_name = arg_defn.keyword.to_s
|
216
270
|
end
|
217
|
-
normalized = normalize_arguments(event_name, arg_defn.type, v)
|
271
|
+
normalized = normalize_arguments(event_name, arg_defn.type, v, context)
|
218
272
|
normalized_args[normalized_arg_name] = normalized
|
219
273
|
else
|
220
274
|
# Couldn't find a matching argument definition
|
@@ -224,16 +278,17 @@ module GraphQL
|
|
224
278
|
|
225
279
|
# Backfill default values so that trigger arguments
|
226
280
|
# match query arguments.
|
227
|
-
arg_owner.arguments.each do |
|
281
|
+
arg_owner.arguments(context).each do |_name, arg_defn|
|
228
282
|
if arg_defn.default_value? && !normalized_args.key?(arg_defn.name)
|
229
|
-
|
283
|
+
default_value = arg_defn.default_value
|
284
|
+
# We don't have an underlying "object" here, so it can't call methods.
|
285
|
+
# This is broken.
|
286
|
+
normalized_args[arg_defn.name] = arg_defn.prepare_value(nil, default_value, context: context)
|
230
287
|
end
|
231
288
|
end
|
232
289
|
|
233
290
|
if missing_arg_names.any?
|
234
|
-
arg_owner_name = if arg_owner.is_a?(GraphQL::Field)
|
235
|
-
"Subscription.#{arg_owner.name}"
|
236
|
-
elsif arg_owner.is_a?(GraphQL::Schema::Field)
|
291
|
+
arg_owner_name = if arg_owner.is_a?(GraphQL::Schema::Field)
|
237
292
|
arg_owner.path
|
238
293
|
elsif arg_owner.is_a?(Class)
|
239
294
|
arg_owner.graphql_name
|
@@ -244,10 +299,10 @@ module GraphQL
|
|
244
299
|
end
|
245
300
|
|
246
301
|
normalized_args
|
247
|
-
when GraphQL::
|
248
|
-
args.map { |a| normalize_arguments(event_name, arg_owner.of_type, a) }
|
249
|
-
when GraphQL::
|
250
|
-
normalize_arguments(event_name, arg_owner.of_type, args)
|
302
|
+
when GraphQL::Schema::List
|
303
|
+
args.map { |a| normalize_arguments(event_name, arg_owner.of_type, a, context) }
|
304
|
+
when GraphQL::Schema::NonNull
|
305
|
+
normalize_arguments(event_name, arg_owner.of_type, args, context)
|
251
306
|
else
|
252
307
|
args
|
253
308
|
end
|
@@ -0,0 +1,16 @@
|
|
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
|
8
|
+
# with a `graphql` suffix.
|
9
|
+
module ActiveSupportNotificationsTrace
|
10
|
+
include NotificationsTrace
|
11
|
+
def initialize(engine: ActiveSupport::Notifications, **rest)
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|