graphql 1.12.12 → 2.2.14

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 (392) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -8
  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/{templates → install/templates}/base_mutation.erb +2 -0
  8. data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
  9. data/lib/generators/graphql/install_generator.rb +14 -4
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  12. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_generator.rb +5 -30
  14. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  15. data/lib/generators/graphql/object_generator.rb +10 -38
  16. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  17. data/lib/generators/graphql/relay.rb +23 -12
  18. data/lib/generators/graphql/scalar_generator.rb +4 -2
  19. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  20. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  21. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  22. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  23. data/lib/generators/graphql/templates/base_field.erb +2 -0
  24. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  25. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  26. data/lib/generators/graphql/templates/base_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_resolver.erb +6 -0
  28. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  29. data/lib/generators/graphql/templates/base_union.erb +2 -0
  30. data/lib/generators/graphql/templates/enum.erb +5 -1
  31. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  32. data/lib/generators/graphql/templates/input.erb +9 -0
  33. data/lib/generators/graphql/templates/interface.erb +4 -2
  34. data/lib/generators/graphql/templates/loader.erb +2 -0
  35. data/lib/generators/graphql/templates/mutation.erb +3 -1
  36. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  37. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  39. data/lib/generators/graphql/templates/node_type.erb +2 -0
  40. data/lib/generators/graphql/templates/object.erb +4 -2
  41. data/lib/generators/graphql/templates/query_type.erb +2 -0
  42. data/lib/generators/graphql/templates/scalar.erb +3 -1
  43. data/lib/generators/graphql/templates/schema.erb +19 -2
  44. data/lib/generators/graphql/templates/union.erb +4 -2
  45. data/lib/generators/graphql/type_generator.rb +46 -10
  46. data/lib/generators/graphql/union_generator.rb +5 -5
  47. data/lib/graphql/analysis/ast/analyzer.rb +7 -0
  48. data/lib/graphql/analysis/ast/field_usage.rb +55 -1
  49. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
  50. data/lib/graphql/analysis/ast/query_complexity.rb +88 -140
  51. data/lib/graphql/analysis/ast/query_depth.rb +7 -3
  52. data/lib/graphql/analysis/ast/visitor.rb +50 -42
  53. data/lib/graphql/analysis/ast.rb +26 -23
  54. data/lib/graphql/analysis.rb +0 -7
  55. data/lib/graphql/backtrace/table.rb +4 -22
  56. data/lib/graphql/backtrace/trace.rb +93 -0
  57. data/lib/graphql/backtrace/tracer.rb +8 -6
  58. data/lib/graphql/backtrace.rb +3 -8
  59. data/lib/graphql/coercion_error.rb +1 -9
  60. data/lib/graphql/dataloader/async_dataloader.rb +85 -0
  61. data/lib/graphql/dataloader/null_dataloader.rb +3 -1
  62. data/lib/graphql/dataloader/request.rb +5 -0
  63. data/lib/graphql/dataloader/source.rb +120 -31
  64. data/lib/graphql/dataloader.rb +168 -142
  65. data/lib/graphql/date_encoding_error.rb +16 -0
  66. data/lib/graphql/dig.rb +1 -1
  67. data/lib/graphql/duration_encoding_error.rb +16 -0
  68. data/lib/graphql/execution/errors.rb +12 -81
  69. data/lib/graphql/execution/interpreter/arguments.rb +2 -2
  70. data/lib/graphql/execution/interpreter/arguments_cache.rb +36 -34
  71. data/lib/graphql/execution/interpreter/resolve.rb +32 -2
  72. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
  73. data/lib/graphql/execution/interpreter/runtime.rb +414 -341
  74. data/lib/graphql/execution/interpreter.rb +122 -80
  75. data/lib/graphql/execution/lazy.rb +11 -21
  76. data/lib/graphql/execution/lookahead.rb +125 -54
  77. data/lib/graphql/execution/multiplex.rb +4 -172
  78. data/lib/graphql/execution.rb +11 -4
  79. data/lib/graphql/integer_encoding_error.rb +18 -2
  80. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  81. data/lib/graphql/introspection/directive_type.rb +5 -3
  82. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  83. data/lib/graphql/introspection/entry_points.rb +11 -18
  84. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  85. data/lib/graphql/introspection/field_type.rb +3 -3
  86. data/lib/graphql/introspection/input_value_type.rb +10 -4
  87. data/lib/graphql/introspection/schema_type.rb +12 -5
  88. data/lib/graphql/introspection/type_type.rb +25 -12
  89. data/lib/graphql/introspection.rb +6 -2
  90. data/lib/graphql/language/block_string.rb +37 -25
  91. data/lib/graphql/language/definition_slice.rb +1 -1
  92. data/lib/graphql/language/document_from_schema_definition.rb +78 -65
  93. data/lib/graphql/language/lexer.rb +345 -1467
  94. data/lib/graphql/language/nodes.rb +145 -91
  95. data/lib/graphql/language/parser.rb +701 -1921
  96. data/lib/graphql/language/printer.rb +351 -155
  97. data/lib/graphql/language/sanitized_printer.rb +25 -27
  98. data/lib/graphql/language/static_visitor.rb +167 -0
  99. data/lib/graphql/language/token.rb +0 -4
  100. data/lib/graphql/language/visitor.rb +188 -141
  101. data/lib/graphql/language.rb +1 -0
  102. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  103. data/lib/graphql/name_validator.rb +0 -4
  104. data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
  105. data/lib/graphql/pagination/array_connection.rb +8 -6
  106. data/lib/graphql/pagination/connection.rb +61 -7
  107. data/lib/graphql/pagination/connections.rb +22 -23
  108. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  109. data/lib/graphql/pagination/relation_connection.rb +60 -28
  110. data/lib/graphql/query/context/scoped_context.rb +101 -0
  111. data/lib/graphql/query/context.rb +109 -189
  112. data/lib/graphql/query/input_validation_result.rb +10 -1
  113. data/lib/graphql/query/null_context.rb +14 -29
  114. data/lib/graphql/query/validation_pipeline.rb +15 -39
  115. data/lib/graphql/query/variable_validation_error.rb +2 -2
  116. data/lib/graphql/query/variables.rb +35 -17
  117. data/lib/graphql/query.rb +78 -65
  118. data/lib/graphql/railtie.rb +8 -109
  119. data/lib/graphql/rake_task/validate.rb +1 -1
  120. data/lib/graphql/rake_task.rb +30 -11
  121. data/lib/graphql/relay/range_add.rb +9 -16
  122. data/lib/graphql/relay.rb +0 -15
  123. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  124. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  125. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  126. data/lib/graphql/rubocop.rb +4 -0
  127. data/lib/graphql/schema/addition.rb +78 -45
  128. data/lib/graphql/schema/always_visible.rb +10 -0
  129. data/lib/graphql/schema/argument.rb +134 -80
  130. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  131. data/lib/graphql/schema/build_from_definition.rb +60 -38
  132. data/lib/graphql/schema/directive/feature.rb +1 -1
  133. data/lib/graphql/schema/directive/flagged.rb +2 -2
  134. data/lib/graphql/schema/directive/include.rb +1 -1
  135. data/lib/graphql/schema/directive/one_of.rb +24 -0
  136. data/lib/graphql/schema/directive/skip.rb +1 -1
  137. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  138. data/lib/graphql/schema/directive/transform.rb +2 -2
  139. data/lib/graphql/schema/directive.rb +33 -21
  140. data/lib/graphql/schema/enum.rb +93 -46
  141. data/lib/graphql/schema/enum_value.rb +4 -21
  142. data/lib/graphql/schema/field/connection_extension.rb +6 -16
  143. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  144. data/lib/graphql/schema/field.rb +432 -337
  145. data/lib/graphql/schema/field_extension.rb +86 -2
  146. data/lib/graphql/schema/find_inherited_value.rb +3 -7
  147. data/lib/graphql/schema/finder.rb +5 -5
  148. data/lib/graphql/schema/has_single_input_argument.rb +156 -0
  149. data/lib/graphql/schema/input_object.rb +88 -90
  150. data/lib/graphql/schema/interface.rb +19 -59
  151. data/lib/graphql/schema/introspection_system.rb +6 -9
  152. data/lib/graphql/schema/late_bound_type.rb +8 -2
  153. data/lib/graphql/schema/list.rb +18 -7
  154. data/lib/graphql/schema/loader.rb +3 -3
  155. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -19
  156. data/lib/graphql/schema/member/build_type.rb +16 -13
  157. data/lib/graphql/schema/member/has_arguments.rb +288 -84
  158. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  159. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  160. data/lib/graphql/schema/member/has_directives.rb +81 -61
  161. data/lib/graphql/schema/member/has_fields.rb +149 -31
  162. data/lib/graphql/schema/member/has_interfaces.rb +143 -0
  163. data/lib/graphql/schema/member/has_validators.rb +32 -6
  164. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  165. data/lib/graphql/schema/member/scoped.rb +19 -0
  166. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  167. data/lib/graphql/schema/member/validates_input.rb +6 -6
  168. data/lib/graphql/schema/member.rb +1 -6
  169. data/lib/graphql/schema/mutation.rb +0 -9
  170. data/lib/graphql/schema/non_null.rb +7 -7
  171. data/lib/graphql/schema/object.rb +30 -119
  172. data/lib/graphql/schema/printer.rb +23 -25
  173. data/lib/graphql/schema/relay_classic_mutation.rb +13 -90
  174. data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
  175. data/lib/graphql/schema/resolver.rb +101 -102
  176. data/lib/graphql/schema/scalar.rb +20 -21
  177. data/lib/graphql/schema/subscription.rb +45 -17
  178. data/lib/graphql/schema/timeout.rb +25 -29
  179. data/lib/graphql/schema/type_expression.rb +1 -1
  180. data/lib/graphql/schema/type_membership.rb +21 -4
  181. data/lib/graphql/schema/union.rb +15 -15
  182. data/lib/graphql/schema/unique_within_type.rb +1 -1
  183. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  184. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  185. data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
  186. data/lib/graphql/schema/validator/format_validator.rb +4 -5
  187. data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
  188. data/lib/graphql/schema/validator/length_validator.rb +5 -3
  189. data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
  190. data/lib/graphql/schema/validator/required_validator.rb +29 -15
  191. data/lib/graphql/schema/validator.rb +35 -27
  192. data/lib/graphql/schema/warden.rb +259 -132
  193. data/lib/graphql/schema/wrapper.rb +0 -5
  194. data/lib/graphql/schema.rb +658 -989
  195. data/lib/graphql/static_validation/all_rules.rb +3 -1
  196. data/lib/graphql/static_validation/base_visitor.rb +14 -28
  197. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  198. data/lib/graphql/static_validation/error.rb +3 -1
  199. data/lib/graphql/static_validation/literal_validator.rb +21 -4
  200. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  201. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  202. data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
  203. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +13 -13
  204. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
  205. data/lib/graphql/static_validation/rules/fields_will_merge.rb +54 -28
  206. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  207. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  208. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  209. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  210. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  211. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  212. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -3
  213. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
  214. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
  215. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  216. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
  217. data/lib/graphql/static_validation/validation_context.rb +16 -6
  218. data/lib/graphql/static_validation/validator.rb +11 -27
  219. data/lib/graphql/static_validation.rb +0 -3
  220. data/lib/graphql/string_encoding_error.rb +13 -3
  221. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +46 -9
  222. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
  223. data/lib/graphql/subscriptions/event.rb +75 -37
  224. data/lib/graphql/subscriptions/serialize.rb +25 -3
  225. data/lib/graphql/subscriptions.rb +59 -47
  226. data/lib/graphql/testing/helpers.rb +129 -0
  227. data/lib/graphql/testing.rb +2 -0
  228. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  229. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  230. data/lib/graphql/tracing/appoptics_trace.rb +251 -0
  231. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  232. data/lib/graphql/tracing/appsignal_trace.rb +77 -0
  233. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  234. data/lib/graphql/tracing/data_dog_trace.rb +183 -0
  235. data/lib/graphql/tracing/data_dog_tracing.rb +25 -15
  236. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
  237. data/lib/graphql/tracing/legacy_trace.rb +69 -0
  238. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  239. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  240. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  241. data/lib/graphql/tracing/platform_trace.rb +118 -0
  242. data/lib/graphql/tracing/platform_tracing.rb +46 -49
  243. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
  244. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  245. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  246. data/lib/graphql/tracing/scout_trace.rb +72 -0
  247. data/lib/graphql/tracing/sentry_trace.rb +112 -0
  248. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  249. data/lib/graphql/tracing/trace.rb +76 -0
  250. data/lib/graphql/tracing.rb +20 -41
  251. data/lib/graphql/type_kinds.rb +6 -3
  252. data/lib/graphql/types/big_int.rb +5 -1
  253. data/lib/graphql/types/int.rb +1 -1
  254. data/lib/graphql/types/iso_8601_date.rb +17 -6
  255. data/lib/graphql/types/iso_8601_date_time.rb +12 -1
  256. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  257. data/lib/graphql/types/relay/base_connection.rb +16 -6
  258. data/lib/graphql/types/relay/connection_behaviors.rb +82 -32
  259. data/lib/graphql/types/relay/edge_behaviors.rb +36 -7
  260. data/lib/graphql/types/relay/has_node_field.rb +2 -2
  261. data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
  262. data/lib/graphql/types/relay/node_behaviors.rb +12 -2
  263. data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
  264. data/lib/graphql/types/relay.rb +0 -3
  265. data/lib/graphql/types/string.rb +2 -2
  266. data/lib/graphql/types.rb +1 -0
  267. data/lib/graphql/unauthorized_error.rb +1 -1
  268. data/lib/graphql/version.rb +1 -1
  269. data/lib/graphql.rb +33 -95
  270. data/readme.md +13 -6
  271. metadata +102 -185
  272. data/lib/graphql/analysis/analyze_query.rb +0 -98
  273. data/lib/graphql/analysis/field_usage.rb +0 -45
  274. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  275. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  276. data/lib/graphql/analysis/query_complexity.rb +0 -88
  277. data/lib/graphql/analysis/query_depth.rb +0 -43
  278. data/lib/graphql/analysis/reducer_state.rb +0 -48
  279. data/lib/graphql/argument.rb +0 -131
  280. data/lib/graphql/authorization.rb +0 -82
  281. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  282. data/lib/graphql/backwards_compatibility.rb +0 -61
  283. data/lib/graphql/base_type.rb +0 -230
  284. data/lib/graphql/boolean_type.rb +0 -2
  285. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  286. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  287. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  288. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  289. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  290. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  291. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  292. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  293. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  294. data/lib/graphql/compatibility.rb +0 -5
  295. data/lib/graphql/define/assign_argument.rb +0 -12
  296. data/lib/graphql/define/assign_connection.rb +0 -13
  297. data/lib/graphql/define/assign_enum_value.rb +0 -18
  298. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  299. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  300. data/lib/graphql/define/assign_object_field.rb +0 -42
  301. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  302. data/lib/graphql/define/instance_definable.rb +0 -240
  303. data/lib/graphql/define/no_definition_error.rb +0 -7
  304. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  305. data/lib/graphql/define/type_definer.rb +0 -31
  306. data/lib/graphql/define.rb +0 -31
  307. data/lib/graphql/deprecated_dsl.rb +0 -47
  308. data/lib/graphql/deprecation.rb +0 -13
  309. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  310. data/lib/graphql/directive/include_directive.rb +0 -2
  311. data/lib/graphql/directive/skip_directive.rb +0 -2
  312. data/lib/graphql/directive.rb +0 -111
  313. data/lib/graphql/enum_type.rb +0 -129
  314. data/lib/graphql/execution/execute.rb +0 -333
  315. data/lib/graphql/execution/flatten.rb +0 -40
  316. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  317. data/lib/graphql/execution/typecast.rb +0 -50
  318. data/lib/graphql/field/resolve.rb +0 -59
  319. data/lib/graphql/field.rb +0 -226
  320. data/lib/graphql/filter.rb +0 -53
  321. data/lib/graphql/float_type.rb +0 -2
  322. data/lib/graphql/function.rb +0 -128
  323. data/lib/graphql/id_type.rb +0 -2
  324. data/lib/graphql/input_object_type.rb +0 -138
  325. data/lib/graphql/int_type.rb +0 -2
  326. data/lib/graphql/interface_type.rb +0 -72
  327. data/lib/graphql/internal_representation/document.rb +0 -27
  328. data/lib/graphql/internal_representation/node.rb +0 -206
  329. data/lib/graphql/internal_representation/print.rb +0 -51
  330. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  331. data/lib/graphql/internal_representation/scope.rb +0 -88
  332. data/lib/graphql/internal_representation/visit.rb +0 -36
  333. data/lib/graphql/internal_representation.rb +0 -7
  334. data/lib/graphql/language/lexer.rl +0 -262
  335. data/lib/graphql/language/parser.y +0 -543
  336. data/lib/graphql/list_type.rb +0 -80
  337. data/lib/graphql/non_null_type.rb +0 -71
  338. data/lib/graphql/object_type.rb +0 -130
  339. data/lib/graphql/query/arguments.rb +0 -189
  340. data/lib/graphql/query/arguments_cache.rb +0 -24
  341. data/lib/graphql/query/executor.rb +0 -52
  342. data/lib/graphql/query/literal_input.rb +0 -136
  343. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  344. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  345. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  346. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  347. data/lib/graphql/query/serial_execution.rb +0 -40
  348. data/lib/graphql/relay/array_connection.rb +0 -83
  349. data/lib/graphql/relay/base_connection.rb +0 -189
  350. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  351. data/lib/graphql/relay/connection_resolve.rb +0 -43
  352. data/lib/graphql/relay/connection_type.rb +0 -41
  353. data/lib/graphql/relay/edge.rb +0 -27
  354. data/lib/graphql/relay/edge_type.rb +0 -19
  355. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  356. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  357. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  358. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  359. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  360. data/lib/graphql/relay/mutation/result.rb +0 -38
  361. data/lib/graphql/relay/mutation.rb +0 -106
  362. data/lib/graphql/relay/node.rb +0 -39
  363. data/lib/graphql/relay/page_info.rb +0 -7
  364. data/lib/graphql/relay/relation_connection.rb +0 -188
  365. data/lib/graphql/relay/type_extensions.rb +0 -32
  366. data/lib/graphql/scalar_type.rb +0 -91
  367. data/lib/graphql/schema/base_64_bp.rb +0 -26
  368. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  369. data/lib/graphql/schema/default_parse_error.rb +0 -10
  370. data/lib/graphql/schema/default_type_error.rb +0 -17
  371. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  372. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
  373. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  374. data/lib/graphql/schema/middleware_chain.rb +0 -82
  375. data/lib/graphql/schema/possible_types.rb +0 -44
  376. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  377. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  378. data/lib/graphql/schema/traversal.rb +0 -228
  379. data/lib/graphql/schema/validation.rb +0 -313
  380. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  381. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  382. data/lib/graphql/static_validation/type_stack.rb +0 -216
  383. data/lib/graphql/string_type.rb +0 -2
  384. data/lib/graphql/subscriptions/instrumentation.rb +0 -79
  385. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  386. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  387. data/lib/graphql/types/relay/default_relay.rb +0 -27
  388. data/lib/graphql/types/relay/node_field.rb +0 -25
  389. data/lib/graphql/types/relay/nodes_field.rb +0 -27
  390. data/lib/graphql/union_type.rb +0 -115
  391. data/lib/graphql/upgrader/member.rb +0 -937
  392. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -20,7 +20,17 @@ module GraphQL
