graphql 1.9.21 → 2.0.0

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 (397) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +21 -10
  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 +44 -7
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/loader_generator.rb +1 -0
  12. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  14. data/lib/generators/graphql/mutation_generator.rb +6 -30
  15. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  16. data/lib/generators/graphql/object_generator.rb +28 -12
  17. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  18. data/lib/generators/graphql/relay.rb +63 -0
  19. data/lib/generators/graphql/relay_generator.rb +21 -0
  20. data/lib/generators/graphql/scalar_generator.rb +4 -2
  21. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  22. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  23. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  24. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  25. data/lib/generators/graphql/templates/base_field.erb +2 -0
  26. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  28. data/lib/generators/graphql/templates/base_object.erb +2 -0
  29. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  30. data/lib/generators/graphql/templates/base_union.erb +2 -0
  31. data/lib/generators/graphql/templates/enum.erb +7 -1
  32. data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
  33. data/lib/generators/graphql/templates/input.erb +9 -0
  34. data/lib/generators/graphql/templates/interface.erb +6 -2
  35. data/lib/generators/graphql/templates/loader.erb +2 -0
  36. data/lib/generators/graphql/templates/mutation.erb +3 -1
  37. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  39. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  40. data/lib/generators/graphql/templates/node_type.erb +9 -0
  41. data/lib/generators/graphql/templates/object.erb +7 -3
  42. data/lib/generators/graphql/templates/query_type.erb +3 -3
  43. data/lib/generators/graphql/templates/scalar.erb +5 -1
  44. data/lib/generators/graphql/templates/schema.erb +22 -27
  45. data/lib/generators/graphql/templates/union.erb +6 -2
  46. data/lib/generators/graphql/type_generator.rb +47 -10
  47. data/lib/generators/graphql/union_generator.rb +5 -5
  48. data/lib/graphql/analysis/ast/field_usage.rb +29 -2
  49. data/lib/graphql/analysis/ast/query_complexity.rb +175 -68
  50. data/lib/graphql/analysis/ast/query_depth.rb +0 -1
  51. data/lib/graphql/analysis/ast/visitor.rb +17 -8
  52. data/lib/graphql/analysis/ast.rb +14 -14
  53. data/lib/graphql/analysis.rb +0 -7
  54. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  55. data/lib/graphql/backtrace/table.rb +37 -16
  56. data/lib/graphql/backtrace/traced_error.rb +0 -1
  57. data/lib/graphql/backtrace/tracer.rb +39 -9
  58. data/lib/graphql/backtrace.rb +20 -17
  59. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  60. data/lib/graphql/dataloader/request.rb +19 -0
  61. data/lib/graphql/dataloader/request_all.rb +19 -0
  62. data/lib/graphql/dataloader/source.rb +155 -0
  63. data/lib/graphql/dataloader.rb +308 -0
  64. data/lib/graphql/date_encoding_error.rb +16 -0
  65. data/lib/graphql/deprecation.rb +9 -0
  66. data/lib/graphql/dig.rb +1 -1
  67. data/lib/graphql/execution/directive_checks.rb +2 -2
  68. data/lib/graphql/execution/errors.rb +108 -14
  69. data/lib/graphql/execution/instrumentation.rb +1 -1
  70. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  71. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  72. data/lib/graphql/execution/interpreter/arguments_cache.rb +105 -0
  73. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  74. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  75. data/lib/graphql/execution/interpreter/runtime.rb +715 -387
  76. data/lib/graphql/execution/interpreter.rb +32 -31
  77. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  78. data/lib/graphql/execution/lazy.rb +5 -1
  79. data/lib/graphql/execution/lookahead.rb +32 -114
  80. data/lib/graphql/execution/multiplex.rb +60 -92
  81. data/lib/graphql/execution.rb +11 -3
  82. data/lib/graphql/filter.rb +1 -1
  83. data/lib/graphql/integer_decoding_error.rb +17 -0
  84. data/lib/graphql/integer_encoding_error.rb +18 -2
  85. data/lib/graphql/introspection/base_object.rb +2 -5
  86. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  87. data/lib/graphql/introspection/directive_type.rb +11 -5
  88. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  89. data/lib/graphql/introspection/entry_points.rb +5 -18
  90. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  91. data/lib/graphql/introspection/field_type.rb +9 -5
  92. data/lib/graphql/introspection/input_value_type.rb +41 -11
  93. data/lib/graphql/introspection/introspection_query.rb +6 -92
  94. data/lib/graphql/introspection/schema_type.rb +10 -10
  95. data/lib/graphql/introspection/type_type.rb +27 -17
  96. data/lib/graphql/introspection.rb +99 -0
  97. data/lib/graphql/invalid_null_error.rb +18 -0
  98. data/lib/graphql/language/block_string.rb +20 -5
  99. data/lib/graphql/language/cache.rb +37 -0
  100. data/lib/graphql/language/definition_slice.rb +21 -10
  101. data/lib/graphql/language/document_from_schema_definition.rb +99 -63
  102. data/lib/graphql/language/lexer.rb +53 -27
  103. data/lib/graphql/language/lexer.rl +5 -3
  104. data/lib/graphql/language/nodes.rb +64 -93
  105. data/lib/graphql/language/parser.rb +929 -896
  106. data/lib/graphql/language/parser.y +125 -102
  107. data/lib/graphql/language/printer.rb +11 -2
  108. data/lib/graphql/language/sanitized_printer.rb +222 -0
  109. data/lib/graphql/language/token.rb +0 -4
  110. data/lib/graphql/language/visitor.rb +2 -2
  111. data/lib/graphql/language.rb +3 -1
  112. data/lib/graphql/name_validator.rb +2 -7
  113. data/lib/graphql/pagination/active_record_relation_connection.rb +85 -0
  114. data/lib/graphql/pagination/array_connection.rb +77 -0
  115. data/lib/graphql/pagination/connection.rb +226 -0
  116. data/lib/graphql/pagination/connections.rb +134 -0
  117. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  118. data/lib/graphql/pagination/relation_connection.rb +226 -0
  119. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  120. data/lib/graphql/pagination.rb +6 -0
  121. data/lib/graphql/parse_error.rb +0 -1
  122. data/lib/graphql/query/context.rb +51 -190
  123. data/lib/graphql/query/fingerprint.rb +26 -0
  124. data/lib/graphql/query/input_validation_result.rb +23 -6
  125. data/lib/graphql/query/literal_input.rb +26 -11
  126. data/lib/graphql/query/null_context.rb +24 -8
  127. data/lib/graphql/query/validation_pipeline.rb +12 -38
  128. data/lib/graphql/query/variable_validation_error.rb +2 -2
  129. data/lib/graphql/query/variables.rb +26 -9
  130. data/lib/graphql/query.rb +62 -32
  131. data/lib/graphql/railtie.rb +6 -102
  132. data/lib/graphql/rake_task/validate.rb +3 -0
  133. data/lib/graphql/rake_task.rb +12 -9
  134. data/lib/graphql/relay/range_add.rb +23 -9
  135. data/lib/graphql/relay.rb +0 -15
  136. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  137. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  138. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  139. data/lib/graphql/rubocop.rb +4 -0
  140. data/lib/graphql/schema/addition.rb +240 -0
  141. data/lib/graphql/schema/argument.rb +262 -28
  142. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  143. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  144. data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
  145. data/lib/graphql/schema/build_from_definition.rb +319 -220
  146. data/lib/graphql/schema/built_in_types.rb +5 -5
  147. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  148. data/lib/graphql/schema/directive/feature.rb +1 -1
  149. data/lib/graphql/schema/directive/flagged.rb +57 -0
  150. data/lib/graphql/schema/directive/include.rb +2 -2
  151. data/lib/graphql/schema/directive/skip.rb +2 -2
  152. data/lib/graphql/schema/directive/transform.rb +14 -2
  153. data/lib/graphql/schema/directive.rb +117 -14
  154. data/lib/graphql/schema/enum.rb +115 -22
  155. data/lib/graphql/schema/enum_value.rb +16 -21
  156. data/lib/graphql/schema/field/connection_extension.rb +46 -20
  157. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  158. data/lib/graphql/schema/field.rb +376 -291
  159. data/lib/graphql/schema/field_extension.rb +89 -2
  160. data/lib/graphql/schema/find_inherited_value.rb +17 -1
  161. data/lib/graphql/schema/finder.rb +16 -14
  162. data/lib/graphql/schema/input_object.rb +147 -60
  163. data/lib/graphql/schema/interface.rb +28 -43
  164. data/lib/graphql/schema/introspection_system.rb +101 -38
  165. data/lib/graphql/schema/late_bound_type.rb +3 -2
  166. data/lib/graphql/schema/list.rb +46 -3
  167. data/lib/graphql/schema/loader.rb +144 -102
  168. data/lib/graphql/schema/member/base_dsl_methods.rb +33 -32
  169. data/lib/graphql/schema/member/build_type.rb +23 -14
  170. data/lib/graphql/schema/member/has_arguments.rb +212 -23
  171. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  172. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  173. data/lib/graphql/schema/member/has_directives.rb +98 -0
  174. data/lib/graphql/schema/member/has_fields.rb +99 -34
  175. data/lib/graphql/schema/member/has_interfaces.rb +88 -0
  176. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  177. data/lib/graphql/schema/member/has_validators.rb +31 -0
  178. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  179. data/lib/graphql/schema/member/validates_input.rb +33 -0
  180. data/lib/graphql/schema/member.rb +11 -6
  181. data/lib/graphql/schema/mutation.rb +4 -9
  182. data/lib/graphql/schema/non_null.rb +34 -4
  183. data/lib/graphql/schema/object.rb +38 -65
  184. data/lib/graphql/schema/printer.rb +16 -35
  185. data/lib/graphql/schema/relay_classic_mutation.rb +57 -32
  186. data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
  187. data/lib/graphql/schema/resolver.rb +133 -79
  188. data/lib/graphql/schema/scalar.rb +40 -15
  189. data/lib/graphql/schema/subscription.rb +57 -21
  190. data/lib/graphql/schema/timeout.rb +29 -15
  191. data/lib/graphql/schema/type_expression.rb +21 -13
  192. data/lib/graphql/schema/type_membership.rb +19 -5
  193. data/lib/graphql/schema/union.rb +39 -14
  194. data/lib/graphql/schema/unique_within_type.rb +1 -2
  195. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  196. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  197. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  198. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  199. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  200. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  201. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  202. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  203. data/lib/graphql/schema/validator.rb +171 -0
  204. data/lib/graphql/schema/warden.rb +182 -32
  205. data/lib/graphql/schema/wrapper.rb +0 -5
  206. data/lib/graphql/schema.rb +687 -891
  207. data/lib/graphql/static_validation/all_rules.rb +2 -0
  208. data/lib/graphql/static_validation/base_visitor.rb +21 -31
  209. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  210. data/lib/graphql/static_validation/error.rb +3 -1
  211. data/lib/graphql/static_validation/literal_validator.rb +51 -26
  212. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +45 -83
  213. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  214. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +35 -26
  215. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  216. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  217. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -14
  218. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  219. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  220. data/lib/graphql/static_validation/rules/fields_will_merge.rb +94 -51
  221. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  222. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  223. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  224. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  225. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  226. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  227. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  228. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  229. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +9 -10
  230. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  231. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
  232. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +19 -14
  233. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  234. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
  235. data/lib/graphql/static_validation/type_stack.rb +2 -2
  236. data/lib/graphql/static_validation/validation_context.rb +13 -3
  237. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  238. data/lib/graphql/static_validation/validator.rb +31 -19
  239. data/lib/graphql/static_validation.rb +1 -2
  240. data/lib/graphql/string_encoding_error.rb +13 -3
  241. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +123 -22
  242. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  243. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +58 -0
  244. data/lib/graphql/subscriptions/event.rb +85 -31
  245. data/lib/graphql/subscriptions/instrumentation.rb +0 -47
  246. data/lib/graphql/subscriptions/serialize.rb +53 -6
  247. data/lib/graphql/subscriptions.rb +111 -52
  248. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -17
  249. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  250. data/lib/graphql/tracing/appsignal_tracing.rb +23 -0
  251. data/lib/graphql/tracing/data_dog_tracing.rb +14 -1
  252. data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
  253. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  254. data/lib/graphql/tracing/platform_tracing.rb +57 -29
  255. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  256. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  257. data/lib/graphql/tracing/scout_tracing.rb +19 -0
  258. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  259. data/lib/graphql/tracing.rb +15 -36
  260. data/lib/graphql/types/big_int.rb +5 -1
  261. data/lib/graphql/types/int.rb +10 -3
  262. data/lib/graphql/types/iso_8601_date.rb +16 -8
  263. data/lib/graphql/types/iso_8601_date_time.rb +32 -10
  264. data/lib/graphql/types/relay/base_connection.rb +6 -88
  265. data/lib/graphql/types/relay/base_edge.rb +2 -34
  266. data/lib/graphql/types/relay/connection_behaviors.rb +170 -0
  267. data/lib/graphql/types/relay/default_relay.rb +21 -0
  268. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  269. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  270. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  271. data/lib/graphql/types/relay/node.rb +2 -4
  272. data/lib/graphql/types/relay/node_behaviors.rb +19 -0
  273. data/lib/graphql/types/relay/page_info.rb +2 -14
  274. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  275. data/lib/graphql/types/relay.rb +11 -5
  276. data/lib/graphql/types/string.rb +8 -2
  277. data/lib/graphql/unauthorized_error.rb +2 -2
  278. data/lib/graphql/unresolved_type_error.rb +2 -2
  279. data/lib/graphql/version.rb +1 -1
  280. data/lib/graphql.rb +41 -58
  281. data/readme.md +3 -6
  282. metadata +97 -231
  283. data/lib/graphql/analysis/analyze_query.rb +0 -91
  284. data/lib/graphql/analysis/field_usage.rb +0 -45
  285. data/lib/graphql/analysis/max_query_complexity.rb +0 -26
  286. data/lib/graphql/analysis/max_query_depth.rb +0 -26
  287. data/lib/graphql/analysis/query_complexity.rb +0 -88
  288. data/lib/graphql/analysis/query_depth.rb +0 -43
  289. data/lib/graphql/analysis/reducer_state.rb +0 -48
  290. data/lib/graphql/argument.rb +0 -159
  291. data/lib/graphql/authorization.rb +0 -82
  292. data/lib/graphql/backwards_compatibility.rb +0 -60
  293. data/lib/graphql/base_type.rb +0 -226
  294. data/lib/graphql/boolean_type.rb +0 -2
  295. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  296. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  297. data/lib/graphql/compatibility/execution_specification.rb +0 -435
  298. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  299. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -213
  300. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -91
  301. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  302. data/lib/graphql/compatibility/query_parser_specification.rb +0 -264
  303. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -680
  304. data/lib/graphql/compatibility.rb +0 -5
  305. data/lib/graphql/define/assign_argument.rb +0 -12
  306. data/lib/graphql/define/assign_connection.rb +0 -13
  307. data/lib/graphql/define/assign_enum_value.rb +0 -18
  308. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  309. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  310. data/lib/graphql/define/assign_object_field.rb +0 -42
  311. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  312. data/lib/graphql/define/instance_definable.rb +0 -311
  313. data/lib/graphql/define/no_definition_error.rb +0 -7
  314. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  315. data/lib/graphql/define/type_definer.rb +0 -31
  316. data/lib/graphql/define.rb +0 -31
  317. data/lib/graphql/deprecated_dsl.rb +0 -42
  318. data/lib/graphql/directive/deprecated_directive.rb +0 -13
  319. data/lib/graphql/directive/include_directive.rb +0 -2
  320. data/lib/graphql/directive/skip_directive.rb +0 -2
  321. data/lib/graphql/directive.rb +0 -104
  322. data/lib/graphql/enum_type.rb +0 -193
  323. data/lib/graphql/execution/execute.rb +0 -326
  324. data/lib/graphql/execution/flatten.rb +0 -40
  325. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  326. data/lib/graphql/execution/typecast.rb +0 -50
  327. data/lib/graphql/field/resolve.rb +0 -59
  328. data/lib/graphql/field.rb +0 -330
  329. data/lib/graphql/float_type.rb +0 -2
  330. data/lib/graphql/function.rb +0 -153
  331. data/lib/graphql/id_type.rb +0 -2
  332. data/lib/graphql/input_object_type.rb +0 -154
  333. data/lib/graphql/int_type.rb +0 -2
  334. data/lib/graphql/interface_type.rb +0 -86
  335. data/lib/graphql/internal_representation/document.rb +0 -27
  336. data/lib/graphql/internal_representation/node.rb +0 -206
  337. data/lib/graphql/internal_representation/print.rb +0 -51
  338. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  339. data/lib/graphql/internal_representation/scope.rb +0 -88
  340. data/lib/graphql/internal_representation/visit.rb +0 -36
  341. data/lib/graphql/internal_representation.rb +0 -7
  342. data/lib/graphql/list_type.rb +0 -80
  343. data/lib/graphql/literal_validation_error.rb +0 -6
  344. data/lib/graphql/non_null_type.rb +0 -81
  345. data/lib/graphql/object_type.rb +0 -141
  346. data/lib/graphql/query/arguments.rb +0 -187
  347. data/lib/graphql/query/arguments_cache.rb +0 -25
  348. data/lib/graphql/query/executor.rb +0 -53
  349. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  350. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  351. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  352. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  353. data/lib/graphql/query/serial_execution.rb +0 -39
  354. data/lib/graphql/relay/array_connection.rb +0 -85
  355. data/lib/graphql/relay/base_connection.rb +0 -172
  356. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  357. data/lib/graphql/relay/connection_resolve.rb +0 -43
  358. data/lib/graphql/relay/connection_type.rb +0 -40
  359. data/lib/graphql/relay/edge.rb +0 -27
  360. data/lib/graphql/relay/edge_type.rb +0 -18
  361. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  362. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  363. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  364. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  365. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  366. data/lib/graphql/relay/mutation/result.rb +0 -38
  367. data/lib/graphql/relay/mutation.rb +0 -190
  368. data/lib/graphql/relay/node.rb +0 -36
  369. data/lib/graphql/relay/page_info.rb +0 -7
  370. data/lib/graphql/relay/relation_connection.rb +0 -190
  371. data/lib/graphql/relay/type_extensions.rb +0 -30
  372. data/lib/graphql/scalar_type.rb +0 -133
  373. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  374. data/lib/graphql/schema/default_parse_error.rb +0 -10
  375. data/lib/graphql/schema/default_type_error.rb +0 -15
  376. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  377. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -26
  378. data/lib/graphql/schema/member/instrumentation.rb +0 -132
  379. data/lib/graphql/schema/middleware_chain.rb +0 -82
  380. data/lib/graphql/schema/possible_types.rb +0 -39
  381. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  382. data/lib/graphql/schema/timeout_middleware.rb +0 -86
  383. data/lib/graphql/schema/traversal.rb +0 -228
  384. data/lib/graphql/schema/validation.rb +0 -303
  385. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  386. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  387. data/lib/graphql/string_type.rb +0 -2
  388. data/lib/graphql/subscriptions/subscription_root.rb +0 -74
  389. data/lib/graphql/tracing/skylight_tracing.rb +0 -62
  390. data/lib/graphql/types/relay/base_field.rb +0 -22
  391. data/lib/graphql/types/relay/base_interface.rb +0 -29
  392. data/lib/graphql/types/relay/base_object.rb +0 -26
  393. data/lib/graphql/types/relay/node_field.rb +0 -43
  394. data/lib/graphql/types/relay/nodes_field.rb +0 -45
  395. data/lib/graphql/union_type.rb +0 -135
  396. data/lib/graphql/upgrader/member.rb +0 -936
  397. data/lib/graphql/upgrader/schema.rb +0 -37
