graphql 2.0.32 → 2.5.22

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.
Files changed (308) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/detailed_trace_generator.rb +77 -0
  3. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  4. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  5. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  6. data/lib/generators/graphql/install_generator.rb +49 -0
  7. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  8. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  9. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  10. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  11. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  12. data/lib/generators/graphql/templates/base_field.erb +2 -0
  13. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  14. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  15. data/lib/generators/graphql/templates/base_object.erb +2 -0
  16. data/lib/generators/graphql/templates/base_resolver.erb +8 -0
  17. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  18. data/lib/generators/graphql/templates/base_union.erb +2 -0
  19. data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
  20. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  21. data/lib/generators/graphql/templates/loader.erb +2 -0
  22. data/lib/generators/graphql/templates/mutation.erb +2 -0
  23. data/lib/generators/graphql/templates/node_type.erb +2 -0
  24. data/lib/generators/graphql/templates/query_type.erb +2 -0
  25. data/lib/generators/graphql/templates/schema.erb +5 -0
  26. data/lib/generators/graphql/type_generator.rb +1 -1
  27. data/lib/graphql/analysis/analyzer.rb +90 -0
  28. data/lib/graphql/analysis/field_usage.rb +82 -0
  29. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  30. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  31. data/lib/graphql/analysis/query_complexity.rb +263 -0
  32. data/lib/graphql/analysis/query_depth.rb +58 -0
  33. data/lib/graphql/analysis/visitor.rb +280 -0
  34. data/lib/graphql/analysis.rb +95 -1
  35. data/lib/graphql/autoload.rb +38 -0
  36. data/lib/graphql/backtrace/table.rb +118 -55
  37. data/lib/graphql/backtrace.rb +1 -19
  38. data/lib/graphql/coercion_error.rb +1 -9
  39. data/lib/graphql/current.rb +57 -0
  40. data/lib/graphql/dashboard/application_controller.rb +41 -0
  41. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  42. data/lib/graphql/dashboard/installable.rb +22 -0
  43. data/lib/graphql/dashboard/landings_controller.rb +9 -0
  44. data/lib/graphql/dashboard/limiters.rb +93 -0
  45. data/lib/graphql/dashboard/operation_store.rb +199 -0
  46. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  47. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  48. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  49. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  50. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  51. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  52. data/lib/graphql/dashboard/statics/icon.png +0 -0
  53. data/lib/graphql/dashboard/statics_controller.rb +31 -0
  54. data/lib/graphql/dashboard/subscriptions.rb +97 -0
  55. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  56. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  57. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  58. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  59. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
  60. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  61. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  62. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  63. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  64. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  65. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  66. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  67. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  68. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  69. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  70. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  71. data/lib/graphql/dashboard.rb +96 -0
  72. data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
  73. data/lib/graphql/dataloader/active_record_source.rb +47 -0
  74. data/lib/graphql/dataloader/async_dataloader.rb +112 -0
  75. data/lib/graphql/dataloader/null_dataloader.rb +55 -10
  76. data/lib/graphql/dataloader/request.rb +5 -0
  77. data/lib/graphql/dataloader/source.rb +35 -12
  78. data/lib/graphql/dataloader.rb +224 -149
  79. data/lib/graphql/date_encoding_error.rb +1 -1
  80. data/lib/graphql/dig.rb +2 -1
  81. data/lib/graphql/duration_encoding_error.rb +16 -0
  82. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  83. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  84. data/lib/graphql/execution/interpreter/resolve.rb +23 -25
  85. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
  86. data/lib/graphql/execution/interpreter/runtime.rb +363 -434
  87. data/lib/graphql/execution/interpreter.rb +91 -164
  88. data/lib/graphql/execution/lookahead.rb +105 -31
  89. data/lib/graphql/execution/multiplex.rb +7 -6
  90. data/lib/graphql/execution/next/field_resolve_step.rb +711 -0
  91. data/lib/graphql/execution/next/load_argument_step.rb +60 -0
  92. data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
  93. data/lib/graphql/execution/next/runner.rb +389 -0
  94. data/lib/graphql/execution/next/selections_step.rb +37 -0
  95. data/lib/graphql/execution/next.rb +70 -0
  96. data/lib/graphql/execution.rb +1 -0
  97. data/lib/graphql/execution_error.rb +13 -10
  98. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  99. data/lib/graphql/introspection/directive_type.rb +7 -3
  100. data/lib/graphql/introspection/dynamic_fields.rb +5 -1
  101. data/lib/graphql/introspection/entry_points.rb +20 -6
  102. data/lib/graphql/introspection/enum_value_type.rb +5 -5
  103. data/lib/graphql/introspection/field_type.rb +13 -5
  104. data/lib/graphql/introspection/input_value_type.rb +21 -13
  105. data/lib/graphql/introspection/schema_type.rb +8 -11
  106. data/lib/graphql/introspection/type_type.rb +64 -28
  107. data/lib/graphql/invalid_name_error.rb +1 -1
  108. data/lib/graphql/invalid_null_error.rb +26 -17
  109. data/lib/graphql/language/block_string.rb +34 -18
  110. data/lib/graphql/language/cache.rb +13 -0
  111. data/lib/graphql/language/comment.rb +18 -0
  112. data/lib/graphql/language/definition_slice.rb +1 -1
  113. data/lib/graphql/language/document_from_schema_definition.rb +90 -61
  114. data/lib/graphql/language/lexer.rb +319 -193
  115. data/lib/graphql/language/nodes.rb +136 -77
  116. data/lib/graphql/language/parser.rb +807 -1985
  117. data/lib/graphql/language/printer.rb +324 -151
  118. data/lib/graphql/language/sanitized_printer.rb +21 -23
  119. data/lib/graphql/language/static_visitor.rb +171 -0
  120. data/lib/graphql/language/visitor.rb +23 -83
  121. data/lib/graphql/language.rb +71 -1
  122. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  123. data/lib/graphql/pagination/array_connection.rb +6 -6
  124. data/lib/graphql/pagination/connection.rb +30 -1
  125. data/lib/graphql/pagination/connections.rb +32 -0
  126. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  127. data/lib/graphql/query/context/scoped_context.rb +101 -0
  128. data/lib/graphql/query/context.rb +82 -144
  129. data/lib/graphql/query/null_context.rb +15 -18
  130. data/lib/graphql/query/partial.rb +179 -0
  131. data/lib/graphql/query/validation_pipeline.rb +4 -4
  132. data/lib/graphql/query/variable_validation_error.rb +1 -1
  133. data/lib/graphql/query/variables.rb +3 -3
  134. data/lib/graphql/query.rb +126 -81
  135. data/lib/graphql/railtie.rb +16 -6
  136. data/lib/graphql/rake_task.rb +3 -12
  137. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  138. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  139. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  140. data/lib/graphql/rubocop.rb +2 -0
  141. data/lib/graphql/schema/addition.rb +26 -13
  142. data/lib/graphql/schema/always_visible.rb +7 -2
  143. data/lib/graphql/schema/argument.rb +75 -9
  144. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  145. data/lib/graphql/schema/build_from_definition.rb +123 -60
  146. data/lib/graphql/schema/directive/flagged.rb +4 -2
  147. data/lib/graphql/schema/directive/one_of.rb +12 -0
  148. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  149. data/lib/graphql/schema/directive.rb +54 -2
  150. data/lib/graphql/schema/enum.rb +110 -27
  151. data/lib/graphql/schema/enum_value.rb +10 -2
  152. data/lib/graphql/schema/field/connection_extension.rb +15 -49
  153. data/lib/graphql/schema/field/scope_extension.rb +23 -7
  154. data/lib/graphql/schema/field.rb +245 -118
  155. data/lib/graphql/schema/field_extension.rb +34 -1
  156. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  157. data/lib/graphql/schema/input_object.rb +116 -60
  158. data/lib/graphql/schema/interface.rb +34 -16
  159. data/lib/graphql/schema/introspection_system.rb +8 -17
  160. data/lib/graphql/schema/late_bound_type.rb +4 -0
  161. data/lib/graphql/schema/list.rb +3 -3
  162. data/lib/graphql/schema/loader.rb +3 -4
  163. data/lib/graphql/schema/member/base_dsl_methods.rb +18 -2
  164. data/lib/graphql/schema/member/has_arguments.rb +132 -100
  165. data/lib/graphql/schema/member/has_authorization.rb +35 -0
  166. data/lib/graphql/schema/member/has_dataloader.rb +99 -0
  167. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  168. data/lib/graphql/schema/member/has_directives.rb +4 -4
  169. data/lib/graphql/schema/member/has_fields.rb +115 -15
  170. data/lib/graphql/schema/member/has_interfaces.rb +26 -12
  171. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  172. data/lib/graphql/schema/member/has_validators.rb +1 -1
  173. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  174. data/lib/graphql/schema/member/scoped.rb +19 -0
  175. data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
  176. data/lib/graphql/schema/member/validates_input.rb +3 -3
  177. data/lib/graphql/schema/member.rb +6 -0
  178. data/lib/graphql/schema/mutation.rb +7 -0
  179. data/lib/graphql/schema/object.rb +34 -8
  180. data/lib/graphql/schema/printer.rb +9 -7
  181. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  182. data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
  183. data/lib/graphql/schema/resolver.rb +90 -32
  184. data/lib/graphql/schema/scalar.rb +4 -9
  185. data/lib/graphql/schema/subscription.rb +63 -10
  186. data/lib/graphql/schema/timeout.rb +19 -2
  187. data/lib/graphql/schema/type_expression.rb +2 -2
  188. data/lib/graphql/schema/union.rb +2 -2
  189. data/lib/graphql/schema/unique_within_type.rb +1 -1
  190. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  191. data/lib/graphql/schema/validator/required_validator.rb +92 -11
  192. data/lib/graphql/schema/validator.rb +3 -1
  193. data/lib/graphql/schema/visibility/migration.rb +188 -0
  194. data/lib/graphql/schema/visibility/profile.rb +445 -0
  195. data/lib/graphql/schema/visibility/visit.rb +190 -0
  196. data/lib/graphql/schema/visibility.rb +311 -0
  197. data/lib/graphql/schema/warden.rb +275 -103
  198. data/lib/graphql/schema.rb +950 -210
  199. data/lib/graphql/static_validation/all_rules.rb +3 -3
  200. data/lib/graphql/static_validation/base_visitor.rb +7 -6
  201. data/lib/graphql/static_validation/literal_validator.rb +6 -7
  202. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  203. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  204. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  205. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
  206. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  207. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  208. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
  209. data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
  210. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  211. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  212. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  213. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  214. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  215. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  216. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  217. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  218. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
  219. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  220. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  221. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
  222. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  223. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  224. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  225. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  226. data/lib/graphql/static_validation/validation_context.rb +21 -5
  227. data/lib/graphql/static_validation/validator.rb +9 -1
  228. data/lib/graphql/static_validation.rb +0 -1
  229. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
  230. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  231. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  232. data/lib/graphql/subscriptions/event.rb +21 -4
  233. data/lib/graphql/subscriptions/serialize.rb +3 -1
  234. data/lib/graphql/subscriptions.rb +21 -17
  235. data/lib/graphql/testing/helpers.rb +161 -0
  236. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  237. data/lib/graphql/testing.rb +3 -0
  238. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  239. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  240. data/lib/graphql/tracing/appoptics_trace.rb +7 -3
  241. data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
  242. data/lib/graphql/tracing/appsignal_trace.rb +32 -59
  243. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  244. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  245. data/lib/graphql/tracing/data_dog_trace.rb +46 -162
  246. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  247. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
  248. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  249. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  250. data/lib/graphql/tracing/detailed_trace.rb +156 -0
  251. data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
  252. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  253. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  254. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  255. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  256. data/lib/graphql/tracing/notifications_trace.rb +183 -37
  257. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  258. data/lib/graphql/tracing/null_trace.rb +9 -0
  259. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  260. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  261. data/lib/graphql/tracing/perfetto_trace.rb +864 -0
  262. data/lib/graphql/tracing/platform_tracing.rb +3 -1
  263. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
  264. data/lib/graphql/tracing/prometheus_trace.rb +73 -73
  265. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  266. data/lib/graphql/tracing/scout_trace.rb +32 -58
  267. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  268. data/lib/graphql/tracing/sentry_trace.rb +82 -0
  269. data/lib/graphql/tracing/statsd_trace.rb +33 -45
  270. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  271. data/lib/graphql/tracing/trace.rb +112 -1
  272. data/lib/graphql/tracing.rb +31 -28
  273. data/lib/graphql/type_kinds.rb +2 -1
  274. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  275. data/lib/graphql/types/relay/connection_behaviors.rb +44 -2
  276. data/lib/graphql/types/relay/edge_behaviors.rb +18 -0
  277. data/lib/graphql/types/relay/has_node_field.rb +13 -8
  278. data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
  279. data/lib/graphql/types/relay/node_behaviors.rb +13 -2
  280. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  281. data/lib/graphql/types.rb +18 -10
  282. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  283. data/lib/graphql/unauthorized_error.rb +5 -1
  284. data/lib/graphql/version.rb +1 -1
  285. data/lib/graphql.rb +71 -54
  286. data/readme.md +12 -2
  287. metadata +233 -37
  288. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  289. data/lib/graphql/analysis/ast/field_usage.rb +0 -57
  290. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  291. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  292. data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
  293. data/lib/graphql/analysis/ast/query_depth.rb +0 -55
  294. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  295. data/lib/graphql/analysis/ast.rb +0 -81
  296. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  297. data/lib/graphql/backtrace/trace.rb +0 -96
  298. data/lib/graphql/backtrace/tracer.rb +0 -80
  299. data/lib/graphql/deprecation.rb +0 -9
  300. data/lib/graphql/filter.rb +0 -59
  301. data/lib/graphql/language/parser.y +0 -560
  302. data/lib/graphql/language/token.rb +0 -34
  303. data/lib/graphql/schema/base_64_bp.rb +0 -26
  304. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  305. data/lib/graphql/schema/null_mask.rb +0 -11
  306. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
  307. data/lib/graphql/static_validation/type_stack.rb +0 -216
  308. data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -7,15 +7,21 @@ module GraphQL
