graphql 1.10.1 → 1.13.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 (292) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +18 -2
  3. data/lib/generators/graphql/install_generator.rb +36 -6
  4. data/lib/generators/graphql/loader_generator.rb +1 -0
  5. data/lib/generators/graphql/mutation_generator.rb +2 -1
  6. data/lib/generators/graphql/object_generator.rb +54 -9
  7. data/lib/generators/graphql/relay.rb +63 -0
  8. data/lib/generators/graphql/relay_generator.rb +21 -0
  9. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  10. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  11. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  12. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  13. data/lib/generators/graphql/templates/base_field.erb +2 -0
  14. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  15. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  16. data/lib/generators/graphql/templates/base_mutation.erb +2 -0
  17. data/lib/generators/graphql/templates/base_object.erb +2 -0
  18. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  19. data/lib/generators/graphql/templates/base_union.erb +2 -0
  20. data/lib/generators/graphql/templates/enum.erb +2 -0
  21. data/lib/generators/graphql/templates/graphql_controller.erb +16 -12
  22. data/lib/generators/graphql/templates/interface.erb +2 -0
  23. data/lib/generators/graphql/templates/loader.erb +2 -0
  24. data/lib/generators/graphql/templates/mutation.erb +2 -0
  25. data/lib/generators/graphql/templates/mutation_type.erb +2 -0
  26. data/lib/generators/graphql/templates/node_type.erb +9 -0
  27. data/lib/generators/graphql/templates/object.erb +3 -1
  28. data/lib/generators/graphql/templates/query_type.erb +3 -3
  29. data/lib/generators/graphql/templates/scalar.erb +2 -0
  30. data/lib/generators/graphql/templates/schema.erb +21 -33
  31. data/lib/generators/graphql/templates/union.erb +3 -1
  32. data/lib/generators/graphql/type_generator.rb +1 -1
  33. data/lib/graphql/analysis/analyze_query.rb +7 -0
  34. data/lib/graphql/analysis/ast/field_usage.rb +24 -1
  35. data/lib/graphql/analysis/ast/query_complexity.rb +126 -109
  36. data/lib/graphql/analysis/ast/visitor.rb +13 -5
  37. data/lib/graphql/analysis/ast.rb +11 -2
  38. data/lib/graphql/argument.rb +3 -3
  39. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  40. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  41. data/lib/graphql/backtrace/table.rb +34 -3
  42. data/lib/graphql/backtrace/traced_error.rb +0 -1
  43. data/lib/graphql/backtrace/tracer.rb +40 -9
  44. data/lib/graphql/backtrace.rb +28 -19
  45. data/lib/graphql/backwards_compatibility.rb +2 -1
  46. data/lib/graphql/base_type.rb +1 -1
  47. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  48. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  49. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  50. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  51. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  52. data/lib/graphql/dataloader/null_dataloader.rb +22 -0
  53. data/lib/graphql/dataloader/request.rb +19 -0
  54. data/lib/graphql/dataloader/request_all.rb +19 -0
  55. data/lib/graphql/dataloader/source.rb +155 -0
  56. data/lib/graphql/dataloader.rb +308 -0
  57. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  58. data/lib/graphql/define/defined_object_proxy.rb +1 -1
  59. data/lib/graphql/define/instance_definable.rb +34 -4
  60. data/lib/graphql/define/type_definer.rb +5 -5
  61. data/lib/graphql/deprecated_dsl.rb +18 -5
  62. data/lib/graphql/deprecation.rb +9 -0
  63. data/lib/graphql/directive.rb +4 -4
  64. data/lib/graphql/enum_type.rb +7 -1
  65. data/lib/graphql/execution/errors.rb +110 -7
  66. data/lib/graphql/execution/execute.rb +8 -1
  67. data/lib/graphql/execution/instrumentation.rb +1 -1
  68. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  69. data/lib/graphql/execution/interpreter/arguments.rb +88 -0
  70. data/lib/graphql/execution/interpreter/arguments_cache.rb +103 -0
  71. data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
  72. data/lib/graphql/execution/interpreter/resolve.rb +37 -25
  73. data/lib/graphql/execution/interpreter/runtime.rb +685 -421
  74. data/lib/graphql/execution/interpreter.rb +42 -13
  75. data/lib/graphql/execution/lazy.rb +5 -1
  76. data/lib/graphql/execution/lookahead.rb +25 -110
  77. data/lib/graphql/execution/multiplex.rb +37 -25
  78. data/lib/graphql/field.rb +5 -1
  79. data/lib/graphql/function.rb +4 -0
  80. data/lib/graphql/input_object_type.rb +6 -0
  81. data/lib/graphql/integer_decoding_error.rb +17 -0
  82. data/lib/graphql/integer_encoding_error.rb +18 -2
  83. data/lib/graphql/interface_type.rb +7 -0
  84. data/lib/graphql/internal_representation/document.rb +2 -2
  85. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  86. data/lib/graphql/internal_representation/scope.rb +2 -2
  87. data/lib/graphql/internal_representation/visit.rb +2 -2
  88. data/lib/graphql/introspection/directive_type.rb +8 -4
  89. data/lib/graphql/introspection/entry_points.rb +2 -2
  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 +15 -3
  93. data/lib/graphql/introspection/introspection_query.rb +6 -92
  94. data/lib/graphql/introspection/schema_type.rb +4 -4
  95. data/lib/graphql/introspection/type_type.rb +16 -12
  96. data/lib/graphql/introspection.rb +96 -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/document_from_schema_definition.rb +73 -25
  101. data/lib/graphql/language/lexer.rb +4 -3
  102. data/lib/graphql/language/lexer.rl +3 -3
  103. data/lib/graphql/language/nodes.rb +51 -89
  104. data/lib/graphql/language/parser.rb +552 -530
  105. data/lib/graphql/language/parser.y +114 -99
  106. data/lib/graphql/language/printer.rb +7 -2
  107. data/lib/graphql/language/sanitized_printer.rb +222 -0
  108. data/lib/graphql/language/token.rb +0 -4
  109. data/lib/graphql/language/visitor.rb +2 -2
  110. data/lib/graphql/language.rb +2 -0
  111. data/lib/graphql/name_validator.rb +2 -7
  112. data/lib/graphql/object_type.rb +44 -35
  113. data/lib/graphql/pagination/active_record_relation_connection.rb +14 -1
  114. data/lib/graphql/pagination/array_connection.rb +2 -2
  115. data/lib/graphql/pagination/connection.rb +75 -20
  116. data/lib/graphql/pagination/connections.rb +83 -31
  117. data/lib/graphql/pagination/relation_connection.rb +34 -14
  118. data/lib/graphql/parse_error.rb +0 -1
  119. data/lib/graphql/query/arguments.rb +4 -3
  120. data/lib/graphql/query/arguments_cache.rb +1 -2
  121. data/lib/graphql/query/context.rb +42 -7
  122. data/lib/graphql/query/executor.rb +0 -1
  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 +1 -1
  126. data/lib/graphql/query/null_context.rb +24 -8
  127. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  128. data/lib/graphql/query/serial_execution.rb +1 -0
  129. data/lib/graphql/query/validation_pipeline.rb +5 -2
  130. data/lib/graphql/query/variable_validation_error.rb +1 -1
  131. data/lib/graphql/query/variables.rb +14 -4
  132. data/lib/graphql/query.rb +68 -13
  133. data/lib/graphql/railtie.rb +9 -1
  134. data/lib/graphql/rake_task.rb +12 -9
  135. data/lib/graphql/relay/array_connection.rb +10 -12
  136. data/lib/graphql/relay/base_connection.rb +26 -13
  137. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  138. data/lib/graphql/relay/connection_type.rb +1 -1
  139. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  140. data/lib/graphql/relay/mutation.rb +1 -0
  141. data/lib/graphql/relay/node.rb +3 -0
  142. data/lib/graphql/relay/range_add.rb +23 -9
  143. data/lib/graphql/relay/relation_connection.rb +8 -10
  144. data/lib/graphql/relay/type_extensions.rb +2 -0
  145. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  146. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  147. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  148. data/lib/graphql/rubocop.rb +4 -0
  149. data/lib/graphql/scalar_type.rb +16 -1
  150. data/lib/graphql/schema/addition.rb +247 -0
  151. data/lib/graphql/schema/argument.rb +210 -12
  152. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  153. data/lib/graphql/schema/build_from_definition/resolve_map.rb +3 -1
  154. data/lib/graphql/schema/build_from_definition.rb +213 -86
  155. data/lib/graphql/schema/default_type_error.rb +2 -0
  156. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  157. data/lib/graphql/schema/directive/feature.rb +1 -1
  158. data/lib/graphql/schema/directive/flagged.rb +57 -0
  159. data/lib/graphql/schema/directive/include.rb +1 -1
  160. data/lib/graphql/schema/directive/skip.rb +1 -1
  161. data/lib/graphql/schema/directive/transform.rb +14 -2
  162. data/lib/graphql/schema/directive.rb +78 -2
  163. data/lib/graphql/schema/enum.rb +80 -9
  164. data/lib/graphql/schema/enum_value.rb +17 -6
  165. data/lib/graphql/schema/field/connection_extension.rb +46 -30
  166. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  167. data/lib/graphql/schema/field.rb +285 -133
  168. data/lib/graphql/schema/find_inherited_value.rb +4 -1
  169. data/lib/graphql/schema/finder.rb +5 -5
  170. data/lib/graphql/schema/input_object.rb +97 -89
  171. data/lib/graphql/schema/interface.rb +24 -19
  172. data/lib/graphql/schema/late_bound_type.rb +2 -2
  173. data/lib/graphql/schema/list.rb +7 -1
  174. data/lib/graphql/schema/loader.rb +137 -103
  175. data/lib/graphql/schema/member/accepts_definition.rb +8 -1
  176. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -19
  177. data/lib/graphql/schema/member/build_type.rb +14 -7
  178. data/lib/graphql/schema/member/has_arguments.rb +205 -12
  179. data/lib/graphql/schema/member/has_ast_node.rb +4 -1
  180. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  181. data/lib/graphql/schema/member/has_directives.rb +98 -0
  182. data/lib/graphql/schema/member/has_fields.rb +95 -30
  183. data/lib/graphql/schema/member/has_interfaces.rb +90 -0
  184. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  185. data/lib/graphql/schema/member/has_validators.rb +31 -0
  186. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  187. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  188. data/lib/graphql/schema/member.rb +6 -0
  189. data/lib/graphql/schema/middleware_chain.rb +1 -1
  190. data/lib/graphql/schema/mutation.rb +4 -0
  191. data/lib/graphql/schema/non_null.rb +5 -0
  192. data/lib/graphql/schema/object.rb +47 -46
  193. data/lib/graphql/schema/possible_types.rb +9 -4
  194. data/lib/graphql/schema/printer.rb +16 -34
  195. data/lib/graphql/schema/relay_classic_mutation.rb +32 -4
  196. data/lib/graphql/schema/resolver/has_payload_type.rb +34 -4
  197. data/lib/graphql/schema/resolver.rb +123 -63
  198. data/lib/graphql/schema/scalar.rb +11 -1
  199. data/lib/graphql/schema/subscription.rb +57 -21
  200. data/lib/graphql/schema/timeout.rb +29 -15
  201. data/lib/graphql/schema/timeout_middleware.rb +3 -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 +41 -1
  205. data/lib/graphql/schema/unique_within_type.rb +1 -2
  206. data/lib/graphql/schema/validation.rb +12 -2
  207. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  208. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  209. data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
  210. data/lib/graphql/schema/validator/format_validator.rb +48 -0
  211. data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
  212. data/lib/graphql/schema/validator/length_validator.rb +59 -0
  213. data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
  214. data/lib/graphql/schema/validator/required_validator.rb +68 -0
  215. data/lib/graphql/schema/validator.rb +174 -0
  216. data/lib/graphql/schema/warden.rb +153 -28
  217. data/lib/graphql/schema.rb +364 -330
  218. data/lib/graphql/static_validation/all_rules.rb +1 -0
  219. data/lib/graphql/static_validation/base_visitor.rb +8 -5
  220. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  221. data/lib/graphql/static_validation/error.rb +3 -1
  222. data/lib/graphql/static_validation/literal_validator.rb +51 -26
  223. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +44 -87
  224. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +22 -6
  225. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +28 -22
  226. data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +4 -2
  227. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  228. data/lib/graphql/static_validation/rules/fields_will_merge.rb +79 -43
  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/required_arguments_are_present.rb +1 -1
  234. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +6 -7
  235. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +9 -10
  236. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +8 -8
  237. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +4 -2
  238. data/lib/graphql/static_validation/validation_context.rb +9 -3
  239. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  240. data/lib/graphql/static_validation/validator.rb +42 -8
  241. data/lib/graphql/static_validation.rb +1 -0
  242. data/lib/graphql/string_encoding_error.rb +13 -3
  243. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +118 -19
  244. data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
  245. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  246. data/lib/graphql/subscriptions/event.rb +81 -30
  247. data/lib/graphql/subscriptions/instrumentation.rb +0 -1
  248. data/lib/graphql/subscriptions/serialize.rb +33 -6
  249. data/lib/graphql/subscriptions/subscription_root.rb +15 -4
  250. data/lib/graphql/subscriptions.rb +88 -45
  251. data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
  252. data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
  253. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  254. data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
  255. data/lib/graphql/tracing/platform_tracing.rb +43 -17
  256. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  257. data/lib/graphql/tracing/scout_tracing.rb +11 -0
  258. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  259. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  260. data/lib/graphql/tracing.rb +9 -33
  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 +3 -3
  264. data/lib/graphql/types/iso_8601_date_time.rb +25 -10
  265. data/lib/graphql/types/relay/base_connection.rb +6 -90
  266. data/lib/graphql/types/relay/base_edge.rb +2 -34
  267. data/lib/graphql/types/relay/connection_behaviors.rb +156 -0
  268. data/lib/graphql/types/relay/default_relay.rb +27 -0
  269. data/lib/graphql/types/relay/edge_behaviors.rb +53 -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 +2 -20
  275. data/lib/graphql/types/relay/nodes_field.rb +2 -20
  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 +2 -2
  281. data/lib/graphql/union_type.rb +2 -0
  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 +65 -31
  286. data/readme.md +3 -6
  287. metadata +77 -112
  288. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
  289. data/lib/graphql/literal_validation_error.rb +0 -6
  290. data/lib/graphql/types/relay/base_field.rb +0 -22
  291. data/lib/graphql/types/relay/base_interface.rb +0 -29
  292. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -5,23 +5,17 @@ module GraphQL
