graphql 1.2.6 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (278) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +3 -1
  3. data/lib/graphql/analysis.rb +1 -0
  4. data/lib/graphql/analysis/analyze_query.rb +1 -0
  5. data/lib/graphql/analysis/field_usage.rb +1 -0
  6. data/lib/graphql/analysis/max_query_complexity.rb +1 -0
  7. data/lib/graphql/analysis/max_query_depth.rb +1 -0
  8. data/lib/graphql/analysis/query_complexity.rb +1 -0
  9. data/lib/graphql/analysis/query_depth.rb +1 -0
  10. data/lib/graphql/analysis/reducer_state.rb +1 -0
  11. data/lib/graphql/analysis_error.rb +1 -0
  12. data/lib/graphql/argument.rb +1 -0
  13. data/lib/graphql/base_type.rb +16 -7
  14. data/lib/graphql/boolean_type.rb +1 -0
  15. data/lib/graphql/compatibility.rb +2 -0
  16. data/lib/graphql/compatibility/execution_specification.rb +113 -192
  17. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +53 -0
  18. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +195 -0
  19. data/lib/graphql/compatibility/lazy_execution_specification.rb +186 -0
  20. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +97 -0
  21. data/lib/graphql/compatibility/query_parser_specification.rb +1 -0
  22. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +1 -0
  23. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +1 -0
  24. data/lib/graphql/compatibility/schema_parser_specification.rb +1 -0
  25. data/lib/graphql/define.rb +1 -0
  26. data/lib/graphql/define/assign_argument.rb +1 -0
  27. data/lib/graphql/define/assign_connection.rb +1 -0
  28. data/lib/graphql/define/assign_enum_value.rb +1 -0
  29. data/lib/graphql/define/assign_global_id_field.rb +1 -0
  30. data/lib/graphql/define/assign_object_field.rb +1 -0
  31. data/lib/graphql/define/defined_object_proxy.rb +1 -0
  32. data/lib/graphql/define/instance_definable.rb +11 -12
  33. data/lib/graphql/define/non_null_with_bang.rb +1 -0
  34. data/lib/graphql/define/type_definer.rb +1 -0
  35. data/lib/graphql/directive.rb +1 -0
  36. data/lib/graphql/directive/deprecated_directive.rb +1 -0
  37. data/lib/graphql/directive/include_directive.rb +1 -0
  38. data/lib/graphql/directive/skip_directive.rb +1 -0
  39. data/lib/graphql/enum_type.rb +8 -1
  40. data/lib/graphql/execution.rb +5 -0
  41. data/lib/graphql/execution/directive_checks.rb +1 -0
  42. data/lib/graphql/execution/execute.rb +222 -0
  43. data/lib/graphql/execution/field_result.rb +52 -0
  44. data/lib/graphql/execution/lazy.rb +59 -0
  45. data/lib/graphql/execution/lazy/lazy_method_map.rb +38 -0
  46. data/lib/graphql/execution/lazy/resolve.rb +68 -0
  47. data/lib/graphql/execution/selection_result.rb +84 -0
  48. data/lib/graphql/execution/typecast.rb +4 -4
  49. data/lib/graphql/execution_error.rb +1 -0
  50. data/lib/graphql/field.rb +68 -18
  51. data/lib/graphql/field/resolve.rb +1 -0
  52. data/lib/graphql/float_type.rb +1 -0
  53. data/lib/graphql/id_type.rb +1 -0
  54. data/lib/graphql/input_object_type.rb +6 -0
  55. data/lib/graphql/int_type.rb +1 -0
  56. data/lib/graphql/interface_type.rb +6 -0
  57. data/lib/graphql/internal_representation.rb +2 -1
  58. data/lib/graphql/internal_representation/node.rb +2 -1
  59. data/lib/graphql/internal_representation/rewrite.rb +1 -0
  60. data/lib/graphql/internal_representation/selection.rb +85 -0
  61. data/lib/graphql/introspection.rb +1 -0
  62. data/lib/graphql/introspection/arguments_field.rb +1 -0
  63. data/lib/graphql/introspection/directive_location_enum.rb +1 -0
  64. data/lib/graphql/introspection/directive_type.rb +1 -0
  65. data/lib/graphql/introspection/enum_value_type.rb +1 -0
  66. data/lib/graphql/introspection/enum_values_field.rb +1 -0
  67. data/lib/graphql/introspection/field_type.rb +1 -0
  68. data/lib/graphql/introspection/fields_field.rb +1 -0
  69. data/lib/graphql/introspection/input_fields_field.rb +1 -0
  70. data/lib/graphql/introspection/input_value_type.rb +2 -1
  71. data/lib/graphql/introspection/interfaces_field.rb +1 -0
  72. data/lib/graphql/introspection/introspection_query.rb +1 -0
  73. data/lib/graphql/introspection/of_type_field.rb +1 -0
  74. data/lib/graphql/introspection/possible_types_field.rb +1 -0
  75. data/lib/graphql/introspection/schema_field.rb +1 -0
  76. data/lib/graphql/introspection/schema_type.rb +1 -0
  77. data/lib/graphql/introspection/type_by_name_field.rb +1 -0
  78. data/lib/graphql/introspection/type_kind_enum.rb +1 -0
  79. data/lib/graphql/introspection/type_type.rb +1 -0
  80. data/lib/graphql/introspection/typename_field.rb +1 -0
  81. data/lib/graphql/invalid_null_error.rb +17 -7
  82. data/lib/graphql/language.rb +10 -0
  83. data/lib/graphql/language/comments.rb +2 -1
  84. data/lib/graphql/language/definition_slice.rb +1 -0
  85. data/lib/graphql/language/generation.rb +25 -24
  86. data/lib/graphql/language/nodes.rb +1 -0
  87. data/lib/graphql/language/token.rb +1 -0
  88. data/lib/graphql/language/visitor.rb +1 -0
  89. data/lib/graphql/list_type.rb +1 -0
  90. data/lib/graphql/non_null_type.rb +2 -1
  91. data/lib/graphql/object_type.rb +12 -0
  92. data/lib/graphql/query.rb +40 -43
  93. data/lib/graphql/query/arguments.rb +1 -0
  94. data/lib/graphql/query/context.rb +31 -7
  95. data/lib/graphql/query/executor.rb +8 -1
  96. data/lib/graphql/query/input_validation_result.rb +1 -0
  97. data/lib/graphql/query/literal_input.rb +1 -0
  98. data/lib/graphql/query/serial_execution.rb +3 -4
  99. data/lib/graphql/query/serial_execution/field_resolution.rb +15 -10
  100. data/lib/graphql/query/serial_execution/operation_resolution.rb +3 -5
  101. data/lib/graphql/query/serial_execution/selection_resolution.rb +4 -5
  102. data/lib/graphql/query/serial_execution/value_resolution.rb +26 -11
  103. data/lib/graphql/query/variable_validation_error.rb +1 -0
  104. data/lib/graphql/query/variables.rb +1 -0
  105. data/lib/graphql/relay.rb +1 -0
  106. data/lib/graphql/relay/array_connection.rb +3 -2
  107. data/lib/graphql/relay/base_connection.rb +20 -8
  108. data/lib/graphql/relay/connection_field.rb +1 -0
  109. data/lib/graphql/relay/connection_resolve.rb +14 -1
  110. data/lib/graphql/relay/connection_type.rb +1 -0
  111. data/lib/graphql/relay/edge.rb +1 -0
  112. data/lib/graphql/relay/edge_type.rb +1 -0
  113. data/lib/graphql/relay/global_id_resolve.rb +1 -0
  114. data/lib/graphql/relay/mutation.rb +13 -0
  115. data/lib/graphql/relay/node.rb +1 -0
  116. data/lib/graphql/relay/page_info.rb +1 -0
  117. data/lib/graphql/relay/relation_connection.rb +3 -2
  118. data/lib/graphql/runtime_type_error.rb +4 -0
  119. data/lib/graphql/scalar_type.rb +2 -1
  120. data/lib/graphql/schema.rb +116 -26
  121. data/lib/graphql/schema/base_64_encoder.rb +14 -0
  122. data/lib/graphql/schema/build_from_definition.rb +4 -0
  123. data/lib/graphql/schema/catchall_middleware.rb +1 -0
  124. data/lib/graphql/schema/default_type_error.rb +15 -0
  125. data/lib/graphql/schema/instrumented_field_map.rb +1 -0
  126. data/lib/graphql/schema/invalid_type_error.rb +1 -0
  127. data/lib/graphql/schema/loader.rb +5 -1
  128. data/lib/graphql/schema/middleware_chain.rb +1 -0
  129. data/lib/graphql/schema/possible_types.rb +1 -0
  130. data/lib/graphql/schema/printer.rb +3 -2
  131. data/lib/graphql/schema/reduce_types.rb +1 -0
  132. data/lib/graphql/schema/rescue_middleware.rb +3 -2
  133. data/lib/graphql/schema/timeout_middleware.rb +1 -0
  134. data/lib/graphql/schema/type_expression.rb +1 -0
  135. data/lib/graphql/schema/type_map.rb +1 -0
  136. data/lib/graphql/schema/unique_within_type.rb +1 -0
  137. data/lib/graphql/schema/validation.rb +57 -1
  138. data/lib/graphql/schema/warden.rb +1 -0
  139. data/lib/graphql/static_validation.rb +1 -0
  140. data/lib/graphql/static_validation/all_rules.rb +1 -0
  141. data/lib/graphql/static_validation/arguments_validator.rb +1 -0
  142. data/lib/graphql/static_validation/literal_validator.rb +1 -0
  143. data/lib/graphql/static_validation/message.rb +1 -0
  144. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -0
  145. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -0
  146. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -0
  147. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -0
  148. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -0
  149. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -0
  150. data/lib/graphql/static_validation/rules/fields_will_merge.rb +6 -3
  151. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +1 -0
  152. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -0
  153. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +1 -0
  154. data/lib/graphql/static_validation/rules/fragments_are_named.rb +1 -0
  155. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -0
  156. data/lib/graphql/static_validation/rules/fragments_are_used.rb +1 -0
  157. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -0
  158. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -0
  159. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -0
  160. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -0
  161. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -0
  162. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -0
  163. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -0
  164. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +1 -0
  165. data/lib/graphql/static_validation/type_stack.rb +1 -0
  166. data/lib/graphql/static_validation/validation_context.rb +2 -1
  167. data/lib/graphql/static_validation/validator.rb +2 -1
  168. data/lib/graphql/string_type.rb +1 -0
  169. data/lib/graphql/type_kinds.rb +1 -0
  170. data/lib/graphql/union_type.rb +13 -0
  171. data/lib/graphql/unresolved_type_error.rb +26 -5
  172. data/lib/graphql/version.rb +2 -1
  173. data/readme.md +1 -5
  174. data/spec/graphql/analysis/analyze_query_spec.rb +1 -0
  175. data/spec/graphql/analysis/field_usage_spec.rb +1 -0
  176. data/spec/graphql/analysis/max_query_complexity_spec.rb +1 -0
  177. data/spec/graphql/analysis/max_query_depth_spec.rb +1 -0
  178. data/spec/graphql/analysis/query_complexity_spec.rb +1 -0
  179. data/spec/graphql/analysis/query_depth_spec.rb +1 -0
  180. data/spec/graphql/argument_spec.rb +1 -0
  181. data/spec/graphql/base_type_spec.rb +13 -0
  182. data/spec/graphql/boolean_type_spec.rb +1 -0
  183. data/spec/graphql/compatibility/execution_specification_spec.rb +1 -0
  184. data/spec/graphql/compatibility/lazy_execution_specification_spec.rb +4 -0
  185. data/spec/graphql/compatibility/query_parser_specification_spec.rb +1 -0
  186. data/spec/graphql/compatibility/schema_parser_specification_spec.rb +1 -0
  187. data/spec/graphql/define/assign_argument_spec.rb +1 -0
  188. data/spec/graphql/define/instance_definable_spec.rb +1 -0
  189. data/spec/graphql/directive_spec.rb +1 -0
  190. data/spec/graphql/enum_type_spec.rb +10 -0
  191. data/spec/graphql/execution/execute_spec.rb +5 -0
  192. data/spec/graphql/execution/lazy_spec.rb +252 -0
  193. data/spec/graphql/execution/typecast_spec.rb +1 -0
  194. data/spec/graphql/execution_error_spec.rb +1 -0
  195. data/spec/graphql/field_spec.rb +17 -0
  196. data/spec/graphql/float_type_spec.rb +1 -0
  197. data/spec/graphql/id_type_spec.rb +1 -0
  198. data/spec/graphql/input_object_type_spec.rb +10 -0
  199. data/spec/graphql/int_type_spec.rb +1 -0
  200. data/spec/graphql/interface_type_spec.rb +10 -0
  201. data/spec/graphql/internal_representation/rewrite_spec.rb +1 -0
  202. data/spec/graphql/introspection/directive_type_spec.rb +1 -0
  203. data/spec/graphql/introspection/input_value_type_spec.rb +1 -0
  204. data/spec/graphql/introspection/introspection_query_spec.rb +1 -0
  205. data/spec/graphql/introspection/schema_type_spec.rb +1 -0
  206. data/spec/graphql/introspection/type_type_spec.rb +1 -0
  207. data/spec/graphql/language/definition_slice_spec.rb +1 -0
  208. data/spec/graphql/language/equality_spec.rb +1 -0
  209. data/spec/graphql/language/generation_spec.rb +1 -0
  210. data/spec/graphql/language/lexer_spec.rb +1 -0
  211. data/spec/graphql/language/nodes_spec.rb +1 -0
  212. data/spec/graphql/language/parser_spec.rb +1 -0
  213. data/spec/graphql/language/visitor_spec.rb +1 -0
  214. data/spec/graphql/list_type_spec.rb +1 -0
  215. data/spec/graphql/non_null_type_spec.rb +17 -0
  216. data/spec/graphql/object_type_spec.rb +19 -0
  217. data/spec/graphql/query/arguments_spec.rb +1 -0
  218. data/spec/graphql/query/context_spec.rb +1 -0
  219. data/spec/graphql/query/executor_spec.rb +1 -0
  220. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +1 -0
  221. data/spec/graphql/query/variables_spec.rb +1 -0
  222. data/spec/graphql/query_spec.rb +25 -0
  223. data/spec/graphql/relay/array_connection_spec.rb +1 -0
  224. data/spec/graphql/relay/base_connection_spec.rb +33 -4
  225. data/spec/graphql/relay/connection_field_spec.rb +1 -0
  226. data/spec/graphql/relay/connection_type_spec.rb +1 -0
  227. data/spec/graphql/relay/mutation_spec.rb +6 -0
  228. data/spec/graphql/relay/node_spec.rb +1 -0
  229. data/spec/graphql/relay/page_info_spec.rb +1 -0
  230. data/spec/graphql/relay/relation_connection_spec.rb +1 -0
  231. data/spec/graphql/scalar_type_spec.rb +1 -0
  232. data/spec/graphql/schema/build_from_definition_spec.rb +9 -1
  233. data/spec/graphql/schema/catchall_middleware_spec.rb +1 -0
  234. data/spec/graphql/schema/loader_spec.rb +7 -0
  235. data/spec/graphql/schema/middleware_chain_spec.rb +1 -0
  236. data/spec/graphql/schema/printer_spec.rb +1 -0
  237. data/spec/graphql/schema/reduce_types_spec.rb +1 -0
  238. data/spec/graphql/schema/rescue_middleware_spec.rb +1 -0
  239. data/spec/graphql/schema/timeout_middleware_spec.rb +1 -0
  240. data/spec/graphql/schema/type_expression_spec.rb +1 -0
  241. data/spec/graphql/schema/unique_within_type_spec.rb +1 -0
  242. data/spec/graphql/schema/validation_spec.rb +55 -0
  243. data/spec/graphql/schema/warden_spec.rb +1 -0
  244. data/spec/graphql/schema_spec.rb +39 -0
  245. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +1 -0
  246. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +1 -0
  247. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +1 -0
  248. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +1 -0
  249. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +1 -0
  250. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +1 -0
  251. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +515 -31
  252. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +1 -0
  253. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +1 -0
  254. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +1 -0
  255. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +1 -0
  256. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +1 -0
  257. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -0
  258. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +1 -0
  259. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +1 -0
  260. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +1 -0
  261. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +1 -0
  262. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +1 -0
  263. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +1 -0
  264. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +1 -0
  265. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +1 -0
  266. data/spec/graphql/static_validation/type_stack_spec.rb +1 -0
  267. data/spec/graphql/static_validation/validator_spec.rb +1 -0
  268. data/spec/graphql/string_type_spec.rb +1 -0
  269. data/spec/graphql/union_type_spec.rb +11 -0
  270. data/spec/spec_helper.rb +1 -0
  271. data/spec/support/dairy_app.rb +1 -0
  272. data/spec/support/dairy_data.rb +1 -0
  273. data/spec/support/minimum_input_object.rb +1 -0
  274. data/spec/support/star_wars_data.rb +1 -0
  275. data/spec/support/star_wars_schema.rb +30 -7
  276. data/spec/support/static_validation_helpers.rb +1 -0
  277. metadata +24 -5
  278. data/lib/graphql/internal_representation/selections.rb +0 -41
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Language
3
4
  module Nodes
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Language
3
4
  # Emitted by the lexer and passed to the parser.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Language