7
7
  class << self
8
8
  # @see {Schema.from_definition}
9
9
  def from_definition(schema_superclass, definition_string, parser: GraphQL.default_parser, **kwargs)
10
+ if defined?(parser::SchemaParser)
11
+ parser = parser::SchemaParser
12
+ end
10
13
  from_document(schema_superclass, parser.parse(definition_string), **kwargs)
11
14
  end
12
15
 
13
16
  def from_definition_path(schema_superclass, definition_path, parser: GraphQL.default_parser, **kwargs)
17
+ if defined?(parser::SchemaParser)
18
+ parser = parser::SchemaParser
19
+ end
14
20
  from_document(schema_superclass, parser.parse_file(definition_path), **kwargs)
15
21
  end
16
22
 
17
- def from_document(schema_superclass, document, default_resolve:, using: {}, relay: false)
18
- Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using)
23
+ def from_document(schema_superclass, document, default_resolve:, using: {}, base_types: {}, relay: false)
24
+ Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using, base_types: base_types)
19
25
  end
20
26
  end
21
27
 
@@ -24,9 +30,18 @@ module GraphQL
24
30
  include GraphQL::EmptyObjects
25
31
  extend self
26
32
 
27
- def build(schema_superclass, document, default_resolve:, using: {}, relay:)
33
+ def build(schema_superclass, document, default_resolve:, using: {}, base_types: {}, relay:)
28
34
  raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
