graphql 1.11.6 → 1.13.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (293) 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/install_generator.rb +17 -7
  8. data/lib/generators/graphql/interface_generator.rb +7 -7
  9. data/lib/generators/graphql/loader_generator.rb +1 -0
  10. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  11. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  12. data/lib/generators/graphql/mutation_generator.rb +6 -30
  13. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  14. data/lib/generators/graphql/object_generator.rb +12 -38
  15. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  16. data/lib/generators/graphql/relay.rb +63 -0
  17. data/lib/generators/graphql/relay_generator.rb +21 -0
  18. data/lib/generators/graphql/scalar_generator.rb +4 -2
  19. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  20. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  21. data/lib/generators/graphql/templates/enum.erb +5 -1
  22. data/lib/generators/graphql/templates/graphql_controller.erb +2 -2
  23. data/lib/generators/graphql/templates/input.erb +9 -0
  24. data/lib/generators/graphql/templates/interface.erb +4 -2
  25. data/lib/generators/graphql/templates/mutation.erb +1 -1
  26. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  27. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  28. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  29. data/lib/generators/graphql/templates/node_type.erb +9 -0
  30. data/lib/generators/graphql/templates/object.erb +5 -3
  31. data/lib/generators/graphql/templates/query_type.erb +1 -3
  32. data/lib/generators/graphql/templates/scalar.erb +3 -1
  33. data/lib/generators/graphql/templates/schema.erb +19 -34
  34. data/lib/generators/graphql/templates/union.erb +4 -2
  35. data/lib/generators/graphql/type_generator.rb +47 -10
  36. data/lib/generators/graphql/union_generator.rb +5 -5
  37. data/lib/graphql/analysis/analyze_query.rb +7 -0
  38. data/lib/graphql/analysis/ast/field_usage.rb +28 -1
  39. data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
  40. data/lib/graphql/analysis/ast/visitor.rb +14 -5
  41. data/lib/graphql/analysis/ast.rb +11 -2
  42. data/lib/graphql/argument.rb +1 -1
  43. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  44. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  45. data/lib/graphql/backtrace/table.rb +34 -3
  46. data/lib/graphql/backtrace/traced_error.rb +0 -1
  47. data/lib/graphql/backtrace/tracer.rb +40 -10
  48. data/lib/graphql/backtrace.rb +28 -19
  49. data/lib/graphql/backwards_compatibility.rb +2 -1
  50. data/lib/graphql/base_type.rb +6 -4
  51. data/lib/graphql/boolean_type.rb +1 -1
  52. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  53. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  54. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  55. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  56. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  57. data/lib/graphql/dataloader/request.rb +19 -0
  58. data/lib/graphql/dataloader/request_all.rb +19 -0
  59. data/lib/graphql/dataloader/source.rb +155 -0
  60. data/lib/graphql/dataloader.rb +308 -0
  61. data/lib/graphql/date_encoding_error.rb +16 -0
  62. data/lib/graphql/define/assign_global_id_field.rb +1 -1
  63. data/lib/graphql/define/instance_definable.rb +48 -3
  64. data/lib/graphql/define/type_definer.rb +5 -5
  65. data/lib/graphql/deprecated_dsl.rb +18 -5
  66. data/lib/graphql/deprecation.rb +9 -0
  67. data/lib/graphql/directive/deprecated_directive.rb +1 -1
  68. data/lib/graphql/directive/include_directive.rb +1 -1
  69. data/lib/graphql/directive/skip_directive.rb +1 -1
  70. data/lib/graphql/directive.rb +1 -5
  71. data/lib/graphql/enum_type.rb +9 -3
  72. data/lib/graphql/execution/errors.rb +110 -7
  73. data/lib/graphql/execution/execute.rb +8 -1
  74. data/lib/graphql/execution/interpreter/arguments.rb +57 -5
  75. data/lib/graphql/execution/interpreter/arguments_cache.rb +49 -15
  76. data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
  77. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  78. data/lib/graphql/execution/interpreter/runtime.rb +670 -294
  79. data/lib/graphql/execution/interpreter.rb +16 -16
  80. data/lib/graphql/execution/lazy.rb +5 -1
  81. data/lib/graphql/execution/lookahead.rb +2 -2
  82. data/lib/graphql/execution/multiplex.rb +39 -23
  83. data/lib/graphql/field.rb +1 -1
  84. data/lib/graphql/float_type.rb +1 -1
  85. data/lib/graphql/function.rb +4 -0
  86. data/lib/graphql/id_type.rb +1 -1
  87. data/lib/graphql/input_object_type.rb +3 -1
  88. data/lib/graphql/int_type.rb +1 -1
  89. data/lib/graphql/integer_decoding_error.rb +17 -0
  90. data/lib/graphql/integer_encoding_error.rb +18 -2
  91. data/lib/graphql/interface_type.rb +4 -2
  92. data/lib/graphql/internal_representation/document.rb +2 -2
  93. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  94. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  95. data/lib/graphql/introspection/directive_type.rb +11 -5
  96. data/lib/graphql/introspection/entry_points.rb +2 -2
  97. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  98. data/lib/graphql/introspection/field_type.rb +3 -3
  99. data/lib/graphql/introspection/input_value_type.rb +10 -4
  100. data/lib/graphql/introspection/schema_type.rb +10 -5
  101. data/lib/graphql/introspection/type_type.rb +18 -12
  102. data/lib/graphql/introspection.rb +5 -2
  103. data/lib/graphql/invalid_null_error.rb +1 -1
  104. data/lib/graphql/language/block_string.rb +2 -6
  105. data/lib/graphql/language/cache.rb +37 -0
  106. data/lib/graphql/language/document_from_schema_definition.rb +60 -26
  107. data/lib/graphql/language/lexer.rb +50 -28
  108. data/lib/graphql/language/lexer.rl +2 -4
  109. data/lib/graphql/language/nodes.rb +14 -4
  110. data/lib/graphql/language/parser.rb +856 -825
  111. data/lib/graphql/language/parser.y +28 -11
  112. data/lib/graphql/language/printer.rb +10 -1
  113. data/lib/graphql/language/sanitized_printer.rb +5 -5
  114. data/lib/graphql/language/token.rb +0 -4
  115. data/lib/graphql/language.rb +1 -0
  116. data/lib/graphql/name_validator.rb +0 -4
  117. data/lib/graphql/object_type.rb +4 -4
  118. data/lib/graphql/pagination/active_record_relation_connection.rb +47 -3
  119. data/lib/graphql/pagination/connection.rb +19 -1
  120. data/lib/graphql/pagination/connections.rb +45 -30
  121. data/lib/graphql/pagination/relation_connection.rb +69 -28
  122. data/lib/graphql/parse_error.rb +0 -1
  123. data/lib/graphql/query/arguments.rb +2 -2
  124. data/lib/graphql/query/arguments_cache.rb +1 -2
  125. data/lib/graphql/query/context.rb +22 -4
  126. data/lib/graphql/query/executor.rb +0 -1
  127. data/lib/graphql/query/input_validation_result.rb +9 -0
  128. data/lib/graphql/query/literal_input.rb +1 -1
  129. data/lib/graphql/query/null_context.rb +21 -9
  130. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  131. data/lib/graphql/query/serial_execution.rb +1 -0
  132. data/lib/graphql/query/validation_pipeline.rb +3 -4
  133. data/lib/graphql/query/variable_validation_error.rb +3 -3
  134. data/lib/graphql/query/variables.rb +35 -4
  135. data/lib/graphql/query.rb +20 -8
  136. data/lib/graphql/railtie.rb +9 -1
  137. data/lib/graphql/rake_task.rb +3 -0
  138. data/lib/graphql/relay/array_connection.rb +2 -2
  139. data/lib/graphql/relay/base_connection.rb +7 -0
  140. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  141. data/lib/graphql/relay/connection_type.rb +16 -3
  142. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  143. data/lib/graphql/relay/global_id_resolve.rb +1 -2
  144. data/lib/graphql/relay/mutation.rb +2 -1
  145. data/lib/graphql/relay/node.rb +3 -0
  146. data/lib/graphql/relay/page_info.rb +1 -1
  147. data/lib/graphql/relay/range_add.rb +14 -5
  148. data/lib/graphql/relay/type_extensions.rb +2 -0
  149. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  150. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  151. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  152. data/lib/graphql/rubocop.rb +4 -0
  153. data/lib/graphql/scalar_type.rb +3 -1
  154. data/lib/graphql/schema/addition.rb +247 -0
  155. data/lib/graphql/schema/argument.rb +177 -21
  156. data/lib/graphql/schema/build_from_definition.rb +150 -55
  157. data/lib/graphql/schema/default_type_error.rb +2 -0
  158. data/lib/graphql/schema/directive/feature.rb +1 -1
  159. data/lib/graphql/schema/directive/flagged.rb +57 -0
  160. data/lib/graphql/schema/directive/include.rb +1 -1
  161. data/lib/graphql/schema/directive/skip.rb +1 -1
  162. data/lib/graphql/schema/directive/transform.rb +14 -2
  163. data/lib/graphql/schema/directive.rb +103 -4
  164. data/lib/graphql/schema/enum.rb +72 -11
  165. data/lib/graphql/schema/enum_value.rb +18 -6
  166. data/lib/graphql/schema/field/connection_extension.rb +4 -2
  167. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  168. data/lib/graphql/schema/field.rb +332 -111
  169. data/lib/graphql/schema/field_extension.rb +89 -2
  170. data/lib/graphql/schema/find_inherited_value.rb +4 -1
  171. data/lib/graphql/schema/finder.rb +5 -5
  172. data/lib/graphql/schema/input_object.rb +79 -55
  173. data/lib/graphql/schema/interface.rb +12 -20
  174. data/lib/graphql/schema/introspection_system.rb +1 -1
  175. data/lib/graphql/schema/list.rb +21 -4
  176. data/lib/graphql/schema/loader.rb +11 -0
  177. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  178. data/lib/graphql/schema/member/base_dsl_methods.rb +5 -16
  179. data/lib/graphql/schema/member/build_type.rb +4 -7
  180. data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
  181. data/lib/graphql/schema/member/has_arguments.rb +166 -74
  182. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  183. data/lib/graphql/schema/member/has_directives.rb +98 -0
  184. data/lib/graphql/schema/member/has_fields.rb +77 -22
  185. data/lib/graphql/schema/member/has_interfaces.rb +100 -0
  186. data/lib/graphql/schema/member/has_validators.rb +31 -0
  187. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  188. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  189. data/lib/graphql/schema/member/validates_input.rb +2 -2
  190. data/lib/graphql/schema/member.rb +5 -0
  191. data/lib/graphql/schema/middleware_chain.rb +1 -1
  192. data/lib/graphql/schema/non_null.rb +9 -3
  193. data/lib/graphql/schema/object.rb +40 -80
  194. data/lib/graphql/schema/printer.rb +16 -20
  195. data/lib/graphql/schema/relay_classic_mutation.rb +38 -4
  196. data/lib/graphql/schema/resolver/has_payload_type.rb +29 -2
  197. data/lib/graphql/schema/resolver.rb +110 -64
  198. data/lib/graphql/schema/scalar.rb +18 -2
  199. data/lib/graphql/schema/subscription.rb +55 -9
  200. data/lib/graphql/schema/timeout_middleware.rb +3 -1
  201. data/lib/graphql/schema/traversal.rb +1 -1
  202. data/lib/graphql/schema/type_expression.rb +1 -1
  203. data/lib/graphql/schema/type_membership.rb +18 -4
  204. data/lib/graphql/schema/union.rb +8 -1
  205. data/lib/graphql/schema/validation.rb +4 -2
  206. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  207. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  208. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  209. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  210. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  211. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  212. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  213. data/lib/graphql/schema/validator/required_validator.rb +82 -0
  214. data/lib/graphql/schema/validator.rb +171 -0
  215. data/lib/graphql/schema/warden.rb +126 -53
  216. data/lib/graphql/schema.rb +262 -281
  217. data/lib/graphql/static_validation/all_rules.rb +2 -0
  218. data/lib/graphql/static_validation/base_visitor.rb +9 -6
  219. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  220. data/lib/graphql/static_validation/error.rb +3 -1
  221. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  222. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +4 -2
  223. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +6 -2
  224. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  225. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  226. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  227. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  228. data/lib/graphql/static_validation/rules/fields_will_merge.rb +90 -47
  229. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  230. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  231. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  232. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  233. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  234. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  235. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -2
  236. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  237. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  238. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
  239. data/lib/graphql/static_validation/validation_context.rb +12 -2
  240. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  241. data/lib/graphql/static_validation/validator.rb +41 -10
  242. data/lib/graphql/static_validation.rb +1 -0
  243. data/lib/graphql/string_encoding_error.rb +13 -3
  244. data/lib/graphql/string_type.rb +1 -1
  245. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +39 -8
  246. data/lib/graphql/subscriptions/broadcast_analyzer.rb +0 -3
  247. data/lib/graphql/subscriptions/event.rb +68 -32
  248. data/lib/graphql/subscriptions/instrumentation.rb +0 -1
  249. data/lib/graphql/subscriptions/serialize.rb +34 -5
  250. data/lib/graphql/subscriptions/subscription_root.rb +1 -1
  251. data/lib/graphql/subscriptions.rb +34 -39
  252. data/lib/graphql/tracing/active_support_notifications_tracing.rb +8 -21
  253. data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
  254. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  255. data/lib/graphql/tracing/data_dog_tracing.rb +24 -2
  256. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  257. data/lib/graphql/tracing/platform_tracing.rb +24 -12
  258. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  259. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  260. data/lib/graphql/tracing.rb +2 -2
  261. data/lib/graphql/types/big_int.rb +5 -1
  262. data/lib/graphql/types/int.rb +10 -3
  263. data/lib/graphql/types/iso_8601_date.rb +13 -5
  264. data/lib/graphql/types/iso_8601_date_time.rb +8 -1
  265. data/lib/graphql/types/relay/base_connection.rb +6 -91
  266. data/lib/graphql/types/relay/base_edge.rb +2 -34
  267. data/lib/graphql/types/relay/connection_behaviors.rb +174 -0
  268. data/lib/graphql/types/relay/default_relay.rb +31 -0
  269. data/lib/graphql/types/relay/edge_behaviors.rb +64 -0
  270. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  271. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  272. data/lib/graphql/types/relay/node.rb +2 -4
  273. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  274. data/lib/graphql/types/relay/node_field.rb +3 -22
  275. data/lib/graphql/types/relay/nodes_field.rb +16 -18
  276. data/lib/graphql/types/relay/page_info.rb +2 -14
  277. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  278. data/lib/graphql/types/relay.rb +11 -3
  279. data/lib/graphql/types/string.rb +8 -2
  280. data/lib/graphql/unauthorized_error.rb +1 -1
  281. data/lib/graphql/union_type.rb +3 -1
  282. data/lib/graphql/upgrader/member.rb +1 -0
  283. data/lib/graphql/upgrader/schema.rb +1 -0
  284. data/lib/graphql/version.rb +1 -1
  285. data/lib/graphql.rb +68 -37
  286. data/readme.md +3 -6
  287. metadata +83 -113
  288. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  289. data/lib/graphql/types/relay/base_field.rb +0 -22
  290. data/lib/graphql/types/relay/base_interface.rb +0 -29
  291. data/lib/graphql/types/relay/base_object.rb +0 -26
  292. /data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +0 -0
  293. /data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +0 -0