@@ -2,12 +2,9 @@
2
2
  module GraphQL
3
3
  class Schema
4
4
  class Scalar < GraphQL::Schema::Member
5
- extend GraphQL::Schema::Member::AcceptsDefinition
5
+ extend GraphQL::Schema::Member::ValidatesInput
6
6
 
7
7
  class << self
8
- extend Forwardable
9
- def_delegators :graphql_definition, :coerce_isolated_input, :coerce_isolated_result
10
-
11
8
  def coerce_input(val, ctx)
12
9
  val
13
10
  end
@@ -16,27 +13,55 @@ module GraphQL
16
13
  val
17
14
  end
18
15
 
19
- def to_graphql
20
- type_defn = GraphQL::ScalarType.new
21
- type_defn.name = graphql_name
22
- type_defn.description = description
23
- type_defn.coerce_result = method(:coerce_result)
24
- type_defn.coerce_input = method(:coerce_input)
25
- type_defn.metadata[:type_class] = self
26
- type_defn.default_scalar = default_scalar
27
- type_defn
28
- end
29
-
30
16
  def kind
31
17
  GraphQL::TypeKinds::SCALAR
32
18
  end
33
19
 
20
+ def specified_by_url(new_url = nil)
21
+ if new_url
22
+ @specified_by_url = new_url
23
+ elsif defined?(@specified_by_url)
24
+ @specified_by_url
25
+ elsif superclass.respond_to?(:specified_by_url)
26
+ superclass.specified_by_url
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
34
32
  def default_scalar(is_default = nil)