29
35
 
36
+ base_types = {
37
+ object: GraphQL::Schema::Object,
38
+ interface: GraphQL::Schema::Interface,
39
+ union: GraphQL::Schema::Union,
40
+ scalar: GraphQL::Schema::Scalar,
41
+ enum: GraphQL::Schema::Enum,
42
+ input_object: GraphQL::Schema::InputObject,
43
+ }.merge!(base_types)
44
+
30
45
  if default_resolve.is_a?(Hash)
31
46
  default_resolve = ResolveMap.new(default_resolve)
32
47
  end
@@ -47,7 +62,7 @@ module GraphQL
47
62
  types[type_name] ||= begin
48
63
  defn = document.definitions.find { |d| d.respond_to?(:name) && d.name == type_name }
49
64
  if defn
50
- build_definition_from_node(defn, directive_type_resolver, default_resolve)
65
+ build_definition_from_node(defn, directive_type_resolver, default_resolve, base_types)
51
66
  elsif (built_in_defn = GraphQL::Schema::BUILT_IN_TYPES[type_name])
52
67
  built_in_defn
53
68
  else
@@ -71,14 +86,20 @@ module GraphQL
71
86
  case definition
72
87
  when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
73
88
  nil # already handled
74
- when GraphQL::Language::Nodes::SchemaExtension
89
+ when GraphQL::Language::Nodes::SchemaExtension,
90
+ GraphQL::Language::Nodes::ScalarTypeExtension,
91
+ GraphQL::Language::Nodes::ObjectTypeExtension,
92
+ GraphQL::Language::Nodes::InterfaceTypeExtension,
93
+ GraphQL::Language::Nodes::UnionTypeExtension,
94
+ GraphQL::Language::Nodes::EnumTypeExtension,
95
+ GraphQL::Language::Nodes::InputObjectTypeExtension
75
96
  schema_extensions ||= []