@@ -4,10 +4,6 @@ require "graphql/schema/build_from_definition/resolve_map"
4
4
  module GraphQL
5
5
  class Schema
6
6
  module BuildFromDefinition
7
- if !String.method_defined?(:-@)
8
- using GraphQL::StringDedupBackport
9
- end
10
-
11
7
  class << self
12
8
  # @see {Schema.from_definition}
13
9
  def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
@@ -18,8 +14,8 @@ module GraphQL
18
14
  from_document(parser.parse_file(definition_path), **kwargs)
19
15
  end
20
16
 
21
- def from_document(document, default_resolve:, using: {}, relay: false, interpreter: true)
22
- Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using, interpreter: interpreter)
17
+ def from_document(document, default_resolve:, using: {}, relay: false)
18
+ Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using)
23
19
  end
24
20
  end
25
21
 
@@ -27,7 +23,7 @@ module GraphQL
27
23
  module Builder
28
24
  extend self
29
25
 
30
- def build(document, default_resolve:, using: {}, interpreter: true, relay:)
26
+ def build(document, default_resolve:, using: {}, relay:)
31
27
  raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
32
28
 
33
29
  if default_resolve.is_a?(Hash)
@@ -41,45 +37,49 @@ module GraphQL
41
37
  schema_definition = schema_defns.first