5
5
  class Schema
6
6
  module BuildFromDefinition
7
7
  class << self
8
- def from_definition(definition_string, default_resolve:, using: {}, interpreter: true, parser: DefaultParser)
9
- document = parser.parse(definition_string)
10
- Builder.build(document, default_resolve: default_resolve, using: using, interpreter: interpreter)
8
+ # @see {Schema.from_definition}
9
+ def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
10
+ from_document(parser.parse(definition_string), **kwargs)
11
11
  end
12
- end
13
12
 
14
- # @api private
15
- DefaultParser = GraphQL::Language::Parser
13
+ def from_definition_path(definition_path, parser: GraphQL.default_parser, **kwargs)
14
+ from_document(parser.parse_file(definition_path), **kwargs)
15
+ end
16
16
 
17
- # @api private
18
- module DefaultResolve
19
- def self.call(type, field, obj, args, ctx)
20
- if field.arguments.any?
21
- obj.public_send(field.name, args, ctx)
22
- else
23
- obj.public_send(field.name)
24
- end
17
+ def from_document(document, default_resolve:, using: {}, relay: false)
18
+ Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using)
25
19
  end
26
20
  end
27
21
 
@@ -29,7 +23,7 @@ module GraphQL
29
23
  module Builder
30
24
  extend self
31
25
 