76
97
  schema_extensions << definition
77
98
  else
78
99
  # It's possible that this was already loaded by the directives
79
100
  prev_type = types[definition.name]
80
101
  if prev_type.nil? || prev_type.is_a?(Schema::LateBoundType)
81
- types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve)
102
+ types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve, base_types)
82
103
  end
83
104
  end
84
105
  end
@@ -118,12 +139,43 @@ module GraphQL
118
139
 
119
140
  raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
120
141
 
142
+ schema_extensions&.each do |ext|
143
+ next if ext.is_a?(GraphQL::Language::Nodes::SchemaExtension)
144
+
145
+ built_type = types[ext.name]
146
+
147
+ case ext
148
+ when GraphQL::Language::Nodes::ScalarTypeExtension
149
+ build_directives(built_type, ext, type_resolver)
150
+ when GraphQL::Language::Nodes::ObjectTypeExtension
151
+ build_directives(built_type, ext, type_resolver)
152
+ build_fields(built_type, ext.fields, type_resolver, default_resolve: true)
153
+ build_interfaces(built_type, ext.interfaces, type_resolver)
154
+ when GraphQL::Language::Nodes::InterfaceTypeExtension
155
+ build_directives(built_type, ext, type_resolver)
156
+ build_fields(built_type, ext.fields, type_resolver, default_resolve: nil)
157
+ build_interfaces(built_type, ext.interfaces, type_resolver)
158
+ when GraphQL::Language::Nodes::UnionTypeExtension
159
+ build_directives(built_type, ext, type_resolver)
160
+ built_type.possible_types(*ext.types.map { |type_name| type_resolver.call(type_name) })
161
+ when GraphQL::Language::Nodes::EnumTypeExtension
162
+ build_directives(built_type, ext, type_resolver)
163
+ build_values(built_type, ext.values, type_resolver)
164
+ when GraphQL::Language::Nodes::InputObjectTypeExtension
165
+ build_directives(built_type, ext, type_resolver)
166
+ build_arguments(built_type, ext.fields, type_resolver)
167
+ end
168
+ end
169
+
121
170
  builder = self
