graphql 1.2.6 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,11 +1,16 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  class SerialExecution
4
5
  module ValueResolution
5
- def self.resolve(parent_type, field_defn, field_type, value, irep_nodes, query_ctx)
6
+ def self.resolve(parent_type, field_defn, field_type, value, selection, query_ctx)
6
7
  if value.nil? || value.is_a?(GraphQL::ExecutionError)
7
8
  if field_type.kind.non_null?
8
- raise GraphQL::InvalidNullError.new(parent_type.name, field_defn.name, value)
9
+ if value.nil?
10
+ type_error = GraphQL::InvalidNullError.new(parent_type, field_defn, value)
11
+ query_ctx.schema.type_error(type_error, query_ctx)
12
+ end
13
+ raise GraphQL::Query::Executor::PropagateNull
9
14
  else
10
15
  nil
11
16
  end
@@ -17,17 +22,25 @@ module GraphQL
17
22
  field_type.coerce_result(value, query_ctx.query.warden)
18
23
  when GraphQL::TypeKinds::LIST
19
24
  wrapped_type = field_type.of_type
20
- result = value.each_with_index.map do |inner_value, index|
21
- inner_ctx = query_ctx.spawn(path: query_ctx.path + [index], irep_node: query_ctx.irep_node)
22
- inner_result = resolve(
25
+ result = []
26
+ i = 0
27
+ value.each do |inner_value|
28
+ inner_ctx = query_ctx.spawn(
29
+ key: i,
30
+ selection: selection,
31
+ parent_type: wrapped_type,
32
+ field: field_defn,
33
+ )
34
+
35
+ result << resolve(
23
36
  parent_type,
24
37
  field_defn,
25
38
  wrapped_type,
26
39
  inner_value,
27
- irep_nodes,
40
+ selection,
28
41
  inner_ctx,
29
42
  )
30
- inner_result
43
+ i += 1
31
44
  end
32
45
  result
33
46
  when GraphQL::TypeKinds::NON_NULL
@@ -37,14 +50,14 @@ module GraphQL
37
50
  field_defn,
38
51
  wrapped_type,
39
52
  value,
40
- irep_nodes,
53
+ selection,
41
54
  query_ctx,
42
55
  )
43
56
  when GraphQL::TypeKinds::OBJECT
44
57
  query_ctx.execution_strategy.selection_resolution.resolve(
45
58
  value,
46
59
  field_type,
47
- irep_nodes,
60
+ selection,
48
61
  query_ctx
49
62
  )
50
63
  when GraphQL::TypeKinds::UNION, GraphQL::TypeKinds::INTERFACE
@@ -53,14 +66,16 @@ module GraphQL
53
66
  possible_types = query.possible_types(field_type)
54
67
 
55
68
  if !possible_types.include?(resolved_type)
56
- raise GraphQL::UnresolvedTypeError.new(irep_nodes.first.definition_name, field_type, parent_type, resolved_type, possible_types)
69
+ type_error = GraphQL::UnresolvedTypeError.new(value, field_defn, parent_type, resolved_type, possible_types)
70
+ query.schema.type_error(type_error, query_ctx)
71
+ raise GraphQL::Query::Executor::PropagateNull
57
72
  else
58
73
  resolve(
59
74
  parent_type,
60
75
  field_defn,
61
76
  resolved_type,
62
77
  value,
63
- irep_nodes,
78
+ selection,
64
79
  query_ctx,
65
80
  )
66
81
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  class VariableValidationError < GraphQL::ExecutionError
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  class Query
3
4
  # Read-only access to query variables, applying default values if needed.
data/lib/graphql/relay.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'base64'
2
3
 
3
4
  require 'graphql/relay/page_info'
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  class ArrayConnection < BaseConnection
4
5
  def cursor_from_node(item)
5
6
  idx = starting_offset + sliced_nodes.find_index(item) + 1
6
- Base64.strict_encode64(idx.to_s)
7
+ encode(idx.to_s)
7
8
  end
8
9
 
9
10
  def has_next_page
@@ -35,7 +36,7 @@ module GraphQL
35
36
  end
36
37
 