20
20
  @payload_type ||= generate_payload_type
21
21
  end
22
22
 
23
- alias :type :payload_type
23
+ def type(new_type = nil, null: nil)
24
+ if new_type
25
+ payload_type(new_type)
26
+ if !null.nil?
27
+ self.null(null)
28
+ end
29
+ else
30
+ super()
31
+ end
32
+ end
33
+
24
34
  alias :type_expr :payload_type
25
35
 
26
36
  def field_class(new_class = nil)
@@ -38,6 +48,9 @@ module GraphQL
38
48
  # @return [Class]
39
49
  def object_class(new_class = nil)
40
50
  if new_class
51
+ if defined?(@payload_type)
52
+ raise "Can't configure `object_class(...)` after the payload type has already been initialized. Move this configuration higher up the class definition."
53
+ end
41
54
  @object_class = new_class
42
55
  else
43
56
  @object_class || find_inherited_value(:object_class, GraphQL::Schema::Object)
@@ -46,6 +59,28 @@ module GraphQL
46
59
 
47
60
  NO_INTERFACES = [].freeze
48
61
 
62
+ def field(*args, **kwargs, &block)
63
+ pt = payload_type # make sure it's initialized with any inherited fields
64
+ field_defn = super
65
+
66
+ # Remove any inherited fields to avoid false conflicts at runtime
67
+ prev_fields = pt.own_fields[field_defn.graphql_name]
68
+ case prev_fields
69
+ when GraphQL::Schema::Field
70
+ if prev_fields.owner != self
71
+ pt.own_fields.delete(field_defn.graphql_name)
72
+ end
73
+ when Array
74
+ prev_fields.reject! { |f| f.owner != self }
75
+ if prev_fields.empty?
76
+ pt.own_fields.delete(field_defn.graphql_name)
77
+ end
78
+ end
79
+
80
+ pt.add_field(field_defn, method_conflict_warning: false)
81
+ field_defn
82
+ end
83
+
49
84
  private
