graphql 1.9.5 → 1.13.19

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (659) hide show
  1. checksums.yaml +5 -5
  2. data/lib/generators/graphql/core.rb +21 -9
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/install/templates/base_mutation.erb +10 -0
  8. data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
  9. data/lib/generators/graphql/install_generator.rb +48 -8
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/loader_generator.rb +1 -0
  12. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  14. data/lib/generators/graphql/mutation_generator.rb +6 -30
  15. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  16. data/lib/generators/graphql/object_generator.rb +28 -12
  17. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  18. data/lib/generators/graphql/relay.rb +63 -0
  19. data/lib/generators/graphql/relay_generator.rb +21 -0
  20. data/lib/generators/graphql/scalar_generator.rb +4 -2
  21. data/lib/generators/graphql/templates/base_argument.erb +6 -0
  22. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  23. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  24. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  25. data/lib/generators/graphql/templates/base_field.erb +7 -0
  26. data/lib/generators/graphql/templates/base_input_object.erb +3 -0
  27. data/lib/generators/graphql/templates/base_interface.erb +4 -0
  28. data/lib/generators/graphql/templates/base_object.erb +3 -0
  29. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  30. data/lib/generators/graphql/templates/base_union.erb +2 -0
  31. data/lib/generators/graphql/templates/enum.erb +7 -1
  32. data/lib/generators/graphql/templates/graphql_controller.erb +21 -12
  33. data/lib/generators/graphql/templates/input.erb +9 -0
  34. data/lib/generators/graphql/templates/interface.erb +6 -2
  35. data/lib/generators/graphql/templates/loader.erb +2 -0
  36. data/lib/generators/graphql/templates/mutation.erb +3 -1
  37. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  39. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  40. data/lib/generators/graphql/templates/node_type.erb +9 -0
  41. data/lib/generators/graphql/templates/object.erb +7 -3
  42. data/lib/generators/graphql/templates/query_type.erb +3 -3
  43. data/lib/generators/graphql/templates/scalar.erb +5 -1
  44. data/lib/generators/graphql/templates/schema.erb +23 -28
  45. data/lib/generators/graphql/templates/union.erb +6 -2
  46. data/lib/generators/graphql/type_generator.rb +47 -10
  47. data/lib/generators/graphql/union_generator.rb +5 -5
  48. data/lib/graphql/analysis/analyze_query.rb +7 -0
  49. data/lib/graphql/analysis/ast/analyzer.rb +34 -12
  50. data/lib/graphql/analysis/ast/field_usage.rb +29 -2
  51. data/lib/graphql/analysis/ast/max_query_complexity.rb +3 -3
  52. data/lib/graphql/analysis/ast/max_query_depth.rb +7 -3
  53. data/lib/graphql/analysis/ast/query_complexity.rb +179 -64
  54. data/lib/graphql/analysis/ast/query_depth.rb +16 -26
  55. data/lib/graphql/analysis/ast/visitor.rb +46 -32
  56. data/lib/graphql/analysis/ast.rb +23 -14
  57. data/lib/graphql/analysis/query_depth.rb +4 -17
  58. data/lib/graphql/argument.rb +16 -38
  59. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  60. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  61. data/lib/graphql/backtrace/table.rb +44 -5
  62. data/lib/graphql/backtrace/traced_error.rb +0 -1
  63. data/lib/graphql/backtrace/tracer.rb +40 -9
  64. data/lib/graphql/backtrace.rb +28 -19
  65. data/lib/graphql/backwards_compatibility.rb +2 -1
  66. data/lib/graphql/base_type.rb +11 -5
  67. data/lib/graphql/boolean_type.rb +1 -1
  68. data/lib/graphql/coercion_error.rb +8 -0
  69. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  70. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  71. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +1 -1
  72. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  73. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
  74. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  75. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  76. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  77. data/lib/graphql/dataloader/request.rb +19 -0
  78. data/lib/graphql/dataloader/request_all.rb +19 -0
  79. data/lib/graphql/dataloader/source.rb +155 -0
  80. data/lib/graphql/dataloader.rb +308 -0
  81. data/lib/graphql/date_encoding_error.rb +16 -0
  82. data/lib/graphql/define/assign_enum_value.rb +1 -1
  83. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  84. data/lib/graphql/define/assign_object_field.rb +3 -3
  85. data/lib/graphql/define/defined_object_proxy.rb +3 -0
  86. data/lib/graphql/define/instance_definable.rb +65 -110
  87. data/lib/graphql/define/type_definer.rb +5 -5
  88. data/lib/graphql/deprecated_dsl.rb +18 -5
  89. data/lib/graphql/deprecation.rb +9 -0
  90. data/lib/graphql/directive/deprecated_directive.rb +1 -12
  91. data/lib/graphql/directive/include_directive.rb +1 -1
  92. data/lib/graphql/directive/skip_directive.rb +1 -1
  93. data/lib/graphql/directive.rb +9 -6
  94. data/lib/graphql/enum_type.rb +14 -74
  95. data/lib/graphql/execution/directive_checks.rb +2 -2
  96. data/lib/graphql/execution/errors.rb +163 -0
  97. data/lib/graphql/execution/execute.rb +10 -3
  98. data/lib/graphql/execution/instrumentation.rb +1 -1
  99. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  100. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  101. data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
  102. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  103. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  104. data/lib/graphql/execution/interpreter/runtime.rb +737 -376
  105. data/lib/graphql/execution/interpreter.rb +42 -19
  106. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  107. data/lib/graphql/execution/lazy.rb +5 -1
  108. data/lib/graphql/execution/lookahead.rb +39 -114
  109. data/lib/graphql/execution/multiplex.rb +58 -29
  110. data/lib/graphql/execution.rb +1 -0
  111. data/lib/graphql/execution_error.rb +3 -2
  112. data/lib/graphql/field.rb +15 -119
  113. data/lib/graphql/filter.rb +1 -1
  114. data/lib/graphql/float_type.rb +1 -1
  115. data/lib/graphql/function.rb +6 -31
  116. data/lib/graphql/id_type.rb +1 -1
  117. data/lib/graphql/input_object_type.rb +11 -26
  118. data/lib/graphql/int_type.rb +1 -1
  119. data/lib/graphql/integer_decoding_error.rb +17 -0
  120. data/lib/graphql/integer_encoding_error.rb +18 -2
  121. data/lib/graphql/interface_type.rb +10 -24
  122. data/lib/graphql/internal_representation/document.rb +2 -2
  123. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  124. data/lib/graphql/internal_representation/scope.rb +2 -2
  125. data/lib/graphql/internal_representation/visit.rb +2 -2
  126. data/lib/graphql/introspection/base_object.rb +2 -5
  127. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  128. data/lib/graphql/introspection/directive_type.rb +12 -6
  129. data/lib/graphql/introspection/entry_points.rb +9 -8
  130. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  131. data/lib/graphql/introspection/field_type.rb +9 -5
  132. data/lib/graphql/introspection/input_value_type.rb +41 -11
  133. data/lib/graphql/introspection/introspection_query.rb +6 -92
  134. data/lib/graphql/introspection/schema_type.rb +13 -12
  135. data/lib/graphql/introspection/type_type.rb +27 -17
  136. data/lib/graphql/introspection.rb +99 -0
  137. data/lib/graphql/invalid_null_error.rb +18 -0
  138. data/lib/graphql/language/block_string.rb +22 -7
  139. data/lib/graphql/language/cache.rb +37 -0
  140. data/lib/graphql/language/definition_slice.rb +21 -10
  141. data/lib/graphql/language/document_from_schema_definition.rb +126 -67
  142. data/lib/graphql/language/lexer.rb +180 -141
  143. data/lib/graphql/language/lexer.rl +75 -51
  144. data/lib/graphql/language/nodes.rb +92 -108
  145. data/lib/graphql/language/parser.rb +933 -897
  146. data/lib/graphql/language/parser.y +129 -103
  147. data/lib/graphql/language/printer.rb +11 -2
  148. data/lib/graphql/language/sanitized_printer.rb +222 -0
  149. data/lib/graphql/language/token.rb +1 -1
  150. data/lib/graphql/language/visitor.rb +11 -8
  151. data/lib/graphql/language.rb +3 -1
  152. data/lib/graphql/name_validator.rb +2 -7
  153. data/lib/graphql/non_null_type.rb +0 -10
  154. data/lib/graphql/object_type.rb +47 -58
  155. data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
  156. data/lib/graphql/pagination/array_connection.rb +77 -0
  157. data/lib/graphql/pagination/connection.rb +226 -0
  158. data/lib/graphql/pagination/connections.rb +160 -0
  159. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  160. data/lib/graphql/pagination/relation_connection.rb +226 -0
  161. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  162. data/lib/graphql/pagination.rb +6 -0
  163. data/lib/graphql/parse_error.rb +0 -1
  164. data/lib/graphql/query/arguments.rb +29 -19
  165. data/lib/graphql/query/arguments_cache.rb +1 -2
  166. data/lib/graphql/query/context.rb +81 -14
  167. data/lib/graphql/query/executor.rb +0 -1
  168. data/lib/graphql/query/fingerprint.rb +26 -0
  169. data/lib/graphql/query/input_validation_result.rb +32 -6
  170. data/lib/graphql/query/literal_input.rb +31 -10
  171. data/lib/graphql/query/null_context.rb +28 -8
  172. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  173. data/lib/graphql/query/serial_execution.rb +1 -0
  174. data/lib/graphql/query/validation_pipeline.rb +6 -4
  175. data/lib/graphql/query/variable_validation_error.rb +3 -3
  176. data/lib/graphql/query/variables.rb +51 -9
  177. data/lib/graphql/query.rb +97 -23
  178. data/lib/graphql/railtie.rb +9 -1
  179. data/lib/graphql/rake_task/validate.rb +3 -0
  180. data/lib/graphql/rake_task.rb +12 -9
  181. data/lib/graphql/relay/array_connection.rb +11 -13
  182. data/lib/graphql/relay/base_connection.rb +33 -16
  183. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  184. data/lib/graphql/relay/connection_type.rb +18 -4
  185. data/lib/graphql/relay/edge_type.rb +1 -0
  186. data/lib/graphql/relay/edges_instrumentation.rb +1 -2
  187. data/lib/graphql/relay/global_id_resolve.rb +1 -2
  188. data/lib/graphql/relay/mutation.rb +3 -87
  189. data/lib/graphql/relay/node.rb +5 -2
  190. data/lib/graphql/relay/page_info.rb +1 -1
  191. data/lib/graphql/relay/range_add.rb +27 -9
  192. data/lib/graphql/relay/relation_connection.rb +17 -15
  193. data/lib/graphql/relay/type_extensions.rb +2 -0
  194. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  195. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  196. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  197. data/lib/graphql/rubocop.rb +4 -0
  198. data/lib/graphql/scalar_type.rb +18 -62
  199. data/lib/graphql/schema/addition.rb +247 -0
  200. data/lib/graphql/schema/argument.rb +289 -11
  201. data/lib/graphql/schema/base_64_bp.rb +3 -2
  202. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  203. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  204. data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
  205. data/lib/graphql/schema/build_from_definition.rb +323 -203
  206. data/lib/graphql/schema/built_in_types.rb +5 -5
  207. data/lib/graphql/schema/default_type_error.rb +2 -0
  208. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  209. data/lib/graphql/schema/directive/feature.rb +2 -2
  210. data/lib/graphql/schema/directive/flagged.rb +57 -0
  211. data/lib/graphql/schema/directive/include.rb +2 -2
  212. data/lib/graphql/schema/directive/skip.rb +2 -2
  213. data/lib/graphql/schema/directive/transform.rb +14 -2
  214. data/lib/graphql/schema/directive.rb +136 -6
  215. data/lib/graphql/schema/enum.rb +121 -12
  216. data/lib/graphql/schema/enum_value.rb +23 -6
  217. data/lib/graphql/schema/field/connection_extension.rb +46 -20
  218. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  219. data/lib/graphql/schema/field.rb +515 -191
  220. data/lib/graphql/schema/field_extension.rb +89 -2
  221. data/lib/graphql/schema/find_inherited_value.rb +36 -0
  222. data/lib/graphql/schema/finder.rb +16 -14
  223. data/lib/graphql/schema/input_object.rb +178 -34
  224. data/lib/graphql/schema/interface.rb +35 -25
  225. data/lib/graphql/schema/introspection_system.rb +111 -35
  226. data/lib/graphql/schema/late_bound_type.rb +3 -2
  227. data/lib/graphql/schema/list.rb +65 -1
  228. data/lib/graphql/schema/loader.rb +147 -97
  229. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  230. data/lib/graphql/schema/member/base_dsl_methods.rb +40 -45
  231. data/lib/graphql/schema/member/build_type.rb +19 -8
  232. data/lib/graphql/schema/member/cached_graphql_definition.rb +34 -2
  233. data/lib/graphql/schema/member/has_arguments.rb +212 -22
  234. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  235. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  236. data/lib/graphql/schema/member/has_directives.rb +98 -0
  237. data/lib/graphql/schema/member/has_fields.rb +113 -28
  238. data/lib/graphql/schema/member/has_interfaces.rb +100 -0
  239. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  240. data/lib/graphql/schema/member/has_validators.rb +31 -0
  241. data/lib/graphql/schema/member/instrumentation.rb +6 -2
  242. data/lib/graphql/schema/member/relay_shortcuts.rb +2 -2
  243. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  244. data/lib/graphql/schema/member/validates_input.rb +33 -0
  245. data/lib/graphql/schema/member.rb +11 -0
  246. data/lib/graphql/schema/middleware_chain.rb +1 -1
  247. data/lib/graphql/schema/mutation.rb +5 -1
  248. data/lib/graphql/schema/non_null.rb +37 -1
  249. data/lib/graphql/schema/object.rb +52 -37
  250. data/lib/graphql/schema/possible_types.rb +12 -7
  251. data/lib/graphql/schema/printer.rb +17 -34
  252. data/lib/graphql/schema/relay_classic_mutation.rb +51 -7
  253. data/lib/graphql/schema/resolver/has_payload_type.rb +36 -5
  254. data/lib/graphql/schema/resolver.rb +159 -59
  255. data/lib/graphql/schema/scalar.rb +43 -3
  256. data/lib/graphql/schema/subscription.rb +83 -25
  257. data/lib/graphql/schema/timeout.rb +123 -0
  258. data/lib/graphql/schema/timeout_middleware.rb +6 -3
  259. data/lib/graphql/schema/traversal.rb +2 -2
  260. data/lib/graphql/schema/type_expression.rb +21 -13
  261. data/lib/graphql/schema/type_membership.rb +48 -0
  262. data/lib/graphql/schema/union.rb +67 -6
  263. data/lib/graphql/schema/unique_within_type.rb +1 -2
  264. data/lib/graphql/schema/validation.rb +30 -8
  265. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  266. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  267. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  268. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  269. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  270. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  271. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  272. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  273. data/lib/graphql/schema/validator.rb +171 -0
  274. data/lib/graphql/schema/warden.rb +263 -30
  275. data/lib/graphql/schema/wrapper.rb +1 -1
  276. data/lib/graphql/schema.rb +1016 -256
  277. data/lib/graphql/static_validation/all_rules.rb +2 -0
  278. data/lib/graphql/static_validation/base_visitor.rb +17 -10
  279. data/lib/graphql/static_validation/definition_dependencies.rb +21 -13
  280. data/lib/graphql/static_validation/error.rb +3 -1
  281. data/lib/graphql/static_validation/literal_validator.rb +52 -27
  282. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +46 -79
  283. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +23 -6
  284. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
  285. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  286. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  287. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -2
  288. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  289. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  290. data/lib/graphql/static_validation/rules/fields_will_merge.rb +105 -55
  291. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  292. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  293. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  294. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  295. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  296. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  297. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  298. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -3
  299. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
  300. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  301. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
  302. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
  303. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  304. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
  305. data/lib/graphql/static_validation/type_stack.rb +2 -2
  306. data/lib/graphql/static_validation/validation_context.rb +13 -3
  307. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  308. data/lib/graphql/static_validation/validator.rb +43 -9
  309. data/lib/graphql/static_validation.rb +1 -0
  310. data/lib/graphql/string_encoding_error.rb +13 -3
  311. data/lib/graphql/string_type.rb +1 -1
  312. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +123 -22
  313. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  314. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  315. data/lib/graphql/subscriptions/event.rb +94 -26
  316. data/lib/graphql/subscriptions/instrumentation.rb +10 -6
  317. data/lib/graphql/subscriptions/serialize.rb +53 -6
  318. data/lib/graphql/subscriptions/subscription_root.rb +15 -5
  319. data/lib/graphql/subscriptions.rb +122 -54
  320. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
  321. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  322. data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
  323. data/lib/graphql/tracing/data_dog_tracing.rb +32 -2
  324. data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
  325. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  326. data/lib/graphql/tracing/platform_tracing.rb +66 -7
  327. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  328. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  329. data/lib/graphql/tracing/scout_tracing.rb +19 -0
  330. data/lib/graphql/tracing/skylight_tracing.rb +9 -0
  331. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  332. data/lib/graphql/tracing.rb +15 -35
  333. data/lib/graphql/types/big_int.rb +5 -1
  334. data/lib/graphql/types/int.rb +10 -3
  335. data/lib/graphql/types/iso_8601_date.rb +42 -0
  336. data/lib/graphql/types/iso_8601_date_time.rb +32 -8
  337. data/lib/graphql/types/relay/base_connection.rb +6 -88
  338. data/lib/graphql/types/relay/base_edge.rb +2 -37
  339. data/lib/graphql/types/relay/connection_behaviors.rb +174 -0
  340. data/lib/graphql/types/relay/default_relay.rb +31 -0
  341. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  342. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  343. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  344. data/lib/graphql/types/relay/node.rb +2 -4
  345. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  346. data/lib/graphql/types/relay/node_field.rb +4 -23
  347. data/lib/graphql/types/relay/nodes_field.rb +16 -18
  348. data/lib/graphql/types/relay/page_info.rb +2 -14
  349. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  350. data/lib/graphql/types/relay.rb +11 -3
  351. data/lib/graphql/types/string.rb +8 -2
  352. data/lib/graphql/types.rb +1 -0
  353. data/lib/graphql/unauthorized_error.rb +2 -2
  354. data/lib/graphql/union_type.rb +61 -46
  355. data/lib/graphql/unresolved_type_error.rb +2 -2
  356. data/lib/graphql/upgrader/member.rb +150 -112
  357. data/lib/graphql/upgrader/schema.rb +1 -0
  358. data/lib/graphql/version.rb +1 -1
  359. data/lib/graphql.rb +89 -18
  360. data/readme.md +4 -7
  361. metadata +115 -703
  362. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  363. data/lib/graphql/literal_validation_error.rb +0 -6
  364. data/lib/graphql/types/relay/base_field.rb +0 -22
  365. data/lib/graphql/types/relay/base_interface.rb +0 -29
  366. data/lib/graphql/types/relay/base_object.rb +0 -26
  367. data/spec/dummy/Gemfile +0 -12
  368. data/spec/dummy/Gemfile.lock +0 -157
  369. data/spec/dummy/README.md +0 -24
  370. data/spec/dummy/Rakefile +0 -7
  371. data/spec/dummy/app/assets/config/manifest.js +0 -1
  372. data/spec/dummy/app/assets/javascripts/application.js +0 -66
  373. data/spec/dummy/app/channels/application_cable/channel.rb +0 -5
  374. data/spec/dummy/app/channels/application_cable/connection.rb +0 -5
  375. data/spec/dummy/app/channels/graphql_channel.rb +0 -116
  376. data/spec/dummy/app/controllers/application_controller.rb +0 -4
  377. data/spec/dummy/app/controllers/pages_controller.rb +0 -5
  378. data/spec/dummy/app/helpers/application_helper.rb +0 -3
  379. data/spec/dummy/app/jobs/application_job.rb +0 -3
  380. data/spec/dummy/app/views/layouts/application.html.erb +0 -12
  381. data/spec/dummy/app/views/pages/show.html +0 -16
  382. data/spec/dummy/bin/bundle +0 -4
  383. data/spec/dummy/bin/rails +0 -5
  384. data/spec/dummy/bin/rake +0 -5
  385. data/spec/dummy/bin/setup +0 -31
  386. data/spec/dummy/bin/update +0 -27
  387. data/spec/dummy/bin/yarn +0 -12
  388. data/spec/dummy/config/application.rb +0 -30
  389. data/spec/dummy/config/boot.rb +0 -4
  390. data/spec/dummy/config/cable.yml +0 -10
  391. data/spec/dummy/config/environment.rb +0 -6
  392. data/spec/dummy/config/environments/development.rb +0 -40
  393. data/spec/dummy/config/environments/production.rb +0 -76
  394. data/spec/dummy/config/environments/test.rb +0 -37
  395. data/spec/dummy/config/initializers/application_controller_renderer.rb +0 -9
  396. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -8
  397. data/spec/dummy/config/initializers/cookies_serializer.rb +0 -6
  398. data/spec/dummy/config/initializers/filter_parameter_logging.rb +0 -5
  399. data/spec/dummy/config/initializers/inflections.rb +0 -17
  400. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  401. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -10
  402. data/spec/dummy/config/locales/en.yml +0 -33
  403. data/spec/dummy/config/puma.rb +0 -57
  404. data/spec/dummy/config/routes.rb +0 -4
  405. data/spec/dummy/config/secrets.yml +0 -32
  406. data/spec/dummy/config.ru +0 -6
  407. data/spec/dummy/log/test.log +0 -199
  408. data/spec/dummy/package.json +0 -5
  409. data/spec/dummy/public/404.html +0 -67
  410. data/spec/dummy/public/422.html +0 -67
  411. data/spec/dummy/public/500.html +0 -66
  412. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  413. data/spec/dummy/public/apple-touch-icon.png +0 -0
  414. data/spec/dummy/public/favicon.ico +0 -0
  415. data/spec/dummy/public/robots.txt +0 -1
  416. data/spec/dummy/test/application_system_test_case.rb +0 -6
  417. data/spec/dummy/test/system/action_cable_subscription_test.rb +0 -45
  418. data/spec/dummy/test/test_helper.rb +0 -4
  419. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4w/4wzXRZrAkwKdgYaSE0pid5eB-fer8vSfSku_NPg4rMA.cache +0 -0
  420. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7I/7IHVBiJT06QSpgLpLoJIxboQ0B-D_tMTxsvoezBTV3Q.cache +0 -1
  421. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8w/8wY_SKagj8wHuwGNAAf6JnQ8joMbC6cEYpHrTAI8Urc.cache +0 -1
  422. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/AK/AKzz1u6bGb4auXcrObA_g5LL-oV0ejNGa448AgAi_WQ.cache +0 -1
  423. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ET/ETW4uxvaYpruL8y6_ZptUH82ZowMaHIqvg5WexBFdEM.cache +0 -3
  424. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F1/F1TWpjjyA56k9Z90n5B3xRn7DUdGjX73QCkYC6k07JQ.cache +0 -0
  425. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F8/F8MUNRzORGFgr329fNM0xLaoWCXdv3BIalT7dsvLfjs.cache +0 -2
  426. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KB/KB07ZaKNC5uXJ7TjLi-WqnY6g7dq8wWp_8N3HNjBNxg.cache +0 -2
  427. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ms/MsKSimH_UCB-H1tLvDABDHuvGciuoW6kVqQWDrXU5FQ.cache +0 -0
  428. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Mt/Mtci-Kim50aPOmeClD4AIicKn1d1WJ0n454IjSd94sk.cache +0 -0
  429. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QH/QHt3Tc1Y6M66Oo_pDuMyWrQNs4Pp3SMeZR5K1wJj2Ts.cache +0 -1
  430. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/XU/XU4k1OXnfMils5SrirorPvDSyDSqiOWLZNtmAH1HH8k.cache +0 -0
  431. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ZI/ZIof7mZxWWCnraIFOCuV6a8QRWzKJXJnx2Xd7C0ZyX0.cache +0 -1
  432. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cG/cGc_puuPS5pZKgUcy1Y_i1L6jl5UtsiIrMH59rTzR6c.cache +0 -3
  433. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/df/dfro_B6bx3KP1Go-7jEOqqZ2j4hVRseXIc3es9PKQno.cache +0 -1
  434. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/jO/jO1DfbqnG0mTULsjJJANc3fefrG2zt7DIMmcptMT628.cache +0 -1
  435. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/pE/pE7gO6pQ-z187Swb4hT554wmqsq-cNzgPWLrCz-LQQQ.cache +0 -0
  436. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/r9/r9iU1l58a6rxkZSW5RSC52_tD-_UQuHxoMVnkfJ7Mhs.cache +0 -1
  437. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xi/xitPPFfPIyDMpaznV0sBBcw8eSCV8PJcLLWin78sCgE.cache +0 -0
  438. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  439. data/spec/fixtures/upgrader/account.original.rb +0 -19
  440. data/spec/fixtures/upgrader/account.transformed.rb +0 -20
  441. data/spec/fixtures/upgrader/blame_range.original.rb +0 -43
  442. data/spec/fixtures/upgrader/blame_range.transformed.rb +0 -30
  443. data/spec/fixtures/upgrader/date_time.original.rb +0 -24
  444. data/spec/fixtures/upgrader/date_time.transformed.rb +0 -23
  445. data/spec/fixtures/upgrader/delete_project.original.rb +0 -28
  446. data/spec/fixtures/upgrader/delete_project.transformed.rb +0 -27
  447. data/spec/fixtures/upgrader/gist_order_field.original.rb +0 -14
  448. data/spec/fixtures/upgrader/gist_order_field.transformed.rb +0 -13
  449. data/spec/fixtures/upgrader/increment_count.original.rb +0 -59
  450. data/spec/fixtures/upgrader/increment_count.transformed.rb +0 -50
  451. data/spec/fixtures/upgrader/photo.original.rb +0 -10
  452. data/spec/fixtures/upgrader/photo.transformed.rb +0 -12
  453. data/spec/fixtures/upgrader/release_order.original.rb +0 -15
  454. data/spec/fixtures/upgrader/release_order.transformed.rb +0 -14
  455. data/spec/fixtures/upgrader/starrable.original.rb +0 -49
  456. data/spec/fixtures/upgrader/starrable.transformed.rb +0 -46
  457. data/spec/fixtures/upgrader/subscribable.original.rb +0 -55
  458. data/spec/fixtures/upgrader/subscribable.transformed.rb +0 -51
  459. data/spec/fixtures/upgrader/type_x.original.rb +0 -65
  460. data/spec/fixtures/upgrader/type_x.transformed.rb +0 -56
  461. data/spec/graphql/analysis/analyze_query_spec.rb +0 -272
  462. data/spec/graphql/analysis/ast/field_usage_spec.rb +0 -51
  463. data/spec/graphql/analysis/ast/max_query_complexity_spec.rb +0 -120
  464. data/spec/graphql/analysis/ast/max_query_depth_spec.rb +0 -114
  465. data/spec/graphql/analysis/ast/query_complexity_spec.rb +0 -299
  466. data/spec/graphql/analysis/ast/query_depth_spec.rb +0 -108
  467. data/spec/graphql/analysis/ast_spec.rb +0 -269
  468. data/spec/graphql/analysis/field_usage_spec.rb +0 -62
  469. data/spec/graphql/analysis/max_query_complexity_spec.rb +0 -102
  470. data/spec/graphql/analysis/max_query_depth_spec.rb +0 -101
  471. data/spec/graphql/analysis/query_complexity_spec.rb +0 -301
  472. data/spec/graphql/analysis/query_depth_spec.rb +0 -81
  473. data/spec/graphql/argument_spec.rb +0 -159
  474. data/spec/graphql/authorization_spec.rb +0 -974
  475. data/spec/graphql/backtrace_spec.rb +0 -206
  476. data/spec/graphql/base_type_spec.rb +0 -171
  477. data/spec/graphql/boolean_type_spec.rb +0 -21
  478. data/spec/graphql/compatibility/execution_specification_spec.rb +0 -4
  479. data/spec/graphql/compatibility/lazy_execution_specification_spec.rb +0 -4
  480. data/spec/graphql/compatibility/query_parser_specification_spec.rb +0 -6
  481. data/spec/graphql/compatibility/schema_parser_specification_spec.rb +0 -6
  482. data/spec/graphql/define/assign_argument_spec.rb +0 -61
  483. data/spec/graphql/define/instance_definable_spec.rb +0 -203
  484. data/spec/graphql/directive/skip_directive_spec.rb +0 -9
  485. data/spec/graphql/directive_spec.rb +0 -295
  486. data/spec/graphql/enum_type_spec.rb +0 -158
  487. data/spec/graphql/execution/execute_spec.rb +0 -303
  488. data/spec/graphql/execution/instrumentation_spec.rb +0 -184
  489. data/spec/graphql/execution/interpreter_spec.rb +0 -485
  490. data/spec/graphql/execution/lazy/lazy_method_map_spec.rb +0 -57
  491. data/spec/graphql/execution/lazy_spec.rb +0 -247
  492. data/spec/graphql/execution/lookahead_spec.rb +0 -390
  493. data/spec/graphql/execution/multiplex_spec.rb +0 -211
  494. data/spec/graphql/execution/typecast_spec.rb +0 -47
  495. data/spec/graphql/execution_error_spec.rb +0 -325
  496. data/spec/graphql/field_spec.rb +0 -246
  497. data/spec/graphql/float_type_spec.rb +0 -16
  498. data/spec/graphql/function_spec.rb +0 -152
  499. data/spec/graphql/id_type_spec.rb +0 -33
  500. data/spec/graphql/input_object_type_spec.rb +0 -25
  501. data/spec/graphql/int_type_spec.rb +0 -35
  502. data/spec/graphql/interface_type_spec.rb +0 -196
  503. data/spec/graphql/internal_representation/print_spec.rb +0 -41
  504. data/spec/graphql/internal_representation/rewrite_spec.rb +0 -376
  505. data/spec/graphql/introspection/directive_type_spec.rb +0 -61
  506. data/spec/graphql/introspection/input_value_type_spec.rb +0 -144
  507. data/spec/graphql/introspection/introspection_query_spec.rb +0 -59
  508. data/spec/graphql/introspection/schema_type_spec.rb +0 -56
  509. data/spec/graphql/introspection/type_type_spec.rb +0 -155
  510. data/spec/graphql/language/block_string_spec.rb +0 -70
  511. data/spec/graphql/language/definition_slice_spec.rb +0 -226
  512. data/spec/graphql/language/document_from_schema_definition_spec.rb +0 -770
  513. data/spec/graphql/language/equality_spec.rb +0 -84
  514. data/spec/graphql/language/generation_spec.rb +0 -38
  515. data/spec/graphql/language/lexer_spec.rb +0 -135
  516. data/spec/graphql/language/nodes_spec.rb +0 -67
  517. data/spec/graphql/language/parser_spec.rb +0 -183
  518. data/spec/graphql/language/printer_spec.rb +0 -215
  519. data/spec/graphql/language/visitor_spec.rb +0 -419
  520. data/spec/graphql/list_type_spec.rb +0 -57
  521. data/spec/graphql/non_null_type_spec.rb +0 -48
  522. data/spec/graphql/object_type_spec.rb +0 -197
  523. data/spec/graphql/query/arguments_spec.rb +0 -346
  524. data/spec/graphql/query/context_spec.rb +0 -292
  525. data/spec/graphql/query/executor_spec.rb +0 -341
  526. data/spec/graphql/query/literal_input_spec.rb +0 -91
  527. data/spec/graphql/query/result_spec.rb +0 -29
  528. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +0 -109
  529. data/spec/graphql/query_spec.rb +0 -800
  530. data/spec/graphql/rake_task_spec.rb +0 -59
  531. data/spec/graphql/scalar_type_spec.rb +0 -66
  532. data/spec/graphql/schema/argument_spec.rb +0 -152
  533. data/spec/graphql/schema/build_from_definition_spec.rb +0 -1187
  534. data/spec/graphql/schema/catchall_middleware_spec.rb +0 -35
  535. data/spec/graphql/schema/directive/feature_spec.rb +0 -81
  536. data/spec/graphql/schema/directive/transform_spec.rb +0 -39
  537. data/spec/graphql/schema/enum_spec.rb +0 -83
  538. data/spec/graphql/schema/enum_value_spec.rb +0 -24
  539. data/spec/graphql/schema/field_extension_spec.rb +0 -137
  540. data/spec/graphql/schema/field_spec.rb +0 -301
  541. data/spec/graphql/schema/finder_spec.rb +0 -135
  542. data/spec/graphql/schema/input_object_spec.rb +0 -347
  543. data/spec/graphql/schema/instrumentation_spec.rb +0 -43
  544. data/spec/graphql/schema/interface_spec.rb +0 -215
  545. data/spec/graphql/schema/introspection_system_spec.rb +0 -56
  546. data/spec/graphql/schema/list_spec.rb +0 -46
  547. data/spec/graphql/schema/loader_spec.rb +0 -286
  548. data/spec/graphql/schema/member/accepts_definition_spec.rb +0 -115
  549. data/spec/graphql/schema/member/build_type_spec.rb +0 -63
  550. data/spec/graphql/schema/member/scoped_spec.rb +0 -217
  551. data/spec/graphql/schema/member/type_system_helpers_spec.rb +0 -63
  552. data/spec/graphql/schema/middleware_chain_spec.rb +0 -57
  553. data/spec/graphql/schema/mutation_spec.rb +0 -150
  554. data/spec/graphql/schema/non_null_spec.rb +0 -46
  555. data/spec/graphql/schema/object_spec.rb +0 -315
  556. data/spec/graphql/schema/printer_spec.rb +0 -869
  557. data/spec/graphql/schema/relay_classic_mutation_spec.rb +0 -252
  558. data/spec/graphql/schema/rescue_middleware_spec.rb +0 -88
  559. data/spec/graphql/schema/resolver_spec.rb +0 -714
  560. data/spec/graphql/schema/scalar_spec.rb +0 -101
  561. data/spec/graphql/schema/subscription_spec.rb +0 -440
  562. data/spec/graphql/schema/timeout_middleware_spec.rb +0 -188
  563. data/spec/graphql/schema/traversal_spec.rb +0 -222
  564. data/spec/graphql/schema/type_expression_spec.rb +0 -39
  565. data/spec/graphql/schema/union_spec.rb +0 -72
  566. data/spec/graphql/schema/unique_within_type_spec.rb +0 -44
  567. data/spec/graphql/schema/validation_spec.rb +0 -355
  568. data/spec/graphql/schema/warden_spec.rb +0 -926
  569. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +0 -413
  570. data/spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb +0 -44
  571. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +0 -112
  572. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +0 -35
  573. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +0 -42
  574. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +0 -167
  575. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +0 -66
  576. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +0 -740
  577. data/spec/graphql/static_validation/rules/fragment_names_are_unique_spec.rb +0 -28
  578. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +0 -52
  579. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +0 -42
  580. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +0 -123
  581. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +0 -24
  582. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +0 -56
  583. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +0 -61
  584. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +0 -39
  585. data/spec/graphql/static_validation/rules/no_definitions_are_present_spec.rb +0 -62
  586. data/spec/graphql/static_validation/rules/operation_names_are_valid_spec.rb +0 -82
  587. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +0 -73
  588. data/spec/graphql/static_validation/rules/required_input_object_attributes_are_present_spec.rb +0 -86
  589. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +0 -34
  590. data/spec/graphql/static_validation/rules/unique_directives_per_location_spec.rb +0 -188
  591. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +0 -196
  592. data/spec/graphql/static_validation/rules/variable_names_are_unique_spec.rb +0 -23
  593. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +0 -236
  594. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +0 -78
  595. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +0 -81
  596. data/spec/graphql/static_validation/type_stack_spec.rb +0 -29
  597. data/spec/graphql/static_validation/validator_spec.rb +0 -204
  598. data/spec/graphql/string_type_spec.rb +0 -80
  599. data/spec/graphql/subscriptions/serialize_spec.rb +0 -49
  600. data/spec/graphql/subscriptions_spec.rb +0 -540
  601. data/spec/graphql/tracing/new_relic_tracing_spec.rb +0 -84
  602. data/spec/graphql/tracing/platform_tracing_spec.rb +0 -141
  603. data/spec/graphql/tracing/prometheus_tracing_spec.rb +0 -42
  604. data/spec/graphql/tracing/scout_tracing_spec.rb +0 -17
  605. data/spec/graphql/tracing/skylight_tracing_spec.rb +0 -63
  606. data/spec/graphql/tracing_spec.rb +0 -52
  607. data/spec/graphql/types/big_int_spec.rb +0 -24
  608. data/spec/graphql/types/iso_8601_date_time_spec.rb +0 -137
  609. data/spec/graphql/types/relay/base_edge_spec.rb +0 -33
  610. data/spec/graphql/union_type_spec.rb +0 -211
  611. data/spec/graphql/upgrader/member_spec.rb +0 -583
  612. data/spec/graphql/upgrader/schema_spec.rb +0 -82
  613. data/spec/integration/mongoid/graphql/relay/mongo_relation_connection_spec.rb +0 -528
  614. data/spec/integration/mongoid/spec_helper.rb +0 -2
  615. data/spec/integration/mongoid/star_trek/data.rb +0 -126
  616. data/spec/integration/mongoid/star_trek/schema.rb +0 -425
  617. data/spec/integration/rails/data.rb +0 -110
  618. data/spec/integration/rails/generators/base_generator_test.rb +0 -7
  619. data/spec/integration/rails/generators/graphql/enum_generator_spec.rb +0 -30
  620. data/spec/integration/rails/generators/graphql/install_generator_spec.rb +0 -218
  621. data/spec/integration/rails/generators/graphql/interface_generator_spec.rb +0 -34
  622. data/spec/integration/rails/generators/graphql/loader_generator_spec.rb +0 -59
  623. data/spec/integration/rails/generators/graphql/mutation_generator_spec.rb +0 -71
  624. data/spec/integration/rails/generators/graphql/object_generator_spec.rb +0 -54
  625. data/spec/integration/rails/generators/graphql/scalar_generator_spec.rb +0 -28
  626. data/spec/integration/rails/generators/graphql/union_generator_spec.rb +0 -67
  627. data/spec/integration/rails/graphql/input_object_type_spec.rb +0 -364
  628. data/spec/integration/rails/graphql/query/variables_spec.rb +0 -375
  629. data/spec/integration/rails/graphql/relay/array_connection_spec.rb +0 -290
  630. data/spec/integration/rails/graphql/relay/base_connection_spec.rb +0 -101
  631. data/spec/integration/rails/graphql/relay/connection_instrumentation_spec.rb +0 -80
  632. data/spec/integration/rails/graphql/relay/connection_resolve_spec.rb +0 -79
  633. data/spec/integration/rails/graphql/relay/connection_type_spec.rb +0 -106
  634. data/spec/integration/rails/graphql/relay/edge_spec.rb +0 -10
  635. data/spec/integration/rails/graphql/relay/mutation_spec.rb +0 -387
  636. data/spec/integration/rails/graphql/relay/node_spec.rb +0 -263
  637. data/spec/integration/rails/graphql/relay/page_info_spec.rb +0 -111
  638. data/spec/integration/rails/graphql/relay/range_add_spec.rb +0 -117
  639. data/spec/integration/rails/graphql/relay/relation_connection_spec.rb +0 -837
  640. data/spec/integration/rails/graphql/schema_spec.rb +0 -489
  641. data/spec/integration/rails/graphql/tracing/active_support_notifications_tracing_spec.rb +0 -62
  642. data/spec/integration/rails/spec_helper.rb +0 -25
  643. data/spec/integration/tmp/app/graphql/types/bird_type.rb +0 -7
  644. data/spec/spec_helper.rb +0 -116
  645. data/spec/support/dummy/data.rb +0 -45
  646. data/spec/support/dummy/schema.rb +0 -511
  647. data/spec/support/error_bubbling_helpers.rb +0 -23
  648. data/spec/support/global_id.rb +0 -23
  649. data/spec/support/jazz.rb +0 -772
  650. data/spec/support/lazy_helpers.rb +0 -192
  651. data/spec/support/magic_cards/schema.graphql +0 -33
  652. data/spec/support/minimum_input_object.rb +0 -21
  653. data/spec/support/new_relic.rb +0 -27
  654. data/spec/support/parser/filename_example.graphql +0 -5
  655. data/spec/support/parser/filename_example_error_1.graphql +0 -4
  656. data/spec/support/parser/filename_example_error_2.graphql +0 -5
  657. data/spec/support/skylight.rb +0 -39
  658. data/spec/support/star_wars/schema.rb +0 -465
  659. data/spec/support/static_validation_helpers.rb +0 -32
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # test_via: ../object.rb
3
2
  require "graphql/schema/field/connection_extension"