32
- def build(document, default_resolve: DefaultResolve, using: {}, interpreter: true)
26
+ def build(document, default_resolve:, using: {}, relay:)
33
27
  raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
34
28
 
35
29
  if default_resolve.is_a?(Hash)
@@ -42,34 +36,50 @@ module GraphQL
42
36
  end
43
37
  schema_definition = schema_defns.first
44
38
  types = {}
45
- types.merge!(GraphQL::Schema::BUILT_IN_TYPES)
46
39
  directives = {}
47
- 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
+ })
57
+
58
+ document.definitions.each do |definition|
59
+ if definition.is_a?(GraphQL::Language::Nodes::DirectiveDefinition)
60
+ directives[definition.name] = build_directive(definition, directive_type_resolver)
61
+ end
62
+ end
63
+
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)
48
68
 
49
69
  document.definitions.each do |definition|
50
70
  case definition
51
- when GraphQL::Language::Nodes::SchemaDefinition
71
+ when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
52
72
  nil # already handled
53
- when GraphQL::Language::Nodes::EnumTypeDefinition
54
- types[definition.name] = build_enum_type(definition, type_resolver)
55
- when GraphQL::Language::Nodes::ObjectTypeDefinition
56
- is_subscription_root = (definition.name == "Subscription" && (schema_definition.nil? || schema_definition.subscription.nil?)) || (schema_definition && (definition.name == schema_definition.subscription))
57
- should_extend_subscription_root = is_subscription_root && interpreter
58
- types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve, extend_subscription_root: should_extend_subscription_root)
59
- when GraphQL::Language::Nodes::InterfaceTypeDefinition
60
- types[definition.name] = build_interface_type(definition, type_resolver)
61
- when GraphQL::Language::Nodes::UnionTypeDefinition
62
- types[definition.name] = build_union_type(definition, type_resolver)
63
- when GraphQL::Language::Nodes::ScalarTypeDefinition
64
- types[definition.name] = build_scalar_type(definition, type_resolver, default_resolve: default_resolve)
65
- when GraphQL::Language::Nodes::InputObjectTypeDefinition
66
- types[definition.name] = build_input_object_type(definition, type_resolver)
67
- when GraphQL::Language::Nodes::DirectiveDefinition
68
- directives[definition.name] = build_directive(definition, type_resolver)
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
69
79
  end
