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.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +5 -1
  3. data/lib/graphql/analysis/ast/analyzer.rb +1 -1
  4. data/lib/graphql/analysis/ast/visitor.rb +6 -1
  5. data/lib/graphql/backwards_compatibility.rb +1 -1
  6. data/lib/graphql/dig.rb +19 -0
  7. data/lib/graphql/directive.rb +13 -1
  8. data/lib/graphql/directive/include_directive.rb +1 -7
  9. data/lib/graphql/directive/skip_directive.rb +1 -8
  10. data/lib/graphql/execution/interpreter.rb +23 -13
  11. data/lib/graphql/execution/interpreter/resolve.rb +56 -0
  12. data/lib/graphql/execution/interpreter/runtime.rb +174 -74
  13. data/lib/graphql/execution/lazy.rb +7 -1
  14. data/lib/graphql/execution/lookahead.rb +71 -6
  15. data/lib/graphql/execution_error.rb +1 -1
  16. data/lib/graphql/introspection/entry_points.rb +5 -1
  17. data/lib/graphql/introspection/type_type.rb +4 -4
  18. data/lib/graphql/language.rb +0 -1
  19. data/lib/graphql/language/block_string.rb +37 -0
  20. data/lib/graphql/language/document_from_schema_definition.rb +1 -1
  21. data/lib/graphql/language/lexer.rb +55 -36
  22. data/lib/graphql/language/lexer.rl +8 -3
  23. data/lib/graphql/language/nodes.rb +27 -4
  24. data/lib/graphql/language/parser.rb +55 -55
  25. data/lib/graphql/language/parser.y +11 -11
  26. data/lib/graphql/language/printer.rb +1 -1
  27. data/lib/graphql/language/visitor.rb +22 -13
  28. data/lib/graphql/literal_validation_error.rb +6 -0
  29. data/lib/graphql/query.rb +13 -0
  30. data/lib/graphql/query/arguments.rb +2 -1
  31. data/lib/graphql/query/context.rb +3 -10
  32. data/lib/graphql/query/executor.rb +1 -1
  33. data/lib/graphql/query/validation_pipeline.rb +1 -1
  34. data/lib/graphql/relay/connection_resolve.rb +1 -1
  35. data/lib/graphql/relay/relation_connection.rb +1 -1
  36. data/lib/graphql/schema.rb +81 -11
  37. data/lib/graphql/schema/argument.rb +1 -1
  38. data/lib/graphql/schema/build_from_definition.rb +2 -4
  39. data/lib/graphql/schema/directive.rb +103 -0
  40. data/lib/graphql/schema/directive/feature.rb +66 -0
  41. data/lib/graphql/schema/directive/include.rb +25 -0
  42. data/lib/graphql/schema/directive/skip.rb +25 -0
  43. data/lib/graphql/schema/directive/transform.rb +48 -0
  44. data/lib/graphql/schema/enum_value.rb +2 -2
  45. data/lib/graphql/schema/field.rb +63 -17
  46. data/lib/graphql/schema/input_object.rb +1 -0
  47. data/lib/graphql/schema/member/base_dsl_methods.rb +4 -2
  48. data/lib/graphql/schema/member/build_type.rb +33 -1
  49. data/lib/graphql/schema/member/has_fields.rb +8 -73
  50. data/lib/graphql/schema/relay_classic_mutation.rb +6 -1
  51. data/lib/graphql/schema/resolver.rb +1 -1
  52. data/lib/graphql/static_validation.rb +2 -1
  53. data/lib/graphql/static_validation/all_rules.rb +1 -0
  54. data/lib/graphql/static_validation/base_visitor.rb +25 -10
  55. data/lib/graphql/static_validation/definition_dependencies.rb +3 -3
  56. data/lib/graphql/static_validation/{message.rb → error.rb} +11 -11
  57. data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
  58. data/lib/graphql/static_validation/literal_validator.rb +54 -11
  59. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +34 -5
  60. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +31 -0
  61. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +2 -2
  62. data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
  63. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +7 -1
  64. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +35 -0
  65. data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -1
  66. data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
  67. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +11 -2
  68. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
  69. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +11 -2
  70. data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
  71. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +14 -2
  72. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
  73. data/lib/graphql/static_validation/rules/fields_will_merge.rb +24 -6
  74. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +32 -0
  75. data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +5 -1
  76. data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
  77. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +8 -1
  78. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
  79. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +5 -1
  80. data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
  81. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +6 -1
  82. data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
  83. data/lib/graphql/static_validation/rules/fragments_are_named.rb +4 -1
  84. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
  85. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +5 -1
  86. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
  87. data/lib/graphql/static_validation/rules/fragments_are_used.rb +13 -3
  88. data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
  89. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +4 -1
  90. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
  91. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +2 -2
  92. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
  93. data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +9 -2
  94. data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
  95. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -1
  96. data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
  97. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +47 -0
  98. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
  99. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +4 -1
  100. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
  101. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +4 -3
  102. data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
  103. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +20 -6
  104. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
  105. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +5 -1
  106. data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
  107. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -1
  108. data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
  109. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +12 -2
  110. data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
  111. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +18 -2
  112. data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
  113. data/lib/graphql/static_validation/validator.rb +24 -14
  114. data/lib/graphql/tracing/new_relic_tracing.rb +2 -2
  115. data/lib/graphql/tracing/skylight_tracing.rb +2 -2
  116. data/lib/graphql/unauthorized_field_error.rb +23 -0
  117. data/lib/graphql/version.rb +1 -1
  118. data/spec/graphql/analysis/ast_spec.rb +40 -0
  119. data/spec/graphql/authorization_spec.rb +93 -20
  120. data/spec/graphql/base_type_spec.rb +3 -1
  121. data/spec/graphql/execution/interpreter_spec.rb +127 -4
  122. data/spec/graphql/execution/lazy_spec.rb +49 -0
  123. data/spec/graphql/execution/lookahead_spec.rb +113 -21
  124. data/spec/graphql/execution/multiplex_spec.rb +2 -1
  125. data/spec/graphql/introspection/type_type_spec.rb +1 -1
  126. data/spec/graphql/language/lexer_spec.rb +72 -3
  127. data/spec/graphql/language/printer_spec.rb +18 -6
  128. data/spec/graphql/query/arguments_spec.rb +21 -0
  129. data/spec/graphql/query/context_spec.rb +10 -0
  130. data/spec/graphql/schema/build_from_definition_spec.rb +144 -29
  131. data/spec/graphql/schema/directive/feature_spec.rb +81 -0
  132. data/spec/graphql/schema/directive/transform_spec.rb +39 -0
  133. data/spec/graphql/schema/enum_spec.rb +5 -3
  134. data/spec/graphql/schema/field_extension_spec.rb +3 -3
  135. data/spec/graphql/schema/field_spec.rb +19 -0
  136. data/spec/graphql/schema/input_object_spec.rb +81 -0
  137. data/spec/graphql/schema/member/build_type_spec.rb +46 -0
  138. data/spec/graphql/schema/member/scoped_spec.rb +3 -3
  139. data/spec/graphql/schema/printer_spec.rb +244 -96
  140. data/spec/graphql/schema/relay_classic_mutation_spec.rb +26 -0
  141. data/spec/graphql/schema/resolver_spec.rb +1 -1
  142. data/spec/graphql/schema/warden_spec.rb +35 -11
  143. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +212 -72
  144. data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +2 -2
  145. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +72 -29
  146. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +4 -2
  147. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +4 -2
  148. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +10 -5
  149. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +10 -5
  150. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -1
  151. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +2 -1
  152. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +6 -3
  153. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +4 -2
  154. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +4 -2
  155. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +2 -1
  156. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +6 -3
  157. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +22 -2
  158. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +2 -1
  159. data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +6 -3
  160. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +13 -4
  161. data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +58 -0
  162. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +2 -1
  163. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +14 -7
  164. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +14 -7
  165. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +8 -4
  166. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +8 -4
  167. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +6 -3
  168. data/spec/graphql/static_validation/validator_spec.rb +6 -4
  169. data/spec/graphql/tracing/new_relic_tracing_spec.rb +10 -0
  170. data/spec/graphql/tracing/skylight_tracing_spec.rb +10 -0
  171. data/spec/graphql/types/iso_8601_date_time_spec.rb +1 -2
  172. data/spec/integration/mongoid/star_trek/schema.rb +5 -5
  173. data/spec/integration/rails/graphql/relay/relation_connection_spec.rb +37 -8
  174. data/spec/integration/rails/graphql/schema_spec.rb +2 -2
  175. data/spec/integration/rails/spec_helper.rb +10 -0
  176. data/spec/integration/tmp/app/graphql/types/bird_type.rb +7 -0
  177. data/spec/integration/tmp/dummy/Gemfile +45 -0
  178. data/spec/integration/tmp/dummy/README.rdoc +28 -0
  179. data/spec/integration/tmp/dummy/Rakefile +6 -0
  180. data/spec/integration/tmp/dummy/app/assets/javascripts/application.js +16 -0
  181. data/spec/integration/tmp/dummy/app/assets/stylesheets/application.css +15 -0
  182. data/spec/integration/tmp/dummy/app/controllers/application_controller.rb +5 -0
  183. data/spec/integration/tmp/dummy/app/controllers/graphql_controller.rb +43 -0
  184. data/spec/integration/tmp/dummy/app/graphql/dummy_schema.rb +34 -0
  185. data/spec/integration/tmp/dummy/app/graphql/types/base_enum.rb +4 -0
  186. data/spec/integration/tmp/dummy/app/graphql/types/base_input_object.rb +4 -0
  187. data/spec/integration/tmp/dummy/app/graphql/types/base_interface.rb +5 -0
  188. data/spec/integration/tmp/dummy/app/graphql/types/base_object.rb +4 -0
  189. data/spec/integration/tmp/dummy/app/graphql/types/base_scalar.rb +4 -0
  190. data/spec/integration/tmp/dummy/app/graphql/types/base_union.rb +4 -0
  191. data/spec/integration/tmp/dummy/app/graphql/types/mutation_type.rb +10 -0
  192. data/spec/integration/tmp/dummy/app/graphql/types/query_type.rb +15 -0
  193. data/spec/integration/tmp/dummy/app/helpers/application_helper.rb +2 -0
  194. data/spec/integration/tmp/dummy/app/views/layouts/application.html.erb +14 -0
  195. data/spec/integration/tmp/dummy/bin/bundle +3 -0
  196. data/spec/integration/tmp/dummy/bin/rails +4 -0
  197. data/spec/integration/tmp/dummy/bin/rake +4 -0
  198. data/spec/integration/tmp/dummy/bin/setup +29 -0
  199. data/spec/integration/tmp/dummy/config.ru +4 -0
  200. data/spec/integration/tmp/dummy/config/application.rb +32 -0
  201. data/spec/integration/tmp/dummy/config/boot.rb +3 -0
  202. data/spec/integration/tmp/dummy/config/environment.rb +5 -0
  203. data/spec/integration/tmp/dummy/config/environments/development.rb +38 -0
  204. data/spec/integration/tmp/dummy/config/environments/production.rb +76 -0
  205. data/spec/integration/tmp/dummy/config/environments/test.rb +42 -0
  206. data/spec/integration/tmp/dummy/config/initializers/assets.rb +11 -0
  207. data/spec/integration/tmp/dummy/config/initializers/backtrace_silencers.rb +7 -0
  208. data/spec/integration/tmp/dummy/config/initializers/cookies_serializer.rb +3 -0
  209. data/spec/integration/tmp/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  210. data/spec/integration/tmp/dummy/config/initializers/inflections.rb +16 -0
  211. data/spec/integration/tmp/dummy/config/initializers/mime_types.rb +4 -0
  212. data/spec/integration/tmp/dummy/config/initializers/session_store.rb +3 -0
  213. data/spec/integration/tmp/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  214. data/spec/integration/tmp/dummy/config/initializers/wrap_parameters.rb +9 -0
  215. data/spec/integration/tmp/dummy/config/locales/en.yml +23 -0
  216. data/spec/integration/tmp/dummy/config/routes.rb +61 -0
  217. data/spec/integration/tmp/dummy/config/secrets.yml +22 -0
  218. data/spec/integration/tmp/dummy/db/seeds.rb +7 -0
  219. data/spec/integration/tmp/dummy/public/404.html +67 -0
  220. data/spec/integration/tmp/dummy/public/422.html +67 -0
  221. data/spec/integration/tmp/dummy/public/500.html +66 -0
  222. data/spec/integration/tmp/dummy/public/favicon.ico +0 -0
  223. data/spec/integration/tmp/dummy/public/robots.txt +5 -0
  224. data/spec/support/dummy/schema.rb +2 -2
  225. data/spec/support/error_bubbling_helpers.rb +23 -0
  226. data/spec/support/jazz.rb +53 -6
  227. data/spec/support/lazy_helpers.rb +26 -8
  228. data/spec/support/new_relic.rb +3 -0
  229. data/spec/support/skylight.rb +3 -0
  230. data/spec/support/star_wars/schema.rb +13 -9
  231. data/spec/support/static_validation_helpers.rb +3 -1
  232. metadata +145 -22
  233. data/lib/graphql/language/comments.rb +0 -45
  234. data/spec/graphql/schema/member/has_fields_spec.rb +0 -132
  235. 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("Directive @#{node.name} is not defined", node)
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("Directives can't be applied to #{ast_parent.class.name}s", ast_directive)
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("'@#{directive_defn.name}' can't be applied to #{location_name} (allowed: #{allowed_location_names.join(", ")})", directive_ast)
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("Selections can't be made directly on unions (see selections on #{parent_type.name})", parent)
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("Field '#{node.name}' doesn't exist on type '#{parent_type.name}'", node)
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::Message::MessageHelper
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
- add_error(msg % { node_name: node_name }, ast_node)
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::Message.new(msg, nodes: [node1, node2])
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::Message.new(msg, nodes: [node1, node2])
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
- fields, fragment_spreads = find_fields_and_fragments(node.selections, owner_type: owner_type, parents: parents)
290
- response_keys = fields.group_by { |f| f.node.alias || f.node.name }
291
- [response_keys, fragment_spreads]
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: [], fragment_spreads: [])
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(%|Fragment name "#{name}" must be unique|, fragments)
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("Fragment#{name} on #{child_type.name} can't be spread inside #{parent_type.name}", node, path: path)
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("No such type #{type_name}, so it can't be a fragment condition", fragment_node)
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