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
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ require "graphql/execution/lazy/lazy_method_map"
3
+ require "graphql/execution/lazy/resolve"
4
+ module GraphQL
5
+ module Execution
6
+ # This wraps a value which is available, but not yet calculated, like a promise or future.
7
+ #
8
+ # Calling `#value` will trigger calculation & return the "lazy" value.
9
+ #
10
+ # This is an itty-bitty promise-like object, with key differences:
11
+ # - It has only two states, not-resolved and resolved
12
+ # - It has no error-catching functionality
13
+ class Lazy
14
+ # Traverse `val`, lazily resolving any values along the way
15
+ # @param val [Object] A data structure containing mixed plain values and `Lazy` instances
16
+ # @return void
17
+ def self.resolve(val)
18
+ Resolve.resolve(val)
19
+ end
20
+
21
+ # Create a {Lazy} which will get its inner value by calling the block
22
+ # @param target [Object]
23
+ # @param method_name [Symbol]
24
+ # @param get_value_func [Proc] a block to get the inner value (later)
25
+ def initialize(target = nil, method_name = nil, &get_value_func)
26
+ if block_given?
27
+ @get_value_func = get_value_func
28
+ else
29
+ @target = target
30
+ @method_name = method_name
31
+ end
32
+ @resolved = false
33
+ end
34
+
35
+ # @return [Object] The wrapped value, calling the lazy block if necessary
36
+ def value
37
+ if !@resolved
38
+ @resolved = true
39
+ if @get_value_func
40
+ @value = @get_value_func.call
41
+ else
42
+ @value = @target.public_send(@method_name)
43
+ end
44
+ end
45
+ @value
46
+ rescue GraphQL::ExecutionError => err
47
+ @resolved = true
48
+ @value = err
49
+ end
50
+
51
+ # @return [Lazy] A {Lazy} whose value depends on another {Lazy}, plus any transformations in `block`
52
+ def then(&block)
53
+ self.class.new {
54
+ next_val = block.call(value)
55
+ }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class Lazy
5
+ # {GraphQL::Schema} uses this to match returned values to lazy resolution methods.
6
+ # Methods may be registered for classes, they apply to its subclasses also.
7
+ # The result of this lookup is cached for future resolutions.
8
+ class LazyMethodMap
9
+ def initialize
10
+ @storage = Hash.new do |h, value_class|
11
+ registered_superclass = h.each_key.find { |lazy_class| value_class < lazy_class }
12
+ if registered_superclass.nil?
13
+ h[value_class] = nil
14
+ else
15
+ h[value_class] = h[registered_superclass]
16
+ end
17
+ end
18
+ end
19
+
20
+ # @param lazy_class [Class] A class which represents a lazy value (subclasses may also be used)
21
+ # @param lazy_value_method [Symbol] The method to call on this class to get its value
22
+ def set(lazy_class, lazy_value_method)
23
+ @storage[lazy_class] = lazy_value_method
24
+ end
25
+
26
+ # @param value [Object] an object which may have a `lazy_value_method` registered for its class or superclasses
27
+ # @return [Symbol, nil] The `lazy_value_method` for this object, or nil
28
+ def get(value)
29
+ @storage[value.class]
30
+ end
31
+
32
+ def each
33
+ @storage.each { |k, v| yield(k,v) }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class Lazy
5
+ # Helpers for dealing with data structures containing {Lazy} instances
6
+ module Resolve
7
+ # Mutate `value`, replacing {Lazy} instances in place with their resolved values
8
+ # @return [void]
9
+ def self.resolve(value)
10
+ lazies = resolve_in_place(value)
11
+ deep_sync(lazies)
12
+ end
13
+
14
+ def self.resolve_in_place(value)
15
+ lazies = []
16
+
17
+ each_lazy(value) do |field_result|
18
+ inner_lazy = field_result.value.then do |inner_v|
19
+ field_result.value = inner_v
20
+ resolve_in_place(inner_v)
21
+ end
22
+ lazies.push(inner_lazy)
23
+ end
24
+
25
+ Lazy.new { lazies.map(&:value) }
26
+ end
27
+
28
+ # If `value` is a collection, call `block`
29
+ # with any {Lazy} instances in the collection
30
+ # @return [void]
31
+ def self.each_lazy(value, &block)
32
+ case value
33
+ when SelectionResult
34
+ value.each do |key, field_result|
35
+ each_lazy(field_result, &block)
36
+ end
37
+ when Array
38
+ value.each do |field_result|
39
+ each_lazy(field_result, &block)
40
+ end
41
+ when FieldResult
42
+ field_value = value.value
43
+ if field_value.is_a?(Lazy)
44
+ yield(value)
45
+ else
46
+ each_lazy(field_value, &block)
47
+ end
48
+ end
49
+ end
50
+
51
+ # Traverse `val`, triggering resolution for each {Lazy}.
52
+ # These {Lazy}s are expected to mutate their owner data structures
53
+ # during resolution! (They're created with the `.then` calls in `resolve_in_place`).
54
+ # @return [void]
55
+ def self.deep_sync(val)
56
+ case val
57
+ when Lazy
58
+ deep_sync(val.value)
59
+ when Array
60
+ val.each { |v| deep_sync(v.value) }
61
+ when Hash
62
+ val.each { |k, v| deep_sync(v.value) }
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ # A set of key-value pairs suitable for a GraphQL response.
5
+ class SelectionResult
6
+ def initialize
7
+ @storage = {}
8
+ @owner = nil
9
+ @invalid_null = false
10
+ end
11
+
12
+ # @param key [String] The name for this value in the result
13
+ # @param field_result [FieldResult] The result for this field
14
+ def set(key, field_result)
15
+ @storage[key] = field_result
16
+ end
17
+
18
+ # @param key [String] The name of an already-defined result
19
+ # @return [FieldResult] The result for this field
20
+ def fetch(key)
21
+ @storage.fetch(key)
22
+ end
23
+
24
+ # Visit each key-result pair in this result
25
+ def each
26
+ @storage.each do |key, field_res|
27
+ yield(key, field_res)
28
+ end
29
+ end
30
+
31
+ # @return [Hash] A plain Hash representation of this result
32
+ def to_h
33
+ if @invalid_null
34
+ nil
35
+ else
36
+ flatten(self)
37
+ end
38
+ end
39
+
40
+ # A field has been unexpectedly nullified.
41
+ # Tell the owner {FieldResult} if it is present.
42
+ # Record {#invalid_null} in case an owner is added later.
43
+ def propagate_null
44
+ if @owner
45
+ @owner.value = GraphQL::Execution::Execute::PROPAGATE_NULL
46
+ end
47
+ @invalid_null = true
48
+ end
49
+
50
+ # @return [Boolean] True if this selection has been nullified by a null child
51
+ def invalid_null?
52
+ @invalid_null
53
+ end
54
+
55
+ # @param field_result [FieldResult] The field that this selection belongs to (used for propagating nulls)
56
+ def owner=(field_result)
57
+ if @owner
58
+ raise("Can't change owners of SelectionResult")
59
+ else
60
+ @owner = field_result
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def flatten(obj)
67
+ case obj
68
+ when SelectionResult
69
+ flattened = {}
70
+ obj.each do |key, val|
71
+ flattened[key] = flatten(val)
72
+ end
73
+ flattened
74
+ when Array
75
+ obj.map { |v| flatten(v) }
76
+ when FieldResult
77
+ flatten(obj.value)
78
+ else
79
+ obj
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Execution
3
4
  # GraphQL object `{value, current_type}` can be cast to `potential_type` when:
@@ -12,10 +13,9 @@ module GraphQL
12
13
  #
13
14
  # This is used for checking whether fragments apply to an object.
14
15
  #
15
- # @param [Object] the value which GraphQL is currently exposing
16
- # @param [GraphQL::BaseType] the type which GraphQL is using for `value` now
17
- # @param [GraphQL::BaseType] can `value` be exposed using this type?
18
- # @param [GraphQL::Query::Context] the context for the current query
16
+ # @param current_type [GraphQL::BaseType] the type which GraphQL is using now
17
+ # @param potential_type [GraphQL::BaseType] can this type be used from here?
18
+ # @param query_ctx [GraphQL::Query::Context] the context for the current query
19
19
  # @return [Boolean] true if `value` be evaluated as a `potential_type`
20
20
  def self.compatible?(current_type, potential_type, query_ctx)
21
21
  if current_type == potential_type
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  # If a field's resolve function returns a {ExecutionError},
3
4
  # the error will be inserted into the response's `"errors"` key
data/lib/graphql/field.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "graphql/field/resolve"
2
3
 
3
4
  module GraphQL
@@ -121,46 +122,65 @@ module GraphQL
121
122
  class Field
122
123
  include GraphQL::Define::InstanceDefinable
123
124
  accepts_definitions :name, :description, :deprecation_reason,