70
80
  end
71
81
 
72
- directives = GraphQL::Schema.default_directives.merge(directives)
82
+ replace_late_bound_types_with_built_in(types)
73
83
 
74
84
  if schema_definition
75
85
  if schema_definition.query
@@ -108,11 +118,11 @@ module GraphQL
108
118
  end
109
119
 
110
120
  if default_resolve.respond_to?(:resolve_type)
111
- define_singleton_method(:resolve_type) do |*args|
112
- default_resolve.resolve_type(*args)
121
+ def self.resolve_type(*args)
122
+ self.definition_default_resolve.resolve_type(*args)
113
123
  end
114
124
  else
115
- define_singleton_method(:resolve_type) do |*args|
125
+ def self.resolve_type(*args)
116
126
  NullResolveType.call(*args)
117
127
  end
118
128
  end
@@ -123,11 +133,6 @@ module GraphQL
123
133
  ast_node(schema_definition)
124
134
  end
125
135
 
126
- if interpreter
127
- use GraphQL::Execution::Interpreter
128
- use GraphQL::Analysis::AST
129
- end
130
-
131
136
  using.each do |plugin, options|
132
137
  if options
133
138
  use(plugin, **options)
@@ -135,6 +140,23 @@ module GraphQL
135
140
  use(plugin)
