graphql 1.9.0.pre1 → 1.9.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class ArgumentsAreDefinedError < StaticValidation::Error
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :type_name
|
7
|
+
attr_reader :argument_name
|
8
|
+
|
9
|
+
def initialize(message, path: nil, nodes: [], name:, type:, argument:)
|
10
|
+
super(message, path: path, nodes: nodes)
|
11
|
+
@name = name
|
12
|
+
@type_name = type
|
13
|
+
@argument_name = argument
|
14
|
+
end
|
15
|
+
|
16
|
+
# A hash representation of this Message
|
17
|
+
def to_h
|
18
|
+
extensions = {
|
19
|
+
"code" => code,
|
20
|
+
"name" => name,
|
21
|
+
"typeName" => type_name,
|
22
|
+
"argumentName" => argument_name
|
23
|
+
}
|
24
|
+
|
25
|
+
super.merge({
|
26
|
+
"extensions" => extensions
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
def code
|
31
|
+
"argumentNotAccepted"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -9,7 +9,11 @@ module GraphQL
|
|
9
9
|
|
10
10
|
def on_directive(node, parent)
|
11
11
|
if !@directive_names.include?(node.name)
|
12
|
-
add_error(
|
12
|
+
add_error(GraphQL::StaticValidation::DirectivesAreDefinedError.new(
|
13
|
+
"Directive @#{node.name} is not defined",
|
14
|
+
nodes: node,
|
15
|
+
directive: node.name
|
16
|
+
))
|
13
17
|
else
|
14
18
|
super
|
15
19
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class DirectivesAreDefinedError < StaticValidation::Error
|
5
|
+
attr_reader :directive_name
|
6
|
+
|
7
|
+
def initialize(message, path: nil, nodes: [], directive:)
|
8
|
+
super(message, path: path, nodes: nodes)
|
9
|
+
@directive_name = directive
|
10
|
+
end
|
11
|
+
|
12
|
+
# A hash representation of this Message
|
13
|
+
def to_h
|
14
|
+
extensions = {
|
15
|
+
"code" => code,
|
16
|
+
"directiveName" => directive_name
|
17
|
+
}
|
18
|
+
|
19
|
+
super.merge({
|
20
|
+
"extensions" => extensions
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
def code
|
25
|
+
"undefinedDirective"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -40,7 +40,11 @@ module GraphQL
|
|
40
40
|
required_location = SIMPLE_LOCATIONS[ast_parent.class]
|
41
41
|
assert_includes_location(directive_defn, ast_directive, required_location)
|
42
42
|
else
|
43
|
-
add_error(
|
43
|
+
add_error(GraphQL::StaticValidation::DirectivesAreInValidLocationsError.new(
|
44
|
+
"Directives can't be applied to #{ast_parent.class.name}s",
|
45
|
+
nodes: ast_directive,
|
46
|
+
target: ast_parent.class.name
|
47
|
+
))
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
@@ -48,7 +52,12 @@ module GraphQL
|
|
48
52
|
if !directive_defn.locations.include?(required_location)
|
49
53
|
location_name = LOCATION_MESSAGE_NAMES[required_location]
|
50
54
|
allowed_location_names = directive_defn.locations.map { |loc| LOCATION_MESSAGE_NAMES[loc] }
|
51
|
-
add_error(
|
55
|
+
add_error(GraphQL::StaticValidation::DirectivesAreInValidLocationsError.new(
|
56
|
+
"'@#{directive_defn.graphql_name}' can't be applied to #{location_name} (allowed: #{allowed_location_names.join(", ")})",
|
57
|
+
nodes: directive_ast,
|
58
|
+
target: location_name,
|
59
|
+
name: directive_defn.name
|
60
|
+
))
|
52
61
|
end
|
53
62
|
end
|
54
63
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class DirectivesAreInValidLocationsError < StaticValidation::Error
|
5
|
+
attr_reader :target_name
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(message, path: nil, nodes: [], target:, name: nil)
|
9
|
+
super(message, path: path, nodes: nodes)
|
10
|
+
@target_name = target
|
11
|
+
@name = name
|
12
|
+
end
|
13
|
+
|
14
|
+
# A hash representation of this Message
|
15
|
+
def to_h
|
16
|
+
extensions = {
|
17
|
+
"code" => code,
|
18
|
+
"targetName" => target_name
|
19
|
+
}.tap { |h| h["name"] = name unless name.nil? }
|
20
|
+
|
21
|
+
super.merge({
|
22
|
+
"extensions" => extensions
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def code
|
27
|
+
"directiveCannotBeApplied"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -8,9 +8,18 @@ module GraphQL
|
|
8
8
|
|
9
9
|
if field.nil?
|
10
10
|
if parent_type.kind.union?
|
11
|
-
add_error(
|
11
|
+
add_error(GraphQL::StaticValidation::FieldsHaveAppropriateSelectionsError.new(
|
12
|
+
"Selections can't be made directly on unions (see selections on #{parent_type.name})",
|
13
|
+
nodes: parent,
|
14
|
+
node_name: parent_type.name
|
15
|
+
))
|
12
16
|
else
|
13
|
-
add_error(
|
17
|
+
add_error(GraphQL::StaticValidation::FieldsAreDefinedOnTypeError.new(
|
18
|
+
"Field '#{node.name}' doesn't exist on type '#{parent_type.name}'",
|
19
|
+
nodes: node,
|
20
|
+
field: node.name,
|
21
|
+
type: parent_type.name
|
22
|
+
))
|
14
23
|
end
|
15
24
|
else
|
16
25
|
super
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class FieldsAreDefinedOnTypeError < StaticValidation::Error
|
5
|
+
attr_reader :type_name
|
6
|
+
attr_reader :field_name
|
7
|
+
|
8
|
+
def initialize(message, path: nil, nodes: [], type:, field:)
|
9
|
+
super(message, path: path, nodes: nodes)
|
10
|
+
@type_name = type
|
11
|
+
@field_name = field
|
12
|
+
end
|
13
|
+
|
14
|
+
# A hash representation of this Message
|
15
|
+
def to_h
|
16
|
+
extensions = {
|
17
|
+
"code" => code,
|
18
|
+
"typeName" => type_name,
|
19
|
+
"fieldName" => field_name
|
20
|
+
}
|
21
|
+
|
22
|
+
super.merge({
|
23
|
+
"extensions" => extensions
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
def code
|
28
|
+
"undefinedField"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -4,7 +4,7 @@ module GraphQL
|
|
4
4
|
# Scalars _can't_ have selections
|
5
5
|
# Objects _must_ have selections
|
6
6
|
module FieldsHaveAppropriateSelections
|
7
|
-
include GraphQL::StaticValidation::
|
7
|
+
include GraphQL::StaticValidation::Error::ErrorHelper
|
8
8
|
|
9
9
|
def on_field(node, parent)
|
10
10
|
field_defn = field_definition
|
@@ -50,7 +50,19 @@ module GraphQL
|
|
50
50
|
else
|
51
51
|
raise("Unexpected node #{ast_node}")
|
52
52
|
end
|
53
|
-
|
53
|
+
extensions = {
|
54
|
+
"rule": "StaticValidation::FieldsHaveAppropriateSelections",
|
55
|
+
"name": node_name.to_s
|
56
|
+
}
|
57
|
+
unless resolved_type.nil?
|
58
|
+
extensions["type"] = resolved_type.to_s
|
59
|
+
end
|
60
|
+
add_error(GraphQL::StaticValidation::FieldsHaveAppropriateSelectionsError.new(
|
61
|
+
msg % { node_name: node_name },
|
62
|
+
nodes: ast_node,
|
63
|
+
node_name: node_name.to_s,
|
64
|
+
type: resolved_type.nil? ? nil : resolved_type.to_s
|
65
|
+
))
|
54
66
|
false
|
55
67
|
else
|
56
68
|
true
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class FieldsHaveAppropriateSelectionsError < StaticValidation::Error
|
5
|
+
attr_reader :type_name
|
6
|
+
attr_reader :node_name
|
7
|
+
|
8
|
+
def initialize(message, path: nil, nodes: [], node_name:, type: nil)
|
9
|
+
super(message, path: path, nodes: nodes)
|
10
|
+
@node_name = node_name
|
11
|
+
@type_name = type
|
12
|
+
end
|
13
|
+
|
14
|
+
# A hash representation of this Message
|
15
|
+
def to_h
|
16
|
+
extensions = {
|
17
|
+
"code" => code,
|
18
|
+
"nodeName" => node_name
|
19
|
+
}.tap { |h| h["typeName"] = type_name unless type_name.nil? }
|
20
|
+
|
21
|
+
super.merge({
|
22
|
+
"extensions" => extensions
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def code
|
27
|
+
"selectionMismatch"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -193,13 +193,25 @@ module GraphQL
|
|
193
193
|
if node1.name != node2.name
|
194
194
|
errored_nodes = [node1.name, node2.name].sort.join(" or ")
|
195
195
|
msg = "Field '#{response_key}' has a field conflict: #{errored_nodes}?"
|
196
|
-
context.errors << GraphQL::StaticValidation::
|
196
|
+
context.errors << GraphQL::StaticValidation::FieldsWillMergeError.new(
|
197
|
+
msg,
|
198
|
+
nodes: [node1, node2],
|
199
|
+
path: [],
|
200
|
+
field_name: response_key,
|
201
|
+
conflicts: errored_nodes
|
202
|
+
)
|
197
203
|
end
|
198
204
|
|
199
205
|
args = possible_arguments(node1, node2)
|
200
206
|
if args.size > 1
|
201
207
|
msg = "Field '#{response_key}' has an argument conflict: #{args.map { |arg| GraphQL::Language.serialize(arg) }.join(" or ")}?"
|
202
|
-
context.errors << GraphQL::StaticValidation::
|
208
|
+
context.errors << GraphQL::StaticValidation::FieldsWillMergeError.new(
|
209
|
+
msg,
|
210
|
+
nodes: [node1, node2],
|
211
|
+
path: [],
|
212
|
+
field_name: response_key,
|
213
|
+
conflicts: args.map { |arg| GraphQL::Language.serialize(arg) }.join(" or ")
|
214
|
+
)
|
203
215
|
end
|
204
216
|
end
|
205
217
|
|
@@ -285,13 +297,19 @@ module GraphQL
|
|
285
297
|
end
|
286
298
|
end
|
287
299
|
|
300
|
+
NO_SELECTIONS = [{}.freeze, [].freeze].freeze
|
301
|
+
|
288
302
|
def fields_and_fragments_from_selection(node, owner_type:, parents:)
|
289
|
-
|
290
|
-
|
291
|
-
|
303
|
+
if node.selections.none?
|
304
|
+
NO_SELECTIONS
|
305
|
+
else
|
306
|
+
fields, fragment_spreads = find_fields_and_fragments(node.selections, owner_type: owner_type, parents: parents, fields: [], fragment_spreads: [])
|
307
|
+
response_keys = fields.group_by { |f| f.node.alias || f.node.name }
|
308
|
+
[response_keys, fragment_spreads]
|
309
|
+
end
|
292
310
|
end
|
293
311
|
|
294
|
-
def find_fields_and_fragments(selections, owner_type:, parents:, fields
|
312
|
+
def find_fields_and_fragments(selections, owner_type:, parents:, fields:, fragment_spreads:)
|
295
313
|
selections.each do |node|
|
296
314
|
case node
|
297
315
|
when GraphQL::Language::Nodes::Field
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class FieldsWillMergeError < StaticValidation::Error
|
5
|
+
attr_reader :field_name
|
6
|
+
attr_reader :conflicts
|
7
|
+
|
8
|
+
def initialize(message, path: nil, nodes: [], field_name:, conflicts:)
|
9
|
+
super(message, path: path, nodes: nodes)
|
10
|
+
@field_name = field_name
|
11
|
+
@conflicts = conflicts
|
12
|
+
end
|
13
|
+
|
14
|
+
# A hash representation of this Message
|
15
|
+
def to_h
|
16
|
+
extensions = {
|
17
|
+
"code" => code,
|
18
|
+
"fieldName" => field_name,
|
19
|
+
"conflicts" => conflicts
|
20
|
+
}
|
21
|
+
|
22
|
+
super.merge({
|
23
|
+
"extensions" => extensions
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
def code
|
28
|
+
"fieldConflict"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -17,7 +17,11 @@ module GraphQL
|
|
17
17
|
super
|
18
18
|
@fragments_by_name.each do |name, fragments|
|
19
19
|
if fragments.length > 1
|
20
|
-
add_error(
|
20
|
+
add_error(GraphQL::StaticValidation::FragmentNamesAreUniqueError.new(
|
21
|
+
%|Fragment name "#{name}" must be unique|,
|
22
|
+
nodes: fragments,
|
23
|
+
name: name
|
24
|
+
))
|
21
25
|
end
|
22
26
|
end
|
23
27
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class FragmentNamesAreUniqueError < StaticValidation::Error
|
5
|
+
attr_reader :fragment_name
|
6
|
+
|
7
|
+
def initialize(message, path: nil, nodes: [], name:)
|
8
|
+
super(message, path: path, nodes: nodes)
|
9
|
+
@fragment_name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
# A hash representation of this Message
|
13
|
+
def to_h
|
14
|
+
extensions = {
|
15
|
+
"code" => code,
|
16
|
+
"fragmentName" => fragment_name
|
17
|
+
}
|
18
|
+
|
19
|
+
super.merge({
|
20
|
+
"extensions" => extensions
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
def code
|
25
|
+
"fragmentNotUnique"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -49,7 +49,14 @@ module GraphQL
|
|
49
49
|
|
50
50
|
if child_types.none? { |c| parent_types.include?(c) }
|
51
51
|
name = node.respond_to?(:name) ? " #{node.name}" : ""
|
52
|
-
add_error(
|
52
|
+
add_error(GraphQL::StaticValidation::FragmentSpreadsArePossibleError.new(
|
53
|
+
"Fragment#{name} on #{child_type.name} can't be spread inside #{parent_type.name}",
|
54
|
+
nodes: node,
|
55
|
+
path: path,
|
56
|
+
fragment_name: name.empty? ? "unknown" : name,
|
57
|
+
type: child_type.name,
|
58
|
+
parent: parent_type.name
|
59
|
+
))
|
53
60
|
end
|
54
61
|
end
|
55
62
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class FragmentSpreadsArePossibleError < StaticValidation::Error
|
5
|
+
attr_reader :type_name
|
6
|
+
attr_reader :fragment_name
|
7
|
+
attr_reader :parent_name
|
8
|
+
|
9
|
+
def initialize(message, path: nil, nodes: [], type:, fragment_name:, parent:)
|
10
|
+
super(message, path: path, nodes: nodes)
|
11
|
+
@type_name = type
|
12
|
+
@fragment_name = fragment_name
|
13
|
+
@parent_name = parent
|
14
|
+
end
|
15
|
+
|
16
|
+
# A hash representation of this Message
|
17
|
+
def to_h
|
18
|
+
extensions = {
|
19
|
+
"code" => code,
|
20
|
+
"typeName" => type_name,
|
21
|
+
"fragmentName" => fragment_name,
|
22
|
+
"parentName" => parent_name
|
23
|
+
}
|
24
|
+
|
25
|
+
super.merge({
|
26
|
+
"extensions" => extensions
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
def code
|
31
|
+
"cannotSpreadFragment"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -23,7 +23,11 @@ module GraphQL
|
|
23
23
|
type_name = fragment_node.type.name
|
24
24
|
type = context.warden.get_type(type_name)
|
25
25
|
if type.nil?
|
26
|
-
add_error(
|
26
|
+
add_error(GraphQL::StaticValidation::FragmentTypesExistError.new(
|
27
|
+
"No such type #{type_name}, so it can't be a fragment condition",
|
28
|
+
nodes: fragment_node,
|
29
|
+
type: type_name
|
30
|
+
))
|
27
31
|
false
|
28
32
|
else
|
29
33
|
true
|