3
4
  # Depth-first traversal through the tree, calling hooks at each stop.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  # A list type modifies another type.
3
4
  #
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  # A non-null type modifies another type.
3
4
  #
@@ -11,7 +12,7 @@ module GraphQL
11
12
  # # or
12
13
  # field :items, ItemType.to_non_null_type
13
14
  #
14
- # (If the application fails to return a value, {InvalidNullError} will be raised.)
15
+ # (If the application fails to return a value, {InvalidNullError} will be passed to {Schema#type_error}.)
15
16
  #
16
17
  # For input types, it says that the incoming value _must_ be provided by the query.
17
18
  #
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  # This type exposes fields on an object.
3
4
  #
@@ -38,6 +39,13 @@ module GraphQL
38
39
  @dirty_interfaces = []
39
40
  end
40
41
 
42
+ def initialize_copy(other)
43
+ super
44
+ @clean_interfaces = nil
45
+ @dirty_interfaces = other.dirty_interfaces.dup
46
+ @fields = other.fields.dup
47
+ end
48
+
41
49
  # @param new_interfaces [Array<GraphQL::Interface>] interfaces that this type implements
42
50
  def interfaces=(new_interfaces)
43
51
  @clean_interfaces = nil
@@ -68,6 +76,10 @@ module GraphQL
68
76
  interface_fields.merge(self.fields).values