4
3
  require "graphql/schema/field/scope_extension"
5
4
 
@@ -9,7 +8,15 @@ module GraphQL
9
8
  include GraphQL::Schema::Member::CachedGraphQLDefinition
10
9
  include GraphQL::Schema::Member::AcceptsDefinition
11
10
  include GraphQL::Schema::Member::HasArguments
11
+ include GraphQL::Schema::Member::HasAstNode
12
12
  include GraphQL::Schema::Member::HasPath
13
+ include GraphQL::Schema::Member::HasValidators
14
+ extend GraphQL::Schema::FindInheritedValue
15
+ include GraphQL::Schema::FindInheritedValue::EmptyObjects
16
+ include GraphQL::Schema::Member::HasDirectives
17
+ include GraphQL::Schema::Member::HasDeprecationReason
18
+
19
+ class FieldImplementationFailed < GraphQL::Error; end
13
20
 
14
21
  # @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
15
22
  attr_reader :name
@@ -17,9 +24,6 @@ module GraphQL
17
24
 
18
25
  attr_writer :description
19
26
 
20
- # @return [String, nil] If present, the field is marked as deprecated with this documentation
21
- attr_accessor :deprecation_reason
22
-
23
27
  # @return [Symbol] Method or hash key on the underlying object to look up
24
28
  attr_reader :method_sym