50
85
 
51
86
  # Build a subclass of {.object_class} based on `self`.
@@ -53,17 +88,17 @@ module GraphQL
53
88
  # Override this hook to customize return type generation.
54
89
  def generate_payload_type
55
90
  resolver_name = graphql_name
56
- resolver_fields = fields
57
- Class.new(object_class) do
58
- graphql_name("#{resolver_name}Payload")
59
- description("Autogenerated return type of #{resolver_name}")
60
- resolver_fields.each do |name, f|
61
- # Reattach the already-defined field here
62
- # (The field's `.owner` will still point to the mutation, not the object type, I think)
63
- # Don't re-warn about a method conflict. Since this type is generated, it should be fixed in the resolver instead.
64
- add_field(f, method_conflict_warning: false)
65
- end
91
+ resolver_fields = all_field_definitions
92
+ pt = Class.new(object_class)
93
+ pt.graphql_name("#{resolver_name}Payload")
94
+ pt.description("Autogenerated return type of #{resolver_name}.")
95
+ resolver_fields.each do |f|
96
+ # Reattach the already-defined field here
97
+ # (The field's `.owner` will still point to the mutation, not the object type, I think)
98
+ # Don't re-warn about a method conflict. Since this type is generated, it should be fixed in the resolver instead.
99
+ pt.add_field(f, method_conflict_warning: false)
66
100
  end