37
38
  def index_from_cursor(cursor)
38
- Base64.decode64(cursor).to_i
39
+ decode(cursor).to_i
39
40
  end
40
41
 
41
42
  def starting_offset
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  # Subclasses must implement:
@@ -15,13 +16,13 @@ module GraphQL
15
16
  CURSOR_SEPARATOR = "---"
16
17
 
17
18
  # Map of collection class names -> connection_classes
18
- # eg {"Array" => ArrayConnection}
19
+ # eg `{"Array" => ArrayConnection}`
19
20
  CONNECTION_IMPLEMENTATIONS = {}
20
21
 
21
22
  class << self
22
23
  # Find a connection implementation suitable for exposing `nodes`
23
24
  #
24
- # @param [Object] A collection of nodes (eg, Array, AR::Relation)
25
+ # @param nodes [Object] A collection of nodes (eg, Array, AR::Relation)
25
26
  # @return [subclass of BaseConnection] a connection Class for wrapping `nodes`
26
27
  def connection_for_nodes(nodes)
27
28
  # Check for class _names_ because classes can be redefined in Rails development
@@ -39,8 +40,8 @@ module GraphQL
39
40
 
40
41
  # Add `connection_class` as the connection wrapper for `nodes_class`
41
42
  # eg, `RelationConnection` is the implementation for `AR::Relation`
42
- # @param [Class] A class representing a collection (eg, Array, AR::Relation)
43
- # @param [Class] A class implementing Connection methods
43
+ # @param nodes_class [Class] A class representing a collection (eg, Array, AR::Relation)
44
+ # @param connection_class [Class] A class implementing Connection methods
44
45
  def register_connection_implementation(nodes_class, connection_class)
45
46
  CONNECTION_IMPLEMENTATIONS[nodes_class.name] = connection_class
46
47
  end
@@ -49,17 +50,28 @@ module GraphQL
49
50
  attr_reader :nodes, :arguments, :max_page_size, :parent, :field
50
51
 
51
52
  # Make a connection, wrapping `nodes`
52
- # @param [Object] The collection of nodes
53
- # @param Query arguments
54
- # @param field [Object] The underlying field
53
+ # @param nodes [Object] The collection of nodes
54
+ # @param arguments [GraphQL::Query::Arguments] Query arguments
55
+ # @param field [GraphQL::Field] The underlying field
55
56
  # @param max_page_size [Int] The maximum number of results to return
56
57
  # @param parent [Object] The object which this collection belongs to
57
- def initialize(nodes, arguments, field: nil, max_page_size: nil, parent: nil)
58
+ # @param context [GraphQL::Query::Context] The context from the field being resolved
59
+ def initialize(nodes, arguments, field: nil, max_page_size: nil, parent: nil, context: nil)
58
60
  @nodes = nodes
59
61
  @arguments = arguments
60
62
  @max_page_size = max_page_size
61
63
  @field = field
62
64
  @parent = parent
65
+ @context = context
66
+ @encoder = context ? @context.schema.cursor_encoder : GraphQL::Schema::Base64Encoder
67
+ end
68
+
69
+ def encode(data)
70
+ @encoder.encode(data, nonce: true)
71
+ end
72
+
73
+ def decode(data)
74
+ @encoder.decode(data, nonce: true)
63
75
  end
64
76
 
65
77
  # Provide easy access to provided arguments:
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  # Provided a GraphQL field which returns a collection of nodes,
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  class ConnectionResolve
@@ -9,8 +10,20 @@ module GraphQL
9
10
 
10
11
  def call(obj, args, ctx)
11
12
  nodes = @underlying_resolve.call(obj, args, ctx)
13
+ if ctx.schema.lazy?(nodes)
14
+ @field.prepare_lazy(nodes, args, ctx).then { |resolved_nodes|
15
+ build_connection(resolved_nodes, args, obj, ctx)
16
+ }
17
+ else
18
+ build_connection(nodes, args, obj, ctx)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def build_connection(nodes, args, parent, ctx)
12
25
  connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(nodes)
