graphql 1.12.12 → 2.4.8

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 (428) 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 +60 -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 +8 -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 +22 -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/analyzer.rb +89 -0
  48. data/lib/graphql/analysis/field_usage.rb +65 -28
  49. data/lib/graphql/analysis/max_query_complexity.rb +11 -17
  50. data/lib/graphql/analysis/max_query_depth.rb +13 -19
  51. data/lib/graphql/analysis/query_complexity.rb +156 -61
  52. data/lib/graphql/analysis/query_depth.rb +38 -23
  53. data/lib/graphql/analysis/visitor.rb +283 -0
  54. data/lib/graphql/analysis.rb +90 -6
  55. data/lib/graphql/autoload.rb +38 -0
  56. data/lib/graphql/backtrace/inspect_result.rb +0 -12
  57. data/lib/graphql/backtrace/table.rb +4 -22
  58. data/lib/graphql/backtrace/trace.rb +93 -0
  59. data/lib/graphql/backtrace/tracer.rb +8 -6
  60. data/lib/graphql/backtrace.rb +3 -8
  61. data/lib/graphql/coercion_error.rb +1 -9
  62. data/lib/graphql/current.rb +52 -0
  63. data/lib/graphql/dataloader/async_dataloader.rb +89 -0
  64. data/lib/graphql/dataloader/null_dataloader.rb +4 -2
  65. data/lib/graphql/dataloader/request.rb +5 -0
  66. data/lib/graphql/dataloader/source.rb +125 -33
  67. data/lib/graphql/dataloader.rb +193 -143
  68. data/lib/graphql/date_encoding_error.rb +16 -0
  69. data/lib/graphql/dig.rb +1 -1
  70. data/lib/graphql/duration_encoding_error.rb +16 -0
  71. data/lib/graphql/execution/errors.rb +12 -81
  72. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  73. data/lib/graphql/execution/interpreter/arguments.rb +2 -2
  74. data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -36
  75. data/lib/graphql/execution/interpreter/resolve.rb +38 -4
  76. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
  77. data/lib/graphql/execution/interpreter/runtime.rb +447 -403
  78. data/lib/graphql/execution/interpreter.rb +126 -80
  79. data/lib/graphql/execution/lazy.rb +11 -21
  80. data/lib/graphql/execution/lookahead.rb +133 -55
  81. data/lib/graphql/execution/multiplex.rb +4 -172
  82. data/lib/graphql/execution.rb +11 -4
  83. data/lib/graphql/integer_encoding_error.rb +18 -2
  84. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  85. data/lib/graphql/introspection/directive_type.rb +6 -4
  86. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  87. data/lib/graphql/introspection/entry_points.rb +11 -18
  88. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  89. data/lib/graphql/introspection/field_type.rb +4 -4
  90. data/lib/graphql/introspection/input_value_type.rb +10 -4
  91. data/lib/graphql/introspection/schema_type.rb +17 -15
  92. data/lib/graphql/introspection/type_type.rb +29 -16
  93. data/lib/graphql/introspection.rb +6 -2
  94. data/lib/graphql/invalid_null_error.rb +1 -1
  95. data/lib/graphql/language/block_string.rb +37 -25
  96. data/lib/graphql/language/cache.rb +13 -0
  97. data/lib/graphql/language/comment.rb +18 -0
  98. data/lib/graphql/language/definition_slice.rb +1 -1
  99. data/lib/graphql/language/document_from_schema_definition.rb +122 -81
  100. data/lib/graphql/language/lexer.rb +364 -1467
  101. data/lib/graphql/language/nodes.rb +197 -106
  102. data/lib/graphql/language/parser.rb +799 -1920
  103. data/lib/graphql/language/printer.rb +372 -160
  104. data/lib/graphql/language/sanitized_printer.rb +25 -27
  105. data/lib/graphql/language/static_visitor.rb +167 -0
  106. data/lib/graphql/language/visitor.rb +188 -141
  107. data/lib/graphql/language.rb +62 -1
  108. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  109. data/lib/graphql/name_validator.rb +0 -4
  110. data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
  111. data/lib/graphql/pagination/array_connection.rb +8 -6
  112. data/lib/graphql/pagination/connection.rb +61 -7
  113. data/lib/graphql/pagination/connections.rb +22 -23
  114. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  115. data/lib/graphql/pagination/relation_connection.rb +60 -28
  116. data/lib/graphql/query/context/scoped_context.rb +101 -0
  117. data/lib/graphql/query/context.rb +146 -222
  118. data/lib/graphql/query/input_validation_result.rb +10 -1
  119. data/lib/graphql/query/null_context.rb +15 -32
  120. data/lib/graphql/query/validation_pipeline.rb +15 -39
  121. data/lib/graphql/query/variable_validation_error.rb +3 -3
  122. data/lib/graphql/query/variables.rb +35 -17
  123. data/lib/graphql/query.rb +149 -82
  124. data/lib/graphql/railtie.rb +15 -109
  125. data/lib/graphql/rake_task/validate.rb +1 -1
  126. data/lib/graphql/rake_task.rb +30 -11
  127. data/lib/graphql/relay/range_add.rb +9 -16
  128. data/lib/graphql/relay.rb +0 -15
  129. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  130. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  131. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  132. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  133. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  134. data/lib/graphql/rubocop.rb +6 -0
  135. data/lib/graphql/schema/addition.rb +98 -54
  136. data/lib/graphql/schema/always_visible.rb +14 -0
  137. data/lib/graphql/schema/argument.rb +179 -82
  138. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  139. data/lib/graphql/schema/build_from_definition.rb +77 -39
  140. data/lib/graphql/schema/directive/feature.rb +1 -1
  141. data/lib/graphql/schema/directive/flagged.rb +4 -4
  142. data/lib/graphql/schema/directive/include.rb +1 -1
  143. data/lib/graphql/schema/directive/one_of.rb +24 -0
  144. data/lib/graphql/schema/directive/skip.rb +1 -1
  145. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  146. data/lib/graphql/schema/directive/transform.rb +2 -2
  147. data/lib/graphql/schema/directive.rb +36 -22
  148. data/lib/graphql/schema/enum.rb +158 -63
  149. data/lib/graphql/schema/enum_value.rb +12 -21
  150. data/lib/graphql/schema/field/connection_extension.rb +7 -17
  151. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  152. data/lib/graphql/schema/field.rb +521 -359
  153. data/lib/graphql/schema/field_extension.rb +86 -2
  154. data/lib/graphql/schema/find_inherited_value.rb +3 -7
  155. data/lib/graphql/schema/finder.rb +5 -5
  156. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  157. data/lib/graphql/schema/input_object.rb +148 -99
  158. data/lib/graphql/schema/interface.rb +41 -64
  159. data/lib/graphql/schema/introspection_system.rb +12 -26
  160. data/lib/graphql/schema/late_bound_type.rb +12 -2
  161. data/lib/graphql/schema/list.rb +18 -7
  162. data/lib/graphql/schema/loader.rb +6 -5
  163. data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
  164. data/lib/graphql/schema/member/build_type.rb +16 -13
  165. data/lib/graphql/schema/member/has_arguments.rb +270 -86
  166. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  167. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  168. data/lib/graphql/schema/member/has_directives.rb +81 -61
  169. data/lib/graphql/schema/member/has_fields.rb +169 -31
  170. data/lib/graphql/schema/member/has_interfaces.rb +143 -0
  171. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  172. data/lib/graphql/schema/member/has_validators.rb +32 -6
  173. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  174. data/lib/graphql/schema/member/scoped.rb +19 -0
  175. data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
  176. data/lib/graphql/schema/member/validates_input.rb +6 -6
  177. data/lib/graphql/schema/member.rb +1 -6
  178. data/lib/graphql/schema/mutation.rb +7 -9
  179. data/lib/graphql/schema/non_null.rb +7 -7
  180. data/lib/graphql/schema/object.rb +38 -119
  181. data/lib/graphql/schema/printer.rb +24 -25
  182. data/lib/graphql/schema/relay_classic_mutation.rb +13 -91
  183. data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
  184. data/lib/graphql/schema/resolver.rb +118 -115
  185. data/lib/graphql/schema/scalar.rb +20 -21
  186. data/lib/graphql/schema/subscription.rb +95 -21
  187. data/lib/graphql/schema/timeout.rb +25 -29
  188. data/lib/graphql/schema/type_expression.rb +2 -2
  189. data/lib/graphql/schema/type_membership.rb +21 -4
  190. data/lib/graphql/schema/union.rb +16 -16
  191. data/lib/graphql/schema/unique_within_type.rb +1 -1
  192. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  193. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  194. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  195. data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
  196. data/lib/graphql/schema/validator/format_validator.rb +4 -5
  197. data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
  198. data/lib/graphql/schema/validator/length_validator.rb +5 -3
  199. data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
  200. data/lib/graphql/schema/validator/required_validator.rb +56 -18
  201. data/lib/graphql/schema/validator.rb +38 -28
  202. data/lib/graphql/schema/visibility/migration.rb +188 -0
  203. data/lib/graphql/schema/visibility/profile.rb +359 -0
  204. data/lib/graphql/schema/visibility/visit.rb +190 -0
  205. data/lib/graphql/schema/visibility.rb +294 -0
  206. data/lib/graphql/schema/warden.rb +423 -134
  207. data/lib/graphql/schema/wrapper.rb +0 -5
  208. data/lib/graphql/schema.rb +1015 -1057
  209. data/lib/graphql/static_validation/all_rules.rb +3 -1
  210. data/lib/graphql/static_validation/base_visitor.rb +15 -28
  211. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  212. data/lib/graphql/static_validation/error.rb +3 -1
  213. data/lib/graphql/static_validation/literal_validator.rb +24 -7
  214. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  215. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  216. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +4 -3
  217. data/lib/graphql/static_validation/rules/directives_are_defined.rb +13 -7
  218. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +15 -13
  219. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  220. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +13 -5
  221. data/lib/graphql/static_validation/rules/fields_will_merge.rb +62 -35
  222. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  223. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  224. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  225. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  226. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  227. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  228. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  229. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  230. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  231. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  232. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  233. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -5
  234. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  235. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  236. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +14 -8
  237. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  238. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  239. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
  240. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  241. data/lib/graphql/static_validation/validation_context.rb +32 -6
  242. data/lib/graphql/static_validation/validator.rb +11 -27
  243. data/lib/graphql/static_validation.rb +0 -3
  244. data/lib/graphql/string_encoding_error.rb +13 -3
  245. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +49 -11
  246. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  247. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
  248. data/lib/graphql/subscriptions/event.rb +87 -38
  249. data/lib/graphql/subscriptions/serialize.rb +27 -3
  250. data/lib/graphql/subscriptions.rb +63 -49
  251. data/lib/graphql/testing/helpers.rb +155 -0
  252. data/lib/graphql/testing.rb +2 -0
  253. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  254. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  255. data/lib/graphql/tracing/appoptics_trace.rb +253 -0
  256. data/lib/graphql/tracing/appoptics_tracing.rb +4 -2
  257. data/lib/graphql/tracing/appsignal_trace.rb +79 -0
  258. data/lib/graphql/tracing/appsignal_tracing.rb +17 -0
  259. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  260. data/lib/graphql/tracing/data_dog_trace.rb +185 -0
  261. data/lib/graphql/tracing/data_dog_tracing.rb +27 -15
  262. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
  263. data/lib/graphql/tracing/legacy_trace.rb +12 -0
  264. data/lib/graphql/tracing/new_relic_trace.rb +77 -0
  265. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  266. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  267. data/lib/graphql/tracing/notifications_tracing.rb +61 -0
  268. data/lib/graphql/tracing/null_trace.rb +9 -0
  269. data/lib/graphql/tracing/platform_trace.rb +118 -0
  270. data/lib/graphql/tracing/platform_tracing.rb +46 -49
  271. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
  272. data/lib/graphql/tracing/prometheus_trace.rb +94 -0
  273. data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
  274. data/lib/graphql/tracing/scout_trace.rb +74 -0
  275. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  276. data/lib/graphql/tracing/sentry_trace.rb +114 -0
  277. data/lib/graphql/tracing/statsd_trace.rb +58 -0
  278. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  279. data/lib/graphql/tracing/trace.rb +79 -0
  280. data/lib/graphql/tracing.rb +29 -52
  281. data/lib/graphql/type_kinds.rb +7 -4
  282. data/lib/graphql/types/big_int.rb +5 -1
  283. data/lib/graphql/types/int.rb +1 -1
  284. data/lib/graphql/types/iso_8601_date.rb +17 -6
  285. data/lib/graphql/types/iso_8601_date_time.rb +12 -1
  286. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  287. data/lib/graphql/types/relay/base_connection.rb +16 -6
  288. data/lib/graphql/types/relay/connection_behaviors.rb +92 -32
  289. data/lib/graphql/types/relay/edge_behaviors.rb +46 -7
  290. data/lib/graphql/types/relay/has_node_field.rb +2 -2
  291. data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
  292. data/lib/graphql/types/relay/node_behaviors.rb +12 -2
  293. data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
  294. data/lib/graphql/types/relay.rb +0 -3
  295. data/lib/graphql/types/string.rb +2 -2
  296. data/lib/graphql/types.rb +18 -10
  297. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  298. data/lib/graphql/unauthorized_error.rb +1 -1
  299. data/lib/graphql/version.rb +1 -1
  300. data/lib/graphql.rb +82 -137
  301. data/readme.md +13 -6
  302. metadata +127 -186
  303. data/lib/graphql/analysis/analyze_query.rb +0 -98
  304. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  305. data/lib/graphql/analysis/ast/field_usage.rb +0 -28
  306. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
  307. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  308. data/lib/graphql/analysis/ast/query_complexity.rb +0 -234
  309. data/lib/graphql/analysis/ast/query_depth.rb +0 -56
  310. data/lib/graphql/analysis/ast/visitor.rb +0 -268
  311. data/lib/graphql/analysis/ast.rb +0 -91
  312. data/lib/graphql/analysis/reducer_state.rb +0 -48
  313. data/lib/graphql/argument.rb +0 -131
  314. data/lib/graphql/authorization.rb +0 -82
  315. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  316. data/lib/graphql/backwards_compatibility.rb +0 -61
  317. data/lib/graphql/base_type.rb +0 -230
  318. data/lib/graphql/boolean_type.rb +0 -2
  319. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  320. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  321. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  322. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  323. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  324. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  325. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  326. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  327. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  328. data/lib/graphql/compatibility.rb +0 -5
  329. data/lib/graphql/define/assign_argument.rb +0 -12
  330. data/lib/graphql/define/assign_connection.rb +0 -13
  331. data/lib/graphql/define/assign_enum_value.rb +0 -18
  332. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  333. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  334. data/lib/graphql/define/assign_object_field.rb +0 -42
  335. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  336. data/lib/graphql/define/instance_definable.rb +0 -240
  337. data/lib/graphql/define/no_definition_error.rb +0 -7
  338. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  339. data/lib/graphql/define/type_definer.rb +0 -31
  340. data/lib/graphql/define.rb +0 -31
  341. data/lib/graphql/deprecated_dsl.rb +0 -47
  342. data/lib/graphql/deprecation.rb +0 -13
  343. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  344. data/lib/graphql/directive/include_directive.rb +0 -2
  345. data/lib/graphql/directive/skip_directive.rb +0 -2
  346. data/lib/graphql/directive.rb +0 -111
  347. data/lib/graphql/enum_type.rb +0 -129
  348. data/lib/graphql/execution/execute.rb +0 -333
  349. data/lib/graphql/execution/flatten.rb +0 -40
  350. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  351. data/lib/graphql/execution/typecast.rb +0 -50
  352. data/lib/graphql/field/resolve.rb +0 -59
  353. data/lib/graphql/field.rb +0 -226
  354. data/lib/graphql/filter.rb +0 -53
  355. data/lib/graphql/float_type.rb +0 -2
  356. data/lib/graphql/function.rb +0 -128
  357. data/lib/graphql/id_type.rb +0 -2
  358. data/lib/graphql/input_object_type.rb +0 -138
  359. data/lib/graphql/int_type.rb +0 -2
  360. data/lib/graphql/interface_type.rb +0 -72
  361. data/lib/graphql/internal_representation/document.rb +0 -27
  362. data/lib/graphql/internal_representation/node.rb +0 -206
  363. data/lib/graphql/internal_representation/print.rb +0 -51
  364. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  365. data/lib/graphql/internal_representation/scope.rb +0 -88
  366. data/lib/graphql/internal_representation/visit.rb +0 -36
  367. data/lib/graphql/internal_representation.rb +0 -7
  368. data/lib/graphql/language/lexer.rl +0 -262
  369. data/lib/graphql/language/parser.y +0 -543
  370. data/lib/graphql/language/token.rb +0 -38
  371. data/lib/graphql/list_type.rb +0 -80
  372. data/lib/graphql/non_null_type.rb +0 -71
  373. data/lib/graphql/object_type.rb +0 -130
  374. data/lib/graphql/query/arguments.rb +0 -189
  375. data/lib/graphql/query/arguments_cache.rb +0 -24
  376. data/lib/graphql/query/executor.rb +0 -52
  377. data/lib/graphql/query/literal_input.rb +0 -136
  378. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  379. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  380. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  381. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  382. data/lib/graphql/query/serial_execution.rb +0 -40
  383. data/lib/graphql/relay/array_connection.rb +0 -83
  384. data/lib/graphql/relay/base_connection.rb +0 -189
  385. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  386. data/lib/graphql/relay/connection_resolve.rb +0 -43
  387. data/lib/graphql/relay/connection_type.rb +0 -41
  388. data/lib/graphql/relay/edge.rb +0 -27
  389. data/lib/graphql/relay/edge_type.rb +0 -19
  390. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  391. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  392. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  393. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  394. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  395. data/lib/graphql/relay/mutation/result.rb +0 -38
  396. data/lib/graphql/relay/mutation.rb +0 -106
  397. data/lib/graphql/relay/node.rb +0 -39
  398. data/lib/graphql/relay/page_info.rb +0 -7
  399. data/lib/graphql/relay/relation_connection.rb +0 -188
  400. data/lib/graphql/relay/type_extensions.rb +0 -32
  401. data/lib/graphql/scalar_type.rb +0 -91
  402. data/lib/graphql/schema/base_64_bp.rb +0 -26
  403. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  404. data/lib/graphql/schema/default_parse_error.rb +0 -10
  405. data/lib/graphql/schema/default_type_error.rb +0 -17
  406. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  407. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  408. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
  409. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  410. data/lib/graphql/schema/middleware_chain.rb +0 -82
  411. data/lib/graphql/schema/possible_types.rb +0 -44
  412. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  413. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  414. data/lib/graphql/schema/traversal.rb +0 -228
  415. data/lib/graphql/schema/validation.rb +0 -313
  416. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  417. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  418. data/lib/graphql/static_validation/type_stack.rb +0 -216
  419. data/lib/graphql/string_type.rb +0 -2
  420. data/lib/graphql/subscriptions/instrumentation.rb +0 -79
  421. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  422. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  423. data/lib/graphql/types/relay/default_relay.rb +0 -27
  424. data/lib/graphql/types/relay/node_field.rb +0 -25
  425. data/lib/graphql/types/relay/nodes_field.rb +0 -27
  426. data/lib/graphql/union_type.rb +0 -115
  427. data/lib/graphql/upgrader/member.rb +0 -937
  428. data/lib/graphql/upgrader/schema.rb +0 -38