35
33
  if !is_default.nil?
36
34
  @default_scalar = is_default
37
35
  end
38
36
  @default_scalar
39
37
  end
38
+
39
+ def default_scalar?
40
+ @default_scalar ||= false
41
+ end
42
+
43
+ def validate_non_null_input(value, ctx)
44
+ result = Query::InputValidationResult.new
45
+ coerced_result = begin
46
+ ctx.query.with_error_handling do
47
+ coerce_input(value, ctx)
48
+ end
49
+ rescue GraphQL::CoercionError => err
50
+ err
51
+ end
52
+
53
+ if coerced_result.nil?
54
+ str_value = if value == Float::INFINITY
55
+ ""
56
+ else
57
+ " #{GraphQL::Language.serialize(value)}"
58
+ end
59
+ result.add_problem("Could not coerce value#{str_value} to #{graphql_name}")
60
+ elsif coerced_result.is_a?(GraphQL::CoercionError)
61
+ result.add_problem(coerced_result.message, message: coerced_result.message, extensions: coerced_result.extensions)
62
+ end
63
+ result
64
+ end
40
65
  end
41
66
  end
42
67
  end
@@ -12,19 +12,9 @@ module GraphQL
12
12
  #
13
13
  # Also, `#unsubscribe` terminates the subscription.