69
77
  end
70
78
 
79
+ protected
80
+
81
+ attr_reader :dirty_interfaces
82
+
71
83
  private
72
84
 
73
85
  # Create a {name => defn} hash for fields inherited from interfaces
data/lib/graphql/query.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "graphql/query/arguments"
2
3
  require "graphql/query/context"
3
4
  require "graphql/query/executor"
@@ -25,7 +26,7 @@ module GraphQL
25
26
  end
26
27
  end
27
28
 
28
- attr_reader :schema, :document, :context, :fragments, :operations, :root_value, :max_depth, :query_string, :warden
29
+ attr_reader :schema, :document, :context, :fragments, :operations, :root_value, :max_depth, :query_string, :warden, :provided_variables
29
30
 
30
31
  # Prepare query `query_string` on `schema`
31
32
  # @param schema [GraphQL::Schema]
@@ -82,22 +83,43 @@ module GraphQL
82
83
  # Trying to execute a document
83
84
  # with no operations returns an empty hash
84
85
  @ast_variables = []
86
+ @mutation = false
85
87
  if @operations.any?
86
88
  @selected_operation = find_operation(@operations, @operation_name)
87
89
  if @selected_operation.nil?
88
90
  @validation_errors << GraphQL::Query::OperationNameMissingError.new(@operations.keys)
