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.
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