122
171
 
172
+ found_types = types.values
173
+ object_types = found_types.select { |t| t.respond_to?(:kind) && t.kind.object? }
123
174
  schema_class = Class.new(schema_superclass) do
124
175
  begin
125
176
  # Add these first so that there's some chance of resolving late-bound types
126
- orphan_types types.values
177
+ add_type_and_traverse(found_types, root: false)
178
+ orphan_types(object_types)
127
179
  query query_root_type
128
180
  mutation mutation_root_type
129
181
  subscription subscription_root_type
@@ -133,6 +185,16 @@ module GraphQL
133
185
  raise InvalidDocumentError, "Type \"#{type_name}\" not found in document.", err_backtrace
134
186
  end
135
187
 
188
+ object_types.each do |t|
189
+ t.interfaces.each do |int_t|
190
+ if int_t.is_a?(LateBoundType)
191
+ int_t = types[int_t.graphql_name]
192
+ t.implements(int_t)
193
+ end
194
+ int_t.orphan_types(t)
195
+ end
196
+ end
197
+
136
198
  if default_resolve.respond_to?(:resolve_type)
137
199
  def self.resolve_type(*args)
138
200
  self.definition_default_resolve.resolve_type(*args)
@@ -173,11 +235,12 @@ module GraphQL
173
235
 
174
236
  def self.inherited(child_class)
175
237
  child_class.definition_default_resolve = self.definition_default_resolve
238
+ super
176
239
  end
177
240
  end
178
241
 
179
- if schema_extensions
180
- schema_extensions.each do |ext|
242
+ schema_extensions&.each do |ext|
243
+ if ext.is_a?(GraphQL::Language::Nodes::SchemaExtension)
181
244
  build_directives(schema_class, ext, type_resolver)
182
245
  end
183
246
  end
@@ -189,20 +252,22 @@ module GraphQL
189
252
  raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
190
253
  }
191
254
 
192
- def build_definition_from_node(definition, type_resolver, default_resolve)
255
+ def build_definition_from_node(definition, type_resolver, default_resolve, base_types)
193
256
  case definition
194
257
  when GraphQL::Language::Nodes::EnumTypeDefinition
195
- build_enum_type(definition, type_resolver)
258
+ build_enum_type(definition, type_resolver, base_types[:enum])
196
259
  when GraphQL::Language::Nodes::ObjectTypeDefinition
197
- build_object_type(definition, type_resolver)
260
+ build_object_type(definition, type_resolver, base_types[:object])
198
261
  when GraphQL::Language::Nodes::InterfaceTypeDefinition
199
- build_interface_type(definition, type_resolver)
262
+ build_interface_type(definition, type_resolver, base_types[:interface])
200
263
  when GraphQL::Language::Nodes::UnionTypeDefinition
201
- build_union_type(definition, type_resolver)
264
+ build_union_type(definition, type_resolver, base_types[:union])
202
265
  when GraphQL::Language::Nodes::ScalarTypeDefinition
203
- build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
266
+ build_scalar_type(definition, type_resolver, base_types[:scalar], default_resolve: default_resolve)
204
267
  when GraphQL::Language::Nodes::InputObjectTypeDefinition
205
- build_input_object_type(definition, type_resolver)
268
+ build_input_object_type(definition, type_resolver, base_types[:input_object])
269
+ when GraphQL::Language::Nodes::DirectiveDefinition
270
+ build_directive(definition, type_resolver)
206
271
  end
207
272
  end
208
273
 
@@ -268,22 +333,26 @@ module GraphQL
268
333
  end
269
334
  end
270
335
 
271
- def build_enum_type(enum_type_definition, type_resolver)
336
+ def build_enum_type(enum_type_definition, type_resolver, base_type)
272
337
  builder = self