25
29
 
@@ -29,10 +33,21 @@ module GraphQL
29
33
  # @return [Symbol] The method on the type to look up
30
34
  attr_reader :resolver_method
31
35
 
32
- # @return [Class] The type that this field belongs to
33
- attr_reader :owner
36
+ # @return [Class] The thing this field was defined on (type, mutation, resolver)
37
+ attr_accessor :owner
38
+
39
+ # @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
40
+ def owner_type
41
+ @owner_type ||= if owner.nil?
42
+ raise GraphQL::InvariantError, "Field #{original_name.inspect} (graphql name: #{graphql_name.inspect}) has no owner, but all fields should have an owner. How did this happen?!"
43
+ elsif owner < GraphQL::Schema::Mutation
44
+ owner.payload_type
45
+ else
46
+ owner
47
+ end
48
+ end
34
49
 
35
- # @return [Symobol] the original name of the field, passed in by the user
50
+ # @return [Symbol] the original name of the field, passed in by the user
36
51
  attr_reader :original_name
37
52
 
38
53
  # @return [Class, nil] The {Schema::Resolver} this field was derived from, if there is one
@@ -40,16 +55,22 @@ module GraphQL
40
55
  @resolver_class
41
56
  end
42
57
 
43
- alias :mutation :resolver
58
+ # @return [Boolean] Is this field a predefined introspection field?
59
+ def introspection?
60
+ @introspection
61
+ end
44
62
 