14
14
  class Subscription < GraphQL::Schema::Resolver
15
- class EarlyTerminationError < StandardError
16
- end
17
-
18
- # Raised when `unsubscribe` is called; caught by `subscriptions.rb`
19
- class UnsubscribedError < EarlyTerminationError
20
- end
21
-
22
- # Raised when `no_update` is returned; caught by `subscriptions.rb`
23
- class NoUpdateError < EarlyTerminationError
24
- end
25
15
  extend GraphQL::Schema::Resolver::HasPayloadType
26
16
  extend GraphQL::Schema::Member::HasFields
27
-
17
+ NO_UPDATE = :no_update
28
18
  # The generated payload type is required; If there's no payload,
29
19
  # propagate null.
30
20
  null false
@@ -35,6 +25,22 @@ module GraphQL
35
25
  @mode = context.query.subscription_update? ? :update : :subscribe
36
26
  end
37
27
 
28
+ def resolve_with_support(**args)
29
+ result = nil
30
+ unsubscribed = true
31
+ catch :graphql_subscription_unsubscribed do
32
+ result = super
33
+ unsubscribed = false
34
+ end
35
+
36
+
37
+ if unsubscribed
38
+ context.skip
39
+ else
40
+ result
41
+ end
42
+ end
43
+
38
44
  # Implement the {Resolve} API