@@ -8,6 +8,7 @@ module GraphQL
8
8
  # - Arguments, via `.argument(...)` helper, which will be applied to the field.
9
9
  # - Return type, via `.type(..., null: ...)`, which will be applied to the field.
10
10
  # - Description, via `.description(...)`, which will be applied to the field
11
+ # - Comment, via `.comment(...)`, which will be applied to the field
11
12
  # - Resolution, via `#resolve(**args)` method, which will be called to resolve the field.
12
13
  # - `#object` and `#context` accessors for use during `#resolve`.
13
14
  #
@@ -15,20 +16,19 @@ module GraphQL
15
16
  #
16
17
  # A resolver's configuration may be overridden with other keywords in the `field(...)` call.
17
18
  #
18
- # See the {.field_options} to see how a Resolver becomes a set of field configuration options.
19
- #
20
19
  # @see {GraphQL::Schema::Mutation} for a concrete subclass of `Resolver`.
21
20
  # @see {GraphQL::Function} `Resolver` is a replacement for `GraphQL::Function`
22
21
  class Resolver
23
22
  include Schema::Member::GraphQLTypeNames
24
- # Really we only need description from here, but:
23
+ # Really we only need description & comment from here, but:
25
24
  extend Schema::Member::BaseDSLMethods
26
25
  extend GraphQL::Schema::Member::HasArguments
