graphql 1.10.1 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
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