124
- :resolve, :type, :arguments,
125
+ :resolve, :lazy_resolve,
126
+ :type, :arguments,
125
127
  :property, :hash_key, :complexity, :mutation,
126
128
  :relay_node_field,
127
129
  argument: GraphQL::Define::AssignArgument
128
130
 
129
-
130
- attr_accessor :name, :deprecation_reason, :description, :property, :hash_key, :mutation, :arguments, :complexity
131
-
132
- # @return [Boolean] True if this is the Relay find-by-id field
133
- attr_accessor :relay_node_field
134
-
135
131
  ensure_defined(
136
132
  :name, :deprecation_reason, :description, :description=, :property, :hash_key, :mutation, :arguments, :complexity,
137
- :resolve, :resolve=, :type, :type=, :name=, :property=, :hash_key=,
133
+ :resolve, :resolve=, :lazy_resolve, :lazy_resolve=, :lazy_resolve_proc,
134
+ :type, :type=, :name=, :property=, :hash_key=,
138
135
  :relay_node_field,
139
136
  )
140
137
 
141
- # @!attribute [r] resolve_proc
142
- # @return [<#call(obj, args,ctx)>] A proc-like object which can be called to return the field's value
138
+ # @return [Boolean] True if this is the Relay find-by-id field
139
+ attr_accessor :relay_node_field
140
+
141
+ # @return [<#call(obj, args, ctx)>] A proc-like object which can be called to return the field's value
143
142
  attr_reader :resolve_proc
144
143
 
145
- # @!attribute name
146
- # @return [String] The name of this field on its {GraphQL::ObjectType} (or {GraphQL::InterfaceType})
144
+ # @return [<#call(obj, args, ctx)>] A proc-like object which can be called trigger a lazy resolution
145
+ attr_reader :lazy_resolve_proc
146
+
147
+ # @return [String] The name of this field on its {GraphQL::ObjectType} (or {GraphQL::InterfaceType})
148
+ attr_accessor :name
149
+
150
+ # @return [String, nil] The client-facing description of this field
151
+ attr_accessor :description
152
+
153
+ # @return [String, nil] The client-facing reason why this field is deprecated (if present, the field is deprecated)
154
+ attr_accessor :deprecation_reason
155
+
156
+ # @return [Hash<String => GraphQL::Argument>] Map String argument names to their {GraphQL::Argument} implementations
157
+ attr_accessor :arguments
147
158
 
148
- # @!attribute arguments
149
- # @return [Hash<String => GraphQL::Argument>] Map String argument names to their {GraphQL::Argument} implementations
159
+ # @return [GraphQL::Relay::Mutation, nil] The mutation this field was derived from, if it was derived from a mutation
160
+ attr_accessor :mutation
150
161
 
151
- # @!attribute mutation
152
- # @return [GraphQL::Relay::Mutation, nil] The mutation this field was derived from, if it was derived from a mutation
162
+ # @return [Numeric, Proc] The complexity for this field (default: 1), as a constant or a proc like `->(query_ctx, args, child_complexity) { } # Numeric`
163
+ attr_accessor :complexity
153
164
 