89
91
  else
90
92
  @ast_variables = @selected_operation.variables
93
+ @mutation = @selected_operation.operation_type == "mutation"
91
94
  end
92
95
  end
96
+ @result = nil
97
+ @executed = false
93
98
  end
94
99
 
95
100
  # Get the result for this query, executing it once
101
+ # @return [Hash] A GraphQL response, with `"data"` and/or `"errors"` keys
96
102
  def result
97
- @result ||= begin
103
+ if @executed
104
+ @result
105
+ else
106
+ @executed = true
98
107
  instrumenters = @schema.instrumenters[:query]
99
- execution_call = ExecutionCall.new(self, instrumenters)
100
- execution_call.call
108
+ begin
109
+ instrumenters.each { |i| i.before_query(self) }
110
+ @result = if !valid?
111
+ all_errors = validation_errors + analysis_errors
112
+ if all_errors.any?
113
+ { "errors" => all_errors.map(&:to_h) }
114
+ else
115
+ nil
116
+ end
117
+ else
118
+ Executor.new(self).result
119
+ end
120
+ ensure
121
+ instrumenters.each { |i| i.after_query(self) }
122
+ end
101
123
  end
102
124
  end
103
125
 
@@ -132,6 +154,14 @@ module GraphQL
132
154
  @internal_representation