27
26
  extend GraphQL::Schema::Member::HasValidators
28
27
  include Schema::Member::HasPath
29
28
  extend Schema::Member::HasPath
29
+ extend Schema::Member::HasDirectives
30
30
 
31
- # @param object [Object] the initialize object, pass to {Query.initialize} as `root_value`
31
+ # @param object [Object] The application object that this field is being resolved on
32
32
  # @param context [GraphQL::Query::Context]
33
33
  # @param field [GraphQL::Schema::Field]
34
34
  def initialize(object:, context:, field:)
@@ -37,10 +37,9 @@ module GraphQL
37
37
  @field = field
38
38
  # Since this hash is constantly rebuilt, cache it for this call
39
39
  @arguments_by_keyword = {}
40
- self.class.arguments.each do |name, arg|
40
+ context.types.arguments(self.class).each do |arg|
41
41
  @arguments_by_keyword[arg.keyword] = arg
42
42
  end
43
- @arguments_loads_as_type = self.class.arguments_loads_as_type
44
43
  @prepared_arguments = nil
45
44
  end
46
45
 
@@ -68,49 +67,47 @@ module GraphQL
68
67
  # @api private
69
68
  def resolve_with_support(**args)
70
69
  # First call the ready? hook which may raise
71
- ready_val = if args.any?
70
+ raw_ready_val = if !args.empty?
72
71
  ready?(**args)