101
+ pt
67
102
  end
68
103
  end
69
104
  end
@@ -15,8 +15,6 @@ module GraphQL
15
15
  #
16
16
  # A resolver's configuration may be overridden with other keywords in the `field(...)` call.
17
17
  #
18
- # See the {.field_options} to see how a Resolver becomes a set of field configuration options.
19
- #
20
18
  # @see {GraphQL::Schema::Mutation} for a concrete subclass of `Resolver`.
21
19
  # @see {GraphQL::Function} `Resolver` is a replacement for `GraphQL::Function`
22
20
  class Resolver
@@ -28,7 +26,7 @@ module GraphQL
28
26
  include Schema::Member::HasPath
29
27
  extend Schema::Member::HasPath
30
28
 
31
- # @param object [Object] the initialize object, pass to {Query.initialize} as `root_value`
29
+ # @param object [Object] The application object that this field is being resolved on
32
30
  # @param context [GraphQL::Query::Context]
33
31
  # @param field [GraphQL::Schema::Field]
34
32
  def initialize(object:, context:, field:)
@@ -37,10 +35,9 @@ module GraphQL
37
35
  @field = field
38
36
  # Since this hash is constantly rebuilt, cache it for this call
39
37
  @arguments_by_keyword = {}
40
- self.class.arguments.each do |name, arg|
38
+ self.class.arguments(context).each do |name, arg|
41
39
  @arguments_by_keyword[arg.keyword] = arg