45
- # @return [Array<Symbol>]
46
- attr_reader :extras
63
+ def inspect
64
+ "#<#{self.class} #{path}#{all_argument_definitions.any? ? "(...)" : ""}: #{type.to_type_signature}>"
65
+ end
66
+
67
+ alias :mutation :resolver
47
68
 
48
69
  # @return [Boolean] Apply tracing to this field? (Default: skip scalars, this is the override value)
49
70
  attr_reader :trace
50
71
 
51
72
  # @return [String, nil]
52
- attr_reader :subscription_scope
73
+ attr_accessor :subscription_scope
53
74
 
54
75
  # Create a field instance from a list of arguments, keyword arguments, and a block.
55
76
  #
@@ -64,11 +85,11 @@ module GraphQL
64
85
  # @see {.initialize} for other options
65
86
  def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
66
87
  if kwargs[:field]
67
- if kwargs[:field] == GraphQL::Relay::Node.field
68
- warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
88
+ if kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodeField.graphql_definition
89
+ GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
69
90
  return GraphQL::Types::Relay::NodeField
70
- elsif kwargs[:field] == GraphQL::Relay::Node.plural_field
71
- warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
91
+ elsif kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodesField.graphql_definition
92
+ GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
72
93
  return GraphQL::Types::Relay::NodesField