39
45
  def resolve(**args)
40
46
  # Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
@@ -52,11 +58,9 @@ module GraphQL
52
58
  end
53
59
  end
54
60
 
55
- # Default implementation returns the root object.
61
+ # The default implementation returns nothing on subscribe.
56
62
  # Override it to return an object or
57
- # `:no_response` to return nothing.
58
- #
59
- # The default is `:no_response`.
63
+ # `:no_response` to (explicitly) return nothing.
60
64
  def subscribe(args = {})
61
65
  :no_response
62
66
  end
@@ -64,15 +68,16 @@ module GraphQL
64
68
  # Wrap the user-provided `#update` hook
65
69
  def resolve_update(**args)
66
70
  ret_val = args.any? ? update(**args) : update
67
- if ret_val == :no_update
68
- raise NoUpdateError
71
+ if ret_val == NO_UPDATE
72
+ context.namespace(:subscriptions)[:no_update] = true
73
+ context.skip
69
74
  else
70
75
  ret_val
71
76
  end
72
77
  end
73
78
 
74
79
  # The default implementation returns the root object.
75
- # Override it to return `:no_update` if you want to
80
+ # Override it to return {NO_UPDATE} if you want to
76
81
  # skip updates sometimes. Or override it to return a different object.
77
82
  def update(args = {})
78
83
  object
@@ -90,17 +95,20 @@ module GraphQL
90
95
 
91
96
  # Call this to halt execution and remove this subscription from the system
92
97
  def unsubscribe
93
- raise UnsubscribedError
98
+ context.namespace(:subscriptions)[:unsubscribed] = true
99
+ throw :graphql_subscription_unsubscribed
94
100
  end
95
101
 
102
+ READING_SCOPE = ::Object.new
96
103
  # Call this method to provide a new subscription_scope; OR
97
104
  # call it without an argument to get the subscription_scope
98
105
  # @param new_scope [Symbol]
106
+ # @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription.
99
107
  # @return [Symbol]
100
- READING_SCOPE = ::Object.new
101
- def self.subscription_scope(new_scope = READING_SCOPE)
108
+ def self.subscription_scope(new_scope = READING_SCOPE, optional: false)
102
109
  if new_scope != READING_SCOPE
103
110
  @subscription_scope = new_scope
111
+ @subscription_scope_optional = optional
104
112
  elsif defined?(@subscription_scope)
105
113
  @subscription_scope
106
114
  else
@@ -108,6 +116,34 @@ module GraphQL
108
116
  end
109
117
  end
110
118
 
119
+ def self.subscription_scope_optional?
120
+ if defined?(@subscription_scope_optional)
121
+ @subscription_scope_optional
122
+ else
123
+ find_inherited_value(:subscription_scope_optional, false)
124
+ end
125
+ end
126
+
127
+ # This is called during initial subscription to get a "name" for this subscription.
128
+ # Later, when `.trigger` is called, this will be called again to build another "name".
129
+ # Any subscribers with matching topic will begin the update flow.
130
+ #
131
+ # The default implementation creates a string using the field name, subscription scope, and argument keys and values.
132
+ # In that implementation, only `.trigger` calls with _exact matches_ result in updates to subscribers.
133
+ #
134
+ # To implement a filtered stream-type subscription flow, override this method to return a string with field name and subscription scope.
135
+ # Then, implement {#update} to compare its arguments to the current `object` and return {NO_UPDATE} when an
136
+ # update should be filtered out.
137
+ #
138
+ # @see {#update} for how to skip updates when an event comes with a matching topic.
139
+ # @param arguments [Hash<String => Object>] The arguments for this topic, in GraphQL-style (camelized strings)
140
+ # @param field [GraphQL::Schema::Field]
141
+ # @param scope [Object, nil] A value corresponding to `.trigger(... scope:)` (for updates) or the `subscription_scope` found in `context` (for initial subscriptions).
142
+ # @return [String] An identifier corresponding to a stream of updates
143
+ def self.topic_for(arguments:, field:, scope:)
144
+ Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
145
+ end
146
+
111
147
  # Overriding Resolver#field_options to include subscription_scope