42
40
  end
43
- @arguments_loads_as_type = self.class.arguments_loads_as_type
44
41
  @prepared_arguments = nil
45
42
  end
46
43
 
@@ -68,41 +65,43 @@ module GraphQL
68
65
  # @api private
69
66
  def resolve_with_support(**args)
70
67
  # First call the ready? hook which may raise
71
- ready_val = if args.any?
68
+ raw_ready_val = if args.any?
72
69
  ready?(**args)
73
70
  else
74
71
  ready?
75
72
  end
76
- context.schema.after_lazy(ready_val) do |is_ready, ready_early_return|
77
- if ready_early_return
73
+ context.query.after_lazy(raw_ready_val) do |ready_val|
74
+ if ready_val.is_a?(Array)
75
+ is_ready, ready_early_return = ready_val
78
76
  if is_ready != false
79
- raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{authorized_result.inspect}, #{ready_early_return.inspect}]"
77
+ raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{is_ready.inspect}, #{ready_early_return.inspect}]"
80
78
  else
81
79
  ready_early_return
82
80
  end
83
- elsif is_ready
81
+ elsif ready_val
84
82
  # Then call each prepare hook, which may return a different value
85
83
  # for that argument, or may return a lazy object
86
84
  load_arguments_val = load_arguments(args)
87
- context.schema.after_lazy(load_arguments_val) do |loaded_args|
85
+ context.query.after_lazy(load_arguments_val) do |loaded_args|
88
86
  @prepared_arguments = loaded_args
89
87
  Schema::Validator.validate!(self.class.validators, object, context, loaded_args, as: @field)
90
88
  # Then call `authorized?`, which may raise or may return a lazy object
91
- authorized_val = if loaded_args.any?
89
+ raw_authorized_val = if loaded_args.any?
92
90
  authorized?(**loaded_args)
93
91
  else
94
92
  authorized?
95
93
  end
96
- context.schema.after_lazy(authorized_val) do |(authorized_result, early_return)|
94
+ context.query.after_lazy(raw_authorized_val) do |authorized_val|
97
95
  # If the `authorized?` returned two values, `false, early_return`,
98
96
  # then use the early return value instead of continuing
99
- if early_return
97
+ if authorized_val.is_a?(Array)
98
+ authorized_result, early_return = authorized_val
100
99
  if authorized_result == false
101
100
  early_return
102
101
  else
103
102
  raise "Unexpected result from #authorized? (expected `true`, `false` or `[false, {...}]`): [#{authorized_result.inspect}, #{early_return.inspect}]"
104
103
  end
105
- elsif authorized_result
104
+ elsif authorized_val
106
105
  # Finally, all the hooks have passed, so resolve it
107
106
  if loaded_args.any?
108
107
  public_send(self.class.resolve_method, **loaded_args)
@@ -110,7 +109,7 @@ module GraphQL
110
109
  public_send(self.class.resolve_method)
111
110
  end
112
111
  else
113
- nil
112
+ raise GraphQL::UnauthorizedFieldError.new(context: context, object: object, type: field.owner, field: field)
114
113
  end
115
114
  end
116
115
  end
@@ -146,14 +145,36 @@ module GraphQL
146
145
  # @raise [GraphQL::UnauthorizedError] To signal an authorization failure
147
146
  # @return [Boolean, early_return_data] If `false`, execution will stop (and `early_return_data` will be returned instead, if present.)
148
147
  def authorized?(**inputs)
149
- self.class.arguments.each_value do |argument|
148
+ arg_owner = @field # || self.class
149
+ args = arg_owner.arguments(context)
150
+ authorize_arguments(args, inputs)
151
+ end
152
+
153
+ # Called when an object loaded by `loads:` fails the `.authorized?` check for its resolved GraphQL object type.
154
+ #
155
+ # By default, the error is re-raised and passed along to {{Schema.unauthorized_object}}.
156
+ #
157
+ # Any value returned here will be used _instead of_ of the loaded object.
158
+ # @param err [GraphQL::UnauthorizedError]
159
+ def unauthorized_object(err)
160
+ raise err
161
+ end
162
+
163
+ private
164
+
165
+ def authorize_arguments(args, inputs)
166
+ args.each_value do |argument|
150
167
  arg_keyword = argument.keyword
151
168
  if inputs.key?(arg_keyword) && !(arg_value = inputs[arg_keyword]).nil? && (arg_value != argument.default_value)
152
- arg_auth, err = argument.authorized?(self, arg_value, context)
153
- if !arg_auth
154
- return arg_auth, err
155
- else
156
- true
169
+ auth_result = argument.authorized?(self, arg_value, context)
170
+ if auth_result.is_a?(Array)
171
+ # only return this second value if the application returned a second value
172
+ arg_auth, err = auth_result
173
+ if !arg_auth
174
+ return arg_auth, err
175
+ end
176
+ elsif auth_result == false
177
+ return auth_result
157
178
  end