273
- Class.new(GraphQL::Schema::Enum) do
338
+ Class.new(base_type) do
274
339
  graphql_name(enum_type_definition.name)
275
340
  builder.build_directives(self, enum_type_definition, type_resolver)
276
341
  description(enum_type_definition.description)
277
342
  ast_node(enum_type_definition)
278
- enum_type_definition.values.each do |enum_value_definition|
279
- value(enum_value_definition.name,
280
- value: enum_value_definition.name,
281
- deprecation_reason: builder.build_deprecation_reason(enum_value_definition.directives),
282
- description: enum_value_definition.description,
283
- directives: builder.prepare_directives(enum_value_definition, type_resolver),
284
- ast_node: enum_value_definition,
285
- )
286
- end
343
+ builder.build_values(self, enum_type_definition.values, type_resolver)
344
+ end
345
+ end
346
+
347
+ def build_values(type_class, enum_value_definitions, type_resolver)
348
+ enum_value_definitions.each do |enum_value_definition|
349
+ type_class.value(enum_value_definition.name,
350
+ value: enum_value_definition.name,
351
+ deprecation_reason: build_deprecation_reason(enum_value_definition.directives),
352
+ description: enum_value_definition.description,
353
+ directives: prepare_directives(enum_value_definition, type_resolver),
354
+ ast_node: enum_value_definition,
355
+ )
287
356
  end
288
357
  end
289
358
 
@@ -297,9 +366,9 @@ module GraphQL
297
366
  reason.value
298
367
  end
299
368
 
300
- def build_scalar_type(scalar_type_definition, type_resolver, default_resolve:)
369
+ def build_scalar_type(scalar_type_definition, type_resolver, base_type, default_resolve:)
301
370
  builder = self
302
- Class.new(GraphQL::Schema::Scalar) do
371
+ Class.new(base_type) do
303
372
  graphql_name(scalar_type_definition.name)
304
373
  description(scalar_type_definition.description)
305
374
  ast_node(scalar_type_definition)
@@ -320,9 +389,9 @@ module GraphQL
320
389
  end
321
390
  end
322
391
 
323
- def build_union_type(union_type_definition, type_resolver)
392
+ def build_union_type(union_type_definition, type_resolver, base_type)
324
393
  builder = self
325
- Class.new(GraphQL::Schema::Union) do
394
+ Class.new(base_type) do
326
395
  graphql_name(union_type_definition.name)
327
396
  description(union_type_definition.description)
328
397
  possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) })
@@ -331,27 +400,28 @@ module GraphQL
331
400
  end
332
401
  end
333
402
 
334
- def build_object_type(object_type_definition, type_resolver)
403
+ def build_object_type(object_type_definition, type_resolver, base_type)
335
404
  builder = self
336
405
 
337
- Class.new(GraphQL::Schema::Object) do
406
+ Class.new(base_type) do
338
407
  graphql_name(object_type_definition.name)
339
408
  description(object_type_definition.description)
340
409
  ast_node(object_type_definition)
341
410
  builder.build_directives(self, object_type_definition, type_resolver)
342
-
343
- object_type_definition.interfaces.each do |interface_name|
344
- interface_defn = type_resolver.call(interface_name)
345
- implements(interface_defn)
346
- end
347
-
411
+ builder.build_interfaces(self, object_type_definition.interfaces, type_resolver)
348
412
  builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
349
413
  end
350
414
  end
351
415
 
352
- def build_input_object_type(input_object_type_definition, type_resolver)
416
+ def build_interfaces(type_class, interface_names, type_resolver)
417
+ interface_names.each do |interface_name|
418
+ type_class.implements(type_resolver.call(interface_name))
419
+ end
420
+ end
421
+
422
+ def build_input_object_type(input_object_type_definition, type_resolver, base_type)
353
423
  builder = self
354
- Class.new(GraphQL::Schema::InputObject) do
424
+ Class.new(base_type) do
355
425
  graphql_name(input_object_type_definition.name)
356
426
  description(input_object_type_definition.description)
357
427
  ast_node(input_object_type_definition)
@@ -411,16 +481,13 @@ module GraphQL
411
481
  end
412
482
  end
413
483
 
414
- def build_interface_type(interface_type_definition, type_resolver)
484
+ def build_interface_type(interface_type_definition, type_resolver, base_type)
415
485
  builder = self
416
486
  Module.new do
417
- include GraphQL::Schema::Interface
487
+ include base_type
418
488
  graphql_name(interface_type_definition.name)
419
489
  description(interface_type_definition.description)
420
- interface_type_definition.interfaces.each do |interface_name|
421
- interface_defn = type_resolver.call(interface_name)
422
- implements(interface_defn)
423
- end
490
+ builder.build_interfaces(self, interface_type_definition.interfaces, type_resolver)
424
491
  ast_node(interface_type_definition)