112
148
  def self.field_options
113
149
  super.merge(
@@ -7,7 +7,7 @@ module GraphQL
7
7
  # to the `errors` key. Any already-resolved fields will be in the `data` key, so
8
8
  # you'll get a partial response.
9
9
  #
10
- # You can subclass `GraphQL::Schema::Timeout` and override the `handle_timeout` method
10
+ # You can subclass `GraphQL::Schema::Timeout` and override `max_seconds` and/or `handle_timeout`
11
11
  # to provide custom logic when a timeout error occurs.
12
12
  #
13
13
  # Note that this will stop a query _in between_ field resolutions, but
@@ -33,8 +33,6 @@ module GraphQL
33
33
  # end
34
34
  #
35
35
  class Timeout
36
- attr_reader :max_seconds
37
-
38
36
  def self.use(schema, **options)
39
37
  tracer = new(**options)
40
38
  schema.tracer(tracer)
@@ -48,32 +46,39 @@ module GraphQL
48
46
  def trace(key, data)
49
47
  case key
50
48
  when 'execute_multiplex'
51
- timeout_state = {
52
- timeout_at: Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) + max_seconds * 1000,
53
- timed_out: false
54
- }
55
-
56
49
  data.fetch(:multiplex).queries.each do |query|
50
+ timeout_duration_s = max_seconds(query)
51
+ timeout_state = if timeout_duration_s == false
52
+ # if the method returns `false`, don't apply a timeout
53
+ false
54
+ else
55
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
56
+ timeout_at = now + (max_seconds(query) * 1000)
57
+ {
58
+ timeout_at: timeout_at,
59
+ timed_out: false
60
+ }
61
+ end
57
62
  query.context.namespace(self.class)[:state] = timeout_state
58
63
  end
59
64
 
60
65
  yield
61
66
  when 'execute_field', 'execute_field_lazy'
62
- query = data[:context] ? data.fetch(:context).query : data.fetch(:query)
63
- timeout_state = query.context.namespace(self.class).fetch(:state)
64
- if Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) > timeout_state.fetch(:timeout_at)
67
+ query_context = data[:context] || data[:query].context
68
+ timeout_state = query_context.namespace(self.class).fetch(:state)
69
+ # If the `:state` is `false`, then `max_seconds(query)` opted out of timeout for this query.
70
+ if timeout_state != false && Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) > timeout_state.fetch(:timeout_at)
65
71
  error = if data[:context]
66
- context = data.fetch(:context)
67
- GraphQL::Schema::Timeout::TimeoutError.new(context.parent_type, context.field)
72
+ GraphQL::Schema::Timeout::TimeoutError.new(query_context.parent_type, query_context.field)
68
73
  else
69
74
  field = data.fetch(:field)
70
75
  GraphQL::Schema::Timeout::TimeoutError.new(field.owner, field)
71
76
  end
72
77
 
73
78
  # Only invoke the timeout callback for the first timeout
74
- unless timeout_state[:timed_out]
79
+ if !timeout_state[:timed_out]
75
80
  timeout_state[:timed_out] = true
76
- handle_timeout(error, query)
81
+ handle_timeout(error, query_context.query)
77
82
  end
78
83
 
79
84
  error
@@ -85,6 +90,15 @@ module GraphQL
85
90
  end
86
91
  end
87
92
 
93
+ # Called at the start of each query.
94
+ # The default implementation returns the `max_seconds:` value from installing this plugin.
95
+ #
96
+ # @param query [GraphQL::Query] The query that's about to run
97
+ # @return [Integer, false] The number of seconds after which to interrupt query execution and call {#handle_error}, or `false` to bypass the timeout.
98
+ def max_seconds(query)
99
+ @max_seconds
100
+ end
101
+
88
102
  # Invoked when a query times out.
89
103
  # @param error [GraphQL::Schema::Timeout::TimeoutError]
90
104
  # @param query [GraphQL::Error]
@@ -5,29 +5,37 @@ module GraphQL
5
5
  module TypeExpression
6
6
  # Fetch a type from a type map by its AST specification.
7
7
  # Return `nil` if not found.
8
- # @param types [GraphQL::Schema::TypeMap]
8
+ # @param type_owner [#get_type] A thing for looking up types by name
9
9
  # @param ast_node [GraphQL::Language::Nodes::AbstractNode]
10
- # @return [GraphQL::BaseType, nil]
11
- def self.build_type(types, ast_node)
10
+ # @return [Class, GraphQL::Schema::NonNull, GraphQL::Schema:List]
11
+ def self.build_type(type_owner, ast_node)
12
12
  case ast_node
13
13
  when GraphQL::Language::Nodes::TypeName
14
- types.fetch(ast_node.name, nil)
14
+ type_owner.get_type(ast_node.name) # rubocop:disable Development/ContextIsPassedCop -- this is a `context` or `warden`, it's already query-aware
15
15
  when GraphQL::Language::Nodes::NonNullType
16
16
  ast_inner_type = ast_node.of_type
17
- inner_type = build_type(types, ast_inner_type)
18
- wrap_type(inner_type, GraphQL::NonNullType)
17
+ inner_type = build_type(type_owner, ast_inner_type)
18
+ wrap_type(inner_type, :to_non_null_type)
19
19
  when GraphQL::Language::Nodes::ListType
20
20
  ast_inner_type = ast_node.of_type