136
141
  end
137
142
  end
143
+
144
+ # Empty `orphan_types` -- this will make unreachable types ... unreachable.
145
+ own_orphan_types.clear
146
+
147
+ class << self
148
+ attr_accessor :definition_default_resolve
149
+ end
150
+
151
+ self.definition_default_resolve = default_resolve
152
+
153
+ def definition_default_resolve
154
+ self.class.definition_default_resolve
155
+ end
156
+
157
+ def self.inherited(child_class)
158
+ child_class.definition_default_resolve = self.definition_default_resolve
159
+ end
138
160
  end
139
161
  end
140
162
 
@@ -142,10 +164,85 @@ module GraphQL
142
164
  raise(GraphQL::RequiredImplementationMissingError, "Generated Schema cannot use Interface or Union types for execution. Implement resolve_type on your resolver.")
143
165
  }
144
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
+
145
241
  def build_enum_type(enum_type_definition, type_resolver)
146
242
  builder = self
147
243
  Class.new(GraphQL::Schema::Enum) do
148
244
  graphql_name(enum_type_definition.name)
245
+ builder.build_directives(self, enum_type_definition, type_resolver)
149
246
  description(enum_type_definition.description)
150
247
  ast_node(enum_type_definition)
151
248
  enum_type_definition.values.each do |enum_value_definition|