42
38
  types = {}
43
39
  directives = {}
44
- type_resolver = ->(type) { resolve_type(types, type) }
40
+ type_resolver = build_resolve_type(types, directives, ->(type_name) { types[type_name] ||= Schema::LateBoundType.new(type_name)})
41
+ # Make a different type resolver because we need to coerce directive arguments
42
+ # _while_ building the schema.
43
+ # It will dig for a type if it encounters a custom type. This could be a problem if there are cycles.
44
+ directive_type_resolver = nil
45
+ directive_type_resolver = build_resolve_type(types, directives, ->(type_name) {
46
+ types[type_name] ||= begin
47
+ defn = document.definitions.find { |d| d.respond_to?(:name) && d.name == type_name }
48
+ if defn
49
+ build_definition_from_node(defn, directive_type_resolver, default_resolve)
50
+ elsif (built_in_defn = GraphQL::Schema::BUILT_IN_TYPES[type_name])
51
+ built_in_defn
52
+ else
53
+ raise "No definition for #{type_name.inspect} found in schema document or built-in types. Add a definition for it or remove it."
54
+ end
55
+ end
56
+ })
45
57
 
46
58
  document.definitions.each do |definition|
47
- case definition
48
- when GraphQL::Language::Nodes::SchemaDefinition
49
- nil # already handled
50
- when GraphQL::Language::Nodes::EnumTypeDefinition
51
- types[definition.name] = build_enum_type(definition, type_resolver)
52
- when GraphQL::Language::Nodes::ObjectTypeDefinition
53
- types[definition.name] = build_object_type(definition, type_resolver)
54
- when GraphQL::Language::Nodes::InterfaceTypeDefinition
55
- types[definition.name] = build_interface_type(definition, type_resolver)
56
- when GraphQL::Language::Nodes::UnionTypeDefinition
57
- types[definition.name] = build_union_type(definition, type_resolver)
58
- when GraphQL::Language::Nodes::ScalarTypeDefinition
59
- types[definition.name] = build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
60
- when GraphQL::Language::Nodes::InputObjectTypeDefinition
61
- types[definition.name] = build_input_object_type(definition, type_resolver)
62
- when GraphQL::Language::Nodes::DirectiveDefinition
63
- directives[definition.name] = build_directive(definition, type_resolver)
59
+ if definition.is_a?(GraphQL::Language::Nodes::DirectiveDefinition)
60
+ directives[definition.name] = build_directive(definition, directive_type_resolver)
64
61
  end