73
72
  else
74
73
  ready?
75
74
  end
76
- context.schema.after_lazy(ready_val) do |is_ready, ready_early_return|
77
- if ready_early_return
75
+ context.query.after_lazy(raw_ready_val) do |ready_val|
76
+ if ready_val.is_a?(Array)
77
+ is_ready, ready_early_return = ready_val
78
78
  if is_ready != false
79
- raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{authorized_result.inspect}, #{ready_early_return.inspect}]"
79
+ raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{is_ready.inspect}, #{ready_early_return.inspect}]"
80
80
  else
81
81
  ready_early_return
82
82
  end
83
- elsif is_ready
83
+ elsif ready_val
84
84
  # Then call each prepare hook, which may return a different value
85
85
  # for that argument, or may return a lazy object
86
86
  load_arguments_val = load_arguments(args)
87
- context.schema.after_lazy(load_arguments_val) do |loaded_args|
87
+ context.query.after_lazy(load_arguments_val) do |loaded_args|
88
88
  @prepared_arguments = loaded_args
89
89
  Schema::Validator.validate!(self.class.validators, object, context, loaded_args, as: @field)
90
90
  # Then call `authorized?`, which may raise or may return a lazy object
91
- authorized_val = if loaded_args.any?
91
+ raw_authorized_val = if !loaded_args.empty?
92
92
  authorized?(**loaded_args)
