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,53 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Compatibility
4
+ module ExecutionSpecification
5
+ module CounterSchema
6
+ def self.build(execution_strategy)
7
+ counter_type = nil
8
+ schema = nil
9
+
10
+ has_count_interface = GraphQL::InterfaceType.define do
11
+ name "HasCount"
12
+ field :count, types.Int
13
+ field :counter, ->{ counter_type }
14
+ end
15
+
16
+ counter_type = GraphQL::ObjectType.define do
17
+ name "Counter"
18
+ interfaces [has_count_interface]
19
+ field :count, types.Int, resolve: ->(o,a,c) { schema.metadata[:count] += 1 }
20
+ field :counter, has_count_interface, resolve: ->(o,a,c) { :counter }
21
+ end
22
+
23
+ alt_counter_type = GraphQL::ObjectType.define do
24
+ name "AltCounter"
25
+ interfaces [has_count_interface]
26
+ field :count, types.Int, resolve: ->(o,a,c) { schema.metadata[:count] += 1 }
27
+ field :counter, has_count_interface, resolve: ->(o,a,c) { :counter }
28
+ end
29
+
30
+ has_counter_interface = GraphQL::InterfaceType.define do
31
+ name "HasCounter"
32
+ field :counter, counter_type
33
+ end
34
+
35
+ query_type = GraphQL::ObjectType.define do
36
+ name "Query"
37
+ interfaces [has_counter_interface]
38
+ field :counter, has_count_interface, resolve: ->(o,a,c) { :counter }
39
+ end
40
+
41
+ schema = GraphQL::Schema.define(
42
+ query: query_type,
43
+ resolve_type: ->(o, c) { o == :counter ? counter_type : nil },
44
+ orphan_types: [alt_counter_type],
45
+ query_execution_strategy: execution_strategy,
46
+ )
47
+ schema.metadata[:count] = 0
48
+ schema
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Compatibility
4
+ module ExecutionSpecification
5
+ module SpecificationSchema
6
+ BOGUS_NODE = OpenStruct.new({ bogus: true })
7
+
8
+ DATA = {
9
+ "1001" => OpenStruct.new({
10
+ name: "Fannie Lou Hamer",
11
+ birthdate: Time.new(1917, 10, 6),
12
+ organization_ids: [],
13
+ }),
14
+ "1002" => OpenStruct.new({
15
+ name: "John Lewis",
16
+ birthdate: Time.new(1940, 2, 21),
17
+ organization_ids: ["2001"],
18
+ }),
19
+ "1003" => OpenStruct.new({
20
+ name: "Diane Nash",
21
+ birthdate: Time.new(1938, 5, 15),
22
+ organization_ids: ["2001", "2002"],
23
+ }),
24
+ "1004" => OpenStruct.new({
25
+ name: "Ralph Abernathy",
26
+ birthdate: Time.new(1926, 3, 11),
27
+ organization_ids: ["2002"],
28
+ }),
29
+ "2001" => OpenStruct.new({
30
+ name: "SNCC",
31
+ leader_id: nil, # fail on purpose
32
+ }),
33
+ "2002" => OpenStruct.new({
34
+ name: "SCLC",
35
+ leader_id: "1004",
36
+ }),
37
+ "2003" => BOGUS_NODE,
38
+ }
39
+
40
+ # A list object must implement #each
41
+ class CustomCollection
42
+ def initialize(storage)
43
+ @storage = storage
44
+ end
45
+
46
+ def each
47
+ @storage.each { |i| yield(i) }
48
+ end
49
+ end
50
+
51
+ module TestMiddleware
52
+ def self.call(parent_type, parent_object, field_definition, field_args, query_context, next_middleware)
53
+ query_context[:middleware_log] && query_context[:middleware_log] << field_definition.name
54
+ next_middleware.call
55
+ end
56
+ end
57
+
58
+ def self.build(execution_strategy)
59
+ organization_type = nil
60
+
61
+ timestamp_type = GraphQL::ScalarType.define do
62
+ name "Timestamp"
63
+ coerce_input ->(value) { Time.at(value.to_i) }
64
+ coerce_result ->(value) { value.to_i }
65
+ end
66
+
67
+ named_entity_interface_type = GraphQL::InterfaceType.define do
68
+ name "NamedEntity"
69
+ field :name, !types.String
70
+ end
71
+
72
+ person_type = GraphQL::ObjectType.define do
73
+ name "Person"
74
+ interfaces [named_entity_interface_type]
75
+ field :name, !types.String
76
+ field :birthdate, timestamp_type
77
+ field :age, types.Int do
78
+ argument :on, !timestamp_type
79
+ resolve ->(obj, args, ctx) {
80
+ if obj.birthdate.nil?
81
+ nil
82
+ else
83
+ age_on = args[:on]
84
+ age_years = age_on.year - obj.birthdate.year
85
+ this_year_birthday = Time.new(age_on.year, obj.birthdate.month, obj.birthdate.day)
86
+ if this_year_birthday > age_on
87
+ age_years -= 1
88
+ end
89
+ end
90
+ age_years
91
+ }
92
+ end
93
+ field :organizations, types[organization_type] do
94
+ resolve ->(obj, args, ctx) {
95
+ CustomCollection.new(obj.organization_ids.map { |id| DATA[id] })
96
+ }
97
+ end
98
+ field :first_organization, !organization_type do
99
+ resolve ->(obj, args, ctx) {
100
+ DATA[obj.organization_ids.first]
101
+ }
102
+ end
103
+ end
104
+
105
+ organization_type = GraphQL::ObjectType.define do
106
+ name "Organization"
107
+ interfaces [named_entity_interface_type]
108
+ field :name, !types.String
109
+ field :leader, !person_type do
110
+ resolve ->(obj, args, ctx) {
111
+ DATA[obj.leader_id] || (ctx[:return_error] ? ExecutionError.new("Error on Nullable") : nil)
112
+ }
113
+ end
114
+ field :returnedError, types.String do
115
+ resolve ->(o, a, c) {
116
+ GraphQL::ExecutionError.new("This error was returned")
117
+ }
118
+ end
119
+ field :raisedError, types.String do
120
+ resolve ->(o, a, c) {
121
+ raise GraphQL::ExecutionError.new("This error was raised")
122
+ }
123
+ end
124
+
125
+ field :nodePresence, !types[!types.Boolean] do
126
+ resolve ->(o, a, ctx) {
127
+ [
128
+ ctx.irep_node.is_a?(GraphQL::InternalRepresentation::Node),
129
+ ctx.ast_node.is_a?(GraphQL::Language::Nodes::AbstractNode),
130
+ false, # just testing
131
+ ]
132
+ }
133
+ end
134
+ end
135
+
136
+ node_union_type = GraphQL::UnionType.define do
137
+ name "Node"
138
+ possible_types [person_type, organization_type]
139
+ end
140
+
141
+ query_type = GraphQL::ObjectType.define do
142
+ name "Query"
143
+ field :node, node_union_type do
144
+ argument :id, !types.ID
145
+ resolve ->(obj, args, ctx) {
146
+ obj[args[:id]]
147
+ }
148
+ end
149
+
150
+ field :requiredNode, node_union_type.to_non_null_type do
151
+ argument :id, !types.ID
152
+ resolve ->(obj, args, ctx) {
153
+ obj[args[:id]]
154
+ }
155
+ end
156
+
157
+ field :organization, !organization_type do
158
+ argument :id, !types.ID
159
+ resolve ->(obj, args, ctx) {
160
+ args[:id].start_with?("2") && obj[args[:id]]
161
+ }
162
+ end
163
+
164
+ field :organizations, types[organization_type] do
165
+ resolve ->(obj, args, ctx) {
166
+ [obj["2001"], obj["2002"]]
167
+ }
168
+ end
169
+ end
170
+
171
+ GraphQL::Schema.define do
172
+ query_execution_strategy execution_strategy
173
+ query query_type
174
+
175
+ resolve_type ->(obj, ctx) {
176
+ if obj.respond_to?(:birthdate)
177
+ person_type
178
+ elsif obj.respond_to?(:leader_id)
179
+ organization_type
180
+ else
181
+ nil
182
+ end
183
+ }
184
+
185
+ type_error ->(err, ctx) {
186
+ ctx[:type_errors] && (ctx[:type_errors] << err.value)
187
+ ctx[:gobble] || GraphQL::Schema::DefaultTypeError.call(err, ctx)
188
+ }
189
+ middleware(TestMiddleware)
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+ require "graphql/compatibility/lazy_execution_specification/lazy_schema"
3
+
4
+ module GraphQL
5
+ module Compatibility
6
+ module LazyExecutionSpecification
7
+ # @param execution_strategy [<#new, #execute>] An execution strategy class
8
+ # @return [Class<Minitest::Test>] A test suite for this execution strategy
9
+ def self.build_suite(execution_strategy)
10
+ Class.new(Minitest::Test) do
11
+ class << self
12
+ attr_accessor :lazy_schema
13
+ end
14
+
15
+ self.lazy_schema = LazySchema.build(execution_strategy)
16
+
17
+ def test_it_resolves_lazy_values
18
+ pushes = []
19
+ query_str = %|
20
+ {
21
+ p1: push(value: 1) {
22
+ value
23
+ }
24
+ p2: push(value: 2) {
25
+ push(value: 3) {
26
+ value
27
+ }
28
+ }
29
+ p3: push(value: 4) {
30
+ push(value: 5) {
31
+ value
32
+ }
33
+ }
34
+ }
35
+ |
36
+ res = self.class.lazy_schema.execute(query_str, context: {pushes: pushes})
37
+
38
+ expected_data = {
39
+ "p1"=>{"value"=>1},
40
+ "p2"=>{"push"=>{"value"=>3}},
41
+ "p3"=>{"push"=>{"value"=>5}},
42
+ }
43
+ assert_equal expected_data, res["data"]
44
+
45
+ expected_pushes = [
46
+ [1,2,4], # first level
47
+ [3,5], # second level
48
+ ]
49
+ assert_equal expected_pushes, pushes
50
+ end
51
+
52
+ def test_it_maintains_path
53
+ query_str = %|
54
+ {
55
+ push(value: 2) {
56
+ push(value: 3) {
57
+ fail1: push(value: 14) {
58
+ value
59
+ }
60
+ fail2: push(value: 14) {
61
+ value
62
+ }
63
+ }
64
+ }
65
+ }
66
+ |
67
+ res = self.class.lazy_schema.execute(query_str, context: {pushes: []})
68
+ assert_equal nil, res["data"]
69
+ assert_equal 2, res["errors"].length
70
+ assert_equal ["push", "push", "fail1", "value"], res["errors"][0]["path"]
71
+ assert_equal ["push", "push", "fail2", "value"], res["errors"][1]["path"]
72
+ end
73
+
74
+ def test_it_resolves_mutation_values_eagerly
75
+ pushes = []
76
+ query_str = %|
77
+ mutation {
78
+ p1: push(value: 1) {
79
+ value
80
+ }
81
+ p2: push(value: 2) {
82
+ push(value: 3) {
83
+ value
84
+ }
85
+ }
86
+ p3: push(value: 4) {
87
+ p5: push(value: 5) {
88
+ value
89
+ }
90
+ p6: push(value: 6) {
91
+ value
92
+ }
93
+ }
94
+ }
95
+ |
96
+ res = self.class.lazy_schema.execute(query_str, context: {pushes: pushes})
97
+
98
+ expected_data = {
99
+ "p1"=>{"value"=>1},
100
+ "p2"=>{"push"=>{"value"=>3}},
101
+ "p3"=>{"p5"=>{"value"=>5},"p6"=>{"value"=>6}},
102
+ }
103
+ assert_equal expected_data, res["data"]
104
+
105
+ expected_pushes = [
106
+ [1], # first operation
107
+ [2], [3], # second operation
108
+ [4], [5, 6], # third operation
109
+ ]
110
+ assert_equal expected_pushes, pushes
111
+ end
112
+
113
+ def test_it_resolves_lazy_connections
114
+ pushes = []
115
+ query_str = %|
116
+ {
117
+ pushes(values: [1,2,3]) {
118
+ edges {
119
+ node {
120
+ value
121
+ push(value: 4) {
122
+ value
123
+ }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ |
129
+ res = self.class.lazy_schema.execute(query_str, context: {pushes: pushes})
130
+
131
+ expected_edges = [
132
+ {"node"=>{"value"=>1, "push"=>{"value"=>4}}},
133
+ {"node"=>{"value"=>2, "push"=>{"value"=>4}}},
134
+ {"node"=>{"value"=>3, "push"=>{"value"=>4}}},
135
+ ]
136
+ assert_equal expected_edges, res["data"]["pushes"]["edges"]
137
+ assert_equal [[1, 2, 3], [4, 4, 4]], pushes
138
+ end
139
+
140
+ def test_it_calls_lazy_resolve_instrumentation
141
+ query_str = %|
142
+ {
143
+ p1: push(value: 1) {
144
+ value
145
+ }
146
+ p2: push(value: 2) {
147
+ push(value: 3) {
148
+ value
149
+ }
150
+ }
151
+ pushes(values: [1,2,3]) {
152
+ edges {
153
+ node {
154
+ value
155
+ push(value: 4) {
156
+ value
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ |
163
+
164
+ log = []
165
+ res = self.class.lazy_schema.execute(query_str, context: {lazy_instrumentation: log, pushes: []})
166
+ expected_log = [
167
+ "PUSH",
168
+ "Query.push: 1",
169
+ "Query.push: 2",
170
+ "PUSH",
171
+ "LazyPush.push: 3",
172
+ "LazyPushEdge.node: 1",
173
+ "LazyPushEdge.node: 2",
174
+ "LazyPushEdge.node: 3",
175
+ "PUSH",
176
+ "LazyPush.push: 4",
177
+ "LazyPush.push: 4",
178
+ "LazyPush.push: 4",
179
+ ]
180
+ assert_equal expected_log, log
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Compatibility
4
+ module LazyExecutionSpecification
5
+ module LazySchema
6
+ class LazyPush
7
+ attr_reader :value
8
+ def initialize(ctx, value)
9
+ if value == 13
10
+ @value = nil
11
+ elsif value == 14
12
+ @value = GraphQL::ExecutionError.new("oops!")
13
+ else
14
+ @value = value
15
+ end
16
+ @context = ctx
17
+ pushes = @context[:lazy_pushes] ||= []
18
+ pushes << @value
19
+ end
20
+
21
+ def push
22
+ if @context[:lazy_pushes].include?(@value)
23
+ @context[:lazy_instrumentation] && @context[:lazy_instrumentation] << "PUSH"
24
+ @context[:pushes] << @context[:lazy_pushes]
25
+ @context[:lazy_pushes] = []
26
+ end
27
+ self
28
+ end
29
+ end
30
+
31
+ class LazyPushCollection
32
+ def initialize(ctx, values)
33
+ @ctx = ctx
34
+ @values = values
35
+ end
36
+
37
+ def push
38
+ @values.map { |v| LazyPush.new(@ctx, v) }
39
+ end
40
+ end
41
+
42
+ module LazyInstrumentation
43
+ def self.instrument(type, field)
44
+ prev_lazy_resolve = field.lazy_resolve_proc
45
+ field.redefine {
46
+ lazy_resolve ->(o, a, c) {
47
+ result = prev_lazy_resolve.call(o, a, c)
48
+ c[:lazy_instrumentation] && c[:lazy_instrumentation].push("#{type.name}.#{field.name}: #{o.value}")
49
+ result
50
+ }
51
+ }
52
+ end
53
+ end
54
+
55
+ def self.build(execution_strategy)
56
+ lazy_push_type = GraphQL::ObjectType.define do
57
+ name "LazyPush"
58
+ field :value, !types.Int
59
+ field :push, !lazy_push_type do
60
+ argument :value, types.Int
61
+ resolve ->(o, a, c) {
62
+ LazyPush.new(c, a[:value])
63
+ }
64
+ end
65
+ end
66
+
67
+ query_type = GraphQL::ObjectType.define do
68
+ name "Query"
69
+ field :push, !lazy_push_type do
70
+ argument :value, types.Int
71
+ resolve ->(o, a, c) {
72
+ LazyPush.new(c, a[:value])
73
+ }
74
+ end
75
+
76
+ connection :pushes, lazy_push_type.connection_type do
77
+ argument :values, types[types.Int]
78
+ resolve ->(o, a, c) {
79
+ LazyPushCollection.new(c, a[:values])
80
+ }
81
+ end
82
+ end
83
+
84
+ GraphQL::Schema.define do
85
+ query(query_type)
86
+ mutation(query_type)
87
+ query_execution_strategy(execution_strategy)
88
+ mutation_execution_strategy(execution_strategy)
89
+ lazy_resolve(LazyPush, :push)
90
+ lazy_resolve(LazyPushCollection, :push)
91
+ instrument(:field, LazyInstrumentation)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end