73
94
  end
74
95
  end
@@ -101,6 +122,9 @@ module GraphQL
101
122
  else
102
123
  kwargs[:type] = type
103
124
  end
125
+ if type.is_a?(Class) && type < GraphQL::Schema::Mutation
126
+ raise ArgumentError, "Use `field #{name.inspect}, mutation: Mutation, ...` to provide a mutation to this field instead"
127
+ end
104
128
  end
105
129
  new(**kwargs, &block)
106
130
  end
@@ -134,6 +158,32 @@ module GraphQL
134
158
  end
135
159
  end
136
160
 
161
+ # This extension is applied to fields when {#connection?} is true.
162
+ #
163
+ # You can override it in your base field definition.
164
+ # @return [Class] A {FieldExtension} subclass for implementing pagination behavior.
165
+ # @example Configuring a custom extension
166
+ # class Types::BaseField < GraphQL::Schema::Field
167
+ # connection_extension(MyCustomExtension)
168
+ # end
169
+ def self.connection_extension(new_extension_class = nil)
170
+ if new_extension_class
171
+ @connection_extension = new_extension_class
172
+ else
173
+ @connection_extension ||= find_inherited_value(:connection_extension, ConnectionExtension)
174
+ end
175
+ end
176
+
177
+ # @return Boolean
178
+ attr_reader :relay_node_field
179
+ # @return Boolean
180
+ attr_reader :relay_nodes_field
181
+
182
+ # @return [Boolean] Should we warn if this field's name conflicts with a built-in method?
183
+ def method_conflict_warning?
184
+ @method_conflict_warning
185
+ end
186
+
137
187
  # @param name [Symbol] The underscore-cased version of this field name (will be camelized for the GraphQL API)
138
188
  # @param type [Class, GraphQL::BaseType, Array] The return type of this field
139
189
  # @param owner [Class] The type that this field belongs to
@@ -142,9 +192,11 @@ module GraphQL
142
192
  # @param deprecation_reason [String] If present, the field is marked "deprecated" with this message
143
193
  # @param method [Symbol] The method to call on the underlying object to resolve this field (defaults to `name`)
144
194
  # @param hash_key [String, Symbol] The hash key to lookup on the underlying object (if its a Hash) to resolve this field (defaults to `name` or `name.to_s`)
195
+ # @param dig [Array<String, Symbol>] The nested hash keys to lookup on the underlying hash to resolve this field using dig
145
196
  # @param resolver_method [Symbol] The method on the type to call to resolve this field (defaults to `name`)
146
197
  # @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
147
- # @param max_page_size [Integer] For connections, the maximum number of items to return from this field
198
+ # @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
199
+ # @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
148
200
  # @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
149
201
  # @param resolve [<#call(obj, args, ctx)>] **deprecated** for compatibility with <1.8.0
150
202
  # @param field [GraphQL::Field, GraphQL::Schema::Field] **deprecated** for compatibility with <1.8.0
@@ -155,9 +207,15 @@ module GraphQL
155
207
  # @param complexity [Numeric] When provided, set the complexity for this field
156
208
  # @param scope [Boolean] If true, the return type's `.scope_items` method will be called on the return value
157
209
  # @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
158
- # @param extensions [Array<Class>] Named extensions to apply to this field (see also {#extension})
210
+ # @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
211
+ # @param directives [Hash{Class => Hash}] Directives to apply to this field
159
212
  # @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
160
- def initialize(type: nil, name: nil, owner: nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: nil, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, extras: [], extensions: [], resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, arguments: {}, &definition_block)
213
+ # @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
214
+ # @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
215
+ # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
216
+ # @param validates [Array<Hash>] Configurations for validating this field
217
+ # @param legacy_edge_class [Class, nil] (DEPRECATED) If present, pass this along to the legacy field definition
218
+ def initialize(type: nil, name: nil, owner: nil, null: true, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, legacy_edge_class: nil, &definition_block)
161
219
  if name.nil?
162
220
  raise ArgumentError, "missing first `name` argument or keyword `name:`"
163
221
  end
@@ -165,16 +223,15 @@ module GraphQL
165
223
  if type.nil?
166
224
  raise ArgumentError, "missing second `type` argument or keyword `type:`"
167
225
  end
168
- if null.nil?
169
- raise ArgumentError, "missing keyword argument null:"
170
- end
171
226
  end
172
227
  if (field || function || resolve) && extras.any?
173
228
  raise ArgumentError, "keyword `extras:` may only be used with method-based resolve and class-based field such as mutation class, please remove `field:`, `function:` or `resolve:`"
174
229
  end
175
230
  @original_name = name
176
- @underscored_name = -Member::BuildType.underscore(name.to_s)
177
- @name = -(camelize ? Member::BuildType.camelize(name.to_s) : name.to_s)
231
+ name_s = -name.to_s
232
+
233
+ @underscored_name = -Member::BuildType.underscore(name_s)
234
+ @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
178
235
  @description = description
179
236
  if field.is_a?(GraphQL::Schema::Field)
180
237
  raise ArgumentError, "Instead of passing a field as `field:`, use `add_field(field)` to add an already-defined field."
@@ -183,10 +240,10 @@ module GraphQL
183
240
  end
184
241
  @function = function
185
242
  @resolve = resolve
186
- @deprecation_reason = deprecation_reason
243
+ self.deprecation_reason = deprecation_reason
187
244
 
188
- if method && hash_key
189
- raise ArgumentError, "Provide `method:` _or_ `hash_key:`, not both. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}`)"
245
+ if method && hash_key && dig
246
+ raise ArgumentError, "Provide `method:`, `hash_key:` _or_ `dig:`, not multiple. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}, dig: #{dig.inspect}`)"
190
247
  end
191
248
 
192
249
  if resolver_method
@@ -194,60 +251,84 @@ module GraphQL
194
251
  raise ArgumentError, "Provide `method:` _or_ `resolver_method:`, not both. (called with: `method: #{method.inspect}, resolver_method: #{resolver_method.inspect}`)"
195
252
  end
196
253
 
197
- if hash_key
198
- raise ArgumentError, "Provide `hash_key:` _or_ `resolver_method:`, not both. (called with: `hash_key: #{hash_key.inspect}, resolver_method: #{resolver_method.inspect}`)"
254
+ if hash_key || dig
255
+ raise ArgumentError, "Provide `hash_key:`, `dig:`, _or_ `resolver_method:`, not multiple. (called with: `hash_key: #{hash_key.inspect}, dig: #{dig.inspect}, resolver_method: #{resolver_method.inspect}`)"
199
256
  end