93
93
  else
94
94
  authorized?
95
95
  end
96
- context.schema.after_lazy(authorized_val) do |(authorized_result, early_return)|
96
+ context.query.after_lazy(raw_authorized_val) do |authorized_val|
97
97
  # If the `authorized?` returned two values, `false, early_return`,
98
98
  # then use the early return value instead of continuing
99
- if early_return
99
+ if authorized_val.is_a?(Array)
100
+ authorized_result, early_return = authorized_val
100
101
  if authorized_result == false
101
102
  early_return
102
103
  else
103
104
  raise "Unexpected result from #authorized? (expected `true`, `false` or `[false, {...}]`): [#{authorized_result.inspect}, #{early_return.inspect}]"
104
105
  end
105
- elsif authorized_result
106
+ elsif authorized_val
106
107
  # Finally, all the hooks have passed, so resolve it
107
- if loaded_args.any?
108
- public_send(self.class.resolve_method, **loaded_args)
109
- else
110
- public_send(self.class.resolve_method)
111
- end
108
+ call_resolve(loaded_args)
112
109
  else
113
- nil
110
+ raise GraphQL::UnauthorizedFieldError.new(context: context, object: object, type: field.owner, field: field)
114
111
  end
115
112
  end
116
113
  end
@@ -118,6 +115,15 @@ module GraphQL
118
115
  end
119
116
  end
120
117
 
118
+ # @api private {GraphQL::Schema::Mutation} uses this to clear the dataloader cache
119
+ def call_resolve(args_hash)
120
+ if !args_hash.empty?
121
+ public_send(self.class.resolve_method, **args_hash)
122
+ else
123
+ public_send(self.class.resolve_method)
124
+ end
125
+ end
126
+
121
127
  # Do the work. Everything happens here.
122
128
  # @return [Object] An object corresponding to the return type
123
129
  def resolve(**args)
@@ -146,23 +152,42 @@ module GraphQL
146
152
  # @raise [GraphQL::UnauthorizedError] To signal an authorization failure
147
153
  # @return [Boolean, early_return_data] If `false`, execution will stop (and `early_return_data` will be returned instead, if present.)
148
154
  def authorized?(**inputs)