158
179
  else
159
180
  true
@@ -161,8 +182,6 @@ module GraphQL
161
182
  end
162
183
  end
163
184
 
164
- private
165
-
166
185
  def load_arguments(args)
167
186
  prepared_args = {}
168
187
  prepare_lazies = []
@@ -170,18 +189,14 @@ module GraphQL
170
189
  args.each do |key, value|
171
190
  arg_defn = @arguments_by_keyword[key]
172
191
  if arg_defn
173
- if value.nil?
174
- prepared_args[key] = value
175
- else
176
- prepped_value = prepared_args[key] = load_argument(key, value)
177
- if context.schema.lazy?(prepped_value)
178
- prepare_lazies << context.schema.after_lazy(prepped_value) do |finished_prepped_value|
179
- prepared_args[key] = finished_prepped_value
180
- end
192
+ prepped_value = prepared_args[key] = arg_defn.load_and_authorize_value(self, value, context)
193
+ if context.schema.lazy?(prepped_value)
194
+ prepare_lazies << context.query.after_lazy(prepped_value) do |finished_prepped_value|
195
+ prepared_args[key] = finished_prepped_value
181
196
  end
182
197
  end
183
198
  else
184
- # These are `extras: [...]`
199
+ # these are `extras:`
185
200
  prepared_args[key] = value
186
201
  end
187
202
  end
@@ -194,11 +209,27 @@ module GraphQL
194
209
  end
195
210
  end
196
211
 
197
- def load_argument(name, value)
198
- public_send("load_#{name}", value)
212
+ def get_argument(name, context = GraphQL::Query::NullContext.instance)
213
+ self.class.get_argument(name, context)
199
214
  end
200
215
 
201
216
  class << self
217
+ def field_arguments(context = GraphQL::Query::NullContext.instance)
218
+ arguments(context)
219
+ end
220
+
221
+ def any_field_arguments?
222
+ any_arguments?
223
+ end
224
+
225
+ def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
226
+ get_argument(name, context)
227
+ end
228
+
229
+ def all_field_argument_definitions
230
+ all_argument_definitions
231
+ end
232
+
202
233
  # Default `:resolve` set below.
203
234
  # @return [Symbol] The method to call on instances of this object to resolve the field
204
235
  def resolve_method(new_method = nil)
@@ -218,8 +249,10 @@ module GraphQL
218
249
  own_extras + (superclass.respond_to?(:extras) ? superclass.extras : [])
219
250
  end
220
251
 
221
- # Specifies whether or not the field is nullable. Defaults to `true`
222
- # TODO unify with {#type}
252
+ # If `true` (default), then the return type for this resolver will be nullable.
253
+ # If `false`, then the return type is non-null.
254
+ #
255
+ # @see #type which sets the return type of this field and accepts a `null:` option
223
256
  # @param allow_null [Boolean] Whether or not the response can be null
224
257
  def null(allow_null = nil)
225
258
  if !allow_null.nil?
@@ -229,6 +262,14 @@ module GraphQL
229
262
  @null.nil? ? (superclass.respond_to?(:null) ? superclass.null : true) : @null
230
263
  end
231
264
 
265
+ def resolver_method(new_method_name = nil)
266
+ if new_method_name
267
+ @resolver_method = new_method_name
268
+ else
269
+ @resolver_method || :resolve_with_support
270
+ end
271
+ end
272
+
232
273
  # Call this method to get the return type of the field,
233
274
  # or use it as a configuration method to assign a return type
234
275
  # instead of generating one.
@@ -244,8 +285,8 @@ module GraphQL
244
285
  @type_expr = new_type
245
286
  @null = null
246
287
  else
247
- if @type_expr
248
- GraphQL::Schema::Member::BuildType.parse_type(@type_expr, null: @null)
288
+ if type_expr
289
+ GraphQL::Schema::Member::BuildType.parse_type(type_expr, null: self.null)
249
290
  elsif superclass.respond_to?(:type)
250
291
  superclass.type
251
292
  else
@@ -280,8 +321,8 @@ module GraphQL
280
321
  # (`nil` means "unlimited max page size".)
281
322
  # @param max_page_size [Integer, nil] Set a new value
282
323
  # @return [Integer, nil] The `max_page_size` assigned to fields that use this resolver
283
- def max_page_size(new_max_page_size = :not_given)
284
- if new_max_page_size != :not_given
324
+ def max_page_size(new_max_page_size = NOT_CONFIGURED)
325
+ if new_max_page_size != NOT_CONFIGURED
285
326
  @max_page_size = new_max_page_size
286
327
  elsif defined?(@max_page_size)
287
328
  @max_page_size
@@ -294,28 +335,28 @@ module GraphQL
294
335
 
295
336
  # @return [Boolean] `true` if this resolver or a superclass has an assigned `max_page_size`
296
337
  def has_max_page_size?
297
- defined?(@max_page_size) || (superclass.respond_to?(:has_max_page_size?) && superclass.has_max_page_size?)
338
+ (!!defined?(@max_page_size)) || (superclass.respond_to?(:has_max_page_size?) && superclass.has_max_page_size?)
298
339
  end
299
340
 
300
- def field_options
301
- field_opts = {
302
- type: type_expr,
303
- description: description,
304
- extras: extras,
305
- resolver_method: :resolve_with_support,
306
- resolver_class: self,
307
- arguments: arguments,
308
- null: null,
309
- complexity: complexity,
310
- extensions: extensions,
311
- broadcastable: broadcastable?,
312
- }
313
-
314
- if has_max_page_size?
315
- field_opts[:max_page_size] = max_page_size
341
+ # Get or set the `default_page_size:` which will be configured for fields using this resolver
342
+ # (`nil` means "unlimited default page size".)
343
+ # @param default_page_size [Integer, nil] Set a new value
344
+ # @return [Integer, nil] The `default_page_size` assigned to fields that use this resolver
345
+ def default_page_size(new_default_page_size = NOT_CONFIGURED)
346
+ if new_default_page_size != NOT_CONFIGURED
347
+ @default_page_size = new_default_page_size
348
+ elsif defined?(@default_page_size)
349
+ @default_page_size
350
+ elsif superclass.respond_to?(:default_page_size)
351
+ superclass.default_page_size
352
+ else
353
+ nil
316
354
  end
