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
@@ -4,81 +4,75 @@ module GraphQL
|
|
4
4
|
# Track fragment dependencies for operations
|
5
5
|
# and expose the fragment definitions which
|
6
6
|
# are used by a given operation
|
7
|
-
|
8
|
-
|
9
|
-
deps = self.new
|
10
|
-
deps.mount(visitor)
|
11
|
-
deps
|
12
|
-
end
|
7
|
+
module DefinitionDependencies
|
8
|
+
attr_reader :dependencies
|
13
9
|
|
14
|
-
def initialize
|
15
|
-
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@defdep_node_paths = {}
|
16
13
|
|
17
14
|
# { name => node } pairs for fragments
|
18
|
-
@
|
15
|
+
@defdep_fragment_definitions = {}
|
19
16
|
|
20
17
|
# This tracks dependencies from fragment to Node where it was used
|
21
18
|
# { fragment_definition_node => [dependent_node, dependent_node]}
|
22
|
-
@
|
19
|
+
@defdep_dependent_definitions = Hash.new { |h, k| h[k] = Set.new }
|
23
20
|
|
24
21
|
# First-level usages of spreads within definitions
|
25
22
|
# (When a key has an empty list as its value,
|
26
|
-
# we can resolve that key's
|
23
|
+
# we can resolve that key's dependents)
|
27
24
|
# { definition_node => [node, node ...] }
|
28
|
-
@
|
29
|
-
end
|
30
|
-
|
31
|
-
# A map of operation definitions to an array of that operation's dependencies
|
32
|
-
# @return [DependencyMap]
|
33
|
-
def dependency_map(&block)
|
34
|
-
@dependency_map ||= resolve_dependencies(&block)
|
35
|
-
end
|
25
|
+
@defdep_immediate_dependencies = Hash.new { |h, k| h[k] = Set.new }
|
36
26
|
|
37
|
-
def mount(context)
|
38
|
-
visitor = context.visitor
|
39
27
|
# When we encounter a spread,
|
40
28
|
# this node is the one who depends on it
|
41
|
-
|
42
|
-
|
43
|
-
visitor[GraphQL::Language::Nodes::Document] << ->(node, prev_node) {
|
44
|
-
node.definitions.each do |definition|
|
45
|
-
case definition
|
46
|
-
when GraphQL::Language::Nodes::OperationDefinition
|
47
|
-
when GraphQL::Language::Nodes::FragmentDefinition
|
48
|
-
@fragment_definitions[definition.name] = definition
|
49
|
-
end
|
50
|
-
end
|
51
|
-
}
|
29
|
+
@defdep_current_parent = nil
|
30
|
+
end
|
52
31
|
|
53
|
-
|
54
|
-
|
55
|
-
|
32
|
+
def on_document(node, parent)
|
33
|
+
node.definitions.each do |definition|
|
34
|
+
if definition.is_a? GraphQL::Language::Nodes::FragmentDefinition
|
35
|
+
@defdep_fragment_definitions[definition.name] = definition
|
36
|
+
end
|
37
|
+
end
|
38
|
+
super
|
39
|
+
@dependencies = dependency_map { |defn, spreads, frag|
|
40
|
+
context.on_dependency_resolve_handlers.each { |h| h.call(defn, spreads, frag) }
|
56
41
|
}
|
42
|
+
end
|
57
43
|
|
58
|
-
|
59
|
-
|
60
|
-
|
44
|
+
def on_operation_definition(node, prev_node)
|
45
|
+
@defdep_node_paths[node] = NodeWithPath.new(node, context.path)
|
46
|
+
@defdep_current_parent = node
|
47
|
+
super
|
48
|
+
@defdep_current_parent = nil
|
49
|
+
end
|
61
50
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
51
|
+
def on_fragment_definition(node, parent)
|
52
|
+
@defdep_node_paths[node] = NodeWithPath.new(node, context.path)
|
53
|
+
@defdep_current_parent = node
|
54
|
+
super
|
55
|
+
@defdep_current_parent = nil
|
56
|
+
end
|
66
57
|
|
67
|
-
|
68
|
-
|
69
|
-
}
|
58
|
+
def on_fragment_spread(node, parent)
|
59
|
+
@defdep_node_paths[node] = NodeWithPath.new(node, context.path)
|
70
60
|
|
71
|
-
|
72
|
-
|
61
|
+
# Track both sides of the dependency
|
62
|
+
@defdep_dependent_definitions[@defdep_fragment_definitions[node.name]] << @defdep_current_parent
|
63
|
+
@defdep_immediate_dependencies[@defdep_current_parent] << node
|
64
|
+
super
|
65
|
+
end
|
73
66
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
67
|
+
# A map of operation definitions to an array of that operation's dependencies
|
68
|
+
# @return [DependencyMap]
|
69
|
+
def dependency_map(&block)
|
70
|
+
@dependency_map ||= resolve_dependencies(&block)
|
78
71
|
end
|
79
72
|
|
73
|
+
|
80
74
|
# Map definition AST nodes to the definition AST nodes they depend on.
|
81
|
-
# Expose circular
|
75
|
+
# Expose circular dependencies.
|
82
76
|
class DependencyMap
|
83
77
|
# @return [Array<GraphQL::Language::Nodes::FragmentDefinition>]
|
84
78
|
attr_reader :cyclical_definitions
|
@@ -122,14 +116,14 @@ module GraphQL
|
|
122
116
|
dependency_map = DependencyMap.new
|
123
117
|
# Don't allow the loop to run more times
|
124
118
|
# than the number of fragments in the document
|
125
|
-
max_loops = @
|
119
|
+
max_loops = @defdep_fragment_definitions.size
|
126
120
|
loops = 0
|
127
121
|
|
128
122
|
# Instead of tracking independent fragments _as you visit_,
|
129
123
|
# determine them at the end. This way, we can treat fragments with the
|
130
124
|
# same name as if they were the same name. If _any_ of the fragments
|
131
125
|
# with that name has a dependency, we record it.
|
132
|
-
independent_fragment_nodes = @
|
126
|
+
independent_fragment_nodes = @defdep_fragment_definitions.values - @defdep_immediate_dependencies.keys
|
133
127
|
|
134
128
|
while fragment_node = independent_fragment_nodes.pop
|
135
129
|
loops += 1
|
@@ -138,26 +132,26 @@ module GraphQL
|
|
138
132
|
end
|
139
133
|
# Since it's independent, let's remove it from here.
|
140
134
|
# That way, we can use the remainder to identify cycles
|
141
|
-
@
|
142
|
-
fragment_usages = @
|
143
|
-
if fragment_usages.
|
135
|
+
@defdep_immediate_dependencies.delete(fragment_node)
|
136
|
+
fragment_usages = @defdep_dependent_definitions[fragment_node]
|
137
|
+
if fragment_usages.empty?
|
144
138
|
# If we didn't record any usages during the visit,
|
145
139
|
# then this fragment is unused.
|
146
|
-
dependency_map.unused_dependencies << @
|
140
|
+
dependency_map.unused_dependencies << @defdep_node_paths[fragment_node]
|
147
141
|
else
|
148
142
|
fragment_usages.each do |definition_node|
|
149
143
|
# Register the dependency AND second-order dependencies
|
150
144
|
dependency_map[definition_node] << fragment_node
|
151
145
|
dependency_map[definition_node].concat(dependency_map[fragment_node])
|
152
|
-
# Since we've
|
153
|
-
deps = @
|
146
|
+
# Since we've registered it, remove it from our to-do list
|
147
|
+
deps = @defdep_immediate_dependencies[definition_node]
|
154
148
|
# Can't find a way to _just_ delete from `deps` and return the deleted entries
|
155
149
|
removed, remaining = deps.partition { |spread| spread.name == fragment_node.name }
|
156
|
-
@
|
150
|
+
@defdep_immediate_dependencies[definition_node] = remaining
|
157
151
|
if block_given?
|
158
152
|
yield(definition_node, removed, fragment_node)
|
159
153
|
end
|
160
|
-
if remaining.
|
154
|
+
if remaining.empty? && definition_node.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
|
161
155
|
# If all of this definition's dependencies have
|
162
156
|
# been resolved, we can now resolve its
|
163
157
|
# own dependents.
|
@@ -170,20 +164,20 @@ module GraphQL
|
|
170
164
|
# If any dependencies were _unmet_
|
171
165
|
# (eg, spreads with no corresponding definition)
|
172
166
|
# then they're still in there
|
173
|
-
@
|
167
|
+
@defdep_immediate_dependencies.each do |defn_node, deps|
|
174
168
|
deps.each do |spread|
|
175
|
-
if @
|
176
|
-
dependency_map.unmet_dependencies[@
|
169
|
+
if @defdep_fragment_definitions[spread.name].nil?
|
170
|
+
dependency_map.unmet_dependencies[@defdep_node_paths[defn_node]] << @defdep_node_paths[spread]
|
177
171
|
deps.delete(spread)
|
178
172
|
end
|
179
173
|
end
|
180
|
-
if deps.
|
181
|
-
@
|
174
|
+
if deps.empty?
|
175
|
+
@defdep_immediate_dependencies.delete(defn_node)
|
182
176
|
end
|
183
177
|
end
|
184
178
|
|
185
179
|
# Anything left in @immediate_dependencies is cyclical
|
186
|
-
cyclical_nodes = @
|
180
|
+
cyclical_nodes = @defdep_immediate_dependencies.keys.map { |n| @defdep_node_paths[n] }
|
187
181
|
# @immediate_dependencies also includes operation names, but we don't care about
|
188
182
|
# those. They became nil when we looked them up on `@fragment_definitions`, so remove them.
|
189
183
|
cyclical_nodes.compact!
|
@@ -2,22 +2,23 @@
|
|
2
2
|
module GraphQL
|
3
3
|
module StaticValidation
|
4
4
|
# Generates GraphQL-compliant validation message.
|
5
|
-
class
|
5
|
+
class Error
|
6
6
|
# Convenience for validators
|
7
|
-
module
|
8
|
-
# Error `
|
9
|
-
def
|
7
|
+
module ErrorHelper
|
8
|
+
# Error `error_message` is located at `node`
|
9
|
+
def error(error_message, nodes, context: nil, path: nil, extensions: {})
|
10
10
|
path ||= context.path
|
11
11
|
nodes = Array(nodes)
|
12
|
-
GraphQL::StaticValidation::
|
12
|
+
GraphQL::StaticValidation::Error.new(error_message, nodes: nodes, path: path)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
attr_reader
|
16
|
+
attr_reader :message
|
17
|
+
attr_accessor :path
|
17
18
|
|
18
|
-
def initialize(message, path:
|
19
|
+
def initialize(message, path: nil, nodes: [])
|
19
20
|
@message = message
|
20
|
-
@nodes = nodes
|
21
|
+
@nodes = Array(nodes)
|
21
22
|
@path = path
|
22
23
|
end
|
23
24
|
|
@@ -25,9 +26,8 @@ module GraphQL
|
|
25
26
|
def to_h
|
26
27
|
{
|
27
28
|
"message" => message,
|
28
|
-
"locations" => locations
|
29
|
-
|
30
|
-
}
|
29
|
+
"locations" => locations
|
30
|
+
}.tap { |h| h["path"] = path unless path.nil? }
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class InterpreterVisitor < BaseVisitor
|
5
|
+
include(GraphQL::StaticValidation::DefinitionDependencies)
|
6
|
+
|
7
|
+
StaticValidation::ALL_RULES.reverse_each do |r|
|
8
|
+
include(r)
|
9
|
+
end
|
10
|
+
|
11
|
+
include(ContextMethods)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -9,29 +9,61 @@ module GraphQL
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def validate(ast_value, type)
|
12
|
-
if
|
13
|
-
|
12
|
+
if type.nil?
|
13
|
+
# this means we're an undefined argument, see #present_input_field_values_are_valid
|
14
|
+
return maybe_raise_if_invalid(ast_value) do
|
15
|
+
false
|
16
|
+
end
|
17
|
+
elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
|
18
|
+
maybe_raise_if_invalid(ast_value) do
|
19
|
+
!type.kind.non_null?
|
20
|
+
end
|
14
21
|
elsif type.kind.non_null?
|
15
|
-
(
|
22
|
+
maybe_raise_if_invalid(ast_value) do
|
23
|
+
(!ast_value.nil?)
|
24
|
+
end && validate(ast_value, type.of_type)
|
16
25
|
elsif type.kind.list?
|
17
26
|
item_type = type.of_type
|
18
27
|
ensure_array(ast_value).all? { |val| validate(val, item_type) }
|
19
28
|
elsif ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
20
29
|
true
|
21
30
|
elsif type.kind.scalar? && constant_scalar?(ast_value)
|
22
|
-
|
23
|
-
|
24
|
-
|
31
|
+
maybe_raise_if_invalid(ast_value) do
|
32
|
+
type.valid_input?(ast_value, @context)
|
33
|
+
end
|
34
|
+
elsif type.kind.enum?
|
35
|
+
maybe_raise_if_invalid(ast_value) do
|
36
|
+
if ast_value.is_a?(GraphQL::Language::Nodes::Enum)
|
37
|
+
type.valid_input?(ast_value.name, @context)
|
38
|
+
else
|
39
|
+
# if our ast_value isn't an Enum it's going to be invalid so return false
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
25
43
|
elsif type.kind.input_object? && ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
|
26
|
-
|
27
|
-
present_input_field_values_are_valid(type, ast_value)
|
44
|
+
maybe_raise_if_invalid(ast_value) do
|
45
|
+
required_input_fields_are_present(type, ast_value) && present_input_field_values_are_valid(type, ast_value)
|
46
|
+
end
|
28
47
|
else
|
29
|
-
|
48
|
+
maybe_raise_if_invalid(ast_value) do
|
49
|
+
false
|
50
|
+
end
|
30
51
|
end
|
31
52
|
end
|
32
53
|
|
33
54
|
private
|
34
55
|
|
56
|
+
def maybe_raise_if_invalid(ast_value)
|
57
|
+
ret = yield
|
58
|
+
if !@context.schema.error_bubbling && !ret
|
59
|
+
e = LiteralValidationError.new
|
60
|
+
e.ast_value = ast_value
|
61
|
+
raise e
|
62
|
+
else
|
63
|
+
ret
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
35
67
|
# The GraphQL grammar supports variables embedded within scalars but graphql.js
|
36
68
|
# doesn't support it so we won't either for simplicity
|
37
69
|
def constant_scalar?(ast_value)
|
@@ -47,19 +79,30 @@ module GraphQL
|
|
47
79
|
end
|
48
80
|
|
49
81
|
def required_input_fields_are_present(type, ast_node)
|
82
|
+
# TODO - would be nice to use these to create an error message so the caller knows
|
83
|
+
# that required fields are missing
|
50
84
|
required_field_names = @warden.arguments(type)
|
51
85
|
.select { |f| f.type.kind.non_null? }
|
52
86
|
.map(&:name)
|
53
87
|
present_field_names = ast_node.arguments.map(&:name)
|
54
88
|
missing_required_field_names = required_field_names - present_field_names
|
55
|
-
|
89
|
+
if @context.schema.error_bubbling
|
90
|
+
missing_required_field_names.empty?
|
91
|
+
else
|
92
|
+
missing_required_field_names.all? do |name|
|
93
|
+
validate(GraphQL::Language::Nodes::NullValue.new(name: name), @warden.arguments(type).find { |f| f.name == name }.type )
|
94
|
+
end
|
95
|
+
end
|
56
96
|
end
|
57
97
|
|
58
98
|
def present_input_field_values_are_valid(type, ast_node)
|
59
99
|
field_map = @warden.arguments(type).reduce({}) { |m, f| m[f.name] = f; m}
|
60
100
|
ast_node.arguments.all? do |value|
|
61
101
|
field = field_map[value.name]
|
62
|
-
|
102
|
+
# we want to call validate on an argument even if it's an invalid one
|
103
|
+
# so that our raise exception is on it instead of the entire InputObject
|
104
|
+
type = field && field.type
|
105
|
+
validate(value.value, type)
|
63
106
|
end
|
64
107
|
end
|
65
108
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class NoValidateVisitor < StaticValidation::BaseVisitor
|
5
|
+
include(GraphQL::InternalRepresentation::Rewrite)
|
6
|
+
include(GraphQL::StaticValidation::DefinitionDependencies)
|
7
|
+
include(ContextMethods)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -1,27 +1,98 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module StaticValidation
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
module ArgumentLiteralsAreCompatible
|
5
|
+
# TODO dedup with ArgumentsAreDefined
|
6
|
+
def on_argument(node, parent)
|
7
|
+
parent_defn = case parent
|
8
|
+
when GraphQL::Language::Nodes::InputObject
|
9
|
+
arg_defn = context.argument_definition
|
10
|
+
if arg_defn.nil?
|
11
|
+
nil
|
12
|
+
else
|
13
|
+
arg_ret_type = arg_defn.type.unwrap
|
14
|
+
if !arg_ret_type.is_a?(GraphQL::InputObjectType)
|
15
|
+
nil
|
16
|
+
else
|
17
|
+
arg_ret_type
|
18
|
+
end
|
19
|
+
end
|
20
|
+
when GraphQL::Language::Nodes::Directive
|
21
|
+
context.schema.directives[parent.name]
|
22
|
+
when GraphQL::Language::Nodes::Field
|
23
|
+
context.field_definition
|
24
|
+
else
|
25
|
+
raise "Unexpected argument parent: #{parent.class} (##{parent})"
|
14
26
|
end
|
15
27
|
|
16
|
-
|
28
|
+
if parent_defn && !node.value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
29
|
+
arg_defn = parent_defn.arguments[node.name]
|
30
|
+
if arg_defn
|
31
|
+
begin
|
32
|
+
valid = context.valid_literal?(node.value, arg_defn.type)
|
33
|
+
rescue GraphQL::CoercionError => err
|
34
|
+
context.schema.error_bubbling
|
35
|
+
if !context.schema.error_bubbling && !arg_defn.type.unwrap.kind.scalar?
|
36
|
+
# if error bubbling is disabled and the arg that caused this error isn't a scalar then
|
37
|
+
# short-circuit here so we avoid bubbling this up to whatever input_object / array contains us
|
38
|
+
return super
|
39
|
+
end
|
40
|
+
error = GraphQL::StaticValidation::ArgumentLiteralsAreCompatibleError.new(err.message, nodes: parent, type: "CoercionError")
|
41
|
+
rescue GraphQL::LiteralValidationError => err
|
42
|
+
# check to see if the ast node that caused the error to be raised is
|
43
|
+
# the same as the node we were checking here.
|
44
|
+
matched = if arg_defn.type.kind.list?
|
45
|
+
# for a list we claim an error if the node is contained in our list
|
46
|
+
Array(node.value).include?(err.ast_value)
|
47
|
+
elsif arg_defn.type.kind.input_object? && node.value.is_a?(GraphQL::Language::Nodes::InputObject)
|
48
|
+
# for an input object we check the arguments
|
49
|
+
node.value.arguments.include?(err.ast_value)
|
50
|
+
else
|
51
|
+
# otherwise we just check equality
|
52
|
+
node.value == (err.ast_value)
|
53
|
+
end
|
54
|
+
if !matched
|
55
|
+
# This node isn't the node that caused the error,
|
56
|
+
# So halt this visit but continue visiting the rest of the tree
|
57
|
+
return super
|
58
|
+
end
|
59
|
+
end
|
17
60
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
61
|
+
if !valid
|
62
|
+
error ||= begin
|
63
|
+
kind_of_node = node_type(parent)
|
64
|
+
error_arg_name = parent_name(parent, parent_defn)
|
65
|
+
|
66
|
+
GraphQL::StaticValidation::ArgumentLiteralsAreCompatibleError.new(
|
67
|
+
"Argument '#{node.name}' on #{kind_of_node} '#{error_arg_name}' has an invalid value. Expected type '#{arg_defn.type}'.",
|
68
|
+
nodes: parent,
|
69
|
+
type: kind_of_node,
|
70
|
+
argument: node.name
|
71
|
+
)
|
72
|
+
end
|
73
|
+
add_error(error)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def parent_name(parent, type_defn)
|
85
|
+
if parent.is_a?(GraphQL::Language::Nodes::Field)
|
86
|
+
parent.alias || parent.name
|
87
|
+
elsif parent.is_a?(GraphQL::Language::Nodes::InputObject)
|
88
|
+
type_defn.name
|
89
|
+
else
|
90
|
+
parent.name
|
22
91
|
end
|
92
|
+
end
|
23
93
|
|
24
|
-
|
94
|
+
def node_type(parent)
|
95
|
+
parent.class.name.split("::").last
|
25
96
|
end
|
26
97
|
end
|
27
98
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class ArgumentLiteralsAreCompatibleError < StaticValidation::Error
|
5
|
+
attr_reader :type_name
|
6
|
+
attr_reader :argument_name
|
7
|
+
|
8
|
+
def initialize(message, path: nil, nodes: [], type:, argument: nil)
|
9
|
+
super(message, path: path, nodes: nodes)
|
10
|
+
@type_name = type
|
11
|
+
@argument_name = argument
|
12
|
+
end
|
13
|
+
|
14
|
+
# A hash representation of this Message
|
15
|
+
def to_h
|
16
|
+
extensions = {
|
17
|
+
"code" => code,
|
18
|
+
"typeName" => type_name
|
19
|
+
}.tap { |h| h["argumentName"] = argument_name unless argument_name.nil? }
|
20
|
+
|
21
|
+
super.merge({
|
22
|
+
"extensions" => extensions
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def code
|
27
|
+
"argumentLiteralsIncompatible"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,27 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module StaticValidation
|
4
|
-
|
5
|
-
include GraphQL::StaticValidation::
|
4
|
+
module ArgumentNamesAreUnique
|
5
|
+
include GraphQL::StaticValidation::Error::ErrorHelper
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
def on_field(node, parent)
|
8
|
+
validate_arguments(node)
|
9
|
+
super
|
10
|
+
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def on_directive(node, parent)
|
13
|
+
validate_arguments(node)
|
14
|
+
super
|
15
15
|
end
|
16
16
|
|
17
|
-
def validate_arguments(node
|
17
|
+
def validate_arguments(node)
|
18
18
|
argument_defns = node.arguments
|
19
19
|
if argument_defns.any?
|
20
20
|
args_by_name = Hash.new { |h, k| h[k] = [] }
|
21
21
|
argument_defns.each { |a| args_by_name[a.name] << a }
|
22
22
|
args_by_name.each do |name, defns|
|
23
23
|
if defns.size > 1
|
24
|
-
|
24
|
+
add_error(GraphQL::StaticValidation::ArgumentNamesAreUniqueError.new("There can be only one argument named \"#{name}\"", nodes: defns, name: name))
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class ArgumentNamesAreUniqueError < StaticValidation::Error
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(message, path: nil, nodes: [], name:)
|
8
|
+
super(message, path: path, nodes: nodes)
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
# A hash representation of this Message
|
13
|
+
def to_h
|
14
|
+
extensions = {
|
15
|
+
"code" => code,
|
16
|
+
"name" => name
|
17
|
+
}
|
18
|
+
|
19
|
+
super.merge({
|
20
|
+
"extensions" => extensions
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
def code
|
25
|
+
"argumentNotUnique"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -1,18 +1,62 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
module StaticValidation
|
4
|
-
|
5
|
-
def
|
6
|
-
|
7
|
-
|
4
|
+
module ArgumentsAreDefined
|
5
|
+
def on_argument(node, parent)
|
6
|
+
parent_defn = case parent
|
7
|
+
when GraphQL::Language::Nodes::InputObject
|
8
|
+
arg_defn = context.argument_definition
|
9
|
+
if arg_defn.nil?
|
10
|
+
nil
|
11
|
+
else
|
12
|
+
arg_ret_type = arg_defn.type.unwrap
|
13
|
+
if !arg_ret_type.is_a?(GraphQL::InputObjectType)
|
14
|
+
nil
|
15
|
+
else
|
16
|
+
arg_ret_type
|
17
|
+
end
|
18
|
+
end
|
19
|
+
when GraphQL::Language::Nodes::Directive
|
20
|
+
context.schema.directives[parent.name]
|
21
|
+
when GraphQL::Language::Nodes::Field
|
22
|
+
context.field_definition
|
23
|
+
else
|
24
|
+
raise "Unexpected argument parent: #{parent.class} (##{parent})"
|
25
|
+
end
|
26
|
+
|
27
|
+
if parent_defn && context.warden.arguments(parent_defn).any? { |arg| arg.name == node.name }
|
28
|
+
super
|
29
|
+
elsif parent_defn
|
8
30
|
kind_of_node = node_type(parent)
|
9
|
-
error_arg_name = parent_name(parent,
|
10
|
-
|
11
|
-
|
31
|
+
error_arg_name = parent_name(parent, parent_defn)
|
32
|
+
add_error(GraphQL::StaticValidation::ArgumentsAreDefinedError.new(
|
33
|
+
"#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'",
|
34
|
+
nodes: node,
|
35
|
+
name: error_arg_name,
|
36
|
+
type: kind_of_node,
|
37
|
+
argument: node.name
|
38
|
+
))
|
39
|
+
else
|
40
|
+
# Some other weird error
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def parent_name(parent, type_defn)
|
48
|
+
if parent.is_a?(GraphQL::Language::Nodes::Field)
|
49
|
+
parent.alias || parent.name
|
50
|
+
elsif parent.is_a?(GraphQL::Language::Nodes::InputObject)
|
51
|
+
type_defn.name
|
12
52
|
else
|
13
|
-
|
53
|
+
parent.name
|
14
54
|
end
|
15
55
|
end
|
56
|
+
|
57
|
+
def node_type(parent)
|
58
|
+
parent.class.name.split("::").last
|
59
|
+
end
|
16
60
|
end
|
17
61
|
end
|
18
62
|
end
|