149
- self.class.arguments.each_value do |argument|
155
+ arg_owner = @field # || self.class
156
+ args = context.types.arguments(arg_owner)
157
+ authorize_arguments(args, inputs)
158
+ end
159
+
160
+ # Called when an object loaded by `loads:` fails the `.authorized?` check for its resolved GraphQL object type.
161
+ #
162
+ # By default, the error is re-raised and passed along to {{Schema.unauthorized_object}}.
163
+ #
164
+ # Any value returned here will be used _instead of_ of the loaded object.
165
+ # @param err [GraphQL::UnauthorizedError]
166
+ def unauthorized_object(err)
167
+ raise err
168
+ end
169
+
170
+ private
171
+
172
+ def authorize_arguments(args, inputs)
173
+ args.each do |argument|
150
174
  arg_keyword = argument.keyword
151
175
  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
176
+ auth_result = argument.authorized?(self, arg_value, context)
177
+ if auth_result.is_a?(Array)
178
+ # only return this second value if the application returned a second value
179
+ arg_auth, err = auth_result
180
+ if !arg_auth
181
+ return arg_auth, err
182
+ end
183
+ elsif auth_result == false
184
+ return auth_result
157
185
  end
158
- else
159
- true
160
186
  end
161
187
  end
188
+ true
162
189
  end
163
190
 
164
- private
165
-
166
191
  def load_arguments(args)
167
192
  prepared_args = {}
168
193
  prepare_lazies = []
@@ -170,35 +195,47 @@ module GraphQL
170
195
  args.each do |key, value|
171
196
  arg_defn = @arguments_by_keyword[key]
172
197
  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
198
+ prepped_value = prepared_args[key] = arg_defn.load_and_authorize_value(self, value, context)
199
+ if context.schema.lazy?(prepped_value)
200
+ prepare_lazies << context.query.after_lazy(prepped_value) do |finished_prepped_value|
201
+ prepared_args[key] = finished_prepped_value
181
202
  end
182
203
  end
183
204
  else
184
- # These are `extras: [...]`
205
+ # these are `extras:`
185
206
  prepared_args[key] = value
186
207
  end
187
208
  end
188
209
 
189
210
  # Avoid returning a lazy if none are needed
190
- if prepare_lazies.any?
211
+ if !prepare_lazies.empty?
191
212
  GraphQL::Execution::Lazy.all(prepare_lazies).then { prepared_args }
192
213
  else
193
214
  prepared_args
194
215
  end
195
216
  end
196
217
 
197
- def load_argument(name, value)
198
- public_send("load_#{name}", value)
218
+ def get_argument(name, context = GraphQL::Query::NullContext.instance)
219
+ self.class.get_argument(name, context)
199
220
  end
200
221
 
201
222
  class << self
223
+ def field_arguments(context = GraphQL::Query::NullContext.instance)
224
+ arguments(context)
225
+ end
226
+
227
+ def any_field_arguments?
228
+ any_arguments?
229
+ end
230
+
231
+ def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
232
+ get_argument(name, context)
233
+ end
234
+
235
+ def all_field_argument_definitions
236
+ all_argument_definitions
237
+ end
238
+
202
239
  # Default `:resolve` set below.
203
240
  # @return [Symbol] The method to call on instances of this object to resolve the field
204
241
  def resolve_method(new_method = nil)
@@ -218,8 +255,10 @@ module GraphQL
218
255
  own_extras + (superclass.respond_to?(:extras) ? superclass.extras : [])
219
256
  end
220
257
 
221
- # Specifies whether or not the field is nullable. Defaults to `true`
222
- # TODO unify with {#type}
258
+ # If `true` (default), then the return type for this resolver will be nullable.
259
+ # If `false`, then the return type is non-null.
260
+ #
261
+ # @see #type which sets the return type of this field and accepts a `null:` option
223
262
  # @param allow_null [Boolean] Whether or not the response can be null
224
263
  def null(allow_null = nil)
225
264
  if !allow_null.nil?
@@ -229,6 +268,14 @@ module GraphQL
229
268
  @null.nil? ? (superclass.respond_to?(:null) ? superclass.null : true) : @null
230
269
  end
231
270
 
271
+ def resolver_method(new_method_name = nil)
272
+ if new_method_name
273
+ @resolver_method = new_method_name
274
+ else
275
+ @resolver_method || :resolve_with_support
276
+ end
277
+ end
278
+
232
279
  # Call this method to get the return type of the field,
233
280
  # or use it as a configuration method to assign a return type
234
281
  # instead of generating one.
@@ -244,8 +291,8 @@ module GraphQL
244
291
  @type_expr = new_type
245
292
  @null = null
246
293
  else
247
- if @type_expr
248
- GraphQL::Schema::Member::BuildType.parse_type(@type_expr, null: @null)
294
+ if type_expr
295
+ GraphQL::Schema::Member::BuildType.parse_type(type_expr, null: self.null)
249
296
  elsif superclass.respond_to?(:type)
250
297
  superclass.type
251
298
  else
@@ -280,8 +327,8 @@ module GraphQL
280
327
  # (`nil` means "unlimited max page size".)
281
328
  # @param max_page_size [Integer, nil] Set a new value
282
329
  # @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
330
+ def max_page_size(new_max_page_size = NOT_CONFIGURED)
331
+ if new_max_page_size != NOT_CONFIGURED
285
332
  @max_page_size = new_max_page_size
286
333
  elsif defined?(@max_page_size)
287
334
  @max_page_size
@@ -294,28 +341,28 @@ module GraphQL
294
341
 
295
342
  # @return [Boolean] `true` if this resolver or a superclass has an assigned `max_page_size`