65
62
  end
66
63
 
67
- # At this point, if types named by the built in types are _late-bound_ types,
68
- # that means they were referenced in the schema but not defined in the schema.
69
- # That's supported for built-in types. (Eg, you can use `String` without defining it.)
70
- # In that case, insert the concrete type definition now.
71
- #
72
- # However, if the type in `types` is a _concrete_ type definition, that means that
73
- # the document contained an explicit definition of the scalar type.
74
- # Don't override it in this case.
75
- GraphQL::Schema::BUILT_IN_TYPES.each do |scalar_name, built_in_scalar|
76
- existing_type = types[scalar_name]
77
- if existing_type.is_a?(GraphQL::Schema::LateBoundType)
78
- types[scalar_name] = built_in_scalar
64
+ directives = GraphQL::Schema.default_directives.merge(directives)
65
+
66
+ # In case any directives referenced built-in types for their arguments:
67
+ replace_late_bound_types_with_built_in(types)
68
+
69
+ document.definitions.each do |definition|
70
+ case definition
71
+ when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
72
+ nil # already handled
73
+ else
74
+ # It's possible that this was already loaded by the directives
75
+ prev_type = types[definition.name]
76
+ if prev_type.nil? || prev_type.is_a?(Schema::LateBoundType)
77
+ types[definition.name] = build_definition_from_node(definition, type_resolver, default_resolve)
78
+ end
79
79
  end
80
80
  end
81
81
 
82
- directives = GraphQL::Schema.default_directives.merge(directives)
82
+ replace_late_bound_types_with_built_in(types)
83
83
 
84
84
  if schema_definition
85
85
  if schema_definition.query
@@ -133,11 +133,6 @@ module GraphQL
133
133
  ast_node(schema_definition)
134
134
  end
135
135
 
136
- if interpreter
137
- use GraphQL::Execution::Interpreter
138
- use GraphQL::Analysis::AST
139
- end
140
-
141
136
  using.each do |plugin, options|