@@ -153,6 +250,7 @@ module GraphQL
153
250
  value: enum_value_definition.name,
154
251
  deprecation_reason: builder.build_deprecation_reason(enum_value_definition.directives),
155
252
  description: enum_value_definition.description,
253
+ directives: builder.prepare_directives(enum_value_definition, type_resolver),
156
254
  ast_node: enum_value_definition,
157
255
  )
158
256
  end
@@ -170,53 +268,54 @@ module GraphQL
170
268
  end
171
269
 
172
270
  def build_scalar_type(scalar_type_definition, type_resolver, default_resolve:)
271
+ builder = self
173
272
  Class.new(GraphQL::Schema::Scalar) do
174
273
  graphql_name(scalar_type_definition.name)
175
274
  description(scalar_type_definition.description)
176
275
  ast_node(scalar_type_definition)
276
+ builder.build_directives(self, scalar_type_definition, type_resolver)
177
277
 
178
278
  if default_resolve.respond_to?(:coerce_input)
179
- define_singleton_method(:coerce_input) do |val, ctx|
180
- default_resolve.coerce_input(self, val, ctx)
181
- end
182
-
183
- define_singleton_method(:coerce_result) do |val, ctx|
184
- default_resolve.coerce_result(self, val, ctx)
185
- end
279
+ # Put these method definitions in another method to avoid retaining `type_resolve`
280
+ # from this method's bindiing
281
+ builder.build_scalar_type_coerce_method(self, :coerce_input, default_resolve)
282
+ builder.build_scalar_type_coerce_method(self, :coerce_result, default_resolve)
186
283
  end
187
284
  end
188
285
  end
189
286
 
287
+ def build_scalar_type_coerce_method(scalar_class, method_name, default_definition_resolve)
288
+ scalar_class.define_singleton_method(method_name) do |val, ctx|
289
+ default_definition_resolve.public_send(method_name, self, val, ctx)
290
+ end
291
+ end
292
+
190
293
  def build_union_type(union_type_definition, type_resolver)
294
+ builder = self
191
295
  Class.new(GraphQL::Schema::Union) do
192
296
  graphql_name(union_type_definition.name)
193
297
  description(union_type_definition.description)
194
298
  possible_types(*union_type_definition.types.map { |type_name| type_resolver.call(type_name) })
195
299
  ast_node(union_type_definition)
300
+ builder.build_directives(self, union_type_definition, type_resolver)
196
301
  end
197
302
  end
198
303
 