296
343
  def has_max_page_size?
297
- defined?(@max_page_size) || (superclass.respond_to?(:has_max_page_size?) && superclass.has_max_page_size?)
344
+ (!!defined?(@max_page_size)) || (superclass.respond_to?(:has_max_page_size?) && superclass.has_max_page_size?)
298
345
  end
299
346
 
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
347
+ # Get or set the `default_page_size:` which will be configured for fields using this resolver
348
+ # (`nil` means "unlimited default page size".)
349
+ # @param default_page_size [Integer, nil] Set a new value
350
+ # @return [Integer, nil] The `default_page_size` assigned to fields that use this resolver
351
+ def default_page_size(new_default_page_size = NOT_CONFIGURED)
352
+ if new_default_page_size != NOT_CONFIGURED
353
+ @default_page_size = new_default_page_size
354
+ elsif defined?(@default_page_size)
355
+ @default_page_size
356
+ elsif superclass.respond_to?(:default_page_size)
357
+ superclass.default_page_size
358
+ else
359
+ nil
316
360
  end
361
+ end
317
362
 
318
- field_opts
363
+ # @return [Boolean] `true` if this resolver or a superclass has an assigned `default_page_size`
364
+ def has_default_page_size?
365
+ (!!defined?(@default_page_size)) || (superclass.respond_to?(:has_default_page_size?) && superclass.has_default_page_size?)
319
366
  end
320
367
 
321
368
  # A non-normalized type configuration, without `null` applied
@@ -327,47 +374,9 @@ module GraphQL
327
374
  # also add some preparation hook methods which will be used for this argument
328
375
  # @see {GraphQL::Schema::Argument#initialize} for the signature
329
376
  def argument(*args, **kwargs, &block)
330
- loads = kwargs[:loads]
331
377
  # Use `from_resolver: true` to short-circuit the InputObject's own `loads:` implementation
332
378
  # 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)
379
+ super(*args, from_resolver: true, **kwargs)
371
380
  end
372
381
 
373
382
  # Registers new extension
@@ -385,7 +394,7 @@ module GraphQL
385
394
  if superclass.respond_to?(:extensions)
386
395
  s_exts = superclass.extensions
387
396
  if own_exts
388
- if s_exts.any?
397
+ if !s_exts.empty?
389
398
  own_exts + s_exts
390
399
  else
391
400
  own_exts
@@ -400,13 +409,7 @@ module GraphQL
400
409
 
401
410
  private
402
411
 
403
- def own_extensions
404
- @own_extensions
405
- end
406
-
407
- def own_arguments_loads_as_type
408
- @own_arguments_loads_as_type ||= {}
409
- end
412
+ attr_reader :own_extensions
410
413
  end
411
414
  end
412
415
  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,34 +14,50 @@ 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
21
21
 
22
+ # @api private
22
23
  def initialize(object:, context:, field:)
23
24
  super
24
25
  # Figure out whether this is an update or an initial subscription
25
26
  @mode = context.query.subscription_update? ? :update : :subscribe
27
+ @subscription_written = false
28
+ @original_arguments = nil
29
+ if (subs_ns = context.namespace(:subscriptions)) &&
30
+ (sub_insts = subs_ns[:subscriptions])
31
+ sub_insts[context.current_path] = self
32
+ end
26
33
  end
27
34
 
35
+ # @api private
28
36
  def resolve_with_support(**args)
37
+ @original_arguments = args # before `loads:` have been run
29
38
  result = nil
30
39
  unsubscribed = true
31
- catch :graphql_subscription_unsubscribed do
40
+ unsubscribed_result = catch :graphql_subscription_unsubscribed do
32
41
  result = super
33
42
  unsubscribed = false
34
43
  end
35
44
 
36
45
 
37
46
  if unsubscribed
38
- context.skip
47
+ if unsubscribed_result
48
+ context.namespace(:subscriptions)[:final_update] = true
49
+ unsubscribed_result
50
+ else
51
+ context.skip
52
+ end
39
53
  else
40
54
  result
41
55
  end
42
56
  end
43
57
 
44
- # Implement the {Resolve} API
58
+ # Implement the {Resolve} API.
59
+ # You can implement this if you want code to run for _both_ the initial subscription
60
+ # and for later updates. Or, implement {#subscribe} and {#update}
45
61
  def resolve(**args)
46
62
  # Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
47
63
  # have an unexpected `@mode`
@@ -49,8 +65,9 @@ module GraphQL
49
65
  end
50
66
 
51
67
  # Wrap the user-defined `#subscribe` hook
68
+ # @api private
52
69
  def resolve_subscribe(**args)
53
- ret_val = args.any? ? subscribe(**args) : subscribe
70
+ ret_val = !args.empty? ? subscribe(**args) : subscribe
54
71
  if ret_val == :no_response
55
72
  context.skip
56
73
  else
@@ -58,19 +75,18 @@ module GraphQL
58
75
  end
59
76
  end
60
77
 
61
- # Default implementation returns the root object.
78
+ # The default implementation returns nothing on subscribe.
62
79
  # Override it to return an object or
63
- # `:no_response` to return nothing.
64
- #
65
- # The default is `:no_response`.
80
+ # `:no_response` to (explicitly) return nothing.
66
81
  def subscribe(args = {})
67
82
  :no_response