425
492
  builder.build_directives(self, interface_type_definition, type_resolver)
426
493
 
@@ -432,14 +499,12 @@ module GraphQL
432
499
  builder = self
433
500
 
434
501
  field_definitions.each do |field_definition|
435
- type_name = resolve_type_name(field_definition.type)
436
502
  resolve_method_name = -"resolve_field_#{field_definition.name}"
437
503
  schema_field_defn = owner.field(
438
504
  field_definition.name,
439
505
  description: field_definition.description,
440
506
  type: type_resolver.call(field_definition.type),
441
507
  null: true,
442
- connection: type_name.end_with?("Connection"),
443
508
  connection_extension: nil,
444
509
  deprecation_reason: build_deprecation_reason(field_definition.directives),
445
510
  ast_node: field_definition,
@@ -447,6 +512,7 @@ module GraphQL
447
512
  camelize: false,
448
513
  directives: prepare_directives(field_definition, type_resolver),
449
514
  resolver_method: resolve_method_name,
515
+ resolve_batch: resolve_method_name,
450
516
  )
451
517
 
452
518
  builder.build_arguments(schema_field_defn, field_definition.arguments, type_resolver)
@@ -460,9 +526,15 @@ module GraphQL
460
526
 
461
527
  def define_field_resolve_method(owner, method_name, field_name)
462
528
  owner.define_method(method_name) { |**args|
463
- field_instance = self.class.get_field(field_name)
529
+ field_instance = context.types.field(owner, field_name)
464
530
  context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
465
531
  }
532
+ owner.define_singleton_method(method_name) { |objects, context, **args|
533
+ field_instance = context.types.field(owner, field_name)
534
+ objects.map do |object|
535
+ context.schema.definition_default_resolve.call(self, field_instance, object, args, context)
536
+ end
537
+ }
466
538
  end
467
539
 
468
540
  def build_resolve_type(lookup_hash, directives, missing_type_handler)
@@ -481,22 +553,13 @@ module GraphQL
481
553
  when GraphQL::Language::Nodes::ListType
482
554
  resolve_type_proc.call(ast_node.of_type).to_list_type
483
555
  when String
484
- directives[ast_node]
556
+ directives[ast_node] ||= missing_type_handler.call(ast_node)
485
557
  else
486
558
  raise "Unexpected ast_node: #{ast_node.inspect}"
487
559
  end
488
560
  }
489
561
  resolve_type_proc
490
562
  end
491
-
492
- def resolve_type_name(type)
493
- case type
494
- when GraphQL::Language::Nodes::TypeName
495
- return type.name
496
- else
497
- resolve_type_name(type.of_type)
498
- end
499
- end
500
563
  end
501
564
 
502
565
  private_constant :Builder
@@ -7,7 +7,7 @@ module GraphQL
7
7
  # In this case, the server hides types and fields _entirely_, unless the current context has certain `:flags` present.
8
8
  class Flagged < GraphQL::Schema::Directive
9
9
  def initialize(target, **options)
10
- if target.is_a?(Module) && !target.ancestors.include?(VisibleByFlag)
10
+ if target.is_a?(Module)
11
11
  # This is type class of some kind, `include` will put this module
12
12
  # in between the type class itself and its super class, so `super` will work fine
13
13
  target.include(VisibleByFlag)
@@ -37,6 +37,8 @@ module GraphQL
37
37
 
38
38
  argument :by, [String], "Flags to check for this schema member"
39
39
 
40
+ repeatable(true)
41
+
40
42
  module VisibleByFlag
41
43
  def self.included(schema_class)
42
44
  schema_class.extend(self)
@@ -45,7 +47,7 @@ module GraphQL
45
47
  def visible?(context)
46
48
  if dir = self.directives.find { |d| d.is_a?(Flagged) }
47
49
  relevant_flags = (f = context[:flags]) && dir.arguments[:by] & f # rubocop:disable Development/ContextIsPassedCop -- definition-related
48
- relevant_flags && relevant_flags.any? && super
50
+ relevant_flags && !relevant_flags.empty? && super
49
51
  else
50
52
  super
51
53
  end
@@ -6,6 +6,18 @@ module GraphQL
6
6
  description "Requires that exactly one field must be supplied and that field must not be `null`."
7
7
  locations(GraphQL::Schema::Directive::INPUT_OBJECT)
8
8
  default_directive true
9
+
10
+ def initialize(...)
11
+ super
12
+
13
+ owner.extend(IsOneOf)
14
+ end
15
+
16
+ module IsOneOf
17
+ def one_of?
18
+ true
19
+ end
20
+ end
9
21
  end
10
22
  end