142
137
  if options
143
138
  use(plugin, **options)
@@ -169,10 +164,85 @@ module GraphQL
169
164
  raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
170
165
  }
171
166
 
167
+ def build_definition_from_node(definition, type_resolver, default_resolve)
168
+ case definition
169
+ when GraphQL::Language::Nodes::EnumTypeDefinition
170
+ build_enum_type(definition, type_resolver)
171
+ when GraphQL::Language::Nodes::ObjectTypeDefinition
172
+ build_object_type(definition, type_resolver)
173
+ when GraphQL::Language::Nodes::InterfaceTypeDefinition
174
+ build_interface_type(definition, type_resolver)
175
+ when GraphQL::Language::Nodes::UnionTypeDefinition
176
+ build_union_type(definition, type_resolver)
177
+ when GraphQL::Language::Nodes::ScalarTypeDefinition
178
+ build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
179
+ when GraphQL::Language::Nodes::InputObjectTypeDefinition
180
+ build_input_object_type(definition, type_resolver)
181
+ end
182
+ end
183
+
184
+ # Modify `types`, replacing any late-bound references to built-in types
185
+ # with their actual definitions.
186
+ #
187
+ # (Schema definitions are allowed to reference those built-ins without redefining them.)
188
+ # @return void
189
+ def replace_late_bound_types_with_built_in(types)
190
+ GraphQL::Schema::BUILT_IN_TYPES.each do |scalar_name, built_in_scalar|
191
+ existing_type = types[scalar_name]
192
+ if existing_type.is_a?(GraphQL::Schema::LateBoundType)
193
+ types[scalar_name] = built_in_scalar
194
+ end
195
+ end
196
+ end
197
+
198
+ def build_directives(definition, ast_node, type_resolver)
199
+ dirs = prepare_directives(ast_node, type_resolver)
200
+ dirs.each do |dir_class, options|
201
+ definition.directive(dir_class, **options)
202
+ end
203
+ end
204
+
205
+ def prepare_directives(ast_node, type_resolver)
206
+ dirs = {}
207
+ ast_node.directives.each do |dir_node|
208
+ if dir_node.name == "deprecated"
209
+ # This is handled using `deprecation_reason`
210
+ next
211
+ else
212
+ dir_class = type_resolver.call(dir_node.name)
213
+ if dir_class.nil?
214
+ raise ArgumentError, "No definition for @#{dir_node.name} on #{ast_node.name} at #{ast_node.line}:#{ast_node.col}"
215
+ end
216
+ options = args_to_kwargs(dir_class, dir_node)
217
+ dirs[dir_class] = options
218
+ end
219
+ end
220
+ dirs
221
+ end
222
+
223
+ def args_to_kwargs(arg_owner, node)
224
+ if node.respond_to?(:arguments)
225
+ kwargs = {}
226
+ node.arguments.each do |arg_node|
227
+ arg_defn = arg_owner.get_argument(arg_node.name)
228
+ kwargs[arg_defn.keyword] = args_to_kwargs(arg_defn.type.unwrap, arg_node.value)
229
+ end
230
+ kwargs
231
+ elsif node.is_a?(Array)
232
+ node.map { |n| args_to_kwargs(arg_owner, n) }
233
+ elsif node.is_a?(Language::Nodes::Enum)
234
+ node.name
235
+ else
236
+ # scalar
237
+ node
238
+ end
239
+ end
240
+
172
241
  def build_enum_type(enum_type_definition, type_resolver)
173
242
  builder = self
174
243
  Class.new(GraphQL::Schema::Enum) do
175
244
  graphql_name(enum_type_definition.name)
245
+ builder.build_directives(self, enum_type_definition, type_resolver)
176
246
  description(enum_type_definition.description)
177
247
  ast_node(enum_type_definition)
178
248
  enum_type_definition.values.each do |enum_value_definition|
@@ -180,6 +250,7 @@ module GraphQL
180
250
  value: enum_value_definition.name,
181
251
  deprecation_reason: builder.build_deprecation_reason(enum_value_definition.directives),
182
252
  description: enum_value_definition.description,
253
+ directives: builder.prepare_directives(enum_value_definition, type_resolver),
183
254
  ast_node: enum_value_definition,
184
255
  )
185
256
  end
@@ -202,6 +273,7 @@ module GraphQL
202
273
  graphql_name(scalar_type_definition.name)
203
274
  description(scalar_type_definition.description)
204
275
  ast_node(scalar_type_definition)
276
+ builder.build_directives(self, scalar_type_definition, type_resolver)
205
277
 
206
278
  if default_resolve.respond_to?(:coerce_input)
207
279
  # Put these method definitions in another method to avoid retaining `type_resolve`
@@ -219,11 +291,13 @@ module GraphQL
219
291
  end
220
292
 
221
293
  def build_union_type(union_type_definition, type_resolver)
294
+ builder = self
222
295
  Class.new(GraphQL::Schema::Union) do
223
296
  graphql_name(union_type_definition.name)
224
297
  description(union_type_definition.description)
225
298
  possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) })
226
299
  ast_node(union_type_definition)
300
+ builder.build_directives(self, union_type_definition, type_resolver)
227
301
  end
228
302
  end
229
303
 
@@ -234,6 +308,7 @@ module GraphQL
234
308
  graphql_name(object_type_definition.name)
235
309
  description(object_type_definition.description)