68
83
  end
69
84
 
70
85
  # Wrap the user-provided `#update` hook
86
+ # @api private
71
87
  def resolve_update(**args)
72
- ret_val = args.any? ? update(**args) : update
73
- if ret_val == :no_update
88
+ ret_val = !args.empty? ? update(**args) : update
89
+ if ret_val == NO_UPDATE
74
90
  context.namespace(:subscriptions)[:no_update] = true
75
91
  context.skip
76
92
  else
@@ -79,7 +95,7 @@ module GraphQL
79
95
  end
80
96
 
81
97
  # The default implementation returns the root object.
82
- # Override it to return `:no_update` if you want to
98
+ # Override it to return {NO_UPDATE} if you want to
83
99
  # skip updates sometimes. Or override it to return a different object.
84
100
  def update(args = {})
85
101
  object
@@ -96,19 +112,22 @@ module GraphQL
96
112
  end
97
113
 
98
114
  # Call this to halt execution and remove this subscription from the system
99
- def unsubscribe
115
+ # @param update_value [Object] if present, deliver this update before unsubscribing
116
+ # @return [void]
117
+ def unsubscribe(update_value = nil)
100
118
  context.namespace(:subscriptions)[:unsubscribed] = true
101
- throw :graphql_subscription_unsubscribed
119
+ throw :graphql_subscription_unsubscribed, update_value
102
120
  end
103
121
 
104
- READING_SCOPE = ::Object.new
105
122
  # Call this method to provide a new subscription_scope; OR
106
123
  # call it without an argument to get the subscription_scope
107
124
  # @param new_scope [Symbol]
125
+ # @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription.
108
126
  # @return [Symbol]
109
- def self.subscription_scope(new_scope = READING_SCOPE)
110
- if new_scope != READING_SCOPE
127
+ def self.subscription_scope(new_scope = NOT_CONFIGURED, optional: false)
128
+ if new_scope != NOT_CONFIGURED
111
129
  @subscription_scope = new_scope
130
+ @subscription_scope_optional = optional
112
131
  elsif defined?(@subscription_scope)
113
132
  @subscription_scope
114
133
  else
@@ -116,10 +135,65 @@ module GraphQL
116
135
  end
117
136
  end
118
137
 
119
- # Overriding Resolver#field_options to include subscription_scope
120
- def self.field_options
121
- super.merge(
122
- subscription_scope: subscription_scope
138
+ def self.subscription_scope_optional?
139
+ if defined?(@subscription_scope_optional)
140
+ @subscription_scope_optional
141
+ else
142
+ find_inherited_value(:subscription_scope_optional, false)
143
+ end
144
+ end
145
+
146
+ # This is called during initial subscription to get a "name" for this subscription.
147
+ # Later, when `.trigger` is called, this will be called again to build another "name".
148
+ # Any subscribers with matching topic will begin the update flow.
149
+ #
150
+ # The default implementation creates a string using the field name, subscription scope, and argument keys and values.
151
+ # In that implementation, only `.trigger` calls with _exact matches_ result in updates to subscribers.
152
+ #
153
+ # To implement a filtered stream-type subscription flow, override this method to return a string with field name and subscription scope.
154
+ # Then, implement {#update} to compare its arguments to the current `object` and return {NO_UPDATE} when an
155
+ # update should be filtered out.
156
+ #
157
+ # @see {#update} for how to skip updates when an event comes with a matching topic.
158
+ # @param arguments [Hash<String => Object>] The arguments for this topic, in GraphQL-style (camelized strings)
159
+ # @param field [GraphQL::Schema::Field]
160
+ # @param scope [Object, nil] A value corresponding to `.trigger(... scope:)` (for updates) or the `subscription_scope` found in `context` (for initial subscriptions).
161
+ # @return [String] An identifier corresponding to a stream of updates
162
+ def self.topic_for(arguments:, field:, scope:)
163
+ Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
164
+ end
165
+
166
+ # Calls through to `schema.subscriptions` to register this subscription with the backend.
167
+ # This is automatically called by GraphQL-Ruby after a query finishes successfully,
168
+ # but if you need to commit the subscription during `#subscribe`, you can call it there.
169
+ # (This method also sets a flag showing that this subscription was already written.)
170
+ #
171
+ # If you call this method yourself, you may also need to {#unsubscribe}
172
+ # or call `subscriptions.delete_subscription` to clean up the database if the query crashes with an error
173
+ # later in execution.
174
+ # @return [void]
175
+ def write_subscription
176
+ if subscription_written?
177
+ raise GraphQL::Error, "`write_subscription` was called but `#{self.class}#subscription_written?` is already true. Remove a call to `write subscription`."
178
+ else
179
+ @subscription_written = true
180
+ context.schema.subscriptions.write_subscription(context.query, [event])
181
+ end
182
+ nil
183
+ end
184
+
185
+ # @return [Boolean] `true` if {#write_subscription} was called already
186
+ def subscription_written?
187
+ @subscription_written
188
+ end
189
+
190
+ # @return [Subscriptions::Event] This object is used as a representation of this subscription for the backend
191
+ def event
192
+ @event ||= Subscriptions::Event.new(
193
+ name: field.name,
194
+ arguments: @original_arguments,
195
+ context: context,
196
+ field: field,
123
197
  )
124
198
  end
125
199
  end