11
23
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Directive < GraphQL::Schema::Member
5
+ class SpecifiedBy < GraphQL::Schema::Directive
6
+ description "Exposes a URL that specifies the behavior of this scalar."
7
+ locations(GraphQL::Schema::Directive::SCALAR)
8
+ default_directive true
9
+
10
+ argument :url, String, description: "The URL that specifies the behavior of this scalar."
11
+ end
12
+ end
13
+ end
14
+ end
@@ -9,6 +9,7 @@ module GraphQL
9
9
  class Directive < GraphQL::Schema::Member
10
10
  extend GraphQL::Schema::Member::HasArguments
11
11
  extend GraphQL::Schema::Member::HasArguments::HasDirectiveArguments
12
+ extend GraphQL::Schema::Member::HasValidators
12
13
 
13
14
  class << self
14
15
  # Directives aren't types, they don't have kinds.
@@ -29,7 +30,7 @@ module GraphQL
29
30
  end
30
31
 
31
32
  def locations(*new_locations)
32
- if new_locations.any?
33
+ if !new_locations.empty?
33
34
  new_locations.each do |new_loc|
34
35
  if !LOCATIONS.include?(new_loc.to_sym)
35
36
  raise ArgumentError, "#{self} (#{self.graphql_name}) has an invalid directive location: `locations #{new_loc}` "
@@ -75,6 +76,10 @@ module GraphQL
75
76
  yield
76
77
  end
77
78
 
79
+ def validate!(arguments, context)
80
+ Schema::Validator.validate!(validators, self, context, arguments)
81
+ end
82
+
78
83
  def on_field?
79
84
  locations.include?(FIELD)
80
85
  end
@@ -111,6 +116,9 @@ module GraphQL
111
116
  # @return [GraphQL::Interpreter::Arguments]
112
117
  attr_reader :arguments
113
118
 
119
+ class InvalidArgumentError < GraphQL::Error
120
+ end
121
+
114
122
  def initialize(owner, **arguments)
115
123
  @owner = owner
116
124
  assert_valid_owner
@@ -119,7 +127,49 @@ module GraphQL
119
127
  # - lazy resolution
120
128
  # Probably, those won't be needed here, since these are configuration arguments,
121
129
  # not runtime arguments.
122
- @arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext)
130
+ context = Query::NullContext.instance
131
+ self.class.all_argument_definitions.each do |arg_defn|
132
+ keyword = arg_defn.keyword
133
+ arg_type = arg_defn.type
134
+ if arguments.key?(keyword)
135
+ value = arguments[keyword]
136
+ # This is a Ruby-land value; convert it to graphql for validation
137
+ graphql_value = begin
138
+ coerce_value = value
139
+ if arg_type.list? && (!coerce_value.nil?) && (!coerce_value.is_a?(Array))
140
+ # When validating inputs, GraphQL accepts a single item
141
+ # and implicitly converts it to a one-item list.
142
+ # However, we're using result coercion here to go from Ruby value
143
+ # to GraphQL value, so it doesn't have that feature.
144
+ # Keep the GraphQL-type behavior but implement it manually:
145
+ wrap_type = arg_type
146
+ while wrap_type.list?
147
+ if wrap_type.non_null?
148
+ wrap_type = wrap_type.of_type
149
+ end
150
+ wrap_type = wrap_type.of_type
151
+ coerce_value = [coerce_value]
152
+ end
153
+ end
154
+ arg_type.coerce_isolated_result(coerce_value)
155
+ rescue GraphQL::Schema::Enum::UnresolvedValueError
156
+ # Let validation handle this
157
+ value
158
+ end
159
+ else
160
+ value = graphql_value = nil
161
+ end
162
+
163
+ result = arg_type.validate_input(graphql_value, context)
164
+ if !result.valid?
165
+ raise InvalidArgumentError, "@#{graphql_name}.#{arg_defn.graphql_name} on #{owner.path} is invalid (#{value.inspect}): #{result.problems.first["explanation"]}"
166
+ end
167
+ end
168
+ self.class.validate!(arguments, context)
169
+ @arguments = self.class.coerce_arguments(nil, arguments, context)
170
+ if @arguments.is_a?(GraphQL::ExecutionError)
171
+ raise @arguments
172
+ end
123
173
  end
124
174
 
125
175
  def graphql_name
@@ -188,6 +238,8 @@ module GraphQL
188
238
  assert_has_location(SCALAR)
189
239
  elsif @owner < GraphQL::Schema
190
240
  assert_has_location(SCHEMA)
241
+ elsif @owner < GraphQL::Schema::Resolver
242
+ assert_has_location(FIELD_DEFINITION)
191
243
  else
192
244
  raise "Unexpected directive owner class: #{@owner}"
193
245
  end