200
257
  end
201
258
 
202
259
  # TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
203
- method_name = method || hash_key || @underscored_name
204
- resolver_method ||= @underscored_name
260
+ method_name = method || hash_key || name_s
261
+ @dig_keys = dig
262
+ if hash_key
263
+ @hash_key = hash_key
264
+ end
265
+
266
+ resolver_method ||= name_s.to_sym
205
267
 
206
- @method_str = method_name.to_s
268
+ @method_str = -method_name.to_s
207
269
  @method_sym = method_name.to_sym
208
270
  @resolver_method = resolver_method
209
271
  @complexity = complexity
210
272
  @return_type_expr = type
211
273
  @return_type_null = null
212
274
  @connection = connection
213
- @max_page_size = max_page_size
275
+ @has_max_page_size = max_page_size != :not_given
276
+ @max_page_size = max_page_size == :not_given ? nil : max_page_size
214
277
  @introspection = introspection
215
278
  @extras = extras
279
+ @broadcastable = broadcastable
216
280
  @resolver_class = resolver_class
217
281
  @scope = scope
218
282
  @trace = trace
219
283
  @relay_node_field = relay_node_field
220
284
  @relay_nodes_field = relay_nodes_field
285
+ @ast_node = ast_node
286
+ @method_conflict_warning = method_conflict_warning
287
+ @legacy_edge_class = legacy_edge_class
221
288
 
222
- # Override the default from HasArguments
223
- @own_arguments = {}
224
289
  arguments.each do |name, arg|
225
- if arg.is_a?(Hash)
290
+ case arg
291
+ when Hash
226
292
  argument(name: name, **arg)
293
+ when GraphQL::Schema::Argument
294
+ add_argument(arg)
295
+ when Array
296
+ arg.each { |a| add_argument(a) }
227
297
  else
228
- @own_arguments[name] = arg
298
+ raise ArgumentError, "Unexpected argument config (#{arg.class}): #{arg.inspect}"
229
299
  end
230
300
  end
231
301
 
232
302
  @owner = owner
233
303
  @subscription_scope = subscription_scope
234
304
 
235
- # Do this last so we have as much context as possible when initializing them:
236
- @extensions = []
237
- if extensions.any?
238
- self.extensions(extensions)
239
- end
305
+ @extensions = EMPTY_ARRAY
306
+ @call_after_define = false
240
307
  # This should run before connection extension,
241
308
  # but should it run after the definition block?
242
309
  if scoped?
243
310
  self.extension(ScopeExtension)
244
311
  end
312
+
245
313
  # The problem with putting this after the definition_block
246
314
  # is that it would override arguments
247
- if connection?
248
- self.extension(ConnectionExtension)
315
+ if connection? && connection_extension
316
+ self.extension(connection_extension)
249
317
  end
250
318
 
319
+ # Do this last so we have as much context as possible when initializing them:
320
+ if extensions.any?
321
+ self.extensions(extensions)
322
+ end
323
+
324
+ if directives.any?
325
+ directives.each do |(dir_class, options)|
326
+ self.directive(dir_class, **options)
327
+ end
328
+ end
329
+
330
+ self.validates(validates)
331
+
251
332
  if definition_block
252
333
  if definition_block.arity == 1
253
334
  yield self
@@ -255,6 +336,16 @@ module GraphQL
255
336
  instance_eval(&definition_block)
256
337
  end
257
338
  end
339
+
340
+ self.extensions.each(&:after_define_apply)
341
+ @call_after_define = true
342
+ end
343
+
344
+ # If true, subscription updates with this field can be shared between viewers
345
+ # @return [Boolean, nil]
346
+ # @see GraphQL::Subscriptions::BroadcastAnalyzer
347
+ def broadcastable?
348
+ @broadcastable
258
349
  end
259
350
 
260
351
  # @param text [String]
@@ -269,39 +360,140 @@ module GraphQL
269
360
 
270
361
  # Read extension instances from this field,
271
362
  # or add new classes/options to be initialized on this field.
363
+ # Extensions are executed in the order they are added.
364
+ #
365
+ # @example adding an extension
366
+ # extensions([MyExtensionClass])
272
367
  #
273
- # @param extensions [Array<Class>, Hash<Class => Object>] Add extensions to this field
368
+ # @example adding multiple extensions
369
+ # extensions([MyExtensionClass, AnotherExtensionClass])
370
+ #
371
+ # @example adding an extension with options
372
+ # extensions([MyExtensionClass, { AnotherExtensionClass => { filter: true } }])
373
+ #
374
+ # @param extensions [Array<Class, Hash<Class => Hash>>] Add extensions to this field. For hash elements, only the first key/value is used.
274
375
  # @return [Array<GraphQL::Schema::FieldExtension>] extensions to apply to this field
275
376
  def extensions(new_extensions = nil)
276
- if new_extensions.nil?
377
+ if new_extensions
378
+ new_extensions.each do |extension_config|
379
+ if extension_config.is_a?(Hash)
380
+ extension_class, options = *extension_config.to_a[0]
381
+ self.extension(extension_class, options)
382
+ else
383
+ self.extension(extension_config)
384
+ end
385
+ end
386
+ end
387
+ @extensions
388
+ end
389
+
390
+ # Add `extension` to this field, initialized with `options` if provided.
391
+ #
392
+ # @example adding an extension
393
+ # extension(MyExtensionClass)
394
+ #
395
+ # @example adding an extension with options
396
+ # extension(MyExtensionClass, filter: true)
397
+ #
398
+ # @param extension_class [Class] subclass of {Schema::FieldExtension}
399
+ # @param options [Hash] if provided, given as `options:` when initializing `extension`.
400
+ # @return [void]
401
+ def extension(extension_class, options = nil)
402
+ extension_inst = extension_class.new(field: self, options: options)
403
+ if @extensions.frozen?
404
+ @extensions = @extensions.dup
405
+ end
406
+ if @call_after_define
407
+ extension_inst.after_define_apply
408
+ end
409
+ @extensions << extension_inst
410
+ nil
411
+ end
412
+
413
+ # Read extras (as symbols) from this field,
414
+ # or add new extras to be opted into by this field's resolver.
415
+ #
416
+ # @param new_extras [Array<Symbol>] Add extras to this field
417
+ # @return [Array<Symbol>]
418
+ def extras(new_extras = nil)
419
+ if new_extras.nil?
277
420
  # Read the value
278
- @extensions
421
+ @extras
279
422
  else
280
- # Normalize to a Hash of {name => options}
281
- extensions_with_options = if new_extensions.last.is_a?(Hash)
282
- new_extensions.pop
283
- else
284
- {}
423
+ if @extras.frozen?
424
+ @extras = @extras.dup
285
425
  end
286
- new_extensions.each do |f|
287
- extensions_with_options[f] = nil
426
+ # Append to the set of extras on this field
427
+ @extras.concat(new_extras)
428
+ end
429
+ end
430
+
431
+ def calculate_complexity(query:, nodes:, child_complexity:)
432
+ if respond_to?(:complexity_for)
433
+ lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
434
+ complexity_for(child_complexity: child_complexity, query: query, lookahead: lookahead)
435
+ elsif connection?
436
+ arguments = query.arguments_for(nodes.first, self)
437
+ max_possible_page_size = nil
438
+ if arguments.respond_to?(:[]) # It might have been an error
439
+ if arguments[:first]
440
+ max_possible_page_size = arguments[:first]
441
+ end
442
+
443
+ if arguments[:last] && (max_possible_page_size.nil? || arguments[:last] > max_possible_page_size)
444
+ max_possible_page_size = arguments[:last]
445
+ end
288
446
  end
289
447
 
290
- # Initialize each class and stash the instance
291
- extensions_with_options.each do |extension_class, options|
292
- @extensions << extension_class.new(field: self, options: options)
448
+ if max_possible_page_size.nil?
449
+ max_possible_page_size = max_page_size || query.schema.default_max_page_size
293
450
  end
294
- end
295
- end
296
451
 
297
- # Add `extension` to this field, initialized with `options` if provided.
298
- # @param extension [Class] subclass of {Schema::Fieldextension}
299
- # @param options [Object] if provided, given as `options:` when initializing `extension`.
300
- def extension(extension, options = nil)
301
- extensions([{extension => options}])
452
+ if max_possible_page_size.nil?
453
+ raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
454
+ else
455
+ metadata_complexity = 0
456
+ lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
457
+
458
+ if (page_info_lookahead = lookahead.selection(:page_info)).selected?
459
+ metadata_complexity += 1 # pageInfo
460
+ metadata_complexity += page_info_lookahead.selections.size # subfields
461
+ end
462
+
463
+ if lookahead.selects?(:total) || lookahead.selects?(:total_count) || lookahead.selects?(:count)
464
+ metadata_complexity += 1
465
+ end
466
+
467
+ nodes_edges_complexity = 0
468
+ nodes_edges_complexity += 1 if lookahead.selects?(:edges)
469
+ nodes_edges_complexity += 1 if lookahead.selects?(:nodes)
470
+
471
+ # Possible bug: selections on `edges` and `nodes` are _both_ multiplied here. Should they be?
472
+ items_complexity = child_complexity - metadata_complexity - nodes_edges_complexity
473
+ # Add 1 for _this_ field
474
+ 1 + (max_possible_page_size * items_complexity) + metadata_complexity + nodes_edges_complexity
475
+ end
476
+ else
477
+ defined_complexity = complexity
478
+ case defined_complexity
479
+ when Proc
480
+ arguments = query.arguments_for(nodes.first, self)
481
+ if arguments.is_a?(GraphQL::ExecutionError)
482
+ return child_complexity
483
+ elsif arguments.respond_to?(:keyword_arguments)
484
+ arguments = arguments.keyword_arguments
485
+ end
486
+
487
+ defined_complexity.call(query.context, arguments, child_complexity)
488
+ when Numeric
489
+ defined_complexity + child_complexity
490
+ else
491
+ raise("Invalid complexity: #{defined_complexity.inspect} on #{path} (#{inspect})")
492
+ end
493
+ end
302
494
  end
303
495
 
304
- def complexity(new_complexity)
496
+ def complexity(new_complexity = nil)
305
497
  case new_complexity
306
498
  when Proc
307
499
  if new_complexity.parameters.size != 3
@@ -314,14 +506,23 @@ module GraphQL
314
506
  end
315
507
  when Numeric
316
508
  @complexity = new_complexity