236
310
  ast_node(object_type_definition)
311
+ builder.build_directives(self, object_type_definition, type_resolver)
237
312
 
238
313
  object_type_definition.interfaces.each do |interface_name|
239
314
  interface_defn = type_resolver.call(interface_name)
@@ -250,6 +325,7 @@ module GraphQL
250
325
  graphql_name(input_object_type_definition.name)
251
326
  description(input_object_type_definition.description)
252
327
  ast_node(input_object_type_definition)
328
+ builder.build_directives(self, input_object_type_definition, type_resolver)
253
329
  builder.build_arguments(self, input_object_type_definition.fields, type_resolver)
254
330
  end
255
331
  end
@@ -290,6 +366,7 @@ module GraphQL
290
366
  ast_node: argument_defn,
291
367
  camelize: false,
292
368
  method_access: false,
369
+ directives: prepare_directives(argument_defn, type_resolver),
293
370
  **default_value_kwargs
294
371
  )
295
372
  end
@@ -300,6 +377,7 @@ module GraphQL
300
377
  Class.new(GraphQL::Schema::Directive) do
301
378
  graphql_name(directive_definition.name)
302
379
  description(directive_definition.description)
380
+ repeatable(directive_definition.repeatable)
303
381
  locations(*directive_definition.locations.map { |location| location.name.to_sym })
304
382
  ast_node(directive_definition)
305
383
  builder.build_arguments(self, directive_definition.arguments, type_resolver)
@@ -312,7 +390,13 @@ module GraphQL
312
390
  include GraphQL::Schema::Interface
313
391
  graphql_name(interface_type_definition.name)
314
392
  description(interface_type_definition.description)
393
+ interface_type_definition.interfaces.each do |interface_name|
394
+ "Implements: #{interface_type_definition} -> #{interface_name}"
395
+ interface_defn = type_resolver.call(interface_name)
396
+ implements(interface_defn)
397
+ end
315
398
  ast_node(interface_type_definition)
399
+ builder.build_directives(self, interface_type_definition, type_resolver)
316
400
 
317
401
  builder.build_fields(self, interface_type_definition.fields, type_resolver, default_resolve: nil)
318
402
  end
@@ -335,6 +419,7 @@ module GraphQL
335
419
  ast_node: field_definition,
336
420
  method_conflict_warning: false,
337
421
  camelize: false,
422
+ directives: prepare_directives(field_definition, type_resolver),
338
423
  resolver_method: resolve_method_name,
339
424
  )
340
425
 
@@ -353,18 +438,28 @@ module GraphQL
353
438
  end
354
439
  end
355
440
 
356
- def resolve_type(types, ast_node)
357
- case ast_node
358
- when GraphQL::Language::Nodes::TypeName
359
- type_name = ast_node.name
360
- types[type_name] ||= GraphQL::Schema::LateBoundType.new(type_name)
361
- when GraphQL::Language::Nodes::NonNullType
362
- resolve_type(types, ast_node.of_type).to_non_null_type
363
- when GraphQL::Language::Nodes::ListType
364
- resolve_type(types, ast_node.of_type).to_list_type
365
- else
366
- raise "Unexpected ast_node: #{ast_node.inspect}"
367
- end
441
+ def build_resolve_type(lookup_hash, directives, missing_type_handler)
442
+ resolve_type_proc = nil
443
+ resolve_type_proc = ->(ast_node) {
444
+ case ast_node
445
+ when GraphQL::Language::Nodes::TypeName
446
+ type_name = ast_node.name
447
+ if lookup_hash.key?(type_name)
448
+ lookup_hash[type_name]
449
+ else
450
+ missing_type_handler.call(type_name)
451
+ end
452
+ when GraphQL::Language::Nodes::NonNullType
453
+ resolve_type_proc.call(ast_node.of_type).to_non_null_type
454
+ when GraphQL::Language::Nodes::ListType
455
+ resolve_type_proc.call(ast_node.of_type).to_list_type
456
+ when String
457
+ directives[ast_node]
458
+ else
459
+ raise "Unexpected ast_node: #{ast_node.inspect}"
460
+ end
461
+ }
462
+ resolve_type_proc
368
463
  end
369
464
 
370
465
  def resolve_type_name(type)
@@ -8,6 +8,8 @@ module GraphQL
8
8
  ctx.errors << type_error
9
9
  when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
10
10
  raise type_error
11
+ when GraphQL::IntegerDecodingError
12
+ nil
11
13
  end
12
14
  end
13
15
  end
@@ -42,7 +42,7 @@ module GraphQL
42
42
  GraphQL::Schema::Directive::INLINE_FRAGMENT
43
43
  )
44
44
 
45
- argument :flag, String, required: true,
45
+ argument :flag, String,
46
46
  description: "The name of the feature to check before continuing"
47
47
 