13
- connection_class.new(nodes, args, field: @field, max_page_size: @max_page_size, parent: obj)
26
+ connection_class.new(nodes, args, field: @field, max_page_size: @max_page_size, parent: parent, context: ctx)
14
27
  end
15
28
  end
16
29
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  module ConnectionType
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  # Mostly an internal concern.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  module EdgeType
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  class GlobalIdResolve
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  # Define a Relay mutation:
@@ -181,6 +182,18 @@ module GraphQL
181
182
  mutation_result = nil
182
183
  end
183
184
 
185
+ if ctx.schema.lazy?(mutation_result)
186
+ @mutation.field.prepare_lazy(mutation_result, args, ctx).then { |inner_obj|
187
+ build_result(inner_obj, args)
188
+ }
189
+ else
190
+ build_result(mutation_result, args)
191
+ end
192
+ end
193
+
194
+ private
195
+
196
+ def build_result(mutation_result, args)
184
197
  if @wrap_result
185
198
  @mutation.result_class.new(client_mutation_id: args[:input][:clientMutationId], result: mutation_result)
186
199
  else
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  # Helpers for working with Relay-specific Node objects.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  # Wrap a Connection and expose its page info
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  module Relay
3
4
  # A connection implementation to expose SQL collection objects.
@@ -11,7 +12,7 @@ module GraphQL
11
12
  raise("Can't generate cursor, item not found in connection: #{item}")
12
13
  else
13
14
  offset = starting_offset + item_index + 1
14
- Base64.strict_encode64(offset.to_s)
15
+ encode(offset.to_s)
15
16
  end
16
17
  end
17
18
 
@@ -36,7 +37,7 @@ module GraphQL
36
37
  end
37
38
 
38
39
  def offset_from_cursor(cursor)
39
- Base64.decode64(cursor).to_i
40
+ decode(cursor).to_i
40
41
  end
41
42
 
42
43
  def starting_offset
@@ -0,0 +1,4 @@
1
+ module GraphQL
2
+ class RuntimeTypeError < GraphQL::Error
3
+ end
4
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module GraphQL
2
3
  # # GraphQL::ScalarType
3
4
  #
@@ -45,7 +46,7 @@ module GraphQL
45
46
  def validate_non_null_input(value, warden)
46
47
  result = Query::InputValidationResult.new
47
48
  if coerce_non_null_input(value).nil?
48
- result.add_problem("Could not coerce value #{JSON.generate(value, quirks_mode: true)} to #{name}")
49
+ result.add_problem("Could not coerce value #{GraphQL::Language.serialize(value)} to #{name}")
49
50
  end
50
51
  result
51
52
  end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+ require "graphql/schema/base_64_encoder"
1
3
  require "graphql/schema/catchall_middleware"
4
+ require "graphql/schema/default_type_error"
2
5
  require "graphql/schema/invalid_type_error"
3
6
  require "graphql/schema/instrumented_field_map"
4
7
  require "graphql/schema/middleware_chain"
@@ -51,12 +54,14 @@ module GraphQL
51
54
  :query, :mutation, :subscription,
52
55
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
53
56
  :max_depth, :max_complexity,
54
- :orphan_types, :resolve_type,
57
+ :orphan_types, :resolve_type, :type_error,
55
58
  :object_from_id, :id_from_object,
59
+ :cursor_encoder,
56
60
  directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.name] = d; m }},
57
61
  instrument: -> (schema, type, instrumenter) { schema.instrumenters[type] << instrumenter },
58
62
  query_analyzer: ->(schema, analyzer) { schema.query_analyzers << analyzer },
59
- middleware: ->(schema, middleware) { schema.middleware << middleware },
63
+ middleware: ->(schema, middleware) { schema.user_middleware << middleware },
64
+ lazy_resolve: ->(schema, lazy_class, lazy_value_method) { schema.lazy_methods.set(lazy_class, lazy_value_method) },
60
65
  rescue_from: ->(schema, err_class, &block) { schema.rescue_from(err_class, &block)}
61
66
 
62
67
  attr_accessor \
@@ -64,7 +69,14 @@ module GraphQL
64
69
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
65
70
  :max_depth, :max_complexity,
66
71
  :orphan_types, :directives,