199
- def build_object_type(object_type_definition, type_resolver, default_resolve:, extend_subscription_root:)
304
+ def build_object_type(object_type_definition, type_resolver)
200
305
  builder = self
201
- type_def = nil
202
- typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
203
306
 
204
307
  Class.new(GraphQL::Schema::Object) do
205
- type_def = self
206
308
  graphql_name(object_type_definition.name)
207
309
  description(object_type_definition.description)
208
310
  ast_node(object_type_definition)
209
- if extend_subscription_root
210
- # This has to come before `field ...` configurations since it modifies them
211
- extend Subscriptions::SubscriptionRoot
212
- end
311
+ builder.build_directives(self, object_type_definition, type_resolver)
213
312
 
214
313
  object_type_definition.interfaces.each do |interface_name|
215
314
  interface_defn = type_resolver.call(interface_name)
216
315
  implements(interface_defn)
217
316
  end
218
317
 
219
- builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: typed_resolve_fn)
318
+ builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
220
319
  end
221
320
  end
222
321
 
@@ -226,6 +325,7 @@ module GraphQL
226
325
  graphql_name(input_object_type_definition.name)
227
326
  description(input_object_type_definition.description)
228
327
  ast_node(input_object_type_definition)
328
+ builder.build_directives(self, input_object_type_definition, type_resolver)
229
329
  builder.build_arguments(self, input_object_type_definition.fields, type_resolver)
230
330
  end
231
331
  end
@@ -245,13 +345,16 @@ module GraphQL
245
345
  end
246
346
  end
247
347
 
348
+ NO_DEFAULT_VALUE = {}.freeze
349
+
248
350
  def build_arguments(type_class, arguments, type_resolver)
249
351
  builder = self
250
352
 
251
353
  arguments.each do |argument_defn|
252
- default_value_kwargs = {}
253
- if !argument_defn.default_value.nil?
254
- default_value_kwargs[:default_value] = builder.build_default_value(argument_defn.default_value)
354
+ default_value_kwargs = if !argument_defn.default_value.nil?
355
+ { default_value: builder.build_default_value(argument_defn.default_value) }
356
+ else
357
+ NO_DEFAULT_VALUE
255
358
  end
256
359
 
257
360
  type_class.argument(
@@ -259,9 +362,11 @@ module GraphQL
259
362
  type: type_resolver.call(argument_defn.type),
260
363
  required: false,
261
364
  description: argument_defn.description,
365
+ deprecation_reason: builder.build_deprecation_reason(argument_defn.directives),
262
366
  ast_node: argument_defn,
263
367
  camelize: false,
264
368
  method_access: false,
369
+ directives: prepare_directives(argument_defn, type_resolver),
265
370
  **default_value_kwargs
266
371
  )
267
372
  end
@@ -284,7 +389,13 @@ module GraphQL
284
389
  include GraphQL::Schema::Interface
285
390
  graphql_name(interface_type_definition.name)
286
391
  description(interface_type_definition.description)
392
+ interface_type_definition.interfaces.each do |interface_name|
393
+ "Implements: #{interface_type_definition} -> #{interface_name}"
394
+ interface_defn = type_resolver.call(interface_name)
395
+ implements(interface_defn)
396
+ end
287
397
  ast_node(interface_type_definition)
398
+ builder.build_directives(self, interface_type_definition, type_resolver)
288
399
 
289
400
  builder.build_fields(self, interface_type_definition.fields, type_resolver, default_resolve: nil)
290
401
  end
@@ -293,45 +404,61 @@ module GraphQL
293
404
  def build_fields(owner, field_definitions, type_resolver, default_resolve:)
294
405
  builder = self
295
406
 
296
- field_definitions.map do |field_definition|
407
+ field_definitions.each do |field_definition|
297
408
  type_name = resolve_type_name(field_definition.type)