154
- # @!attribute complexity
155
- # @return [Numeric, Proc] The complexity for this field (default: 1), as a constant or a proc like `->(query_ctx, args, child_complexity) { } # Numeric`
165
+ # @return [Symbol, nil] The method to call on `obj` to return this field (overrides {#name} if present)
166
+ attr_accessor :property
167
+
168
+ # @return [Object, nil] The key to access with `obj.[]` to resolve this field (overrides {#name} if present)
169
+ attr_accessor :hash_key
156
170
 
157
171
  def initialize
158
172
  @complexity = 1
159
173
  @arguments = {}
160
174
  @resolve_proc = build_default_resolver
175
+ @lazy_resolve_proc = DefaultLazyResolve
161
176
  @relay_node_field = false
162
177
  end
163
178
 
179
+ def initialize_copy(other)
180
+ super
181
+ @arguments = other.arguments.dup
182
+ end
183
+
164
184
  # Get a value for this field
165
185
  # @example resolving a field value
166
186
  # field.resolve(obj, args, ctx)
@@ -217,10 +237,40 @@ module GraphQL
217
237
  "<Field name:#{name || "not-named"} desc:#{description} resolve:#{resolve_proc}>"
218
238
  end
219
239
 
240
+ # If {#resolve} returned and object which should be handled lazily,
241
+ # this method will be called later force the object to return its value.
242
+ # @param obj [Object] The {#resolve}-provided object, registered with {Schema#lazy_resolve}
243
+ # @param args [GraphQL::Query::Arguments] Arguments to this field
244
+ # @param ctx [GraphQL::Query::Context] Context for this field
245
+ # @return [Object] The result of calling the registered method on `obj`
246
+ def lazy_resolve(obj, args, ctx)
247
+ @lazy_resolve_proc.call(obj, args, ctx)
248
+ end
249
+
250
+ # Assign a new resolve proc to this field. Used for {#lazy_resolve}
251
+ def lazy_resolve=(new_lazy_resolve_proc)
252
+ @lazy_resolve_proc = new_lazy_resolve_proc
253
+ end
254
+
255
+ # Prepare a lazy value for this field. It may be `then`-ed and resolved later.
256
+ # @return [GraphQL::Execution::Lazy] A lazy wrapper around `obj` and its registered method name
257
+ def prepare_lazy(obj, args, ctx)
258
+ GraphQL::Execution::Lazy.new {
259
+ lazy_resolve(obj, args, ctx)
260
+ }
261
+ end
262
+
220
263
  private
221
264
 
222
265
  def build_default_resolver
223
266
  GraphQL::Field::Resolve.create_proc(self)
224
267
  end
268
+
269
+ module DefaultLazyResolve
270
+ def self.call(obj, args, ctx)
271
+ method_name = ctx.schema.lazy_method_name(obj)
272
+ obj.public_send(method_name)
273
+ end
274
+ end
225
275
  end
226
276
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Field
3
4
  # Create resolve procs ahead of time based on a {GraphQL::Field}'s `name`, `property`, and `hash_key` configuration.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  GraphQL::FLOAT_TYPE = GraphQL::ScalarType.define do
2
3
  name "Float"
3
4
  description "Represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)."
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  GraphQL::ID_TYPE = GraphQL::ScalarType.define do
2
3
  name "ID"
3
4
  description "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID."
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  # {InputObjectType}s are key-value inputs for fields.
3
4
  #
@@ -44,6 +45,11 @@ module GraphQL
44
45
  @arguments = {}
45
46
  end
46
47
 
48
+ def initialize_copy(other)
49
+ super
50
+ @arguments = other.arguments.dup
51
+ end
52
+
47
53
  def kind
48
54
  GraphQL::TypeKinds::INPUT_OBJECT
49
55
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  GraphQL::INT_TYPE = GraphQL::ScalarType.define do
2
3
  name "Int"
3
4
  description "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1."