67
- :query_analyzers, :middleware, :instrumenters
72
+ :query_analyzers, :user_middleware, :instrumenters, :lazy_methods,
73
+ :cursor_encoder
74
+
75
+ class << self
76
+ attr_accessor :default_execution_strategy
77
+ end
78
+
79
+ self.default_execution_strategy = GraphQL::Execution::Execute
68
80
 
69
81
  BUILT_IN_TYPES = Hash[[INT_TYPE, STRING_TYPE, FLOAT_TYPE, BOOLEAN_TYPE, ID_TYPE].map{ |type| [type.name, type] }]
70
82
  DIRECTIVES = [GraphQL::Directive::IncludeDirective, GraphQL::Directive::SkipDirective, GraphQL::Directive::DeprecatedDirective]
@@ -72,28 +84,51 @@ module GraphQL
72
84
 
73
85
  attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
74
86
 
75
- # @!attribute [r] middleware
76
- # @return [Array<#call>] Middlewares suitable for MiddlewareChain, applied to fields during execution
77
-
78
- # @param query [GraphQL::ObjectType] the query root for the schema
79
- # @param mutation [GraphQL::ObjectType] the mutation root for the schema
80
- # @param subscription [GraphQL::ObjectType] the subscription root for the schema
81
- # @param max_depth [Integer] maximum query nesting (if it's greater, raise an error)
82
- # @param types [Array<GraphQL::BaseType>] additional types to include in this schema
83
87
  def initialize
84
88
  @orphan_types = []
85
89
  @directives = DIRECTIVES.reduce({}) { |m, d| m[d.name] = d; m }
86
90
  @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
87
- @middleware = []
91
+ @user_middleware = []
88
92
  @query_analyzers = []
89
93
  @resolve_type_proc = nil
90
94
  @object_from_id_proc = nil
91
95
  @id_from_object_proc = nil
96
+ @type_error_proc = DefaultTypeError
92
97
  @instrumenters = Hash.new { |h, k| h[k] = [] }
98
+ @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
99
+ @cursor_encoder = Base64Encoder
93
100
  # Default to the built-in execution strategy:
94
- @query_execution_strategy = GraphQL::Query::SerialExecution
95
- @mutation_execution_strategy = GraphQL::Query::SerialExecution
96
- @subscription_execution_strategy = GraphQL::Query::SerialExecution
101
+ @query_execution_strategy = self.class.default_execution_strategy
102
+ @mutation_execution_strategy = self.class.default_execution_strategy
103
+ @subscription_execution_strategy = self.class.default_execution_strategy
104
+ end
105
+
106
+ def initialize_copy(other)
107
+ super
108
+ @orphan_types = other.orphan_types.dup
109
+ @directives = other.directives.dup
110
+ @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
111
+ @user_middleware = other.user_middleware.dup
112
+ @middleware = nil
113
+ @query_analyzers = other.query_analyzers.dup
114
+
115
+ @possible_types = GraphQL::Schema::PossibleTypes.new(self)
116
+
117
+ @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
118
+ other.lazy_methods.each { |lazy_class, lazy_method| @lazy_methods.set(lazy_class, lazy_method) }
119
+
120
+ @instrumenters = Hash.new { |h, k| h[k] = [] }
121
+ other.instrumenters.each do |key, insts|
122
+ @instrumenters[key].concat(insts)
123
+ end
124
+
125
+ if other.rescues?
126
+ @rescue_middleware = other.rescue_middleware
127
+ end
128
+
129
+ # This will be rebuilt when it's requested
130
+ # or during a later `define` call
131
+ @types = nil
97
132
  end
98
133
 
99
134
  def rescue_from(*args, &block)
@@ -107,12 +142,11 @@ module GraphQL
107
142
  def define(**kwargs, &block)
108
143
  super
109
144
  ensure_defined
110
- all_types = orphan_types + [query, mutation, subscription, GraphQL::Introspection::SchemaType]
111
- @types = GraphQL::Schema::ReduceTypes.reduce(all_types.compact)
112
- build_instrumented_field_map
145
+ build_types_map
113
146
  # Assert that all necessary configs are present:
114
147
  validation_error = Validation.validate(self)
115
148
  validation_error && raise(NotImplementedError, validation_error)
149
+ build_instrumented_field_map
116
150
  nil
117
151
  end
118
152
 
@@ -127,10 +161,11 @@ module GraphQL
127
161
  end
128
162
  end
129
163
 
130
-
131
164
  # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
132
165
  # @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
133
- attr_reader :types
166
+ def types
167
+ @types ||= build_types_map
168
+ end
134
169
 
135
170
  # Execute a query on itself.
136
171
  # See {Query#initialize} for arguments.
@@ -240,6 +275,35 @@ module GraphQL
240
275
  @object_from_id_proc = new_proc
241
276
  end
242
277
 
278
+ # When we encounter a type error during query execution, we call this hook.
279
+ #
280
+ # You can use this hook to write a log entry,
281
+ # add a {GraphQL::ExecutionError} to the response (with `ctx.add_error`)
282
+ # or raise an exception and halt query execution.
283
+ #
284
+ # @example A `nil` is encountered by a non-null field
285
+ # type_error ->(err, query_ctx) {
286
+ # err.is_a?(GraphQL::InvalidNullError) # => true
287
+ # }
288
+ #
289
+ # @example An object doesn't resolve to one of a {UnionType}'s members
290
+ # type_error ->(err, query_ctx) {
291
+ # err.is_a?(GraphQL::UnresolvedTypeError) # => true
292
+ # }
293
+ #
294
+ # @see {DefaultTypeError} is the default behavior.
295
+ # @param err [GraphQL::TypeError] The error encountered during execution
296
+ # @param ctx [GraphQL::Query::Context] The context for the field where the error occurred
297
+ # @return void
298
+ def type_error(err, ctx)
299
+ @type_error_proc.call(err, ctx)
300
+ end
301
+
302
+ # @param new_proc [#call] A new callable for handling type errors during execution
303
+ def type_error=(new_proc)
304
+ @type_error_proc = new_proc
305
+ end
306
+
243
307
  # Get a unique identifier from this object
244
308
  # @param object [Any] An application object
245
309
  # @param type [GraphQL::BaseType] The current type definition
@@ -275,20 +339,46 @@ module GraphQL
275
339
  # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
276
340
  class InvalidDocumentError < Error; end;
277
341
 
278
- private
342
+ # @return [Symbol, nil] The method name to lazily resolve `obj`, or nil if `obj`'s class wasn't registered wtih {#lazy_resolve}.
343
+ def lazy_method_name(obj)
344
+ @lazy_methods.get(obj)
345
+ end
346
+
347
+ # @return [Boolean] True if this object should be lazily resolved
348
+ def lazy?(obj)
349
+ !!lazy_method_name(obj)
350
+ end
351
+
352
+ # @return [Array<#call>] Middlewares suitable for MiddlewareChain, applied to fields during execution
353
+ def middleware
354
+ @middleware ||= if @rescue_middleware
355
+ [@rescue_middleware].concat(@user_middleware)
356
+ else
357
+ @user_middleware
358
+ end
359
+ end
360
+
361
+ protected
362
+
363
+ def rescues?
364
+ !!@rescue_middleware
365
+ end
279
366
 
280
367
  # Lazily create a middleware and add it to the schema
281
368
  # (Don't add it if it's not used)
282
369
  def rescue_middleware
283
- @rescue_middleware ||= begin
284
- middleware = GraphQL::Schema::RescueMiddleware.new
285
- @middleware << middleware
286
- middleware
287
- end
370
+ @rescue_middleware ||= GraphQL::Schema::RescueMiddleware.new
288
371
  end
289
372
 
373
+ private
374
+
290
375
  def build_instrumented_field_map
291
376
  @instrumented_field_map = InstrumentedFieldMap.new(self, @instrumenters[:field])
292
377
  end
378
+
379
+ def build_types_map
380
+ all_types = orphan_types + [query, mutation, subscription, GraphQL::Introspection::SchemaType]
381
+ @types = GraphQL::Schema::ReduceTypes.reduce(all_types.compact)
382
+ end
293
383
  end
294
384
  end