298
-
299
- owner.field(
409
+ resolve_method_name = -"resolve_field_#{field_definition.name}"
410
+ schema_field_defn = owner.field(
300
411
  field_definition.name,
301
412
  description: field_definition.description,
302
413
  type: type_resolver.call(field_definition.type),
303
414
  null: true,
304
415
  connection: type_name.end_with?("Connection"),
416
+ connection_extension: nil,
305
417
  deprecation_reason: build_deprecation_reason(field_definition.directives),
306
418
  ast_node: field_definition,
307
419
  method_conflict_warning: false,
308
420
  camelize: false,
309
- ) do
310
- builder.build_arguments(self, field_definition.arguments, type_resolver)
311
-
312
- # Don't do this for interfaces
313
- if default_resolve
314
- # TODO fragile hack. formalize this API?
315
- define_singleton_method :resolve_field_method do |obj, args, ctx|
316
- default_resolve.call(self, obj.object, args, ctx)
421
+ directives: prepare_directives(field_definition, type_resolver),
422
+ resolver_method: resolve_method_name,
423
+ )
424
+
425
+ builder.build_arguments(schema_field_defn, field_definition.arguments, type_resolver)
426
+
427
+ # Don't do this for interfaces
428
+ if default_resolve
429
+ owner.class_eval <<-RUBY, __FILE__, __LINE__
430
+ # frozen_string_literal: true
431
+ def #{resolve_method_name}(**args)
432
+ field_instance = self.class.get_field("#{field_definition.name}")
433
+ context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
317
434
  end
318
- end
435
+ RUBY
319
436
  end
320
437
  end
321
438
  end
322
439
 
323
- def resolve_type(types, ast_node)
324
- case ast_node
325
- when GraphQL::Language::Nodes::TypeName
326
- type_name = ast_node.name
327
- types[type_name] ||= GraphQL::Schema::LateBoundType.new(type_name)
328
- when GraphQL::Language::Nodes::NonNullType
329
- resolve_type(types, ast_node.of_type).to_non_null_type
330
- when GraphQL::Language::Nodes::ListType
331
- resolve_type(types, ast_node.of_type).to_list_type
332
- else
333
- raise "Unexpected ast_node: #{ast_node.inspect}"
334
- end
440
+ def build_resolve_type(lookup_hash, directives, missing_type_handler)
441
+ resolve_type_proc = nil
442
+ resolve_type_proc = ->(ast_node) {
443
+ case ast_node
444
+ when GraphQL::Language::Nodes::TypeName
445
+ type_name = ast_node.name
446
+ if lookup_hash.key?(type_name)
447
+ lookup_hash[type_name]
448
+ else
449
+ missing_type_handler.call(type_name)
450
+ end
451
+ when GraphQL::Language::Nodes::NonNullType
452
+ resolve_type_proc.call(ast_node.of_type).to_non_null_type
453
+ when GraphQL::Language::Nodes::ListType
454
+ resolve_type_proc.call(ast_node.of_type).to_list_type
455
+ when String
456
+ directives[ast_node]
457
+ else
458
+ raise "Unexpected ast_node: #{ast_node.inspect}"
459
+ end
460
+ }
461
+ resolve_type_proc
335
462
  end
336
463
 
337
464
  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
@@ -4,7 +4,7 @@ module GraphQL
4
4
  class Directive < GraphQL::Schema::Member
5
5
  class Deprecated < GraphQL::Schema::Directive
6
6
  description "Marks an element of a GraphQL schema as no longer supported."
7
- locations(GraphQL::Schema::Directive::FIELD_DEFINITION, GraphQL::Schema::Directive::ENUM_VALUE)
7
+ locations(GraphQL::Schema::Directive::FIELD_DEFINITION, GraphQL::Schema::Directive::ENUM_VALUE, GraphQL::Schema::Directive::ARGUMENT_DEFINITION, GraphQL::Schema::Directive::INPUT_FIELD_DEFINITION)
8
8
 
9
9
  reason_description = "Explains why this element was deprecated, usually also including a "\
10
10
  "suggestion for how to access supported similar data. Formatted "\
@@ -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