21
- inner_type = build_type(types, ast_inner_type)
22
- wrap_type(inner_type, GraphQL::ListType)
21
+ inner_type = build_type(type_owner, ast_inner_type)
22
+ wrap_type(inner_type, :to_list_type)
23
+ else
24
+ raise "Invariant: unexpected type from ast: #{ast_node.inspect}"
23
25
  end
24
26
  end
25
27
 
26
- def self.wrap_type(type, wrapper)
27
- if type.nil?
28
- nil
29
- else
30
- wrapper.new(of_type: type)
28
+ class << self
29
+ private
30
+
31
+ def wrap_type(type, wrapper_method)
32
+ if type.nil?
33
+ nil
34
+ elsif wrapper_method == :to_list_type || wrapper_method == :to_non_null_type
35
+ type.public_send(wrapper_method)
36
+ else
37
+ raise ArgumentError, "Unexpected wrapper method: #{wrapper_method.inspect}"
38
+ end
31
39
  end
32
40
  end
33
41
  end
@@ -4,11 +4,9 @@ module GraphQL
4
4
  class Schema
5
5
  # This class joins an object type to an abstract type (interface or union) of which
6
6
  # it is a member.
7
- #
8
- # TODO: Not yet implemented for interfaces.
9
7
  class TypeMembership
10
8
  # @return [Class<GraphQL::Schema::Object>]
11
- attr_reader :object_type
9
+ attr_accessor :object_type
12
10
 
13
11
  # @return [Class<GraphQL::Schema::Union>, Module<GraphQL::Schema::Interface>]
14
12
  attr_reader :abstract_type
@@ -26,9 +24,25 @@ module GraphQL
26
24
  end
27
25
 
28
26
  # @return [Boolean] if false, {#object_type} will be treated as _not_ a member of {#abstract_type}
29
- def visible?(_ctx)
30
- true
27
+ def visible?(ctx)
28
+ warden = Warden.from_context(ctx)
29
+ (@object_type.respond_to?(:visible?) ? warden.visible_type?(@object_type, ctx) : true) &&
30
+ (@abstract_type.respond_to?(:visible?) ? warden.visible_type?(@abstract_type, ctx) : true)
31
31
  end
32
+
33
+ def graphql_name
34
+ "#{@object_type.graphql_name}.#{@abstract_type.kind.interface? ? "implements" : "belongsTo" }.#{@abstract_type.graphql_name}"
35
+ end
36
+
37
+ def path
38
+ graphql_name
39
+ end
40
+
41
+ def inspect
42
+ "#<#{self.class} #{@object_type.inspect} => #{@abstract_type.inspect}>"
43
+ end
44
+
45
+ alias :type_class :itself
32
46
  end
33
47
  end
34
48
  end
@@ -2,18 +2,25 @@
2
2
  module GraphQL
3
3
  class Schema
4
4
  class Union < GraphQL::Schema::Member
5
- extend GraphQL::Schema::Member::AcceptsDefinition
5
+ extend GraphQL::Schema::Member::HasUnresolvedTypeError
6
6
 
7
7
  class << self
8
+ def inherited(child_class)
9
+ add_unresolved_type_error(child_class)
10
+ super
11
+ end
12
+
8
13
  def possible_types(*types, context: GraphQL::Query::NullContext, **options)
9
14
  if types.any?
10
15
  types.each do |t|
16
+ assert_valid_union_member(t)
11
17
  type_memberships << type_membership_class.new(self, t, **options)
12
18
  end
13
19
  else
14
20
  visible_types = []
21
+ warden = Warden.from_context(context)
15
22
  type_memberships.each do |type_membership|
16
- if type_membership.visible?(context)
23
+ if warden.visible_type_membership?(type_membership, context)
17
24
  visible_types << type_membership.object_type
18
25
  end
19
26
  end
@@ -21,16 +28,8 @@ module GraphQL
21
28
  end
22
29
  end
23
30
 
24
- def to_graphql
25
- type_defn = GraphQL::UnionType.new
26
- type_defn.name = graphql_name
27
- type_defn.description = description
28
- type_defn.type_memberships = type_memberships
29
- if respond_to?(:resolve_type)
30
- type_defn.resolve_type = method(:resolve_type)
31
- end
32
- type_defn.metadata[:type_class] = self
33
- type_defn
31
+ def all_possible_types
32
+ type_memberships.map(&:object_type)
34
33
  end
35
34
 
36
35
  def type_membership_class(membership_class = nil)
@@ -45,11 +44,37 @@ module GraphQL
45
44
  GraphQL::TypeKinds::UNION
46
45
  end
47
46
 
48
- private
49
-
50
47
  def type_memberships
51
48
  @type_memberships ||= []
52
49
  end
50
+
51
+ # Update a type membership whose `.object_type` is a string or late-bound type
52
+ # so that the type membership's `.object_type` is the given `object_type`.
53
+ # (This is used for updating the union after the schema as lazily loaded the union member.)
54
+ # @api private
55
+ def assign_type_membership_object_type(object_type)
56
+ assert_valid_union_member(object_type)
57
+ type_memberships.each { |tm|
58
+ possible_type = tm.object_type
59
+ if possible_type.is_a?(String) && (possible_type == object_type.name)
60
+ # This is a match of Ruby class names, not graphql names,
61
+ # since strings are used to refer to constants.
62
+ tm.object_type = object_type
63
+ elsif possible_type.is_a?(LateBoundType) && possible_type.graphql_name == object_type.graphql_name
64
+ tm.object_type = object_type
65
+ end
66
+ }
67
+ nil
68
+ end
69
+
70
+ private
71
+
72
+ def assert_valid_union_member(type_defn)
73
+ if type_defn.is_a?(Module) && !type_defn.is_a?(Class)
74
+ # it's an interface type, defined as a module
75
+ raise ArgumentError, "Union possible_types can only be object types (not interface types), remove #{type_defn.graphql_name} (#{type_defn.inspect})"
76
+ end
77
+ end
53
78
  end