355
+ end
317
356
 
318
- field_opts
357
+ # @return [Boolean] `true` if this resolver or a superclass has an assigned `default_page_size`
358
+ def has_default_page_size?
359
+ (!!defined?(@default_page_size)) || (superclass.respond_to?(:has_default_page_size?) && superclass.has_default_page_size?)
319
360
  end
320
361
 
321
362
  # A non-normalized type configuration, without `null` applied
@@ -327,47 +368,9 @@ module GraphQL
327
368
  # also add some preparation hook methods which will be used for this argument
328
369
  # @see {GraphQL::Schema::Argument#initialize} for the signature
329
370
  def argument(*args, **kwargs, &block)
330
- loads = kwargs[:loads]
331
371
  # Use `from_resolver: true` to short-circuit the InputObject's own `loads:` implementation
332
372
  # so that we can support `#load_{x}` methods below.
333
- arg_defn = super(*args, from_resolver: true, **kwargs)
334
- own_arguments_loads_as_type[arg_defn.keyword] = loads if loads
335
-
336
- if !method_defined?(:"load_#{arg_defn.keyword}")
337
- if loads && arg_defn.type.list?
338
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
339
- def load_#{arg_defn.keyword}(values)
340
- argument = @arguments_by_keyword[:#{arg_defn.keyword}]
341
- lookup_as_type = @arguments_loads_as_type[:#{arg_defn.keyword}]
342
- context.schema.after_lazy(values) do |values2|
343
- GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, lookup_as_type, value, context) })
344
- end
345
- end
346
- RUBY
347
- elsif loads
348
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
349
- def load_#{arg_defn.keyword}(value)
350
- argument = @arguments_by_keyword[:#{arg_defn.keyword}]
351
- lookup_as_type = @arguments_loads_as_type[:#{arg_defn.keyword}]
352
- load_application_object(argument, lookup_as_type, value, context)
353
- end
354
- RUBY
355
- else
356
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
357
- def load_#{arg_defn.keyword}(value)
358
- value
359
- end
360
- RUBY
361
- end
362
- end
363
-
364
- arg_defn
365
- end
366
-
367
- # @api private
368
- def arguments_loads_as_type
369
- inherited_lookups = superclass.respond_to?(:arguments_loads_as_type) ? superclass.arguments_loads_as_type : {}
370
- inherited_lookups.merge(own_arguments_loads_as_type)
373
+ super(*args, from_resolver: true, **kwargs)
371
374
  end
372
375
 
373
376
  # Registers new extension
@@ -403,10 +406,6 @@ module GraphQL
403
406
  def own_extensions
404
407
  @own_extensions
405
408
  end
406
-
407
- def own_arguments_loads_as_type
408
- @own_arguments_loads_as_type ||= {}
409
- end
410
409
  end
411
410
  end
412
411
  end
@@ -2,7 +2,6 @@
2
2
  module GraphQL
3
3
  class Schema
4
4
  class Scalar < GraphQL::Schema::Member
5
- extend GraphQL::Schema::Member::AcceptsDefinition
6
5
  extend GraphQL::Schema::Member::ValidatesInput
7
6
 
8
7
  class << self
@@ -14,22 +13,22 @@ module GraphQL
14
13
  val
15
14
  end
16
15
 
17
- def to_graphql
18
- type_defn = GraphQL::ScalarType.new
19
- type_defn.name = graphql_name
20
- type_defn.description = description
21
- type_defn.coerce_result = method(:coerce_result)
22
- type_defn.coerce_input = method(:coerce_input)
23
- type_defn.metadata[:type_class] = self
24
- type_defn.default_scalar = default_scalar
25
- type_defn.ast_node = ast_node
26
- type_defn
27
- end
28
-
29
16
  def kind
30
17
  GraphQL::TypeKinds::SCALAR
31
18
  end
32
19
 
20
+ def specified_by_url(new_url = nil)
21
+ if new_url
22
+ directive(GraphQL::Schema::Directive::SpecifiedBy, url: new_url)
23
+ elsif (directive = directives.find { |dir| dir.graphql_name == "specifiedBy" })
24
+ directive.arguments[:url] # rubocop:disable Development/ContextIsPassedCop
25
+ elsif superclass.respond_to?(:specified_by_url)
26
+ superclass.specified_by_url
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
33
32
  def default_scalar(is_default = nil)
34
33
  if !is_default.nil?
35
34
  @default_scalar = is_default
@@ -41,14 +40,13 @@ module GraphQL
41
40
  @default_scalar ||= false
42
41
  end
43
42
 
44
- def validate_non_null_input(value, ctx)
45
- result = Query::InputValidationResult.new
43
+ def validate_non_null_input(value, ctx, max_errors: nil)
46
44
  coerced_result = begin
47
- ctx.query.with_error_handling do
48
- coerce_input(value, ctx)
49
- end
45
+ coerce_input(value, ctx)
50
46
  rescue GraphQL::CoercionError => err
51
47
  err
48
+ rescue StandardError => err
49
+ ctx.query.handle_or_reraise(err)
52
50
  end
53
51
 
54
52
  if coerced_result.nil?
@@ -57,11 +55,12 @@ module GraphQL
57
55
  else
58
56
  " #{GraphQL::Language.serialize(value)}"
59
57
  end
60
- result.add_problem("Could not coerce value#{str_value} to #{graphql_name}")
58
+ Query::InputValidationResult.from_problem("Could not coerce value#{str_value} to #{graphql_name}")
61
59
  elsif coerced_result.is_a?(GraphQL::CoercionError)
62
- result.add_problem(coerced_result.message, message: coerced_result.message, extensions: coerced_result.extensions)
60
+ Query::InputValidationResult.from_problem(coerced_result.message, message: coerced_result.message, extensions: coerced_result.extensions)
61
+ else
62
+ nil
63
63
  end
64
- result
65
64
  end
66
65
  end
67
66
  end
@@ -14,7 +14,7 @@ module GraphQL
14
14
  class Subscription < GraphQL::Schema::Resolver
15
15
  extend GraphQL::Schema::Resolver::HasPayloadType
16
16
  extend GraphQL::Schema::Member::HasFields
17
-
17
+ NO_UPDATE = :no_update
18
18
  # The generated payload type is required; If there's no payload,
19
19
  # propagate null.
20
20
  null false
@@ -28,14 +28,19 @@ module GraphQL
28
28
  def resolve_with_support(**args)
29
29
  result = nil
30
30
  unsubscribed = true
31
- catch :graphql_subscription_unsubscribed do
31
+ unsubscribed_result = catch :graphql_subscription_unsubscribed do
32
32
  result = super
33
33
  unsubscribed = false
34
34
  end
35
35
 
36
36
 
37
37
  if unsubscribed
38
- context.skip
38
+ if unsubscribed_result
39
+ context.namespace(:subscriptions)[:final_update] = true
40
+ unsubscribed_result
41
+ else
42
+ context.skip
43
+ end
39
44
  else
40
45
  result
41
46
  end
@@ -58,11 +63,9 @@ module GraphQL
58
63
  end
59
64
  end
60
65
 
61
- # Default implementation returns the root object.
66
+ # The default implementation returns nothing on subscribe.
62
67
  # Override it to return an object or
63
- # `:no_response` to return nothing.
64
- #
65
- # The default is `:no_response`.
68
+ # `:no_response` to (explicitly) return nothing.
66
69
  def subscribe(args = {})
67
70
  :no_response
68
71
  end
@@ -70,7 +73,7 @@ module GraphQL
70
73
  # Wrap the user-provided `#update` hook
71
74
  def resolve_update(**args)
72
75
  ret_val = args.any? ? update(**args) : update
73
- if ret_val == :no_update
76
+ if ret_val == NO_UPDATE
74
77
  context.namespace(:subscriptions)[:no_update] = true
75
78
  context.skip
76
79
  else
@@ -79,7 +82,7 @@ module GraphQL
79
82
  end
80
83
 
81
84
  # The default implementation returns the root object.
82
- # Override it to return `:no_update` if you want to
85
+ # Override it to return {NO_UPDATE} if you want to
83
86
  # skip updates sometimes. Or override it to return a different object.
84
87
  def update(args = {})
85
88
  object
@@ -96,19 +99,23 @@ module GraphQL
96
99
  end
97
100
 
98
101
  # Call this to halt execution and remove this subscription from the system
99
- def unsubscribe
102
+ # @param update_value [Object] if present, deliver this update before unsubscribing
103
+ # @return [void]
104
+ def unsubscribe(update_value = nil)
100
105
  context.namespace(:subscriptions)[:unsubscribed] = true
101
- throw :graphql_subscription_unsubscribed
106
+ throw :graphql_subscription_unsubscribed, update_value
102
107
  end
103
108
 
104
109
  READING_SCOPE = ::Object.new
105
110
  # Call this method to provide a new subscription_scope; OR
106
111
  # call it without an argument to get the subscription_scope
107
112
  # @param new_scope [Symbol]
113
+ # @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription.
108
114
  # @return [Symbol]
109
- def self.subscription_scope(new_scope = READING_SCOPE)
115
+ def self.subscription_scope(new_scope = READING_SCOPE, optional: false)
110
116
  if new_scope != READING_SCOPE
111
117
  @subscription_scope = new_scope
118
+ @subscription_scope_optional = optional
112
119
  elsif defined?(@subscription_scope)
113
120
  @subscription_scope
114
121
  else
@@ -116,11 +123,32 @@ module GraphQL
116
123
  end
117
124
  end
118
125
 
119
- # Overriding Resolver#field_options to include subscription_scope
120
- def self.field_options
121
- super.merge(
122
- subscription_scope: subscription_scope
123
- )
126
+ def self.subscription_scope_optional?
127
+ if defined?(@subscription_scope_optional)
128
+ @subscription_scope_optional
129
+ else
130
+ find_inherited_value(:subscription_scope_optional, false)
131
+ end
132
+ end
133
+
134
+ # This is called during initial subscription to get a "name" for this subscription.
135
+ # Later, when `.trigger` is called, this will be called again to build another "name".
136
+ # Any subscribers with matching topic will begin the update flow.
137
+ #
138
+ # The default implementation creates a string using the field name, subscription scope, and argument keys and values.
139
+ # In that implementation, only `.trigger` calls with _exact matches_ result in updates to subscribers.
140
+ #
141
+ # To implement a filtered stream-type subscription flow, override this method to return a string with field name and subscription scope.
142
+ # Then, implement {#update} to compare its arguments to the current `object` and return {NO_UPDATE} when an
143
+ # update should be filtered out.
144
+ #
145
+ # @see {#update} for how to skip updates when an event comes with a matching topic.
146
+ # @param arguments [Hash<String => Object>] The arguments for this topic, in GraphQL-style (camelized strings)
147
+ # @param field [GraphQL::Schema::Field]
148
+ # @param scope [Object, nil] A value corresponding to `.trigger(... scope:)` (for updates) or the `subscription_scope` found in `context` (for initial subscriptions).
149
+ # @return [String] An identifier corresponding to a stream of updates
150
+ def self.topic_for(arguments:, field:, scope:)
151
+ Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
124
152
  end
125
153
  end
126
154
  end