graphql 1.12.12 → 2.2.14

Sign up to get free protection for your applications and to get access to all the features.
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