133
155
  end
134
156
 
157
+ def irep_selection
158
+ @selection ||= begin
159
+ irep_root = internal_representation[selected_operation.name]
160
+ GraphQL::InternalRepresentation::Selection.new(query: self, nodes: [irep_root])
161
+ end
162
+ end
163
+
164
+
135
165
  # TODO this should probably contain error instances, not hashes
136
166
  # @return [Array<Hash>] Static validation errors for the query string
137
167
  def validation_errors
@@ -171,17 +201,13 @@ module GraphQL
171
201
  @valid
172
202
  end
173
203
 
174
- def selections(nodes, type)
175
- @selections ||= Hash.new { |h, k| h[k] = GraphQL::InternalRepresentation::Selections.build(self, k) }
176
- @selections[nodes][type]
177
- end
178
-
179
204
  def get_type(type_name)
180
205
  @warden.get_type(type_name)
181
206
  end
182
207
 
183
208
  def get_field(type, name)
184
- @warden.get_field(type, name)
209
+ @fields ||= Hash.new { |h, k| h[k] = Hash.new { |h2, k2| h2[k2] = @warden.get_field(k, k2) } }
210
+ @fields[type][name]
185
211
  end
186
212
 
187
213
  def possible_types(type)
@@ -192,6 +218,10 @@ module GraphQL
192
218
  @schema.resolve_type(type, @context)