54
79
  end
55
80
  end
@@ -27,8 +27,7 @@ module GraphQL
27
27
  # @param node_id [String] A unique ID generated by {.encode}
28
28
  # @return [Array<(String, String)>] The type name & value passed to {.encode}
29
29
  def decode(node_id, separator: self.default_id_separator)
30
- # urlsafe_decode64 is for forward compatibility
31
- Base64Bp.urlsafe_decode64(node_id).split(separator, 2)
30
+ GraphQL::Schema::Base64Encoder.decode(node_id).split(separator, 2)
32
31
  end
33
32
  end
34
33
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Validator
6
+ # Use this to specifically reject values that respond to `.blank?` and respond truthy for that method.
7
+ #
8
+ # @example Require a non-empty string for an argument
9
+ # argument :name, String, required: true, validate: { allow_blank: false }
10
+ class AllowBlankValidator < Validator
11
+ def initialize(allow_blank_positional, allow_blank: nil, message: "%{validated} can't be blank", **default_options)
12
+ @message = message
13
+ super(**default_options)
14
+ @allow_blank = allow_blank.nil? ? allow_blank_positional : allow_blank
15
+ end
16
+
17
+ def validate(_object, _context, value)
18
+ if value.respond_to?(:blank?) && value.blank?
19
+ if (value.nil? && @allow_null) || @allow_blank
20
+ # pass
21
+ else
22
+ @message
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Validator
6
+ # Use this to specifically reject or permit `nil` values (given as `null` from GraphQL).
7
+ #
8
+ # @example require a non-null value for an argument if it is provided
9
+ # argument :name, String, required: false, validates: { allow_null: false }
10
+ class AllowNullValidator < Validator
11
+ MESSAGE = "%{validated} can't be null"
12
+ def initialize(allow_null_positional, allow_null: nil, message: MESSAGE, **default_options)
13
+ @message = message
14
+ super(**default_options)
15
+ @allow_null = allow_null.nil? ? allow_null_positional : allow_null
16
+ end
17
+
18
+ def validate(_object, _context, value)
19
+ if value.nil? && !@allow_null
20
+ @message
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Validator
6
+ # Use this to specifically reject values from an argument.
7
+ #
8
+ # @example disallow certain values
9
+ #
10
+ # argument :favorite_non_prime, Integer, required: true,
11
+ # validates: { exclusion: { in: [2, 3, 5, 7, ... ]} }
12
+ #
13
+ class ExclusionValidator < Validator
14
+ # @param message [String]
15
+ # @param in [Array] The values to reject
16
+ def initialize(message: "%{validated} is reserved", in:, **default_options)
17
+ # `in` is a reserved word, so work around that
18
+ @in_list = binding.local_variable_get(:in)
19
+ @message = message
20
+ super(**default_options)
21
+ end
22
+
23
+ def validate(_object, _context, value)
24
+ if permitted_empty_value?(value)
25
+ # pass
26
+ elsif @in_list.include?(value)
27
+ @message
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Validator
6
+ # Use this to assert that string values match (or don't match) the given RegExp.
7
+ #
8
+ # @example requiring input to match a pattern
9
+ #
10
+ # argument :handle, String, required: true,
11
+ # validates: { format: { with: /\A[a-z0-9_]+\Z/ } }
12
+ #
13
+ # @example reject inputs that match a pattern
14
+ #
15
+ # argument :word_that_doesnt_begin_with_a_vowel, String, required: true,
16
+ # validates: { format: { without: /\A[aeiou]/ } }
17
+ #
18
+ # # It's pretty hard to come up with a legitimate use case for `without:`
19
+ #
20
+ class FormatValidator < Validator
21
+ # @param with [RegExp, nil]
22
+ # @param without [Regexp, nil]
23
+ # @param message [String]
24
+ def initialize(
25
+ with: nil,
26
+ without: nil,
27
+ message: "%{validated} is invalid",
28
+ **default_options
29
+ )
30
+ @with_pattern = with
31
+ @without_pattern = without
32
+ @message = message
33
+ super(**default_options)
34
+ end
35
+
36
+ def validate(_object, _context, value)
37
+ if permitted_empty_value?(value)
38
+ # Do nothing
39
+ elsif value.nil? ||
40
+ (@with_pattern && !value.match?(@with_pattern)) ||
41
+ (@without_pattern && value.match?(@without_pattern))
42
+ @message
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Validator
6
+ # You can use this to allow certain values for an argument.
7
+ #
8
+ # Usually, a {GraphQL::Schema::Enum} is better for this, because it's self-documenting.
9
+ #
10
+ # @example only allow certain values for an argument
11
+ #
12
+ # argument :favorite_prime, Integer, required: true,
13
+ # validates: { inclusion: { in: [2, 3, 5, 7, 11, ... ] } }
14
+ #
15
+ class InclusionValidator < Validator
16
+ # @param message [String]
17
+ # @param in [Array] The values to allow
18
+ def initialize(in:, message: "%{validated} is not included in the list", **default_options)
19
+ # `in` is a reserved word, so work around that
20
+ @in_list = binding.local_variable_get(:in)
21
+ @message = message
22
+ super(**default_options)
23
+ end
24
+
25
+ def validate(_object, _context, value)
26
+ if permitted_empty_value?(value)
27
+ # pass
28
+ elsif !@in_list.include?(value)
29
+ @message
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end