48
48
  # Implement the Directive API
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class Directive < GraphQL::Schema::Member
5
+ # This is _similar_ to {Directive::Feature}, except it's prescribed by the server, not the client.
6
+ #
7
+ # In this case, the server hides types and fields _entirely_, unless the current context has certain `:flags` present.
8
+ class Flagged < GraphQL::Schema::Directive
9
+ def initialize(target, **options)
10
+ if target.is_a?(Module) && !target.ancestors.include?(VisibleByFlag)
11
+ # This is type class of some kind, `include` will put this module
12
+ # in between the type class itself and its super class, so `super` will work fine
13
+ target.include(VisibleByFlag)
14
+ elsif !target.is_a?(VisibleByFlag)
15
+ # This is an instance of a base class. `include` won't put this in front of the
16
+ # base class implementation, so we need to `.prepend`.
17
+ # `#visible?` could probably be moved to a module and then this could use `include` instead.
18
+ target.class.prepend(VisibleByFlag)
19
+ end
20
+ super
21
+ end
22
+
23
+ description "Hides this part of the schema unless the named flag is present in context[:flags]"
24
+
25
+ locations(
26
+ GraphQL::Schema::Directive::FIELD_DEFINITION,
27
+ GraphQL::Schema::Directive::OBJECT,
28
+ GraphQL::Schema::Directive::SCALAR,
29
+ GraphQL::Schema::Directive::ENUM,
30
+ GraphQL::Schema::Directive::UNION,
31
+ GraphQL::Schema::Directive::INTERFACE,
32
+ GraphQL::Schema::Directive::INPUT_OBJECT,
33
+ GraphQL::Schema::Directive::ENUM_VALUE,
34
+ GraphQL::Schema::Directive::ARGUMENT_DEFINITION,
35
+ GraphQL::Schema::Directive::INPUT_FIELD_DEFINITION,
36
+ )
37
+
38
+ argument :by, [String], "Flags to check for this schema member"
39
+
40
+ module VisibleByFlag
41
+ def self.included(schema_class)
42
+ schema_class.extend(self)
43
+ end
44
+
45
+ def visible?(context)
46
+ if dir = self.directives.find { |d| d.is_a?(Flagged) }
47
+ relevant_flags = (f = context[:flags]) && dir.arguments[:by] & f # rubocop:disable Development/ContextIsPassedCop -- definition-related
48
+ relevant_flags && relevant_flags.any? && super
49
+ else
50
+ super
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -11,7 +11,7 @@ module GraphQL
11
11
  GraphQL::Schema::Directive::INLINE_FRAGMENT
12
12
  )
13
13
 
14
- argument :if, Boolean, required: true,
14
+ argument :if, Boolean,
15
15
  description: "Included when true."
16
16
 
17
17
  default_directive true
@@ -11,7 +11,7 @@ module GraphQL
11
11
  GraphQL::Schema::Directive::INLINE_FRAGMENT
12
12
  )
13
13
 
14
- argument :if, Boolean, required: true,
14
+ argument :if, Boolean,
15
15
  description: "Skipped when true."
16
16
 
17
17
  default_directive true
@@ -24,7 +24,7 @@ module GraphQL
24
24
  GraphQL::Schema::Directive::FIELD,
25
25
  )
26
26
 
27
- argument :by, String, required: true,
27
+ argument :by, String,
28
28
  description: "The name of the transform to run if applicable"
29
29
 
30
30
  TRANSFORMS = [
@@ -39,7 +39,19 @@ module GraphQL
39
39
  transform_name = arguments[:by]
40
40
  if TRANSFORMS.include?(transform_name) && return_value.respond_to?(transform_name)
41
41
  return_value = return_value.public_send(transform_name)
42
- context.namespace(:interpreter)[:runtime].write_in_response(path, return_value)
42
+ response = context.namespace(:interpreter)[:runtime].final_result
43
+ *keys, last = path
44
+ keys.each do |key|
45
+ if response && (response = response[key])
46
+ next
47
+ else
48
+ break
49
+ end
50
+ end
51
+ if response
52
+ response[last] = return_value
53
+ end
54
+ nil
43
55
  end
44
56
  end
45
57
  end
@@ -8,12 +8,21 @@ module GraphQL
8
8
  # - {.resolve}: Wraps field resolution (so it should call `yield` to continue)
9
9
  class Directive < GraphQL::Schema::Member
10
10
  extend GraphQL::Schema::Member::HasArguments
11
+ extend GraphQL::Schema::Member::AcceptsDefinition
12
+
11
13
  class << self
14
+ # Directives aren't types, they don't have kinds.
15
+ undef_method :kind
16
+
17
+ def path
18
+ "@#{super}"
19
+ end
20
+
12
21
  # Return a name based on the class name,
13
22
  # but downcase the first letter.
14
23
  def default_graphql_name
15
24
  @default_graphql_name ||= begin
16
- camelized_name = super
25
+ camelized_name = super.dup
17
26
  camelized_name[0] = camelized_name[0].downcase
18
27
  camelized_name
19
28
  end
@@ -21,6 +30,11 @@ module GraphQL
21
30
 
22
31
  def locations(*new_locations)
23
32
  if new_locations.any?
33
+ new_locations.each do |new_loc|
34
+ if !LOCATIONS.include?(new_loc.to_sym)
35
+ raise ArgumentError, "#{self} (#{self.graphql_name}) has an invalid directive location: `locations #{new_loc}` "
36
+ end
37
+ end
24
38
  @locations = new_locations
25
39
  else
26
40
  @locations ||= (superclass.respond_to?(:locations) ? superclass.locations : [])
@@ -41,6 +55,8 @@ module GraphQL
41
55
  default_directive
42
56
  end
43
57
 
58
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
59
+
44
60
  def to_graphql
45
61
  defn = GraphQL::Directive.new
46
62
  defn.name = self.graphql_name
@@ -49,9 +65,9 @@ module GraphQL
49
65
  defn.default_directive = self.default_directive
50
66
  defn.ast_node = ast_node
51
67
  defn.metadata[:type_class] = self
52
- arguments.each do |name, arg_defn|
53
- arg_graphql = arg_defn.to_graphql
54
- defn.arguments[arg_graphql.name] = arg_graphql
68
+ all_argument_definitions.each do |arg_defn|
69
+ arg_graphql = arg_defn.to_graphql(silence_deprecation_warning: true)
70
+ defn.arguments[arg_graphql.name] = arg_graphql # rubocop:disable Development/ContextIsPassedCop -- legacy-related
55
71
  end
56
72
  # Make a reference to a classic-style Arguments class
57
73
  defn.arguments_class = GraphQL::Query::Arguments.construct_arguments_class(defn)
@@ -74,6 +90,11 @@ module GraphQL
74
90
  yield
75
91
  end
76
92
 
93
+ # Continuing is passed as a block, yield to continue.
94
+ def resolve_each(object, arguments, context)
95
+ yield
96
+ end
97
+
77
98
  def on_field?
78
99
  locations.include?(FIELD)
79
100
  end
@@ -85,6 +106,35 @@ module GraphQL
85
106
  def on_operation?
86
107
  locations.include?(QUERY) && locations.include?(MUTATION) && locations.include?(SUBSCRIPTION)
87
108
  end
109
+
110
+ def repeatable?
111
+ !!@repeatable
112
+ end
113
+
114
+ def repeatable(new_value)
115
+ @repeatable = new_value
116
+ end
117
+ end
118
+
119
+ # @return [GraphQL::Schema::Field, GraphQL::Schema::Argument, Class, Module]
120
+ attr_reader :owner
121
+
122
+ # @return [GraphQL::Interpreter::Arguments]
123
+ attr_reader :arguments
124
+
125
+ def initialize(owner, **arguments)
126
+ @owner = owner
127
+ assert_valid_owner
128
+ # It's be nice if we had the real context here, but we don't. What we _would_ get is:
129
+ # - error handling
130
+ # - lazy resolution
131
+ # Probably, those won't be needed here, since these are configuration arguments,
132
+ # not runtime arguments.
133
+ @arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext)
134
+ end
135
+
136
+ def graphql_name
137
+ self.class.graphql_name
88
138
  end