193
219
  end
194
220
 
221
+ def mutation?
222
+ @mutation
223
+ end
224
+
195
225
  private
196
226
 
197
227
  # Assert that the passed-in query string is internally consistent
@@ -227,38 +257,5 @@ module GraphQL
227
257
  operations[operation_name]
228
258
  end
229
259
  end
230
-
231
- class ExecutionCall
232
- def initialize(query, instrumenters)
233
- @query = query
234
- @instrumenters = instrumenters
235
- end
236
-
237
- # Check if the query is valid, and if it is,
238
- # execute it, calling instrumenters along the way
239
- # @return [Hash] The GraphQL response
240
- def call
241
- @instrumenters.each { |i| i.before_query(@query) }
242
- result = get_result
243
- ensure
244
- @instrumenters.each { |i| i.after_query(@query) }
245
- result
246
- end
247
-
248
- private
249
-
250
- def get_result
251
- if !@query.valid?
252
- all_errors = @query.validation_errors + @query.analysis_errors
253
- if all_errors.any?
254
- { "errors" => all_errors.map(&:to_h) }
255
- else
256
- nil
257
- end
258
- else
259
- Executor.new(@query).result
260
- end
261
- end
262
- end
263
260
  end
264
261
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  # Read-only access to values, normalizing all keys to strings
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  # Expose some query-specific info to field resolve functions.
@@ -59,33 +60,46 @@ module GraphQL
59
60
  @values[key] = value
