graphql 1.8.7 → 1.9.0
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_generator.rb +2 -1
- data/lib/generators/graphql/scalar_generator.rb +20 -0
- data/lib/generators/graphql/templates/base_scalar.erb +4 -0
- data/lib/generators/graphql/templates/scalar.erb +13 -0
- data/lib/graphql/analysis/ast/analyzer.rb +62 -0
- data/lib/graphql/analysis/ast/field_usage.rb +28 -0
- data/lib/graphql/analysis/ast/max_query_complexity.rb +23 -0
- data/lib/graphql/analysis/ast/max_query_depth.rb +18 -0
- data/lib/graphql/analysis/ast/query_complexity.rb +114 -0
- data/lib/graphql/analysis/ast/query_depth.rb +66 -0
- data/lib/graphql/analysis/ast/visitor.rb +255 -0
- data/lib/graphql/analysis/ast.rb +82 -0
- data/lib/graphql/analysis.rb +1 -0
- data/lib/graphql/argument.rb +5 -0
- data/lib/graphql/authorization.rb +1 -0
- data/lib/graphql/backwards_compatibility.rb +1 -1
- data/lib/graphql/base_type.rb +1 -1
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +1 -2
- data/lib/graphql/compatibility/schema_parser_specification.rb +2 -6
- data/lib/graphql/dig.rb +19 -0
- data/lib/graphql/directive/include_directive.rb +1 -7
- data/lib/graphql/directive/skip_directive.rb +1 -8
- data/lib/graphql/directive.rb +13 -1
- data/lib/graphql/enum_type.rb +8 -0
- data/lib/graphql/execution/execute.rb +36 -17
- data/lib/graphql/execution/instrumentation.rb +2 -0
- data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
- data/lib/graphql/execution/interpreter/hash_response.rb +46 -0
- data/lib/graphql/execution/interpreter/resolve.rb +58 -0
- data/lib/graphql/execution/interpreter/runtime.rb +597 -0
- data/lib/graphql/execution/interpreter.rb +99 -0
- data/lib/graphql/execution/lazy.rb +8 -1
- data/lib/graphql/execution/lookahead.rb +351 -0
- data/lib/graphql/execution/multiplex.rb +37 -29
- data/lib/graphql/execution.rb +2 -0
- data/lib/graphql/execution_error.rb +1 -1
- data/lib/graphql/field.rb +1 -7
- data/lib/graphql/integer_encoding_error.rb +12 -0
- data/lib/graphql/internal_representation/rewrite.rb +127 -142
- data/lib/graphql/introspection/dynamic_fields.rb +8 -2
- data/lib/graphql/introspection/entry_points.rb +11 -6
- data/lib/graphql/introspection/enum_value_type.rb +4 -0
- data/lib/graphql/introspection/schema_type.rb +7 -2
- data/lib/graphql/introspection/type_type.rb +9 -5
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/block_string.rb +37 -0
- data/lib/graphql/language/document_from_schema_definition.rb +10 -7
- data/lib/graphql/language/lexer.rb +55 -36
- data/lib/graphql/language/lexer.rl +8 -3
- data/lib/graphql/language/nodes.rb +440 -362
- data/lib/graphql/language/parser.rb +56 -56
- data/lib/graphql/language/parser.y +12 -12
- data/lib/graphql/language/printer.rb +2 -2
- data/lib/graphql/language/visitor.rb +158 -15
- data/lib/graphql/language.rb +0 -1
- data/lib/graphql/literal_validation_error.rb +6 -0
- data/lib/graphql/query/arguments.rb +3 -2
- data/lib/graphql/query/arguments_cache.rb +1 -1
- data/lib/graphql/query/context.rb +14 -5
- data/lib/graphql/query/executor.rb +1 -1
- data/lib/graphql/query/result.rb +1 -1
- data/lib/graphql/query/validation_pipeline.rb +35 -11
- data/lib/graphql/query/variable_validation_error.rb +10 -1
- data/lib/graphql/query.rb +16 -2
- data/lib/graphql/relay/base_connection.rb +2 -0
- data/lib/graphql/relay/connection_instrumentation.rb +3 -1
- data/lib/graphql/relay/connection_resolve.rb +1 -1
- data/lib/graphql/relay/node.rb +2 -28
- data/lib/graphql/relay/relation_connection.rb +1 -1
- data/lib/graphql/schema/argument.rb +13 -5
- data/lib/graphql/schema/base_64_encoder.rb +4 -4
- data/lib/graphql/schema/build_from_definition.rb +2 -4
- data/lib/graphql/schema/default_type_error.rb +1 -1
- data/lib/graphql/schema/directive/feature.rb +66 -0
- data/lib/graphql/schema/directive/include.rb +25 -0
- data/lib/graphql/schema/directive/skip.rb +25 -0
- data/lib/graphql/schema/directive/transform.rb +48 -0
- data/lib/graphql/schema/directive.rb +103 -0
- data/lib/graphql/schema/enum_value.rb +3 -2
- data/lib/graphql/schema/field/connection_extension.rb +50 -0
- data/lib/graphql/schema/field/scope_extension.rb +18 -0
- data/lib/graphql/schema/field.rb +273 -64
- data/lib/graphql/schema/field_extension.rb +69 -0
- data/lib/graphql/schema/input_object.rb +16 -8
- data/lib/graphql/schema/interface.rb +1 -0
- data/lib/graphql/schema/loader.rb +22 -16
- data/lib/graphql/schema/member/base_dsl_methods.rb +8 -2
- data/lib/graphql/schema/member/build_type.rb +33 -1
- data/lib/graphql/schema/member/has_arguments.rb +6 -2
- data/lib/graphql/schema/member/has_fields.rb +18 -70
- data/lib/graphql/schema/member/has_path.rb +25 -0
- data/lib/graphql/schema/member/instrumentation.rb +10 -7
- data/lib/graphql/schema/member.rb +2 -0
- data/lib/graphql/schema/mutation.rb +6 -48
- data/lib/graphql/schema/non_null.rb +5 -1
- data/lib/graphql/schema/object.rb +18 -4
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +42 -9
- data/lib/graphql/schema/resolver/has_payload_type.rb +65 -0
- data/lib/graphql/schema/resolver.rb +45 -20
- data/lib/graphql/schema/subscription.rb +97 -0
- data/lib/graphql/schema/traversal.rb +11 -7
- data/lib/graphql/schema.rb +186 -38
- data/lib/graphql/static_validation/all_rules.rb +3 -2
- data/lib/graphql/static_validation/base_visitor.rb +199 -0
- data/lib/graphql/static_validation/default_visitor.rb +15 -0
- data/lib/graphql/static_validation/definition_dependencies.rb +62 -68
- data/lib/graphql/static_validation/{message.rb → error.rb} +11 -11
- data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
- data/lib/graphql/static_validation/literal_validator.rb +54 -11
- data/lib/graphql/static_validation/no_validate_visitor.rb +10 -0
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +87 -16
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +31 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +11 -11
- data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +52 -8
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +12 -15
- data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +19 -14
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +17 -19
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +30 -14
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +356 -29
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +20 -13
- data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +37 -29
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +25 -17
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +12 -10
- data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +7 -11
- data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +16 -16
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +21 -14
- data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +10 -14
- data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +30 -30
- data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +25 -17
- data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +17 -18
- data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +47 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +10 -14
- data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +28 -17
- data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +35 -27
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +15 -14
- data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +41 -30
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +18 -14
- data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +73 -65
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
- data/lib/graphql/static_validation/validation_context.rb +8 -51
- data/lib/graphql/static_validation/validator.rb +23 -15
- data/lib/graphql/static_validation.rb +5 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -2
- data/lib/graphql/subscriptions/event.rb +28 -5
- data/lib/graphql/subscriptions/subscription_root.rb +66 -0
- data/lib/graphql/subscriptions.rb +16 -2
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +0 -1
- data/lib/graphql/tracing/appsignal_tracing.rb +1 -1
- data/lib/graphql/tracing/data_dog_tracing.rb +1 -1
- data/lib/graphql/tracing/new_relic_tracing.rb +3 -3
- data/lib/graphql/tracing/platform_tracing.rb +17 -1
- data/lib/graphql/tracing/prometheus_tracing.rb +1 -1
- data/lib/graphql/tracing/scout_tracing.rb +1 -1
- data/lib/graphql/tracing/skylight_tracing.rb +3 -3
- data/lib/graphql/tracing.rb +8 -8
- data/lib/graphql/types/float.rb +1 -1
- data/lib/graphql/types/int.rb +11 -2
- data/lib/graphql/types/iso_8601_date_time.rb +15 -1
- data/lib/graphql/types/relay/base_connection.rb +15 -1
- data/lib/graphql/types/relay/node.rb +0 -1
- data/lib/graphql/types/relay/node_field.rb +43 -0
- data/lib/graphql/types/relay/nodes_field.rb +45 -0
- data/lib/graphql/types/relay.rb +2 -0
- data/lib/graphql/unauthorized_error.rb +4 -0
- data/lib/graphql/unauthorized_field_error.rb +23 -0
- data/lib/graphql/upgrader/member.rb +5 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +6 -1
- data/readme.md +7 -7
- data/spec/dummy/Gemfile +1 -1
- data/spec/dummy/Gemfile.lock +157 -0
- data/spec/dummy/app/channels/graphql_channel.rb +22 -11
- data/spec/dummy/config/locales/en.yml +1 -1
- data/spec/dummy/log/test.log +199 -0
- data/spec/dummy/test/test_helper.rb +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4w/4wzXRZrAkwKdgYaSE0pid5eB-fer8vSfSku_NPg4rMA.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7I/7IHVBiJT06QSpgLpLoJIxboQ0B-D_tMTxsvoezBTV3Q.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8w/8wY_SKagj8wHuwGNAAf6JnQ8joMbC6cEYpHrTAI8Urc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/AK/AKzz1u6bGb4auXcrObA_g5LL-oV0ejNGa448AgAi_WQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ET/ETW4uxvaYpruL8y6_ZptUH82ZowMaHIqvg5WexBFdEM.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F1/F1TWpjjyA56k9Z90n5B3xRn7DUdGjX73QCkYC6k07JQ.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F8/F8MUNRzORGFgr329fNM0xLaoWCXdv3BIalT7dsvLfjs.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KB/KB07ZaKNC5uXJ7TjLi-WqnY6g7dq8wWp_8N3HNjBNxg.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ms/MsKSimH_UCB-H1tLvDABDHuvGciuoW6kVqQWDrXU5FQ.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mt/Mtci-Kim50aPOmeClD4AIicKn1d1WJ0n454IjSd94sk.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QH/QHt3Tc1Y6M66Oo_pDuMyWrQNs4Pp3SMeZR5K1wJj2Ts.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/XU/XU4k1OXnfMils5SrirorPvDSyDSqiOWLZNtmAH1HH8k.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ZI/ZIof7mZxWWCnraIFOCuV6a8QRWzKJXJnx2Xd7C0ZyX0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cG/cGc_puuPS5pZKgUcy1Y_i1L6jl5UtsiIrMH59rTzR6c.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/df/dfro_B6bx3KP1Go-7jEOqqZ2j4hVRseXIc3es9PKQno.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/jO/jO1DfbqnG0mTULsjJJANc3fefrG2zt7DIMmcptMT628.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pE/pE7gO6pQ-z187Swb4hT554wmqsq-cNzgPWLrCz-LQQQ.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/r9/r9iU1l58a6rxkZSW5RSC52_tD-_UQuHxoMVnkfJ7Mhs.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xi/xitPPFfPIyDMpaznV0sBBcw8eSCV8PJcLLWin78sCgE.cache +0 -0
- data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
- data/spec/graphql/analysis/analyze_query_spec.rb +1 -1
- data/spec/graphql/analysis/ast/field_usage_spec.rb +51 -0
- data/spec/graphql/analysis/ast/max_query_complexity_spec.rb +120 -0
- data/spec/graphql/analysis/ast/max_query_depth_spec.rb +114 -0
- data/spec/graphql/analysis/ast/query_complexity_spec.rb +299 -0
- data/spec/graphql/analysis/ast/query_depth_spec.rb +108 -0
- data/spec/graphql/analysis/ast_spec.rb +269 -0
- data/spec/graphql/authorization_spec.rb +120 -23
- data/spec/graphql/base_type_spec.rb +6 -4
- data/spec/graphql/enum_type_spec.rb +6 -1
- data/spec/graphql/execution/execute_spec.rb +9 -9
- data/spec/graphql/execution/instrumentation_spec.rb +19 -0
- data/spec/graphql/execution/interpreter_spec.rb +485 -0
- data/spec/graphql/execution/lazy_spec.rb +67 -1
- data/spec/graphql/execution/lookahead_spec.rb +363 -0
- data/spec/graphql/execution/multiplex_spec.rb +31 -3
- data/spec/graphql/execution/typecast_spec.rb +20 -20
- data/spec/graphql/execution_error_spec.rb +110 -96
- data/spec/graphql/field_spec.rb +1 -1
- data/spec/graphql/input_object_type_spec.rb +13 -352
- data/spec/graphql/int_type_spec.rb +19 -0
- data/spec/graphql/interface_type_spec.rb +4 -4
- data/spec/graphql/internal_representation/rewrite_spec.rb +2 -0
- data/spec/graphql/introspection/input_value_type_spec.rb +1 -1
- data/spec/graphql/introspection/type_type_spec.rb +1 -2
- data/spec/graphql/language/document_from_schema_definition_spec.rb +2 -2
- data/spec/graphql/language/lexer_spec.rb +72 -3
- data/spec/graphql/language/nodes_spec.rb +20 -0
- data/spec/graphql/language/printer_spec.rb +18 -6
- data/spec/graphql/language/visitor_spec.rb +320 -14
- data/spec/graphql/non_null_type_spec.rb +1 -1
- data/spec/graphql/object_type_spec.rb +32 -27
- data/spec/graphql/query/arguments_spec.rb +21 -0
- data/spec/graphql/query/context_spec.rb +28 -0
- data/spec/graphql/query/executor_spec.rb +40 -36
- data/spec/graphql/query_spec.rb +12 -6
- data/spec/graphql/schema/argument_spec.rb +35 -1
- data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
- data/spec/graphql/schema/catchall_middleware_spec.rb +16 -15
- data/spec/graphql/schema/directive/feature_spec.rb +81 -0
- data/spec/graphql/schema/directive/transform_spec.rb +39 -0
- data/spec/graphql/schema/enum_spec.rb +12 -3
- data/spec/graphql/schema/enum_value_spec.rb +11 -0
- data/spec/graphql/schema/field_extension_spec.rb +115 -0
- data/spec/graphql/schema/field_spec.rb +47 -7
- data/spec/graphql/schema/input_object_spec.rb +95 -0
- data/spec/graphql/schema/instrumentation_spec.rb +3 -0
- data/spec/graphql/schema/interface_spec.rb +8 -2
- data/spec/graphql/schema/introspection_system_spec.rb +9 -1
- data/spec/graphql/schema/loader_spec.rb +5 -0
- data/spec/graphql/schema/member/accepts_definition_spec.rb +4 -0
- data/spec/graphql/schema/member/build_type_spec.rb +46 -0
- data/spec/graphql/schema/member/scoped_spec.rb +19 -3
- data/spec/graphql/schema/mutation_spec.rb +5 -3
- data/spec/graphql/schema/object_spec.rb +9 -1
- data/spec/graphql/schema/printer_spec.rb +255 -93
- data/spec/graphql/schema/relay_classic_mutation_spec.rb +133 -0
- data/spec/graphql/schema/resolver_spec.rb +173 -9
- data/spec/graphql/schema/scalar_spec.rb +6 -0
- data/spec/graphql/schema/subscription_spec.rb +416 -0
- data/spec/graphql/schema/traversal_spec.rb +10 -10
- data/spec/graphql/schema/type_expression_spec.rb +2 -2
- data/spec/graphql/schema/union_spec.rb +7 -0
- data/spec/graphql/schema/validation_spec.rb +1 -1
- data/spec/graphql/schema/warden_spec.rb +145 -88
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +213 -73
- data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +72 -29
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +10 -5
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -5
- data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +131 -5
- data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
- data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +22 -2
- data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +6 -3
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +13 -4
- data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +58 -0
- data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -1
- data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +14 -7
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +14 -7
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +8 -4
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +23 -3
- data/spec/graphql/static_validation/type_stack_spec.rb +10 -19
- data/spec/graphql/static_validation/validator_spec.rb +50 -2
- data/spec/graphql/subscriptions_spec.rb +27 -16
- data/spec/graphql/tracing/new_relic_tracing_spec.rb +16 -0
- data/spec/graphql/tracing/platform_tracing_spec.rb +59 -37
- data/spec/graphql/tracing/prometheus_tracing_spec.rb +3 -0
- data/spec/graphql/tracing/skylight_tracing_spec.rb +16 -0
- data/spec/graphql/types/iso_8601_date_time_spec.rb +29 -2
- data/spec/graphql/union_type_spec.rb +2 -2
- data/spec/graphql/upgrader/member_spec.rb +67 -0
- data/spec/{graphql → integration/mongoid/graphql}/relay/mongo_relation_connection_spec.rb +11 -22
- data/spec/integration/mongoid/spec_helper.rb +2 -0
- data/spec/{support → integration/mongoid}/star_trek/data.rb +0 -0
- data/spec/{support → integration/mongoid}/star_trek/schema.rb +56 -34
- data/spec/{support/star_wars → integration/rails}/data.rb +1 -0
- data/spec/{support → integration/rails/generators}/base_generator_test.rb +0 -0
- data/spec/{generators → integration/rails/generators}/graphql/enum_generator_spec.rb +0 -0
- data/spec/{generators → integration/rails/generators}/graphql/install_generator_spec.rb +1 -1
- data/spec/{generators → integration/rails/generators}/graphql/interface_generator_spec.rb +0 -0
- data/spec/{generators → integration/rails/generators}/graphql/loader_generator_spec.rb +0 -0
- data/spec/{generators → integration/rails/generators}/graphql/mutation_generator_spec.rb +0 -0
- data/spec/{generators → integration/rails/generators}/graphql/object_generator_spec.rb +0 -0
- data/spec/integration/rails/generators/graphql/scalar_generator_spec.rb +28 -0
- data/spec/{generators → integration/rails/generators}/graphql/union_generator_spec.rb +0 -0
- data/spec/integration/rails/graphql/input_object_type_spec.rb +364 -0
- data/spec/{graphql → integration/rails/graphql}/query/variables_spec.rb +7 -7
- data/spec/{graphql → integration/rails/graphql}/relay/array_connection_spec.rb +9 -9
- data/spec/{graphql → integration/rails/graphql}/relay/base_connection_spec.rb +11 -3
- data/spec/{graphql → integration/rails/graphql}/relay/connection_instrumentation_spec.rb +19 -22
- data/spec/{graphql → integration/rails/graphql}/relay/connection_resolve_spec.rb +16 -0
- data/spec/{graphql → integration/rails/graphql}/relay/connection_type_spec.rb +0 -0
- data/spec/{graphql → integration/rails/graphql}/relay/edge_spec.rb +0 -0
- data/spec/{graphql → integration/rails/graphql}/relay/mutation_spec.rb +48 -0
- data/spec/{graphql → integration/rails/graphql}/relay/node_spec.rb +0 -0
- data/spec/{graphql → integration/rails/graphql}/relay/page_info_spec.rb +22 -22
- data/spec/{graphql → integration/rails/graphql}/relay/range_add_spec.rb +4 -4
- data/spec/{graphql → integration/rails/graphql}/relay/relation_connection_spec.rb +56 -27
- data/spec/{graphql → integration/rails/graphql}/schema_spec.rb +15 -11
- data/spec/{graphql → integration/rails/graphql}/tracing/active_support_notifications_tracing_spec.rb +16 -9
- data/spec/integration/rails/spec_helper.rb +25 -0
- data/spec/integration/tmp/app/graphql/types/family_type.rb +9 -0
- data/spec/spec_helper.rb +23 -39
- data/spec/support/dummy/data.rb +20 -17
- data/spec/support/dummy/schema.rb +315 -305
- data/spec/support/error_bubbling_helpers.rb +23 -0
- data/spec/support/jazz.rb +213 -46
- data/spec/support/lazy_helpers.rb +69 -27
- data/spec/support/new_relic.rb +3 -0
- data/spec/support/skylight.rb +3 -0
- data/spec/support/star_wars/schema.rb +131 -81
- data/spec/support/static_validation_helpers.rb +9 -5
- metadata +418 -261
- data/lib/graphql/language/comments.rb +0 -45
- data/lib/graphql/static_validation/arguments_validator.rb +0 -50
- data/spec/graphql/schema/member/has_fields_spec.rb +0 -129
- data/spec/rails_dependency_sanity_spec.rb +0 -14
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class VariablesAreInputTypesError < StaticValidation::Error
|
5
|
+
attr_reader :type_name
|
6
|
+
attr_reader :variable_name
|
7
|
+
|
8
|
+
def initialize(message, path: nil, nodes: [], type:, name:)
|
9
|
+
super(message, path: path, nodes: nodes)
|
10
|
+
@type_name = type
|
11
|
+
@variable_name = name
|
12
|
+
end
|
13
|
+
|
14
|
+
# A hash representation of this Message
|
15
|
+
def to_h
|
16
|
+
extensions = {
|
17
|
+
"code" => code,
|
18
|
+
"typeName" => type_name,
|
19
|
+
"variableName" => variable_name
|
20
|
+
}
|
21
|
+
|
22
|
+
super.merge({
|
23
|
+
"extensions" => extensions
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
def code
|
28
|
+
"variableRequiresValidType"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -11,9 +11,7 @@ module GraphQL
|
|
11
11
|
# - re-visiting the AST for each validator
|
12
12
|
# - allowing validators to say `followSpreads: true`
|
13
13
|
#
|
14
|
-
|
15
|
-
include GraphQL::StaticValidation::Message::MessageHelper
|
16
|
-
|
14
|
+
module VariablesAreUsedAndDefined
|
17
15
|
class VariableUsage
|
18
16
|
attr_accessor :ast_node, :used_by, :declared_by, :path
|
19
17
|
def used?
|
@@ -25,73 +23,67 @@ module GraphQL
|
|
25
23
|
end
|
26
24
|
end
|
27
25
|
|
28
|
-
def
|
29
|
-
|
26
|
+
def initialize(*)
|
27
|
+
super
|
28
|
+
@variable_usages_for_context = Hash.new {|hash, key| hash[key] = Hash.new {|h, k| h[k] = VariableUsage.new } }
|
29
|
+
@spreads_for_context = Hash.new {|hash, key| hash[key] = [] }
|
30
|
+
@variable_context_stack = []
|
30
31
|
end
|
31
32
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
variable_context_stack
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
variable_context_stack.push(node)
|
43
|
-
}
|
44
|
-
|
45
|
-
pop_variable_context_stack = ->(node, parent) {
|
46
|
-
variable_context_stack.pop
|
47
|
-
}
|
48
|
-
|
49
|
-
|
50
|
-
context.visitor[GraphQL::Language::Nodes::OperationDefinition] << push_variable_context_stack
|
51
|
-
context.visitor[GraphQL::Language::Nodes::OperationDefinition] << ->(node, parent) {
|
52
|
-
# mark variables as defined:
|
53
|
-
var_hash = variable_usages_for_context[node]
|
54
|
-
node.variables.each { |var|
|
55
|
-
var_usage = var_hash[var.name]
|
56
|
-
var_usage.declared_by = node
|
57
|
-
var_usage.path = context.path
|
58
|
-
}
|
33
|
+
def on_operation_definition(node, parent)
|
34
|
+
# initialize the hash of vars for this context:
|
35
|
+
@variable_usages_for_context[node]
|
36
|
+
@variable_context_stack.push(node)
|
37
|
+
# mark variables as defined:
|
38
|
+
var_hash = @variable_usages_for_context[node]
|
39
|
+
node.variables.each { |var|
|
40
|
+
var_usage = var_hash[var.name]
|
41
|
+
var_usage.declared_by = node
|
42
|
+
var_usage.path = context.path
|
59
43
|
}
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
context.visitor[GraphQL::Language::Nodes::FragmentDefinition].leave << pop_variable_context_stack
|
44
|
+
super
|
45
|
+
@variable_context_stack.pop
|
46
|
+
end
|
64
47
|
|
65
|
-
|
66
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
48
|
+
def on_fragment_definition(node, parent)
|
49
|
+
# initialize the hash of vars for this context:
|
50
|
+
@variable_usages_for_context[node]
|
51
|
+
@variable_context_stack.push(node)
|
52
|
+
super
|
53
|
+
@variable_context_stack.pop
|
54
|
+
end
|
72
55
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
usage.ast_node = node
|
82
|
-
usage.path = context.path
|
83
|
-
}
|
56
|
+
# For FragmentSpreads:
|
57
|
+
# - find the context on the stack
|
58
|
+
# - mark the context as containing this spread
|
59
|
+
def on_fragment_spread(node, parent)
|
60
|
+
variable_context = @variable_context_stack.last
|
61
|
+
@spreads_for_context[variable_context] << node.name
|
62
|
+
super
|
63
|
+
end
|
84
64
|
|
65
|
+
# For VariableIdentifiers:
|
66
|
+
# - mark the variable as used
|
67
|
+
# - assign its AST node
|
68
|
+
def on_variable_identifier(node, parent)
|
69
|
+
usage_context = @variable_context_stack.last
|
70
|
+
declared_variables = @variable_usages_for_context[usage_context]
|
71
|
+
usage = declared_variables[node.name]
|
72
|
+
usage.used_by = usage_context
|
73
|
+
usage.ast_node = node
|
74
|
+
usage.path = context.path
|
75
|
+
super
|
76
|
+
end
|
85
77
|
|
86
|
-
|
87
|
-
|
88
|
-
|
78
|
+
def on_document(node, parent)
|
79
|
+
super
|
80
|
+
fragment_definitions = @variable_usages_for_context.select { |key, value| key.is_a?(GraphQL::Language::Nodes::FragmentDefinition) }
|
81
|
+
operation_definitions = @variable_usages_for_context.select { |key, value| key.is_a?(GraphQL::Language::Nodes::OperationDefinition) }
|
89
82
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
}
|
83
|
+
operation_definitions.each do |node, node_variables|
|
84
|
+
follow_spreads(node, node_variables, @spreads_for_context, fragment_definitions, [])
|
85
|
+
create_errors(node_variables)
|
86
|
+
end
|
95
87
|
end
|
96
88
|
|
97
89
|
private
|
@@ -129,16 +121,32 @@ module GraphQL
|
|
129
121
|
|
130
122
|
# Determine all the error messages,
|
131
123
|
# Then push messages into the validation context
|
132
|
-
def create_errors(node_variables
|
124
|
+
def create_errors(node_variables)
|
133
125
|
# Declared but not used:
|
134
126
|
node_variables
|
135
127
|
.select { |name, usage| usage.declared? && !usage.used? }
|
136
|
-
.each { |var_name, usage|
|
128
|
+
.each { |var_name, usage|
|
129
|
+
add_error(GraphQL::StaticValidation::VariablesAreUsedAndDefinedError.new(
|
130
|
+
"Variable $#{var_name} is declared by #{usage.declared_by.name} but not used",
|
131
|
+
nodes: usage.declared_by,
|
132
|
+
path: usage.path,
|
133
|
+
name: var_name,
|
134
|
+
error_type: VariablesAreUsedAndDefinedError::VIOLATIONS[:VARIABLE_NOT_USED]
|
135
|
+
))
|
136
|
+
}
|
137
137
|
|
138
138
|
# Used but not declared:
|
139
139
|
node_variables
|
140
140
|
.select { |name, usage| usage.used? && !usage.declared? }
|
141
|
-
.each { |var_name, usage|
|
141
|
+
.each { |var_name, usage|
|
142
|
+
add_error(GraphQL::StaticValidation::VariablesAreUsedAndDefinedError.new(
|
143
|
+
"Variable $#{var_name} is used by #{usage.used_by.name} but not declared",
|
144
|
+
nodes: usage.ast_node,
|
145
|
+
path: usage.path,
|
146
|
+
name: var_name,
|
147
|
+
error_type: VariablesAreUsedAndDefinedError::VIOLATIONS[:VARIABLE_NOT_DEFINED]
|
148
|
+
))
|
149
|
+
}
|
142
150
|
end
|
143
151
|
end
|
144
152
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class VariablesAreUsedAndDefinedError < StaticValidation::Error
|
5
|
+
attr_reader :variable_name
|
6
|
+
attr_reader :violation
|
7
|
+
|
8
|
+
VIOLATIONS = {
|
9
|
+
:VARIABLE_NOT_USED => "variableNotUsed",
|
10
|
+
:VARIABLE_NOT_DEFINED => "variableNotDefined",
|
11
|
+
}
|
12
|
+
|
13
|
+
def initialize(message, path: nil, nodes: [], name:, error_type:)
|
14
|
+
super(message, path: path, nodes: nodes)
|
15
|
+
@variable_name = name
|
16
|
+
raise("Unexpected error type: #{error_type}") if !VIOLATIONS.values.include?(error_type)
|
17
|
+
@violation = error_type
|
18
|
+
end
|
19
|
+
|
20
|
+
# A hash representation of this Message
|
21
|
+
def to_h
|
22
|
+
extensions = {
|
23
|
+
"code" => code,
|
24
|
+
"variableName" => variable_name
|
25
|
+
}
|
26
|
+
|
27
|
+
super.merge({
|
28
|
+
"extensions" => extensions
|
29
|
+
})
|
30
|
+
end
|
31
|
+
|
32
|
+
def code
|
33
|
+
@violation
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -14,70 +14,27 @@ module GraphQL
|
|
14
14
|
class ValidationContext
|
15
15
|
extend Forwardable
|
16
16
|
|
17
|
-
attr_reader :query, :errors, :visitor,
|
17
|
+
attr_reader :query, :errors, :visitor,
|
18
|
+
:on_dependency_resolve_handlers
|
18
19
|
|
19
20
|
def_delegators :@query, :schema, :document, :fragments, :operations, :warden
|
20
21
|
|
21
|
-
def initialize(query)
|
22
|
+
def initialize(query, visitor_class)
|
22
23
|
@query = query
|
23
24
|
@literal_validator = LiteralValidator.new(context: query.context)
|
24
25
|
@errors = []
|
25
|
-
@visitor = GraphQL::Language::Visitor.new(document)
|
26
|
-
@type_stack = GraphQL::StaticValidation::TypeStack.new(schema, visitor)
|
27
|
-
definition_dependencies = DefinitionDependencies.mount(self)
|
28
26
|
@on_dependency_resolve_handlers = []
|
29
|
-
@
|
30
|
-
visitor[GraphQL::Language::Nodes::Document].leave << ->(_n, _p) {
|
31
|
-
@dependencies = definition_dependencies.dependency_map { |defn, spreads, frag|
|
32
|
-
@on_dependency_resolve_handlers.each { |h| h.call(defn, spreads, frag) }
|
33
|
-
}
|
34
|
-
}
|
27
|
+
@visitor = visitor_class.new(document, self)
|
35
28
|
end
|
36
29
|
|
30
|
+
def_delegators :@visitor,
|
31
|
+
:path, :type_definition, :field_definition, :argument_definition,
|
32
|
+
:parent_type_definition, :directive_definition, :object_types, :dependencies
|
33
|
+
|
37
34
|
def on_dependency_resolve(&handler)
|
38
35
|
@on_dependency_resolve_handlers << handler
|
39
36
|
end
|
40
37
|
|
41
|
-
def object_types
|
42
|
-
@type_stack.object_types
|
43
|
-
end
|
44
|
-
|
45
|
-
def each_irep_node(&handler)
|
46
|
-
@each_irep_node_handlers << handler
|
47
|
-
end
|
48
|
-
|
49
|
-
# @return [GraphQL::BaseType] The current object type
|
50
|
-
def type_definition
|
51
|
-
object_types.last
|
52
|
-
end
|
53
|
-
|
54
|
-
# @return [GraphQL::BaseType] The type which the current type came from
|
55
|
-
def parent_type_definition
|
56
|
-
object_types[-2]
|
57
|
-
end
|
58
|
-
|
59
|
-
# @return [GraphQL::Field, nil] The most-recently-entered GraphQL::Field, if currently inside one
|
60
|
-
def field_definition
|
61
|
-
@type_stack.field_definitions.last
|
62
|
-
end
|
63
|
-
|
64
|
-
# @return [Array<String>] Field names to get to the current field
|
65
|
-
def path
|
66
|
-
@type_stack.path.dup
|
67
|
-
end
|
68
|
-
|
69
|
-
# @return [GraphQL::Directive, nil] The most-recently-entered GraphQL::Directive, if currently inside one
|
70
|
-
def directive_definition
|
71
|
-
@type_stack.directive_definitions.last
|
72
|
-
end
|
73
|
-
|
74
|
-
# @return [GraphQL::Argument, nil] The most-recently-entered GraphQL::Argument, if currently inside one
|
75
|
-
def argument_definition
|
76
|
-
# Don't get the _last_ one because that's the current one.
|
77
|
-
# Get the second-to-last one, which is the parent of the current one.
|
78
|
-
@type_stack.argument_definitions[-2]
|
79
|
-
end
|
80
|
-
|
81
38
|
def valid_literal?(ast_value, type)
|
82
39
|
@literal_validator.validate(ast_value, type)
|
83
40
|
end
|
@@ -23,29 +23,37 @@ module GraphQL
|
|
23
23
|
# @return [Array<Hash>]
|
24
24
|
def validate(query, validate: true)
|
25
25
|
query.trace("validate", { validate: validate, query: query }) do
|
26
|
-
|
27
|
-
|
26
|
+
can_skip_rewrite = query.context.interpreter? && query.schema.using_ast_analysis?
|
27
|
+
errors = if validate == false && can_skip_rewrite
|
28
|
+
[]
|
29
|
+
else
|
30
|
+
rules_to_use = validate ? @rules : []
|
31
|
+
visitor_class = BaseVisitor.including_rules(rules_to_use, rewrite: !can_skip_rewrite)
|
28
32
|
|
29
|
-
|
30
|
-
rewrite.validate(context)
|
33
|
+
context = GraphQL::StaticValidation::ValidationContext.new(query, visitor_class)
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
# Attach legacy-style rules
|
36
|
+
rules_to_use.each do |rule_class_or_module|
|
37
|
+
if rule_class_or_module.method_defined?(:validate)
|
38
|
+
rule_class_or_module.new.validate(context)
|
39
|
+
end
|
36
40
|
end
|
41
|
+
|
42
|
+
context.visitor.visit
|
43
|
+
context.errors
|
37
44
|
end
|
38
45
|
|
39
|
-
context.visitor.visit
|
40
|
-
rewrite_result = rewrite.document
|
41
46
|
|
42
|
-
|
43
|
-
|
47
|
+
irep = if errors.empty? && context
|
48
|
+
# Only return this if there are no errors and validation was actually run
|
49
|
+
context.visitor.rewrite_document
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
44
53
|
|
45
54
|
{
|
46
|
-
errors:
|
47
|
-
|
48
|
-
irep: context.errors.any? ? nil : rewrite_result,
|
55
|
+
errors: errors,
|
56
|
+
irep: irep,
|
49
57
|
}
|
50
58
|
end
|
51
59
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "graphql/static_validation/
|
3
|
-
require "graphql/static_validation/arguments_validator"
|
2
|
+
require "graphql/static_validation/error"
|
4
3
|
require "graphql/static_validation/definition_dependencies"
|
5
4
|
require "graphql/static_validation/type_stack"
|
6
5
|
require "graphql/static_validation/validator"
|
7
6
|
require "graphql/static_validation/validation_context"
|
8
7
|
require "graphql/static_validation/literal_validator"
|
9
|
-
|
8
|
+
require "graphql/static_validation/base_visitor"
|
9
|
+
require "graphql/static_validation/no_validate_visitor"
|
10
10
|
|
11
11
|
rules_glob = File.expand_path("../static_validation/rules/*.rb", __FILE__)
|
12
12
|
Dir.glob(rules_glob).each do |file|
|
@@ -14,3 +14,5 @@ Dir.glob(rules_glob).each do |file|
|
|
14
14
|
end
|
15
15
|
|
16
16
|
require "graphql/static_validation/all_rules"
|
17
|
+
require "graphql/static_validation/default_visitor"
|
18
|
+
require "graphql/static_validation/interpreter_visitor"
|
@@ -39,7 +39,7 @@ module GraphQL
|
|
39
39
|
# })
|
40
40
|
#
|
41
41
|
# payload = {
|
42
|
-
# result: result.subscription? ? nil : result.to_h,
|
42
|
+
# result: result.subscription? ? { data: nil } : result.to_h,
|
43
43
|
# more: result.subscription?,
|
44
44
|
# }
|
45
45
|
#
|
@@ -54,9 +54,28 @@ module GraphQL
|
|
54
54
|
#
|
55
55
|
# def unsubscribed
|
56
56
|
# @subscription_ids.each { |sid|
|
57
|
-
#
|
57
|
+
# MySchema.subscriptions.delete_subscription(sid)
|
58
58
|
# }
|
59
59
|
# end
|
60
|
+
#
|
61
|
+
# private
|
62
|
+
#
|
63
|
+
# def ensure_hash(ambiguous_param)
|
64
|
+
# case ambiguous_param
|
65
|
+
# when String
|
66
|
+
# if ambiguous_param.present?
|
67
|
+
# ensure_hash(JSON.parse(ambiguous_param))
|
68
|
+
# else
|
69
|
+
# {}
|
70
|
+
# end
|
71
|
+
# when Hash, ActionController::Parameters
|
72
|
+
# ambiguous_param
|
73
|
+
# when nil
|
74
|
+
# {}
|
75
|
+
# else
|
76
|
+
# raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
|
77
|
+
# end
|
78
|
+
# end
|
60
79
|
# end
|
61
80
|
#
|
62
81
|
class ActionCableSubscriptions < GraphQL::Subscriptions
|
@@ -36,11 +36,15 @@ module GraphQL
|
|
36
36
|
when GraphQL::Query::Arguments
|
37
37
|
arguments
|
38
38
|
when Hash
|
39
|
-
GraphQL::
|
40
|
-
arguments
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
if field.is_a?(GraphQL::Schema::Field)
|
40
|
+
stringify_args(arguments)
|
41
|
+
else
|
42
|
+
GraphQL::Query::LiteralInput.from_arguments(
|
43
|
+
arguments,
|
44
|
+
field,
|
45
|
+
nil,
|
46
|
+
)
|
47
|
+
end
|
44
48
|
else
|
45
49
|
raise ArgumentError, "Unexpected arguments: #{arguments}, must be Hash or GraphQL::Arguments"
|
46
50
|
end
|
@@ -48,6 +52,25 @@ module GraphQL
|
|
48
52
|
sorted_h = normalized_args.to_h.sort.to_h
|
49
53
|
Serialize.dump_recursive([scope, name, sorted_h])
|
50
54
|
end
|
55
|
+
|
56
|
+
class << self
|
57
|
+
private
|
58
|
+
def stringify_args(args)
|
59
|
+
case args
|
60
|
+
when Hash
|
61
|
+
next_args = {}
|
62
|
+
args.each do |k, v|
|
63
|
+
str_k = GraphQL::Schema::Member::BuildType.camelize(k.to_s)
|
64
|
+
next_args[str_k] = stringify_args(v)
|
65
|
+
end
|
66
|
+
next_args
|
67
|
+
when Array
|
68
|
+
args.map { |a| stringify_args(a) }
|
69
|
+
else
|
70
|
+
args
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
51
74
|
end
|
52
75
|
end
|
53
76
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
class Subscriptions
|
5
|
+
# Extend this module in your subscription root when using {GraphQL::Execution::Interpreter}.
|
6
|
+
module SubscriptionRoot
|
7
|
+
def self.extended(child_cls)
|
8
|
+
child_cls.include(InstanceMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
# This is for maintaining backwards compatibility:
|
12
|
+
# if a subscription field is created without a `subscription:` resolver class,
|
13
|
+
# then implement the method with the previous default behavior.
|
14
|
+
module InstanceMethods
|
15
|
+
def skip_subscription_root(*)
|
16
|
+
if context.query.subscription_update?
|
17
|
+
object
|
18
|
+
else
|
19
|
+
context.skip
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def field(*args, extensions: [], **rest, &block)
|
25
|
+
extensions += [Extension]
|
26
|
+
# Backwards-compat for schemas
|
27
|
+
if !rest[:subscription]
|
28
|
+
name = args.first
|
29
|
+
alias_method(name, :skip_subscription_root)
|
30
|
+
end
|
31
|
+
super(*args, extensions: extensions, **rest, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
class Extension < GraphQL::Schema::FieldExtension
|
35
|
+
def after_resolve(value:, context:, object:, arguments:, **rest)
|
36
|
+
if value.is_a?(GraphQL::ExecutionError)
|
37
|
+
value
|
38
|
+
elsif (events = context.namespace(:subscriptions)[:events])
|
39
|
+
# This is the first execution, so gather an Event
|
40
|
+
# for the backend to register:
|
41
|
+
events << Subscriptions::Event.new(
|
42
|
+
name: field.name,
|
43
|
+
arguments: arguments,
|
44
|
+
context: context,
|
45
|
+
field: field,
|
46
|
+
)
|
47
|
+
# TODO compat with non-class-based subscriptions?
|
48
|
+
value
|
49
|
+
elsif context.query.subscription_topic == Subscriptions::Event.serialize(
|
50
|
+
field.name,
|
51
|
+
arguments,
|
52
|
+
field,
|
53
|
+
scope: (field.subscription_scope ? context[field.subscription_scope] : nil),
|
54
|
+
)
|
55
|
+
# This is a subscription update. The resolver returned `skip` if it should be skipped,
|
56
|
+
# or else it returned an object to resolve the update.
|
57
|
+
value
|
58
|
+
else
|
59
|
+
# This is a subscription update, but this event wasn't triggered.
|
60
|
+
context.skip
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -6,6 +6,7 @@ require "graphql/subscriptions/serialize"
|
|
6
6
|
if defined?(ActionCable)
|
7
7
|
require "graphql/subscriptions/action_cable_subscriptions"
|
8
8
|
end
|
9
|
+
require "graphql/subscriptions/subscription_root"
|
9
10
|
|
10
11
|
module GraphQL
|
11
12
|
class Subscriptions
|
@@ -99,6 +100,12 @@ module GraphQL
|
|
99
100
|
}
|
100
101
|
)
|
101
102
|
deliver(subscription_id, result)
|
103
|
+
rescue GraphQL::Schema::Subscription::NoUpdateError
|
104
|
+
# This update was skipped in user code; do nothing.
|
105
|
+
rescue GraphQL::Schema::Subscription::UnsubscribedError
|
106
|
+
# `unsubscribe` was called, clean up on our side
|
107
|
+
# TODO also send `{more: false}` to client?
|
108
|
+
delete_subscription(subscription_id)
|
102
109
|
end
|
103
110
|
|
104
111
|
# Event `event` occurred on `object`,
|
@@ -132,9 +139,8 @@ module GraphQL
|
|
132
139
|
# The result should be send to `subscription_id`.
|
133
140
|
# @param subscription_id [String]
|
134
141
|
# @param result [Hash]
|
135
|
-
# @param context [GraphQL::Query::Context]
|
136
142
|
# @return [void]
|
137
|
-
def deliver(subscription_id, result
|
143
|
+
def deliver(subscription_id, result)
|
138
144
|
raise NotImplementedError
|
139
145
|
end
|
140
146
|
|
@@ -147,6 +153,14 @@ module GraphQL
|
|
147
153
|
raise NotImplementedError
|
148
154
|
end
|
149
155
|
|
156
|
+
# A subscription was terminated server-side.
|
157
|
+
# Clean up the database.
|
158
|
+
# @param subscription_id [String]
|
159
|
+
# @return void.
|
160
|
+
def delete_subscription(subscription_id)
|
161
|
+
raise NotImplementedError
|
162
|
+
end
|
163
|
+
|
150
164
|
# @return [String] A new unique identifier for a subscription
|
151
165
|
def build_id
|
152
166
|
SecureRandom.uuid
|
@@ -5,7 +5,6 @@ module GraphQL
|
|
5
5
|
# This implementation forwards events to ActiveSupport::Notifications
|
6
6
|
# with a `graphql.` prefix.
|
7
7
|
#
|
8
|
-
# Installed automatically when `ActiveSupport::Notifications` is discovered.
|
9
8
|
module ActiveSupportNotificationsTracing
|
10
9
|
# A cache of frequently-used keys to avoid needless string allocations
|
11
10
|
KEYS = {
|
@@ -17,8 +17,8 @@ module GraphQL
|
|
17
17
|
# @param set_transaction_name [Boolean] If true, the GraphQL operation name will be used as the transaction name.
|
18
18
|
# This is not advised if you run more than one query per HTTP request, for example, with `graphql-client` or multiplexing.
|
19
19
|
# It can also be specified per-query with `context[:set_new_relic_transaction_name]`.
|
20
|
-
def initialize(
|
21
|
-
@set_transaction_name = set_transaction_name
|
20
|
+
def initialize(options = {})
|
21
|
+
@set_transaction_name = options.fetch(:set_transaction_name, false)
|
22
22
|
super
|
23
23
|
end
|
24
24
|
|
@@ -47,7 +47,7 @@ module GraphQL
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def platform_field_key(type, field)
|
50
|
-
"GraphQL/#{type.
|
50
|
+
"GraphQL/#{type.graphql_name}/#{field.graphql_name}"
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -26,7 +26,23 @@ module GraphQL
|
|
26
26
|
yield
|
27
27
|
end
|
28
28
|
when "execute_field", "execute_field_lazy"
|
29
|
-
if
|
29
|
+
if data[:context]
|
30
|
+
field = data[:context].field
|
31
|
+
platform_key = field.metadata[:platform_key]
|
32
|
+
trace_field = true # implemented with instrumenter
|
33
|
+
else
|
34
|
+
field = data[:field]
|
35
|
+
# Lots of duplicated work here, can this be done ahead of time?
|
36
|
+
platform_key = platform_field_key(field.owner, field)
|
37
|
+
return_type = field.type.unwrap
|
38
|
+
trace_field = if return_type.kind.scalar? || return_type.kind.enum?
|
39
|
+
(field.trace.nil? && @trace_scalars) || field.trace
|
40
|
+
else
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if platform_key && trace_field
|
30
46
|
platform_trace(platform_key, key, data) do
|
31
47
|
yield
|
32
48
|
end
|