graphql 1.9.0.pre1 → 1.9.0.pre2
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/graphql.rb +5 -1
- data/lib/graphql/analysis/ast/analyzer.rb +1 -1
- data/lib/graphql/analysis/ast/visitor.rb +6 -1
- data/lib/graphql/backwards_compatibility.rb +1 -1
- data/lib/graphql/dig.rb +19 -0
- data/lib/graphql/directive.rb +13 -1
- data/lib/graphql/directive/include_directive.rb +1 -7
- data/lib/graphql/directive/skip_directive.rb +1 -8
- data/lib/graphql/execution/interpreter.rb +23 -13
- data/lib/graphql/execution/interpreter/resolve.rb +56 -0
- data/lib/graphql/execution/interpreter/runtime.rb +174 -74
- data/lib/graphql/execution/lazy.rb +7 -1
- data/lib/graphql/execution/lookahead.rb +71 -6
- data/lib/graphql/execution_error.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +5 -1
- data/lib/graphql/introspection/type_type.rb +4 -4
- data/lib/graphql/language.rb +0 -1
- data/lib/graphql/language/block_string.rb +37 -0
- data/lib/graphql/language/document_from_schema_definition.rb +1 -1
- data/lib/graphql/language/lexer.rb +55 -36
- data/lib/graphql/language/lexer.rl +8 -3
- data/lib/graphql/language/nodes.rb +27 -4
- data/lib/graphql/language/parser.rb +55 -55
- data/lib/graphql/language/parser.y +11 -11
- data/lib/graphql/language/printer.rb +1 -1
- data/lib/graphql/language/visitor.rb +22 -13
- data/lib/graphql/literal_validation_error.rb +6 -0
- data/lib/graphql/query.rb +13 -0
- data/lib/graphql/query/arguments.rb +2 -1
- data/lib/graphql/query/context.rb +3 -10
- data/lib/graphql/query/executor.rb +1 -1
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/relay/connection_resolve.rb +1 -1
- data/lib/graphql/relay/relation_connection.rb +1 -1
- data/lib/graphql/schema.rb +81 -11
- data/lib/graphql/schema/argument.rb +1 -1
- data/lib/graphql/schema/build_from_definition.rb +2 -4
- data/lib/graphql/schema/directive.rb +103 -0
- 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/enum_value.rb +2 -2
- data/lib/graphql/schema/field.rb +63 -17
- data/lib/graphql/schema/input_object.rb +1 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +4 -2
- data/lib/graphql/schema/member/build_type.rb +33 -1
- data/lib/graphql/schema/member/has_fields.rb +8 -73
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -1
- data/lib/graphql/schema/resolver.rb +1 -1
- data/lib/graphql/static_validation.rb +2 -1
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +25 -10
- data/lib/graphql/static_validation/definition_dependencies.rb +3 -3
- 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/rules/argument_literals_are_compatible.rb +34 -5
- 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 +2 -2
- data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +7 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -1
- 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 +11 -2
- 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 +11 -2
- 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 +14 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +24 -6
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +5 -1
- 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 +8 -1
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +5 -1
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -1
- data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +4 -1
- 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 +5 -1
- 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 +13 -3
- data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +4 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +2 -2
- 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 +9 -2
- 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 +7 -1
- 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 +4 -1
- data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +4 -3
- 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 +20 -6
- 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 +5 -1
- 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 +8 -1
- 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 +12 -2
- 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 +18 -2
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
- data/lib/graphql/static_validation/validator.rb +24 -14
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -2
- data/lib/graphql/tracing/skylight_tracing.rb +2 -2
- data/lib/graphql/unauthorized_field_error.rb +23 -0
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/analysis/ast_spec.rb +40 -0
- data/spec/graphql/authorization_spec.rb +93 -20
- data/spec/graphql/base_type_spec.rb +3 -1
- data/spec/graphql/execution/interpreter_spec.rb +127 -4
- data/spec/graphql/execution/lazy_spec.rb +49 -0
- data/spec/graphql/execution/lookahead_spec.rb +113 -21
- data/spec/graphql/execution/multiplex_spec.rb +2 -1
- data/spec/graphql/introspection/type_type_spec.rb +1 -1
- data/spec/graphql/language/lexer_spec.rb +72 -3
- data/spec/graphql/language/printer_spec.rb +18 -6
- data/spec/graphql/query/arguments_spec.rb +21 -0
- data/spec/graphql/query/context_spec.rb +10 -0
- data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
- 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 +5 -3
- data/spec/graphql/schema/field_extension_spec.rb +3 -3
- data/spec/graphql/schema/field_spec.rb +19 -0
- data/spec/graphql/schema/input_object_spec.rb +81 -0
- data/spec/graphql/schema/member/build_type_spec.rb +46 -0
- data/spec/graphql/schema/member/scoped_spec.rb +3 -3
- data/spec/graphql/schema/printer_spec.rb +244 -96
- data/spec/graphql/schema/relay_classic_mutation_spec.rb +26 -0
- data/spec/graphql/schema/resolver_spec.rb +1 -1
- data/spec/graphql/schema/warden_spec.rb +35 -11
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +212 -72
- 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 +2 -1
- 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 +6 -3
- data/spec/graphql/static_validation/validator_spec.rb +6 -4
- data/spec/graphql/tracing/new_relic_tracing_spec.rb +10 -0
- data/spec/graphql/tracing/skylight_tracing_spec.rb +10 -0
- data/spec/graphql/types/iso_8601_date_time_spec.rb +1 -2
- data/spec/integration/mongoid/star_trek/schema.rb +5 -5
- data/spec/integration/rails/graphql/relay/relation_connection_spec.rb +37 -8
- data/spec/integration/rails/graphql/schema_spec.rb +2 -2
- data/spec/integration/rails/spec_helper.rb +10 -0
- data/spec/integration/tmp/app/graphql/types/bird_type.rb +7 -0
- data/spec/integration/tmp/dummy/Gemfile +45 -0
- data/spec/integration/tmp/dummy/README.rdoc +28 -0
- data/spec/integration/tmp/dummy/Rakefile +6 -0
- data/spec/integration/tmp/dummy/app/assets/javascripts/application.js +16 -0
- data/spec/integration/tmp/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/integration/tmp/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/integration/tmp/dummy/app/controllers/graphql_controller.rb +43 -0
- data/spec/integration/tmp/dummy/app/graphql/dummy_schema.rb +34 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_enum.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_input_object.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_interface.rb +5 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_object.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_scalar.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/base_union.rb +4 -0
- data/spec/integration/tmp/dummy/app/graphql/types/mutation_type.rb +10 -0
- data/spec/integration/tmp/dummy/app/graphql/types/query_type.rb +15 -0
- data/spec/integration/tmp/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/integration/tmp/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/integration/tmp/dummy/bin/bundle +3 -0
- data/spec/integration/tmp/dummy/bin/rails +4 -0
- data/spec/integration/tmp/dummy/bin/rake +4 -0
- data/spec/integration/tmp/dummy/bin/setup +29 -0
- data/spec/integration/tmp/dummy/config.ru +4 -0
- data/spec/integration/tmp/dummy/config/application.rb +32 -0
- data/spec/integration/tmp/dummy/config/boot.rb +3 -0
- data/spec/integration/tmp/dummy/config/environment.rb +5 -0
- data/spec/integration/tmp/dummy/config/environments/development.rb +38 -0
- data/spec/integration/tmp/dummy/config/environments/production.rb +76 -0
- data/spec/integration/tmp/dummy/config/environments/test.rb +42 -0
- data/spec/integration/tmp/dummy/config/initializers/assets.rb +11 -0
- data/spec/integration/tmp/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/integration/tmp/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/integration/tmp/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/integration/tmp/dummy/config/initializers/inflections.rb +16 -0
- data/spec/integration/tmp/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/integration/tmp/dummy/config/initializers/session_store.rb +3 -0
- data/spec/integration/tmp/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
- data/spec/integration/tmp/dummy/config/initializers/wrap_parameters.rb +9 -0
- data/spec/integration/tmp/dummy/config/locales/en.yml +23 -0
- data/spec/integration/tmp/dummy/config/routes.rb +61 -0
- data/spec/integration/tmp/dummy/config/secrets.yml +22 -0
- data/spec/integration/tmp/dummy/db/seeds.rb +7 -0
- data/spec/integration/tmp/dummy/public/404.html +67 -0
- data/spec/integration/tmp/dummy/public/422.html +67 -0
- data/spec/integration/tmp/dummy/public/500.html +66 -0
- data/spec/integration/tmp/dummy/public/favicon.ico +0 -0
- data/spec/integration/tmp/dummy/public/robots.txt +5 -0
- data/spec/support/dummy/schema.rb +2 -2
- data/spec/support/error_bubbling_helpers.rb +23 -0
- data/spec/support/jazz.rb +53 -6
- data/spec/support/lazy_helpers.rb +26 -8
- data/spec/support/new_relic.rb +3 -0
- data/spec/support/skylight.rb +3 -0
- data/spec/support/star_wars/schema.rb +13 -9
- data/spec/support/static_validation_helpers.rb +3 -1
- metadata +145 -22
- data/lib/graphql/language/comments.rb +0 -45
- data/spec/graphql/schema/member/has_fields_spec.rb +0 -132
- data/spec/integration/tmp/app/graphql/types/family_type.rb +0 -9
@@ -22,21 +22,24 @@ describe GraphQL::StaticValidation::RequiredArgumentsArePresent do
|
|
22
22
|
query_root_error = {
|
23
23
|
"message"=>"Field 'cheese' is missing required arguments: id",
|
24
24
|
"locations"=>[{"line"=>4, "column"=>7}],
|
25
|
-
"
|
25
|
+
"path"=>["query getCheese", "cheese"],
|
26
|
+
"extensions"=>{"code"=>"missingRequiredArguments", "className"=>"Field", "name"=>"cheese", "arguments"=>"id"}
|
26
27
|
}
|
27
28
|
assert_includes(errors, query_root_error)
|
28
29
|
|
29
30
|
fragment_error = {
|
30
31
|
"message"=>"Field 'similarCheese' is missing required arguments: source",
|
31
32
|
"locations"=>[{"line"=>8, "column"=>7}],
|
32
|
-
"
|
33
|
+
"path"=>["fragment cheeseFields", "similarCheese"],
|
34
|
+
"extensions"=>{"code"=>"missingRequiredArguments", "className"=>"Field", "name"=>"similarCheese", "arguments"=>"source"}
|
33
35
|
}
|
34
36
|
assert_includes(errors, fragment_error)
|
35
37
|
|
36
38
|
directive_error = {
|
37
39
|
"message"=>"Directive 'skip' is missing required arguments: if",
|
38
40
|
"locations"=>[{"line"=>10, "column"=>10}],
|
39
|
-
"
|
41
|
+
"path"=>["fragment cheeseFields", "id"],
|
42
|
+
"extensions"=>{"code"=>"missingRequiredArguments", "className"=>"Directive", "name"=>"skip", "arguments"=>"if"}
|
40
43
|
}
|
41
44
|
assert_includes(errors, directive_error)
|
42
45
|
end
|
@@ -55,7 +58,13 @@ describe GraphQL::StaticValidation::RequiredArgumentsArePresent do
|
|
55
58
|
"locations"=>[
|
56
59
|
{"line"=>3, "column"=>9}
|
57
60
|
],
|
58
|
-
"
|
61
|
+
"path"=>["query", "__type"],
|
62
|
+
"extensions"=>{
|
63
|
+
"code"=>"missingRequiredArguments",
|
64
|
+
"className"=>"Field",
|
65
|
+
"name"=>"__type",
|
66
|
+
"arguments"=>"name"
|
67
|
+
}
|
59
68
|
}
|
60
69
|
]
|
61
70
|
assert_equal(expected_errors, errors)
|
data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe GraphQL::StaticValidation::RequiredInputObjectAttributesArePresent do
|
5
|
+
include StaticValidationHelpers
|
6
|
+
include ErrorBubblingHelpers
|
7
|
+
|
8
|
+
let(:query_string) {%|
|
9
|
+
query getCheese {
|
10
|
+
stringCheese: cheese(id: "aasdlkfj") { ...cheeseFields }
|
11
|
+
cheese(id: 1) { source @skip(if: "whatever") }
|
12
|
+
yakSource: searchDairy(product: [{source: COW, fatContent: 1.1}]) { __typename }
|
13
|
+
badSource: searchDairy(product: [{source: 1.1}]) { __typename }
|
14
|
+
missingSource: searchDairy(product: [{fatContent: 1.1}]) { __typename }
|
15
|
+
listCoerce: cheese(id: 1) { similarCheese(source: YAK) { __typename } }
|
16
|
+
missingInputField: searchDairy(product: [{source: YAK, wacky: 1}]) { __typename }
|
17
|
+
}
|
18
|
+
|
19
|
+
fragment cheeseFields on Cheese {
|
20
|
+
similarCheese(source: 4.5) { __typename }
|
21
|
+
}
|
22
|
+
|}
|
23
|
+
describe "with error bubbling disabled" do
|
24
|
+
missing_required_field_error = {
|
25
|
+
"message"=>"Argument 'product' on Field 'missingSource' has an invalid value. Expected type '[DairyProductInput]'.",
|
26
|
+
"locations"=>[{"line"=>7, "column"=>7}],
|
27
|
+
"path"=>["query getCheese", "missingSource", "product"],
|
28
|
+
"extensions"=>{
|
29
|
+
"code"=>"argumentLiteralsIncompatible",
|
30
|
+
"typeName"=>"Field",
|
31
|
+
"argumentName"=>"product",
|
32
|
+
},
|
33
|
+
}
|
34
|
+
missing_source_error = {
|
35
|
+
"message"=>"Argument 'source' on InputObject 'DairyProductInput' is required. Expected type DairyAnimal!",
|
36
|
+
"locations"=>[{"line"=>7, "column"=>44}],
|
37
|
+
"path"=>["query getCheese", "missingSource", "product", "source"],
|
38
|
+
"extensions"=>{
|
39
|
+
"code"=>"missingRequiredInputObjectAttribute",
|
40
|
+
"argumentName"=>"source",
|
41
|
+
"argumentType"=>"DairyAnimal!",
|
42
|
+
"inputObjectType"=>"DairyProductInput"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
it "finds undefined or missing-required arguments to fields and directives" do
|
46
|
+
without_error_bubbling(schema) do
|
47
|
+
assert_includes(errors, missing_source_error)
|
48
|
+
refute_includes(errors, missing_required_field_error)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
it 'works with error bubbling enabled' do
|
52
|
+
with_error_bubbling(schema) do
|
53
|
+
assert_includes(errors, missing_required_field_error)
|
54
|
+
assert_includes(errors, missing_source_error)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -26,7 +26,8 @@ describe GraphQL::StaticValidation::SubscriptionRootExists do
|
|
26
26
|
missing_subscription_root_error = {
|
27
27
|
"message"=>"Schema is not configured for subscriptions",
|
28
28
|
"locations"=>[{"line"=>2, "column"=>5}],
|
29
|
-
"
|
29
|
+
"path"=>["subscription"],
|
30
|
+
"extensions"=>{"code"=>"missingSubscriptionConfiguration"}
|
30
31
|
}
|
31
32
|
assert_includes(errors, missing_subscription_root_error)
|
32
33
|
end
|
@@ -101,7 +101,8 @@ describe GraphQL::StaticValidation::UniqueDirectivesPerLocation do
|
|
101
101
|
assert_includes errors, {
|
102
102
|
"message" => 'The directive "A" can only be used once at this location.',
|
103
103
|
"locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 20 }],
|
104
|
-
"
|
104
|
+
"path" => ["query", "type", "field"],
|
105
|
+
"extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
|
105
106
|
}
|
106
107
|
end
|
107
108
|
end
|
@@ -120,13 +121,15 @@ describe GraphQL::StaticValidation::UniqueDirectivesPerLocation do
|
|
120
121
|
assert_includes errors, {
|
121
122
|
"message" => 'The directive "A" can only be used once at this location.',
|
122
123
|
"locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 20 }],
|
123
|
-
"
|
124
|
+
"path" => ["query", "type", "field"],
|
125
|
+
"extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
|
124
126
|
}
|
125
127
|
|
126
128
|
assert_includes errors, {
|
127
129
|
"message" => 'The directive "A" can only be used once at this location.',
|
128
130
|
"locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 23 }],
|
129
|
-
"
|
131
|
+
"path" => ["query", "type", "field"],
|
132
|
+
"extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
|
130
133
|
}
|
131
134
|
end
|
132
135
|
end
|
@@ -144,13 +147,15 @@ describe GraphQL::StaticValidation::UniqueDirectivesPerLocation do
|
|
144
147
|
assert_includes errors, {
|
145
148
|
"message" => 'The directive "A" can only be used once at this location.',
|
146
149
|
"locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 23 }],
|
147
|
-
"
|
150
|
+
"path" => ["query", "type", "field"],
|
151
|
+
"extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
|
148
152
|
}
|
149
153
|
|
150
154
|
assert_includes errors, {
|
151
155
|
"message" => 'The directive "B" can only be used once at this location.',
|
152
156
|
"locations" => [{ "line" => 4, "column" => 20 }, { "line" => 4, "column" => 26 }],
|
153
|
-
"
|
157
|
+
"path" => ["query", "type", "field"],
|
158
|
+
"extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"B"}
|
154
159
|
}
|
155
160
|
end
|
156
161
|
end
|
@@ -168,13 +173,15 @@ describe GraphQL::StaticValidation::UniqueDirectivesPerLocation do
|
|
168
173
|
assert_includes errors, {
|
169
174
|
"message" => 'The directive "A" can only be used once at this location.',
|
170
175
|
"locations" => [{ "line" => 3, "column" => 14 }, { "line" => 3, "column" => 17 }],
|
171
|
-
"
|
176
|
+
"path" => ["query", "type"],
|
177
|
+
"extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
|
172
178
|
}
|
173
179
|
|
174
180
|
assert_includes errors, {
|
175
181
|
"message" => 'The directive "A" can only be used once at this location.',
|
176
182
|
"locations" => [{ "line" => 4, "column" => 17 }, { "line" => 4, "column" => 20 }],
|
177
|
-
"
|
183
|
+
"path" => ["query", "type", "field"],
|
184
|
+
"extensions" => {"code"=>"directiveNotUniqueForLocation", "directiveName"=>"A"}
|
178
185
|
}
|
179
186
|
end
|
180
187
|
end
|
data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb
CHANGED
@@ -29,17 +29,20 @@ describe GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTyped do
|
|
29
29
|
{
|
30
30
|
"message"=>"Default value for $badInt doesn't match type Int",
|
31
31
|
"locations"=>[{"line"=>6, "column"=>7}],
|
32
|
-
"
|
32
|
+
"path"=>["query getCheese"],
|
33
|
+
"extensions"=>{"code"=>"defaultValueInvalidType", "variableName"=>"badInt", "typeName"=>"Int"}
|
33
34
|
},
|
34
35
|
{
|
35
36
|
"message"=>"Default value for $badInput doesn't match type DairyProductInput",
|
36
37
|
"locations"=>[{"line"=>8, "column"=>7}],
|
37
|
-
"
|
38
|
+
"path"=>["query getCheese"],
|
39
|
+
"extensions"=>{"code"=>"defaultValueInvalidType", "variableName"=>"badInput", "typeName"=>"DairyProductInput"}
|
38
40
|
},
|
39
41
|
{
|
40
42
|
"message"=>"Non-null variable $nonNull can't have a default value",
|
41
43
|
"locations"=>[{"line"=>9, "column"=>7}],
|
42
|
-
"
|
44
|
+
"path"=>["query getCheese"],
|
45
|
+
"extensions"=>{"code"=>"defaultValueInvalidOnNonNullVariable", "variableName"=>"nonNull"}
|
43
46
|
}
|
44
47
|
]
|
45
48
|
assert_equal(expected, errors)
|
@@ -116,17 +119,20 @@ describe GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTyped do
|
|
116
119
|
{
|
117
120
|
"message"=>"Non-null variable $a can't have a default value",
|
118
121
|
"locations"=>[{"line"=>3, "column"=>11}],
|
119
|
-
"
|
122
|
+
"path"=>["query getCheese"],
|
123
|
+
"extensions"=>{"code"=>"defaultValueInvalidOnNonNullVariable", "variableName"=>"a"}
|
120
124
|
},
|
121
125
|
{
|
122
126
|
"message"=>"Non-null variable $b can't have a default value",
|
123
127
|
"locations"=>[{"line"=>4, "column"=>11}],
|
124
|
-
"
|
128
|
+
"path"=>["query getCheese"],
|
129
|
+
"extensions"=>{"code"=>"defaultValueInvalidOnNonNullVariable", "variableName"=>"b"}
|
125
130
|
},
|
126
131
|
{
|
127
132
|
"message"=>"Default value for $c doesn't match type ComplexInput",
|
128
133
|
"locations"=>[{"line"=>5, "column"=>11}],
|
129
|
-
"
|
134
|
+
"path"=>["query getCheese"],
|
135
|
+
"extensions"=>{"code"=>"defaultValueInvalidType", "variableName"=>"c", "typeName"=>"ComplexInput"}
|
130
136
|
}
|
131
137
|
]
|
132
138
|
|
@@ -182,7 +188,8 @@ describe GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTyped do
|
|
182
188
|
assert_includes errors, {
|
183
189
|
"message"=> "cannot coerce to Float",
|
184
190
|
"locations"=>[{"line"=>3, "column"=>9}],
|
185
|
-
"
|
191
|
+
"path"=>["query"],
|
192
|
+
"extensions"=>{"code"=>"defaultValueInvalidType", "variableName"=>"value", "typeName"=>"Time"}
|
186
193
|
}
|
187
194
|
end
|
188
195
|
end
|
@@ -43,22 +43,26 @@ describe GraphQL::StaticValidation::VariableUsagesAreAllowed do
|
|
43
43
|
{
|
44
44
|
"message"=>"Nullability mismatch on variable $badInt and argument id (Int / Int!)",
|
45
45
|
"locations"=>[{"line"=>14, "column"=>28}],
|
46
|
-
"
|
46
|
+
"path"=>["query getCheese", "badCheese", "id"],
|
47
|
+
"extensions"=>{"code"=>"variableMismatch", "variableName"=>"badInt", "typeName"=>"Int", "argumentName"=>"id", "errorMessage"=>"Nullability mismatch"}
|
47
48
|
},
|
48
49
|
{
|
49
50
|
"message"=>"Type mismatch on variable $badStr and argument id (String! / Int!)",
|
50
51
|
"locations"=>[{"line"=>15, "column"=>28}],
|
51
|
-
"
|
52
|
+
"path"=>["query getCheese", "badStrCheese", "id"],
|
53
|
+
"extensions"=>{"code"=>"variableMismatch", "variableName"=>"badStr", "typeName"=>"String!", "argumentName"=>"id", "errorMessage"=>"Type mismatch"}
|
52
54
|
},
|
53
55
|
{
|
54
56
|
"message"=>"Nullability mismatch on variable $badAnimals and argument source ([DairyAnimal]! / [DairyAnimal!]!)",
|
55
57
|
"locations"=>[{"line"=>18, "column"=>30}],
|
56
|
-
"
|
58
|
+
"path"=>["query getCheese", "cheese", "other", "source"],
|
59
|
+
"extensions"=>{"code"=>"variableMismatch", "variableName"=>"badAnimals", "typeName"=>"[DairyAnimal]!", "argumentName"=>"source", "errorMessage"=>"Nullability mismatch"}
|
57
60
|
},
|
58
61
|
{
|
59
62
|
"message"=>"List dimension mismatch on variable $deepAnimals and argument source ([[DairyAnimal!]!]! / [DairyAnimal!]!)",
|
60
63
|
"locations"=>[{"line"=>19, "column"=>32}],
|
61
|
-
"
|
64
|
+
"path"=>["query getCheese", "cheese", "tooDeep", "source"],
|
65
|
+
"extensions"=>{"code"=>"variableMismatch", "variableName"=>"deepAnimals", "typeName"=>"[[DairyAnimal!]!]!", "argumentName"=>"source", "errorMessage"=>"List dimension mismatch"}
|
62
66
|
}
|
63
67
|
]
|
64
68
|
assert_equal(expected, errors)
|
@@ -22,25 +22,29 @@ describe GraphQL::StaticValidation::VariablesAreInputTypes do
|
|
22
22
|
assert_includes(errors, {
|
23
23
|
"message"=>"AnimalProduct isn't a valid input type (on $interface)",
|
24
24
|
"locations"=>[{"line"=>5, "column"=>7}],
|
25
|
-
"
|
25
|
+
"path"=>["query getCheese"],
|
26
|
+
"extensions"=> {"code"=>"variableRequiresValidType", "typeName"=>"AnimalProduct", "variableName"=>"interface"}
|
26
27
|
})
|
27
28
|
|
28
29
|
assert_includes(errors, {
|
29
30
|
"message"=>"Milk isn't a valid input type (on $object)",
|
30
31
|
"locations"=>[{"line"=>6, "column"=>7}],
|
31
|
-
"
|
32
|
+
"path"=>["query getCheese"],
|
33
|
+
"extensions"=>{"code"=>"variableRequiresValidType", "typeName"=>"Milk", "variableName"=>"object"}
|
32
34
|
})
|
33
35
|
|
34
36
|
assert_includes(errors, {
|
35
37
|
"message"=>"Cheese isn't a valid input type (on $objects)",
|
36
38
|
"locations"=>[{"line"=>7, "column"=>7}],
|
37
|
-
"
|
39
|
+
"path"=>["query getCheese"],
|
40
|
+
"extensions"=>{"code"=>"variableRequiresValidType", "typeName"=>"Cheese", "variableName"=>"objects"}
|
38
41
|
})
|
39
42
|
|
40
43
|
assert_includes(errors, {
|
41
44
|
"message"=>"Nonsense isn't a defined input type (on $unknownType)",
|
42
45
|
"locations"=>[{"line"=>8, "column"=>7}],
|
43
|
-
"
|
46
|
+
"path"=>["query getCheese"],
|
47
|
+
"extensions"=>{"code"=>"variableRequiresValidType", "typeName"=>"Nonsense", "variableName"=>"unknownType"}
|
44
48
|
})
|
45
49
|
end
|
46
50
|
|
@@ -42,17 +42,20 @@ describe GraphQL::StaticValidation::VariablesAreUsedAndDefined do
|
|
42
42
|
{
|
43
43
|
"message"=>"Variable $notUsedVar is declared by getCheese but not used",
|
44
44
|
"locations"=>[{"line"=>2, "column"=>5}],
|
45
|
-
"
|
45
|
+
"path"=>["query getCheese"],
|
46
|
+
"extensions"=>{"code"=>"variableNotUsed", "variableName"=>"notUsedVar"}
|
46
47
|
},
|
47
48
|
{
|
48
49
|
"message"=>"Variable $undefinedVar is used by getCheese but not declared",
|
49
50
|
"locations"=>[{"line"=>19, "column"=>22}],
|
50
|
-
"
|
51
|
+
"path"=>["query getCheese", "c3", "id"],
|
52
|
+
"extensions"=>{"code"=>"variableNotDefined", "variableName"=>"undefinedVar"}
|
51
53
|
},
|
52
54
|
{
|
53
55
|
"message"=>"Variable $undefinedFragmentVar is used by innerCheeseFields but not declared",
|
54
56
|
"locations"=>[{"line"=>29, "column"=>22}],
|
55
|
-
"
|
57
|
+
"path"=>["fragment innerCheeseFields", "c4", "id"],
|
58
|
+
"extensions"=>{"code"=>"variableNotDefined", "variableName"=>"undefinedFragmentVar"}
|
56
59
|
},
|
57
60
|
]
|
58
61
|
|
@@ -34,7 +34,8 @@ describe GraphQL::StaticValidation::Validator do
|
|
34
34
|
expected_errors = [{
|
35
35
|
"message" => "Variable $undefinedVar is used by but not declared",
|
36
36
|
"locations" => [{"line" => 1, "column" => 14, "filename" => "not_a_real.graphql"}],
|
37
|
-
"
|
37
|
+
"path" => ["query", "cheese", "id"],
|
38
|
+
"extensions"=>{"code"=>"variableNotDefined", "variableName"=>"undefinedVar"}
|
38
39
|
}]
|
39
40
|
assert_equal expected_errors, errors
|
40
41
|
end
|
@@ -115,7 +116,8 @@ describe GraphQL::StaticValidation::Validator do
|
|
115
116
|
{
|
116
117
|
"message"=>"Fragment cheeseFields contains an infinite loop",
|
117
118
|
"locations"=>[{"line"=>10, "column"=>9}],
|
118
|
-
"
|
119
|
+
"path"=>["fragment cheeseFields"],
|
120
|
+
"extensions"=>{"code"=>"infiniteLoop", "fragmentName"=>"cheeseFields"}
|
119
121
|
}
|
120
122
|
]
|
121
123
|
assert_equal(expected, errors)
|
@@ -180,10 +182,10 @@ describe GraphQL::StaticValidation::Validator do
|
|
180
182
|
describe "With a legacy-style rule" do
|
181
183
|
# GraphQL-Pro's operation store uses this
|
182
184
|
class ValidatorSpecLegacyRule
|
183
|
-
include GraphQL::StaticValidation::
|
185
|
+
include GraphQL::StaticValidation::Error::ErrorHelper
|
184
186
|
def validate(ctx)
|
185
187
|
ctx.visitor[GraphQL::Language::Nodes::OperationDefinition] << ->(n, _p) {
|
186
|
-
ctx.errors <<
|
188
|
+
ctx.errors << error("Busted!", n, context: ctx)
|
187
189
|
}
|
188
190
|
end
|
189
191
|
end
|
@@ -26,6 +26,11 @@ describe GraphQL::Tracing::NewRelicTracing do
|
|
26
26
|
use GraphQL::Execution::Interpreter
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
class SchemaWithScalarTrace < GraphQL::Schema
|
31
|
+
query(Query)
|
32
|
+
use(GraphQL::Tracing::NewRelicTracing, trace_scalars: true)
|
33
|
+
end
|
29
34
|
end
|
30
35
|
|
31
36
|
before do
|
@@ -50,4 +55,9 @@ describe GraphQL::Tracing::NewRelicTracing do
|
|
50
55
|
NewRelicTest::SchemaWithoutTransactionName.execute "{ int }", context: { set_new_relic_transaction_name: true }
|
51
56
|
assert_equal ["GraphQL/query.anonymous"], NewRelic::TRANSACTION_NAMES
|
52
57
|
end
|
58
|
+
|
59
|
+
it "traces scalars when trace_scalars is true" do
|
60
|
+
NewRelicTest::SchemaWithScalarTrace.execute "query X { int }"
|
61
|
+
assert_includes NewRelic::EXECUTION_SCOPES, "GraphQL/Query/int"
|
62
|
+
end
|
53
63
|
end
|
@@ -26,6 +26,11 @@ describe GraphQL::Tracing::SkylightTracing do
|
|
26
26
|
use GraphQL::Execution::Interpreter
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
class SchemaWithScalarTrace < GraphQL::Schema
|
31
|
+
query(Query)
|
32
|
+
use(GraphQL::Tracing::SkylightTracing, trace_scalars: true)
|
33
|
+
end
|
29
34
|
end
|
30
35
|
|
31
36
|
before do
|
@@ -50,4 +55,9 @@ describe GraphQL::Tracing::SkylightTracing do
|
|
50
55
|
SkylightTest::SchemaWithoutTransactionName.execute "{ int }", context: { set_skylight_endpoint_name: true }
|
51
56
|
assert_equal ["GraphQL/query.<anonymous>"], Skylight::ENDPOINT_NAMES
|
52
57
|
end
|
58
|
+
|
59
|
+
it "traces scalars when trace_scalars is true" do
|
60
|
+
SkylightTest::SchemaWithScalarTrace.execute "query X { int }"
|
61
|
+
assert_includes Skylight::TITLE_NAMES, "graphql.Query.int"
|
62
|
+
end
|
53
63
|
end
|
@@ -11,8 +11,7 @@ describe GraphQL::Types::ISO8601DateTime do
|
|
11
11
|
field :minute, Integer, null: false
|
12
12
|
field :second, Integer, null: false
|
13
13
|
field :zone, String, null: false
|
14
|
-
|
15
|
-
field :iso8601, GraphQL::Types::ISO8601DateTime, null: false, method: :object
|
14
|
+
field :iso8601, GraphQL::Types::ISO8601DateTime, null: false, method: :itself
|
16
15
|
end
|
17
16
|
|
18
17
|
class Query < GraphQL::Schema::Object
|
@@ -169,11 +169,11 @@ module StarTrek
|
|
169
169
|
all_bases.to_a
|
170
170
|
end
|
171
171
|
|
172
|
-
field :basesWithMaxLimitRelation, BaseType.connection_type, null: true, max_page_size: 2,
|
173
|
-
field :basesWithMaxLimitArray, BaseType.connection_type, null: true, max_page_size: 2,
|
174
|
-
field :basesWithDefaultMaxLimitRelation, BaseType.connection_type, null: true,
|
175
|
-
field :basesWithDefaultMaxLimitArray, BaseType.connection_type, null: true,
|
176
|
-
field :basesWithLargeMaxLimitRelation, BaseType.connection_type, null: true, max_page_size: 1000,
|
172
|
+
field :basesWithMaxLimitRelation, BaseType.connection_type, null: true, max_page_size: 2, resolver_method: :all_bases
|
173
|
+
field :basesWithMaxLimitArray, BaseType.connection_type, null: true, max_page_size: 2, resolver_method: :all_bases_array
|
174
|
+
field :basesWithDefaultMaxLimitRelation, BaseType.connection_type, null: true, resolver_method: :all_bases
|
175
|
+
field :basesWithDefaultMaxLimitArray, BaseType.connection_type, null: true, resolver_method: :all_bases_array
|
176
|
+
field :basesWithLargeMaxLimitRelation, BaseType.connection_type, null: true, max_page_size: 1000, resolver_method: :all_bases
|
177
177
|
|
178
178
|
field :basesWithCustomEdge, CustomEdgeBaseConnectionType, null: true, connection: true
|
179
179
|
def bases_with_custom_edge
|
@@ -21,7 +21,7 @@ describe GraphQL::Relay::RelationConnection do
|
|
21
21
|
|
22
22
|
describe "results" do
|
23
23
|
let(:query_string) {%|
|
24
|
-
query getShips($first: Int, $after: String, $last: Int, $before: String,
|
24
|
+
query getShips($first: Int, $after: String, $last: Int, $before: String, $nameIncludes: String){
|
25
25
|
empire {
|
26
26
|
bases(first: $first, after: $after, last: $last, before: $before, nameIncludes: $nameIncludes) {
|
27
27
|
... basesConnection
|
@@ -66,6 +66,39 @@ describe GraphQL::Relay::RelationConnection do
|
|
66
66
|
assert_equal("Mw", get_last_cursor(result))
|
67
67
|
end
|
68
68
|
|
69
|
+
it "uses unscope(:order) count(*) when the relation has some complicated SQL" do
|
70
|
+
query_s = <<-GRAPHQL
|
71
|
+
query getShips($first: Int, $after: String, $complexOrder: Boolean){
|
72
|
+
empire {
|
73
|
+
bases(first: $first, after: $after, complexOrder: $complexOrder) {
|
74
|
+
edges {
|
75
|
+
node {
|
76
|
+
name
|
77
|
+
}
|
78
|
+
}
|
79
|
+
pageInfo {
|
80
|
+
hasNextPage
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
GRAPHQL
|
86
|
+
result = nil
|
87
|
+
log = with_active_record_log do
|
88
|
+
result = star_wars_query(query_s, "first" => 1, "after" => "MQ==", "complexOrder" => true)
|
89
|
+
end
|
90
|
+
|
91
|
+
conn = result["data"]["empire"]["bases"]
|
92
|
+
assert_equal(1, conn["edges"].size)
|
93
|
+
assert_equal(true, conn["pageInfo"]["hasNextPage"])
|
94
|
+
|
95
|
+
log_entries = log.split("\n")
|
96
|
+
assert_equal 2, log_entries.size, "It ran 2 sql queries"
|
97
|
+
edges_query, has_next_page_query = log_entries
|
98
|
+
assert_includes edges_query, "ORDER BY bases.name", "The query for edges _is_ ordered"
|
99
|
+
refute_includes has_next_page_query, "ORDER BY bases.name", "The count query **does not** have an order"
|
100
|
+
end
|
101
|
+
|
69
102
|
it 'provides custom fields on the connection type' do
|
70
103
|
result = star_wars_query(query_string, "first" => 2)
|
71
104
|
assert_equal(
|
@@ -90,15 +123,11 @@ describe GraphQL::Relay::RelationConnection do
|
|
90
123
|
}
|
91
124
|
}
|
92
125
|
GRAPHQL
|
93
|
-
|
94
|
-
|
95
|
-
prev_logger = ActiveRecord::Base.logger
|
96
|
-
ActiveRecord::Base.logger = Logger.new(io)
|
126
|
+
result = nil
|
127
|
+
log = with_active_record_log do
|
97
128
|
result = star_wars_query(query_str, "first" => 2)
|
98
|
-
ensure
|
99
|
-
ActiveRecord::Base.logger = prev_logger
|
100
129
|
end
|
101
|
-
assert_equal 2,
|
130
|
+
assert_equal 2, log.scan("\n").count, "Two log entries"
|
102
131
|
assert_equal 3, result["data"]["empire"]["bases"]["totalCount"]
|
103
132
|
assert_equal 2, result["data"]["empire"]["bases"]["edges"].size
|
104
133
|
end
|