89
139
 
90
140
  LOCATIONS = [
@@ -106,6 +156,7 @@ module GraphQL
106
156
  ENUM_VALUE = :ENUM_VALUE,
107
157
  INPUT_OBJECT = :INPUT_OBJECT,
108
158
  INPUT_FIELD_DEFINITION = :INPUT_FIELD_DEFINITION,
159
+ VARIABLE_DEFINITION = :VARIABLE_DEFINITION,
109
160
  ]
110
161
 
111
162
  DEFAULT_DEPRECATION_REASON = 'No longer supported'
@@ -128,7 +179,55 @@ module GraphQL
128
179
  ENUM_VALUE: 'Location adjacent to an enum value definition.',
129
180
  INPUT_OBJECT: 'Location adjacent to an input object type definition.',
130
181
  INPUT_FIELD_DEFINITION: 'Location adjacent to an input object field definition.',
182
+ VARIABLE_DEFINITION: 'Location adjacent to a variable definition.',
131
183
  }
184
+
185
+ private
186
+
187
+ def assert_valid_owner
188
+ case @owner
189
+ when Class
190
+ if @owner < GraphQL::Schema::Object
191
+ assert_has_location(OBJECT)
192
+ elsif @owner < GraphQL::Schema::Union
193
+ assert_has_location(UNION)
194
+ elsif @owner < GraphQL::Schema::Enum
195
+ assert_has_location(ENUM)
196
+ elsif @owner < GraphQL::Schema::InputObject
197
+ assert_has_location(INPUT_OBJECT)
198
+ elsif @owner < GraphQL::Schema::Scalar
199
+ assert_has_location(SCALAR)
200
+ elsif @owner < GraphQL::Schema
201
+ assert_has_location(SCHEMA)
202
+ else
203
+ raise "Unexpected directive owner class: #{@owner}"
204
+ end
205
+ when Module
206
+ assert_has_location(INTERFACE)
207
+ when GraphQL::Schema::Argument
208
+ if @owner.owner.is_a?(GraphQL::Schema::Field)
209
+ assert_has_location(ARGUMENT_DEFINITION)
210
+ else
211
+ assert_has_location(INPUT_FIELD_DEFINITION)
212
+ end
213
+ when GraphQL::Schema::Field
214
+ assert_has_location(FIELD_DEFINITION)
215
+ when GraphQL::Schema::EnumValue
216
+ assert_has_location(ENUM_VALUE)
217
+ else
218
+ raise "Unexpected directive owner: #{@owner.inspect}"
219
+ end
220
+ end
221
+
222
+ def assert_has_location(location)
223
+ if !self.class.locations.include?(location)
224
+ raise ArgumentError, <<-MD
225
+ Directive `@#{self.class.graphql_name}` can't be attached to #{@owner.graphql_name} because #{location} isn't included in its locations (#{self.class.locations.join(", ")}).
226
+
227
+ Use `locations(#{location})` to update this directive's definition, or remove it from #{@owner.graphql_name}.
228
+ MD
229
+ end
230
+ end
132
231
  end
133
232
  end
134
233
  end