60
61
  end
61
62
 
62
- def spawn(path:, irep_node:)
63
- FieldResolutionContext.new(context: self, path: path, irep_node: irep_node)
63
+ def spawn(key:, selection:, parent_type:, field:)
64
+ FieldResolutionContext.new(
65
+ context: self,
66
+ path: path + [key],
67
+ selection: selection,
68
+ parent_type: parent_type,
69
+ field: field,
70
+ )
64
71
  end
65
72
 
66
73
  class FieldResolutionContext
67
74
  extend Forwardable
68
75
 
69
- attr_reader :path, :irep_node
76
+ attr_reader :path, :selection, :field, :parent_type
70
77
 
71
- def initialize(context:, path:, irep_node:)
78
+ def initialize(context:, path:, selection:, field:, parent_type:)
72
79
  @context = context
73
80
  @path = path
74
- @irep_node = irep_node
81
+ @selection = selection
82
+ @field = field
83
+ @parent_type = parent_type
75
84
  end
76
85
 
77
86
  def_delegators :@context, :[], :[]=, :spawn, :query, :schema, :warden, :errors, :execution_strategy, :strategy
78
87
 
79
88
  # @return [GraphQL::Language::Nodes::Field] The AST node for the currently-executing field
80
89
  def ast_node
81
- @irep_node.ast_node
90
+ selection.irep_node.ast_node
91
+ end
92
+
93
+ # @return [GraphQL::InternalRepresentation::Node]
94
+ def irep_node
95
+ selection.irep_node
82
96
  end
83
97
 
84
98
  # Add error to current field resolution.
85
99
  # @param error [GraphQL::ExecutionError] an execution error
86
100
  # @return [void]
87
101
  def add_error(error)
88
- unless error.is_a?(ExecutionError)
102
+ if !error.is_a?(ExecutionError)
89
103
  raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
90
104
  end
91
105
 
@@ -94,6 +108,16 @@ module GraphQL
94
108
  errors << error
95
109
  nil
96
110
  end
111
+
112
+ def spawn(key:, selection:, parent_type:, field:)
113
+ FieldResolutionContext.new(
114
+ context: @context,
115
+ path: path + [key],
116
+ selection: selection,
117
+ parent_type: parent_type,
118
+ field: field,
119
+ )
120
+ end
97
121
  end
98
122
  end
99
123
  end
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  class Executor
5
+ class PropagateNull < StandardError; end
6
+
4
7
  # @return [GraphQL::Query] the query being executed
5
8
  attr_reader :query
6
9
 
@@ -30,7 +33,11 @@ module GraphQL
30
33
  execution_strategy = execution_strategy_class.new
31
34
 
32
35
  query.context.execution_strategy = execution_strategy
33
- data_result = execution_strategy.execute(operation, root_type, query)
36
+ data_result = begin
37
+ execution_strategy.execute(operation, root_type, query)
38
+ rescue PropagateNull
39
+ nil
40
+ end
34
41
  result = { "data" => data_result }
35
42
  error_result = query.context.errors.map(&:to_h)
36
43
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  class InputValidationResult
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  # Turn query string values into something useful for query execution
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "graphql/query/serial_execution/value_resolution"
2
3
  require "graphql/query/serial_execution/field_resolution"
3
4
  require "graphql/query/serial_execution/operation_resolution"
@@ -12,13 +13,11 @@ module GraphQL
12
13
  #
13
14
  # @param ast_operation [GraphQL::Language::Nodes::OperationDefinition] The operation definition to run
14
15
  # @param root_type [GraphQL::ObjectType] either the query type or the mutation type
15
- # @param query_obj [GraphQL::Query] the query object for this execution
16
+ # @param query_object [GraphQL::Query] the query object for this execution
16
17
  # @return [Hash] a spec-compliant GraphQL result, as a hash
17
18
  def execute(ast_operation, root_type, query_object)