509
+ when nil
510
+ @complexity
317
511
  else
318
512
  raise("Invalid complexity: #{new_complexity.inspect} on #{@name}")
319
513
  end
320
514
  end
321
515
 
322
- # @return [Integer, nil] Applied to connections if present
516
+ # @return [Boolean] True if this field's {#max_page_size} should override the schema default.
517
+ def has_max_page_size?
518
+ @has_max_page_size
519
+ end
520
+
521
+ # @return [Integer, nil] Applied to connections if {#has_max_page_size?}
323
522
  attr_reader :max_page_size
324
523
 
524
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
525
+
325
526
  # @return [GraphQL::Field]
326
527
  def to_graphql
327
528
  field_defn = if @field
@@ -341,8 +542,8 @@ module GraphQL
341
542
  field_defn.description = @description
342
543
  end
343
544
 
344
- if @deprecation_reason
345
- field_defn.deprecation_reason = @deprecation_reason
545
+ if self.deprecation_reason
546
+ field_defn.deprecation_reason = self.deprecation_reason
346
547
  end
347
548
 
348
549
  if @resolver_class
@@ -364,16 +565,21 @@ module GraphQL
364
565
  field_defn.relay_nodes_field = @relay_nodes_field
365
566
  end
366
567
 
568
+ if @legacy_edge_class
569
+ field_defn.edge_class = @legacy_edge_class
570
+ end
571
+
367
572
  field_defn.resolve = self.method(:resolve_field)
368
573
  field_defn.connection = connection?
369
574
  field_defn.connection_max_page_size = max_page_size
370
575
  field_defn.introspection = @introspection
371
576
  field_defn.complexity = @complexity
372
577
  field_defn.subscription_scope = @subscription_scope
578
+ field_defn.ast_node = ast_node
373
579
 
374
- arguments.each do |name, defn|
375
- arg_graphql = defn.to_graphql
376
- field_defn.arguments[arg_graphql.name] = arg_graphql
580
+ all_argument_definitions.each do |defn|
581
+ arg_graphql = defn.deprecated_to_graphql
582
+ field_defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
377
583
  end
378
584
 
379
585
  # Support a passed-in proc, one way or another
@@ -387,14 +593,33 @@ module GraphQL
387
593
 
388
594
  # Ok, `self` isn't a class, but this is for consistency with the classes
389
595
  field_defn.metadata[:type_class] = self
390
-
596
+ field_defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(field_defn)
391
597
  field_defn
392
598
  end
393
599
 
600
+ class MissingReturnTypeError < GraphQL::Error; end
601
+ attr_writer :type
602
+
394
603
  def type
395
- @type ||= Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
396
- rescue
397
- raise ArgumentError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: #{$!.message}", $!.backtrace
604
+ @type ||= if @function
605
+ Member::BuildType.parse_type(@function.type, null: false)
606
+ elsif @field
607
+ Member::BuildType.parse_type(@field.type, null: false)
608
+ elsif @return_type_expr.nil?
609
+ # Not enough info to determine type
610
+ message = "Can't determine the return type for #{self.path}"
611
+ if @resolver_class
612
+ message += " (it has `resolver: #{@resolver_class}`, consider configuration a `type ...` for that class)"
613
+ end
614
+ raise MissingReturnTypeError, message
615
+ else
616
+ Member::BuildType.parse_type(@return_type_expr, null: @return_type_null)
617
+ end
618
+ rescue GraphQL::Schema::InvalidDocumentError, MissingReturnTypeError => err
619
+ # Let this propagate up
620
+ raise err
621
+ rescue StandardError => err
622
+ raise MissingReturnTypeError, "Failed to build return type for #{@owner.graphql_name}.#{name} from #{@return_type_expr.inspect}: (#{err.class}) #{err.message}", err.backtrace
398
623
  end
399
624
 
400
625
  def visible?(context)
@@ -413,23 +638,46 @@ module GraphQL
413
638
  end
414
639
  end
415
640
 
416
- def authorized?(object, context)
417
- self_auth = if @resolver_class
641
+ def authorized?(object, args, context)
642
+ if @resolver_class
643
+ # The resolver _instance_ will check itself during `resolve()`
418
644
  @resolver_class.authorized?(object, context)
419
645
  else
420
- true
421
- end
646
+ if (arg_values = context[:current_arguments])
647
+ # ^^ that's provided by the interpreter at runtime, and includes info about whether the default value was used or not.
648
+ using_arg_values = true
649
+ arg_values = arg_values.argument_values
650
+ else
651
+ arg_values = args
652
+ using_arg_values = false
653
+ end
654
+ if args.size > 0
655
+ args = context.warden.arguments(self)
656
+ args.each do |arg|
657
+ arg_key = arg.keyword
658
+ if arg_values.key?(arg_key)
659
+ arg_value = arg_values[arg_key]
660
+ if using_arg_values
661
+ if arg_value.default_used?
662
+ # pass -- no auth required for default used
663
+ next
664
+ else
665
+ application_arg_value = arg_value.value
666
+ if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
667
+ application_arg_value.keyword_arguments
668
+ end
669
+ end
670
+ else
671
+ application_arg_value = arg_value
672
+ end
422
673
 
423
- if self_auth
424
- # Faster than `.any?`
425
- arguments.each_value do |arg|
426
- if !arg.authorized?(object, context)
427
- return false
674
+ if !arg.authorized?(object, application_arg_value, context)
675
+ return false
676
+ end
677
+ end
428
678
  end
429
679
  end
430
680
  true
431
- else
432
- false
433
681
  end
434
682
  end
435
683
 
@@ -444,21 +692,22 @@ module GraphQL
444
692
  # Some legacy fields can have `nil` here, not exactly sure why.
445
693
  # @see https://github.com/rmosolgo/graphql-ruby/issues/1990 before removing
446
694
  inner_obj = after_obj && after_obj.object
447
- if authorized?(inner_obj, query_ctx)
448
- ruby_args = to_ruby_args(after_obj, args, ctx)
449
- # Then if it passed, resolve the field
450
- if @resolve_proc
451
- # Might be nil, still want to call the func in that case
452
- with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
453
- # Pass the GraphQL args here for compatibility:
454
- @resolve_proc.call(extended_obj, args, ctx)
695
+ ctx.schema.after_lazy(to_ruby_args(after_obj, args, ctx)) do |ruby_args|
696
+ if authorized?(inner_obj, ruby_args, query_ctx)
697
+ # Then if it passed, resolve the field
698
+ if @resolve_proc
699
+ # Might be nil, still want to call the func in that case
700
+ with_extensions(inner_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
701
+ # Pass the GraphQL args here for compatibility:
702
+ @resolve_proc.call(extended_obj, args, ctx)
703
+ end
704
+ else
705
+ public_send_field(after_obj, ruby_args, query_ctx)
455
706
  end
456
707
  else
457
- public_send_field(after_obj, ruby_args, ctx)
708
+ err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
709
+ query_ctx.schema.unauthorized_field(err)
458
710
  end
459
- else
460
- err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
461
- query_ctx.schema.unauthorized_field(err)
462
711
  end
463
712
  end
464
713
  end
@@ -475,34 +724,15 @@ module GraphQL
475
724
  begin
476
725
  # Unwrap the GraphQL object to get the application object.
477
726
  application_object = object.object
478
- if self.authorized?(application_object, ctx)
479
- # Apply field extensions
480
- with_extensions(object, args, ctx) do |extended_obj, extended_args|
481
- field_receiver = if @resolver_class
482
- resolver_obj = if extended_obj.is_a?(GraphQL::Schema::Object)
483
- extended_obj.object
484
- else
485
- extended_obj
486
- end
487
- @resolver_class.new(object: resolver_obj, context: ctx)
488
- else
489
- extended_obj
490
- end
491
727
 
492
- if field_receiver.respond_to?(@resolver_method)
493
- # Call the method with kwargs, if there are any
494
- if extended_args.any?
495
- field_receiver.public_send(@resolver_method, **extended_args)
496
- else
497
- field_receiver.public_send(@resolver_method)
498
- end
499
- else
500
- resolve_field_method(field_receiver, extended_args, ctx)
501
- end
728
+ Schema::Validator.validate!(validators, application_object, ctx, args)
729
+
730
+ ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
731
+ if is_authorized
732
+ public_send_field(object, args, ctx)
733
+ else
734
+ raise GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
502
735
  end
503
- else
504
- err = GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
505
- ctx.schema.unauthorized_field(err)
506
736
  end
507
737
  rescue GraphQL::UnauthorizedFieldError => err
508
738
  err.field ||= self
@@ -514,51 +744,14 @@ module GraphQL
514
744
  err
515
745
  end
516
746
 
517
- # Find a way to resolve this field, checking:
518
- #
519
- # - Hash keys, if the wrapped object is a hash;
520
- # - A method on the wrapped object;
521
- # - Or, raise not implemented.
522
- #
523
- # This can be overridden by defining a method on the object type.
524
- # @param obj [GraphQL::Schema::Object]
525
- # @param ruby_kwargs [Hash<Symbol => Object>]
526
- # @param ctx [GraphQL::Query::Context]
527
- def resolve_field_method(obj, ruby_kwargs, ctx)
528
- if obj.object.is_a?(Hash)
529
- inner_object = obj.object
530
- if inner_object.key?(@method_sym)
531
- inner_object[@method_sym]
532
- else
533
- inner_object[@method_str]
534
- end
535
- elsif obj.object.respond_to?(@method_sym)
536
- if ruby_kwargs.any?
537
- obj.object.public_send(@method_sym, **ruby_kwargs)
538
- else
539
- obj.object.public_send(@method_sym)
540
- end
541
- else
542
- raise <<-ERR
543
- Failed to implement #{@owner.graphql_name}.#{@name}, tried:
544
-
545
- - `#{obj.class}##{@resolver_method}`, which did not exist
546
- - `#{obj.object.class}##{@method_sym}`, which did not exist
547
- - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
548
-
549
- To implement this field, define one of the methods above (and check for typos)
550
- ERR
551
- end
552
- end
553
-
554
747
  # @param ctx [GraphQL::Query::Context::FieldResolutionContext]
555
748
  def fetch_extra(extra_name, ctx)
556
- if extra_name != :path && respond_to?(extra_name)
749
+ if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
557
750
  self.public_send(extra_name)
558
751
  elsif ctx.respond_to?(extra_name)
559
752
  ctx.public_send(extra_name)
560
753
  else
561
- raise NotImplementedError, "Unknown field extra for #{self.path}: #{extra_name.inspect}"
754
+ raise GraphQL::RequiredImplementationMissingError, "Unknown field extra for #{self.path}: #{extra_name.inspect}"
562
755
  end
563
756
  end
564
757
 
@@ -576,11 +769,36 @@ module GraphQL
576
769
  if graphql_args.any? || @extras.any?
577
770
  # Splat the GraphQL::Arguments to Ruby keyword arguments
578
771
  ruby_kwargs = graphql_args.to_kwargs
772
+ maybe_lazies = []
579
773
  # Apply any `prepare` methods. Not great code organization, can this go somewhere better?
580
- arguments.each do |name, arg_defn|
774
+ arguments(field_ctx).each do |name, arg_defn|
581
775
  ruby_kwargs_key = arg_defn.keyword
582
- if ruby_kwargs.key?(ruby_kwargs_key) && arg_defn.prepare
583
- ruby_kwargs[ruby_kwargs_key] = arg_defn.prepare_value(obj, ruby_kwargs[ruby_kwargs_key])
776
+
777
+ if ruby_kwargs.key?(ruby_kwargs_key)
778
+ loads = arg_defn.loads
779
+ value = ruby_kwargs[ruby_kwargs_key]
780
+ loaded_value = if loads && !arg_defn.from_resolver?
781
+ if arg_defn.type.list?
782
+ loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, field_ctx.query.context) }
783
+ field_ctx.schema.after_any_lazies(loaded_values) { |result| result }
784
+ else
785
+ load_application_object(arg_defn, loads, value, field_ctx.query.context)
786
+ end
787
+ elsif arg_defn.type.list? && value.is_a?(Array)
788
+ field_ctx.schema.after_any_lazies(value, &:itself)
789
+ else
790
+ value
791
+ end
792
+
793
+ maybe_lazies << field_ctx.schema.after_lazy(loaded_value) do |loaded_value|
794
+ prepared_value = if arg_defn.prepare
795
+ arg_defn.prepare_value(obj, loaded_value)
796
+ else
797
+ loaded_value
798
+ end
799
+
800
+ ruby_kwargs[ruby_kwargs_key] = prepared_value
801
+ end
584
802
  end
