graphql 1.2.6 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (278) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +3 -1
  3. data/lib/graphql/analysis.rb +1 -0
  4. data/lib/graphql/analysis/analyze_query.rb +1 -0
  5. data/lib/graphql/analysis/field_usage.rb +1 -0
  6. data/lib/graphql/analysis/max_query_complexity.rb +1 -0
  7. data/lib/graphql/analysis/max_query_depth.rb +1 -0
  8. data/lib/graphql/analysis/query_complexity.rb +1 -0
  9. data/lib/graphql/analysis/query_depth.rb +1 -0
  10. data/lib/graphql/analysis/reducer_state.rb +1 -0
  11. data/lib/graphql/analysis_error.rb +1 -0
  12. data/lib/graphql/argument.rb +1 -0
  13. data/lib/graphql/base_type.rb +16 -7
  14. data/lib/graphql/boolean_type.rb +1 -0
  15. data/lib/graphql/compatibility.rb +2 -0
  16. data/lib/graphql/compatibility/execution_specification.rb +113 -192
  17. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +53 -0
  18. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +195 -0
  19. data/lib/graphql/compatibility/lazy_execution_specification.rb +186 -0
  20. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +97 -0
  21. data/lib/graphql/compatibility/query_parser_specification.rb +1 -0
  22. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +1 -0
  23. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +1 -0
  24. data/lib/graphql/compatibility/schema_parser_specification.rb +1 -0
  25. data/lib/graphql/define.rb +1 -0
  26. data/lib/graphql/define/assign_argument.rb +1 -0
  27. data/lib/graphql/define/assign_connection.rb +1 -0
  28. data/lib/graphql/define/assign_enum_value.rb +1 -0
  29. data/lib/graphql/define/assign_global_id_field.rb +1 -0
  30. data/lib/graphql/define/assign_object_field.rb +1 -0
  31. data/lib/graphql/define/defined_object_proxy.rb +1 -0
  32. data/lib/graphql/define/instance_definable.rb +11 -12
  33. data/lib/graphql/define/non_null_with_bang.rb +1 -0
  34. data/lib/graphql/define/type_definer.rb +1 -0
  35. data/lib/graphql/directive.rb +1 -0
  36. data/lib/graphql/directive/deprecated_directive.rb +1 -0
  37. data/lib/graphql/directive/include_directive.rb +1 -0
  38. data/lib/graphql/directive/skip_directive.rb +1 -0
  39. data/lib/graphql/enum_type.rb +8 -1
  40. data/lib/graphql/execution.rb +5 -0
  41. data/lib/graphql/execution/directive_checks.rb +1 -0
  42. data/lib/graphql/execution/execute.rb +222 -0
  43. data/lib/graphql/execution/field_result.rb +52 -0
  44. data/lib/graphql/execution/lazy.rb +59 -0
  45. data/lib/graphql/execution/lazy/lazy_method_map.rb +38 -0
  46. data/lib/graphql/execution/lazy/resolve.rb +68 -0
  47. data/lib/graphql/execution/selection_result.rb +84 -0
  48. data/lib/graphql/execution/typecast.rb +4 -4
  49. data/lib/graphql/execution_error.rb +1 -0
  50. data/lib/graphql/field.rb +68 -18
  51. data/lib/graphql/field/resolve.rb +1 -0
  52. data/lib/graphql/float_type.rb +1 -0
  53. data/lib/graphql/id_type.rb +1 -0
  54. data/lib/graphql/input_object_type.rb +6 -0
  55. data/lib/graphql/int_type.rb +1 -0
  56. data/lib/graphql/interface_type.rb +6 -0
  57. data/lib/graphql/internal_representation.rb +2 -1
  58. data/lib/graphql/internal_representation/node.rb +2 -1
  59. data/lib/graphql/internal_representation/rewrite.rb +1 -0
  60. data/lib/graphql/internal_representation/selection.rb +85 -0
  61. data/lib/graphql/introspection.rb +1 -0
  62. data/lib/graphql/introspection/arguments_field.rb +1 -0
  63. data/lib/graphql/introspection/directive_location_enum.rb +1 -0
  64. data/lib/graphql/introspection/directive_type.rb +1 -0
  65. data/lib/graphql/introspection/enum_value_type.rb +1 -0
  66. data/lib/graphql/introspection/enum_values_field.rb +1 -0
  67. data/lib/graphql/introspection/field_type.rb +1 -0
  68. data/lib/graphql/introspection/fields_field.rb +1 -0
  69. data/lib/graphql/introspection/input_fields_field.rb +1 -0
  70. data/lib/graphql/introspection/input_value_type.rb +2 -1
  71. data/lib/graphql/introspection/interfaces_field.rb +1 -0
  72. data/lib/graphql/introspection/introspection_query.rb +1 -0
  73. data/lib/graphql/introspection/of_type_field.rb +1 -0
  74. data/lib/graphql/introspection/possible_types_field.rb +1 -0
  75. data/lib/graphql/introspection/schema_field.rb +1 -0
  76. data/lib/graphql/introspection/schema_type.rb +1 -0
  77. data/lib/graphql/introspection/type_by_name_field.rb +1 -0
  78. data/lib/graphql/introspection/type_kind_enum.rb +1 -0
  79. data/lib/graphql/introspection/type_type.rb +1 -0
  80. data/lib/graphql/introspection/typename_field.rb +1 -0
  81. data/lib/graphql/invalid_null_error.rb +17 -7
  82. data/lib/graphql/language.rb +10 -0
  83. data/lib/graphql/language/comments.rb +2 -1
  84. data/lib/graphql/language/definition_slice.rb +1 -0
  85. data/lib/graphql/language/generation.rb +25 -24
  86. data/lib/graphql/language/nodes.rb +1 -0
  87. data/lib/graphql/language/token.rb +1 -0
  88. data/lib/graphql/language/visitor.rb +1 -0
  89. data/lib/graphql/list_type.rb +1 -0
  90. data/lib/graphql/non_null_type.rb +2 -1
  91. data/lib/graphql/object_type.rb +12 -0
  92. data/lib/graphql/query.rb +40 -43
  93. data/lib/graphql/query/arguments.rb +1 -0
  94. data/lib/graphql/query/context.rb +31 -7
  95. data/lib/graphql/query/executor.rb +8 -1
  96. data/lib/graphql/query/input_validation_result.rb +1 -0
  97. data/lib/graphql/query/literal_input.rb +1 -0
  98. data/lib/graphql/query/serial_execution.rb +3 -4
  99. data/lib/graphql/query/serial_execution/field_resolution.rb +15 -10
  100. data/lib/graphql/query/serial_execution/operation_resolution.rb +3 -5
  101. data/lib/graphql/query/serial_execution/selection_resolution.rb +4 -5
  102. data/lib/graphql/query/serial_execution/value_resolution.rb +26 -11
  103. data/lib/graphql/query/variable_validation_error.rb +1 -0
  104. data/lib/graphql/query/variables.rb +1 -0
  105. data/lib/graphql/relay.rb +1 -0
  106. data/lib/graphql/relay/array_connection.rb +3 -2
  107. data/lib/graphql/relay/base_connection.rb +20 -8
  108. data/lib/graphql/relay/connection_field.rb +1 -0
  109. data/lib/graphql/relay/connection_resolve.rb +14 -1
  110. data/lib/graphql/relay/connection_type.rb +1 -0
  111. data/lib/graphql/relay/edge.rb +1 -0
  112. data/lib/graphql/relay/edge_type.rb +1 -0
  113. data/lib/graphql/relay/global_id_resolve.rb +1 -0
  114. data/lib/graphql/relay/mutation.rb +13 -0
  115. data/lib/graphql/relay/node.rb +1 -0
  116. data/lib/graphql/relay/page_info.rb +1 -0
  117. data/lib/graphql/relay/relation_connection.rb +3 -2
  118. data/lib/graphql/runtime_type_error.rb +4 -0
  119. data/lib/graphql/scalar_type.rb +2 -1
  120. data/lib/graphql/schema.rb +116 -26
  121. data/lib/graphql/schema/base_64_encoder.rb +14 -0
  122. data/lib/graphql/schema/build_from_definition.rb +4 -0
  123. data/lib/graphql/schema/catchall_middleware.rb +1 -0
  124. data/lib/graphql/schema/default_type_error.rb +15 -0
  125. data/lib/graphql/schema/instrumented_field_map.rb +1 -0
  126. data/lib/graphql/schema/invalid_type_error.rb +1 -0
  127. data/lib/graphql/schema/loader.rb +5 -1
  128. data/lib/graphql/schema/middleware_chain.rb +1 -0
  129. data/lib/graphql/schema/possible_types.rb +1 -0
  130. data/lib/graphql/schema/printer.rb +3 -2
  131. data/lib/graphql/schema/reduce_types.rb +1 -0
  132. data/lib/graphql/schema/rescue_middleware.rb +3 -2
  133. data/lib/graphql/schema/timeout_middleware.rb +1 -0
  134. data/lib/graphql/schema/type_expression.rb +1 -0
  135. data/lib/graphql/schema/type_map.rb +1 -0
  136. data/lib/graphql/schema/unique_within_type.rb +1 -0
  137. data/lib/graphql/schema/validation.rb +57 -1
  138. data/lib/graphql/schema/warden.rb +1 -0
  139. data/lib/graphql/static_validation.rb +1 -0
  140. data/lib/graphql/static_validation/all_rules.rb +1 -0
  141. data/lib/graphql/static_validation/arguments_validator.rb +1 -0
  142. data/lib/graphql/static_validation/literal_validator.rb +1 -0
  143. data/lib/graphql/static_validation/message.rb +1 -0
  144. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -0
  145. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -0
  146. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -0
  147. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -0
  148. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -0
  149. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -0
  150. data/lib/graphql/static_validation/rules/fields_will_merge.rb +6 -3
  151. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +1 -0
  152. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -0
  153. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +1 -0
  154. data/lib/graphql/static_validation/rules/fragments_are_named.rb +1 -0
  155. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -0
  156. data/lib/graphql/static_validation/rules/fragments_are_used.rb +1 -0
  157. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -0
  158. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -0
  159. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -0
  160. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -0
  161. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -0
  162. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -0
  163. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -0
  164. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +1 -0
  165. data/lib/graphql/static_validation/type_stack.rb +1 -0
  166. data/lib/graphql/static_validation/validation_context.rb +2 -1
  167. data/lib/graphql/static_validation/validator.rb +2 -1
  168. data/lib/graphql/string_type.rb +1 -0
  169. data/lib/graphql/type_kinds.rb +1 -0
  170. data/lib/graphql/union_type.rb +13 -0
  171. data/lib/graphql/unresolved_type_error.rb +26 -5
  172. data/lib/graphql/version.rb +2 -1
  173. data/readme.md +1 -5
  174. data/spec/graphql/analysis/analyze_query_spec.rb +1 -0
  175. data/spec/graphql/analysis/field_usage_spec.rb +1 -0
  176. data/spec/graphql/analysis/max_query_complexity_spec.rb +1 -0
  177. data/spec/graphql/analysis/max_query_depth_spec.rb +1 -0
  178. data/spec/graphql/analysis/query_complexity_spec.rb +1 -0
  179. data/spec/graphql/analysis/query_depth_spec.rb +1 -0
  180. data/spec/graphql/argument_spec.rb +1 -0
  181. data/spec/graphql/base_type_spec.rb +13 -0
  182. data/spec/graphql/boolean_type_spec.rb +1 -0
  183. data/spec/graphql/compatibility/execution_specification_spec.rb +1 -0
  184. data/spec/graphql/compatibility/lazy_execution_specification_spec.rb +4 -0
  185. data/spec/graphql/compatibility/query_parser_specification_spec.rb +1 -0
  186. data/spec/graphql/compatibility/schema_parser_specification_spec.rb +1 -0
  187. data/spec/graphql/define/assign_argument_spec.rb +1 -0
  188. data/spec/graphql/define/instance_definable_spec.rb +1 -0
  189. data/spec/graphql/directive_spec.rb +1 -0
  190. data/spec/graphql/enum_type_spec.rb +10 -0
  191. data/spec/graphql/execution/execute_spec.rb +5 -0
  192. data/spec/graphql/execution/lazy_spec.rb +252 -0
  193. data/spec/graphql/execution/typecast_spec.rb +1 -0
  194. data/spec/graphql/execution_error_spec.rb +1 -0
  195. data/spec/graphql/field_spec.rb +17 -0
  196. data/spec/graphql/float_type_spec.rb +1 -0
  197. data/spec/graphql/id_type_spec.rb +1 -0
  198. data/spec/graphql/input_object_type_spec.rb +10 -0
  199. data/spec/graphql/int_type_spec.rb +1 -0
  200. data/spec/graphql/interface_type_spec.rb +10 -0
  201. data/spec/graphql/internal_representation/rewrite_spec.rb +1 -0
  202. data/spec/graphql/introspection/directive_type_spec.rb +1 -0
  203. data/spec/graphql/introspection/input_value_type_spec.rb +1 -0
  204. data/spec/graphql/introspection/introspection_query_spec.rb +1 -0
  205. data/spec/graphql/introspection/schema_type_spec.rb +1 -0
  206. data/spec/graphql/introspection/type_type_spec.rb +1 -0
  207. data/spec/graphql/language/definition_slice_spec.rb +1 -0
  208. data/spec/graphql/language/equality_spec.rb +1 -0
  209. data/spec/graphql/language/generation_spec.rb +1 -0
  210. data/spec/graphql/language/lexer_spec.rb +1 -0
  211. data/spec/graphql/language/nodes_spec.rb +1 -0
  212. data/spec/graphql/language/parser_spec.rb +1 -0
  213. data/spec/graphql/language/visitor_spec.rb +1 -0
  214. data/spec/graphql/list_type_spec.rb +1 -0
  215. data/spec/graphql/non_null_type_spec.rb +17 -0
  216. data/spec/graphql/object_type_spec.rb +19 -0
  217. data/spec/graphql/query/arguments_spec.rb +1 -0
  218. data/spec/graphql/query/context_spec.rb +1 -0
  219. data/spec/graphql/query/executor_spec.rb +1 -0
  220. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +1 -0
  221. data/spec/graphql/query/variables_spec.rb +1 -0
  222. data/spec/graphql/query_spec.rb +25 -0
  223. data/spec/graphql/relay/array_connection_spec.rb +1 -0
  224. data/spec/graphql/relay/base_connection_spec.rb +33 -4
  225. data/spec/graphql/relay/connection_field_spec.rb +1 -0
  226. data/spec/graphql/relay/connection_type_spec.rb +1 -0
  227. data/spec/graphql/relay/mutation_spec.rb +6 -0
  228. data/spec/graphql/relay/node_spec.rb +1 -0
  229. data/spec/graphql/relay/page_info_spec.rb +1 -0
  230. data/spec/graphql/relay/relation_connection_spec.rb +1 -0
  231. data/spec/graphql/scalar_type_spec.rb +1 -0
  232. data/spec/graphql/schema/build_from_definition_spec.rb +9 -1
  233. data/spec/graphql/schema/catchall_middleware_spec.rb +1 -0
  234. data/spec/graphql/schema/loader_spec.rb +7 -0
  235. data/spec/graphql/schema/middleware_chain_spec.rb +1 -0
  236. data/spec/graphql/schema/printer_spec.rb +1 -0
  237. data/spec/graphql/schema/reduce_types_spec.rb +1 -0
  238. data/spec/graphql/schema/rescue_middleware_spec.rb +1 -0
  239. data/spec/graphql/schema/timeout_middleware_spec.rb +1 -0
  240. data/spec/graphql/schema/type_expression_spec.rb +1 -0
  241. data/spec/graphql/schema/unique_within_type_spec.rb +1 -0
  242. data/spec/graphql/schema/validation_spec.rb +55 -0
  243. data/spec/graphql/schema/warden_spec.rb +1 -0
  244. data/spec/graphql/schema_spec.rb +39 -0
  245. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +1 -0
  246. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +1 -0
  247. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +1 -0
  248. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +1 -0
  249. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +1 -0
  250. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +1 -0
  251. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +515 -31
  252. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +1 -0
  253. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +1 -0
  254. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +1 -0
  255. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +1 -0
  256. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +1 -0
  257. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +1 -0
  258. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +1 -0
  259. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +1 -0
  260. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +1 -0
  261. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +1 -0
  262. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +1 -0
  263. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +1 -0
  264. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +1 -0
  265. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +1 -0
  266. data/spec/graphql/static_validation/type_stack_spec.rb +1 -0
  267. data/spec/graphql/static_validation/validator_spec.rb +1 -0
  268. data/spec/graphql/string_type_spec.rb +1 -0
  269. data/spec/graphql/union_type_spec.rb +11 -0
  270. data/spec/spec_helper.rb +1 -0
  271. data/spec/support/dairy_app.rb +1 -0
  272. data/spec/support/dairy_data.rb +1 -0
  273. data/spec/support/minimum_input_object.rb +1 -0
  274. data/spec/support/star_wars_data.rb +1 -0
  275. data/spec/support/star_wars_schema.rb +30 -7
  276. data/spec/support/static_validation_helpers.rb +1 -0
  277. metadata +24 -5
  278. data/lib/graphql/internal_representation/selections.rb +0 -41
@@ -1,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