18
- irep_root = query_object.internal_representation[ast_operation.name]
19
-
20
19
  operation_resolution.resolve(
21
- irep_root,
20
+ query_object.irep_selection,
22
21
  root_type,
23
22
  query_object
24
23
  )
@@ -1,17 +1,23 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  class SerialExecution
4
5
  class FieldResolution
5
6
  attr_reader :irep_node, :parent_type, :target, :field, :arguments, :query
6
7
 
7
- def initialize(irep_nodes, parent_type, target, query_ctx)
8
- @irep_node = irep_nodes.first
9
- @irep_nodes = irep_nodes
8
+ def initialize(selection, parent_type, target, query_ctx)
9
+ @irep_node = selection.irep_node
10
+ @selection = selection
10
11
  @parent_type = parent_type
11
12
  @target = target
12
- @field_ctx = query_ctx.spawn(path: query_ctx.path + [irep_node.name], irep_node: irep_node)
13
13
  @query = query_ctx.query
14
14
  @field = @query.get_field(parent_type, irep_node.definition_name)
15
+ @field_ctx = query_ctx.spawn(
16
+ key: irep_node.name,
17
+ selection: selection,
18
+ parent_type: parent_type,
19
+ field: field,
20
+ )
15
21
  @arguments = @query.arguments_for(irep_node, @field)
16
22
  end
17
23
 
@@ -33,14 +39,14 @@ module GraphQL
33
39
  def get_finished_value(raw_value)
34
40
  case raw_value
35
41
  when GraphQL::ExecutionError
36
- raw_value.ast_node = irep_node.ast_node
42
+ raw_value.ast_node = @field_ctx.ast_node
37
43
  raw_value.path = @field_ctx.path
38
44
  @query.context.errors.push(raw_value)
39
45
  when Array
40
46
  list_errors = raw_value.each_with_index.select { |value, _| value.is_a?(GraphQL::ExecutionError) }
41
47
  if list_errors.any?
42
48
  list_errors.each do |error, index|
43
- error.ast_node = irep_node.ast_node
49
+ error.ast_node = @field_ctx.ast_node
44
50
  error.path = @field_ctx.path + [index]
45
51
  @query.context.errors.push(error)
46
52
  end
@@ -53,14 +59,13 @@ module GraphQL
53
59
  field,
54
60
  field.type,
55
61
  raw_value,
56
- @irep_nodes,
62
+ @selection,
57
63
  @field_ctx,
58
64
  )
59
- rescue GraphQL::InvalidNullError => err
65
+ rescue GraphQL::Query::Executor::PropagateNull
60
66
  if field.type.kind.non_null?
61
- raise(err)
67
+ raise
62
68
  else
63
- err.parent_error? || @query.context.errors.push(err)
64
69
  nil
65
70
  end
66
71
  end
@@ -1,19 +1,17 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  class SerialExecution
4
5
  module OperationResolution
5
- def self.resolve(irep_node, target, query)
6
+ def self.resolve(selection, target, query)
6
7
  result = query.context.execution_strategy.selection_resolution.resolve(
7
8
  query.root_value,
8
9
  target,
9
- [irep_node],
10
+ selection,
10
11
  query.context,
11
12
  )
12
13
 
13
14
  result
14
- rescue GraphQL::InvalidNullError => err
15
- err.parent_error? || query.context.errors.push(err)
16
- nil
17
15
  end
18
16
  end
19
17
  end
@@ -1,15 +1,14 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  class SerialExecution
4
5
  module SelectionResolution
5
- def self.resolve(target, current_type, irep_nodes, query_ctx)
6
- own_selections = query_ctx.query.selections(irep_nodes, current_type)
7
-
6
+ def self.resolve(target, current_type, selection, query_ctx)
8
7
  selection_result = {}
9
8
 
10
- own_selections.each do |name, child_irep_nodes|
9
+ selection.each_selection(type: current_type) do |name, subselection|
11
10
  selection_result.merge!(query_ctx.execution_strategy.field_resolution.new(
12
- child_irep_nodes,
11
+ subselection,
13
12
  current_type,
14
13
  target,
15
14
  query_ctx