585
803
  end
586
804
 
@@ -588,32 +806,118 @@ module GraphQL
588
806
  ruby_kwargs[extra_arg] = fetch_extra(extra_arg, field_ctx)
589
807
  end
590
808
 
591
- ruby_kwargs
809
+ field_ctx.schema.after_any_lazies(maybe_lazies) do
810
+ ruby_kwargs
811
+ end
592
812
  else
593
813
  NO_ARGS
594
814
  end
595
815
  end
596
816
 
597
- def public_send_field(obj, ruby_kwargs, field_ctx)
598
- query_ctx = field_ctx.query.context
599
- with_extensions(obj, ruby_kwargs, query_ctx) do |extended_obj, extended_args|
600
- if @resolver_class
601
- if extended_obj.is_a?(GraphQL::Schema::Object)
602
- extended_obj = extended_obj.object
817
+ def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
818
+ with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
819
+ begin
820
+ method_receiver = nil
821
+ method_to_call = nil
822
+ if @resolver_class
823
+ if obj.is_a?(GraphQL::Schema::Object)
824
+ obj = obj.object
825
+ end
826
+ obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
827
+ end
828
+
829
+ # Find a way to resolve this field, checking:
830
+ #
831
+ # - A method on the type instance;
832
+ # - Hash keys, if the wrapped object is a hash or responds to `#[]`
833
+ # - A method on the wrapped object;
834
+ # - Or, raise not implemented.
835
+ #
836
+ if obj.respond_to?(@resolver_method)
837
+ method_to_call = @resolver_method
838
+ method_receiver = obj
839
+ # Call the method with kwargs, if there are any
840
+ if ruby_kwargs.any?
841
+ obj.public_send(@resolver_method, **ruby_kwargs)
842
+ else
843
+ obj.public_send(@resolver_method)
844
+ end
845
+ elsif obj.object.is_a?(Hash)
846
+ inner_object = obj.object
847
+ if @dig_keys
848
+ inner_object.dig(*@dig_keys)
849
+ elsif inner_object.key?(@method_sym)
850
+ inner_object[@method_sym]
851
+ else
852
+ inner_object[@method_str]
853
+ end
854
+ elsif defined?(@hash_key) && obj.object.respond_to?(:[])
855
+ obj.object[@hash_key]
856
+ elsif obj.object.respond_to?(@method_sym)
857
+ method_to_call = @method_sym
858
+ method_receiver = obj.object
859
+ if ruby_kwargs.any?
860
+ obj.object.public_send(@method_sym, **ruby_kwargs)
861
+ else
862
+ obj.object.public_send(@method_sym)
863
+ end
864
+ else
865
+ raise <<-ERR
866
+ Failed to implement #{@owner.graphql_name}.#{@name}, tried:
867
+
868
+ - `#{obj.class}##{@resolver_method}`, which did not exist
869
+ - `#{obj.object.class}##{@method_sym}`, which did not exist
870
+ - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
871
+
872
+ To implement this field, define one of the methods above (and check for typos)
873
+ ERR
603
874
  end
604
- extended_obj = @resolver_class.new(object: extended_obj, context: query_ctx)
875
+ rescue ArgumentError
876
+ assert_satisfactory_implementation(method_receiver, method_to_call, ruby_kwargs)
877
+ # if the line above doesn't raise, re-raise
878
+ raise
605
879
  end
880
+ end
881
+ end
606
882
 
607
- if extended_obj.respond_to?(@resolver_method)
608
- if extended_args.any?
609
- extended_obj.public_send(@resolver_method, **extended_args)
883
+ def assert_satisfactory_implementation(receiver, method_name, ruby_kwargs)
884
+ method_defn = receiver.method(method_name)
885
+ unsatisfied_ruby_kwargs = ruby_kwargs.dup
886
+ unsatisfied_method_params = []
887
+ encountered_keyrest = false
888
+ method_defn.parameters.each do |(param_type, param_name)|
889
+ case param_type
890
+ when :key
891
+ unsatisfied_ruby_kwargs.delete(param_name)
892
+ when :keyreq
893
+ if unsatisfied_ruby_kwargs.key?(param_name)
894
+ unsatisfied_ruby_kwargs.delete(param_name)
610
895
  else
611
- extended_obj.public_send(@resolver_method)
896
+ unsatisfied_method_params << "- `#{param_name}:` is required by Ruby, but not by GraphQL. Consider `#{param_name}: nil` instead, or making this argument required in GraphQL."
612
897
  end
613
- else
614
- resolve_field_method(extended_obj, extended_args, query_ctx)
898
+ when :keyrest
899
+ encountered_keyrest = true
900
+ when :req
901
+ unsatisfied_method_params << "- `#{param_name}` is required by Ruby, but GraphQL doesn't pass positional arguments. If it's meant to be a GraphQL argument, use `#{param_name}:` instead. Otherwise, remove it."
902
+ when :opt, :rest
903
+ # This is fine, although it will never be present
615
904
  end
616
905
  end
906
+
907
+ if encountered_keyrest
908
+ unsatisfied_ruby_kwargs.clear
909
+ end
910
+
911
+ if unsatisfied_ruby_kwargs.any? || unsatisfied_method_params.any?
912
+ raise FieldImplementationFailed.new, <<-ERR
913
+ Failed to call #{method_name} on #{receiver.inspect} because the Ruby method params were incompatible with the GraphQL arguments:
914
+
915
+ #{ unsatisfied_ruby_kwargs
916
+ .map { |key, value| "- `#{key}: #{value}` was given by GraphQL but not defined in the Ruby method. Add `#{key}:` to the method parameters." }
917
+ .concat(unsatisfied_method_params)
918
+ .join("\n") }
919
+ ERR
920
+ end
617
921
  end
618
922
 
619
923
  # Wrap execution with hooks.
@@ -623,32 +927,52 @@ module GraphQL
623
927
  if @extensions.empty?
624
928
  yield(obj, args)
625
929
  else
626
- # Save these so that the originals can be re-given to `after_resolve` handlers.
627
- original_args = args
628
- original_obj = obj
629
-
630
- memos = []
631
- value = run_extensions_before_resolve(memos, obj, args, ctx) do |extended_obj, extended_args|
632
- yield(extended_obj, extended_args)
930
+ # This is a hack to get the _last_ value for extended obj and args,
931
+ # in case one of the extensions doesn't `yield`.
932
+ # (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
933
+ extended = { args: args, obj: obj, memos: nil, added_extras: nil }
934
+ value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
935
+ if (added_extras = extended[:added_extras])
936
+ args = args.dup
937
+ added_extras.each { |e| args.delete(e) }
938
+ end
939
+ yield(obj, args)
633
940
  end
634
941
 
942
+ extended_obj = extended[:obj]
943
+ extended_args = extended[:args]
944
+ memos = extended[:memos] || EMPTY_HASH
945
+
635
946
  ctx.schema.after_lazy(value) do |resolved_value|
636
- @extensions.each_with_index do |ext, idx|
947
+ idx = 0
948
+ @extensions.each do |ext|
637
949
  memo = memos[idx]
638
950
  # TODO after_lazy?
639
- resolved_value = ext.after_resolve(object: original_obj, arguments: original_args, context: ctx, value: resolved_value, memo: memo)
951
+ resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
952
+ idx += 1
640
953
  end
641
954
  resolved_value
642
955
  end
643
956
  end
644
957
  end
645
958
 
646
- def run_extensions_before_resolve(memos, obj, args, ctx, idx: 0)
959
+ def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
647
960
  extension = @extensions[idx]
648
961
  if extension
649
962
  extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
650
- memos << memo
651
- run_extensions_before_resolve(memos, extended_obj, extended_args, ctx, idx: idx + 1) { |o, a| yield(o, a) }
963
+ if memo
964
+ memos = extended[:memos] ||= {}
965
+ memos[idx] = memo
966
+ end
967
+
968
+ if (extras = extension.added_extras)
969
+ ae = extended[:added_extras] ||= []
970
+ ae.concat(extras)
971
+ end
972
+
973
+ extended[:obj] = extended_obj
974
+ extended[:args] = extended_args
975
+ run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
652
976
  end
653
977
  else
654
978
  yield(obj, args)