graphql 1.11.7 → 1.12.4

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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +7 -5
  3. data/lib/generators/graphql/relay.rb +55 -0
  4. data/lib/generators/graphql/relay_generator.rb +20 -0
  5. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  6. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  7. data/lib/generators/graphql/templates/node_type.erb +9 -0
  8. data/lib/generators/graphql/templates/object.erb +1 -1
  9. data/lib/generators/graphql/templates/query_type.erb +1 -3
  10. data/lib/generators/graphql/templates/schema.erb +8 -35
  11. data/lib/graphql.rb +38 -4
  12. data/lib/graphql/analysis/analyze_query.rb +7 -0
  13. data/lib/graphql/analysis/ast.rb +11 -2
  14. data/lib/graphql/analysis/ast/visitor.rb +9 -1
  15. data/lib/graphql/backtrace.rb +28 -19
  16. data/lib/graphql/backtrace/inspect_result.rb +0 -1
  17. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  18. data/lib/graphql/backtrace/table.rb +22 -3
  19. data/lib/graphql/backtrace/traced_error.rb +0 -1
  20. data/lib/graphql/backtrace/tracer.rb +37 -10
  21. data/lib/graphql/backwards_compatibility.rb +2 -1
  22. data/lib/graphql/base_type.rb +1 -1
  23. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  24. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  25. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  26. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  27. data/lib/graphql/dataloader.rb +208 -0
  28. data/lib/graphql/dataloader/null_dataloader.rb +21 -0
  29. data/lib/graphql/dataloader/request.rb +19 -0
  30. data/lib/graphql/dataloader/request_all.rb +19 -0
  31. data/lib/graphql/dataloader/source.rb +107 -0
  32. data/lib/graphql/define/assign_global_id_field.rb +1 -1
  33. data/lib/graphql/define/instance_definable.rb +32 -2
  34. data/lib/graphql/define/type_definer.rb +5 -5
  35. data/lib/graphql/deprecated_dsl.rb +7 -2
  36. data/lib/graphql/deprecation.rb +13 -0
  37. data/lib/graphql/enum_type.rb +2 -0
  38. data/lib/graphql/execution/errors.rb +4 -0
  39. data/lib/graphql/execution/execute.rb +7 -0
  40. data/lib/graphql/execution/interpreter.rb +11 -7
  41. data/lib/graphql/execution/interpreter/arguments.rb +51 -14
  42. data/lib/graphql/execution/interpreter/arguments_cache.rb +37 -14
  43. data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
  44. data/lib/graphql/execution/interpreter/resolve.rb +33 -25
  45. data/lib/graphql/execution/interpreter/runtime.rb +173 -123
  46. data/lib/graphql/execution/multiplex.rb +36 -23
  47. data/lib/graphql/function.rb +4 -0
  48. data/lib/graphql/input_object_type.rb +2 -0
  49. data/lib/graphql/interface_type.rb +3 -1
  50. data/lib/graphql/internal_representation/document.rb +2 -2
  51. data/lib/graphql/internal_representation/rewrite.rb +1 -1
  52. data/lib/graphql/language/document_from_schema_definition.rb +50 -23
  53. data/lib/graphql/object_type.rb +2 -2
  54. data/lib/graphql/pagination/connection.rb +5 -1
  55. data/lib/graphql/pagination/connections.rb +6 -16
  56. data/lib/graphql/parse_error.rb +0 -1
  57. data/lib/graphql/query.rb +10 -2
  58. data/lib/graphql/query/arguments.rb +1 -1
  59. data/lib/graphql/query/arguments_cache.rb +0 -1
  60. data/lib/graphql/query/context.rb +4 -2
  61. data/lib/graphql/query/executor.rb +0 -1
  62. data/lib/graphql/query/null_context.rb +3 -2
  63. data/lib/graphql/query/serial_execution.rb +1 -0
  64. data/lib/graphql/query/variable_validation_error.rb +1 -1
  65. data/lib/graphql/relay/base_connection.rb +7 -0
  66. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  67. data/lib/graphql/relay/connection_type.rb +1 -1
  68. data/lib/graphql/relay/mutation.rb +1 -0
  69. data/lib/graphql/relay/node.rb +3 -0
  70. data/lib/graphql/relay/type_extensions.rb +2 -0
  71. data/lib/graphql/scalar_type.rb +2 -0
  72. data/lib/graphql/schema.rb +64 -26
  73. data/lib/graphql/schema/argument.rb +86 -7
  74. data/lib/graphql/schema/build_from_definition.rb +139 -51
  75. data/lib/graphql/schema/directive.rb +76 -0
  76. data/lib/graphql/schema/directive/flagged.rb +57 -0
  77. data/lib/graphql/schema/enum.rb +3 -0
  78. data/lib/graphql/schema/enum_value.rb +12 -6
  79. data/lib/graphql/schema/field.rb +40 -16
  80. data/lib/graphql/schema/field/connection_extension.rb +3 -2
  81. data/lib/graphql/schema/find_inherited_value.rb +3 -1
  82. data/lib/graphql/schema/input_object.rb +39 -24
  83. data/lib/graphql/schema/interface.rb +1 -0
  84. data/lib/graphql/schema/member.rb +4 -0
  85. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -0
  86. data/lib/graphql/schema/member/build_type.rb +3 -3
  87. data/lib/graphql/schema/member/has_arguments.rb +54 -49
  88. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  89. data/lib/graphql/schema/member/has_directives.rb +98 -0
  90. data/lib/graphql/schema/member/has_fields.rb +1 -4
  91. data/lib/graphql/schema/member/has_validators.rb +31 -0
  92. data/lib/graphql/schema/member/instrumentation.rb +0 -1
  93. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  94. data/lib/graphql/schema/middleware_chain.rb +1 -1
  95. data/lib/graphql/schema/object.rb +11 -0
  96. data/lib/graphql/schema/printer.rb +5 -4
  97. data/lib/graphql/schema/resolver.rb +7 -0
  98. data/lib/graphql/schema/resolver/has_payload_type.rb +2 -0
  99. data/lib/graphql/schema/subscription.rb +19 -1
  100. data/lib/graphql/schema/timeout_middleware.rb +3 -1
  101. data/lib/graphql/schema/validation.rb +4 -2
  102. data/lib/graphql/schema/validator.rb +163 -0
  103. data/lib/graphql/schema/validator/exclusion_validator.rb +31 -0
  104. data/lib/graphql/schema/validator/format_validator.rb +49 -0
  105. data/lib/graphql/schema/validator/inclusion_validator.rb +33 -0
  106. data/lib/graphql/schema/validator/length_validator.rb +57 -0
  107. data/lib/graphql/schema/validator/numericality_validator.rb +71 -0
  108. data/lib/graphql/schema/validator/required_validator.rb +68 -0
  109. data/lib/graphql/static_validation/validator.rb +4 -0
  110. data/lib/graphql/subscriptions.rb +17 -20
  111. data/lib/graphql/subscriptions/event.rb +0 -1
  112. data/lib/graphql/subscriptions/instrumentation.rb +0 -1
  113. data/lib/graphql/subscriptions/serialize.rb +0 -1
  114. data/lib/graphql/subscriptions/subscription_root.rb +1 -1
  115. data/lib/graphql/tracing.rb +2 -2
  116. data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
  117. data/lib/graphql/tracing/platform_tracing.rb +3 -1
  118. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  119. data/lib/graphql/types/relay.rb +11 -3
  120. data/lib/graphql/types/relay/base_connection.rb +2 -92
  121. data/lib/graphql/types/relay/base_edge.rb +2 -35
  122. data/lib/graphql/types/relay/connection_behaviors.rb +123 -0
  123. data/lib/graphql/types/relay/default_relay.rb +27 -0
  124. data/lib/graphql/types/relay/edge_behaviors.rb +42 -0
  125. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  126. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  127. data/lib/graphql/types/relay/node.rb +2 -4
  128. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  129. data/lib/graphql/types/relay/node_field.rb +1 -19
  130. data/lib/graphql/types/relay/nodes_field.rb +1 -19
  131. data/lib/graphql/types/relay/page_info.rb +2 -14
  132. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  133. data/lib/graphql/union_type.rb +2 -0
  134. data/lib/graphql/upgrader/member.rb +1 -0
  135. data/lib/graphql/upgrader/schema.rb +1 -0
  136. data/lib/graphql/version.rb +1 -1
  137. metadata +50 -93
  138. data/lib/graphql/types/relay/base_field.rb +0 -22
  139. data/lib/graphql/types/relay/base_interface.rb +0 -29
  140. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -22,7 +22,7 @@ module GraphQL
22
22
  method_names.each do |method_name|
23
23
  # Don't define a helper method if it would override something.
24
24
  if method_defined?(method_name)
25
- warn(
25
+ GraphQL::Deprecation.warn(
26
26
  "Unable to define a helper for argument with name '#{method_name}' "\
27
27
  "as this is a reserved name. Add `method_access: false` to stop this warning."
28
28
  )
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # test_via: ../query.rb
3
2
  module GraphQL
4
3
  class Query
5
4
  module ArgumentsCache
@@ -1,6 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # test_via: ../execution/execute.rb
3
- # test_via: ../execution/lazy.rb
4
2
  module GraphQL
5
3
  class Query
6
4
  # Expose some query-specific info to field resolve functions.
@@ -158,6 +156,10 @@ module GraphQL
158
156
  @scoped_context = {}
159
157
  end
160
158
 
159
+ def dataloader
160
+ @dataloader ||= query.multiplex ? query.multiplex.dataloader : schema.dataloader_class.new
161
+ end
162
+
161
163
  # @api private
162
164
  attr_writer :interpreter
163
165
 
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- # test_via: ../query.rb
3
2
  module GraphQL
4
3
  class Query
5
4
  class Executor
@@ -9,10 +9,11 @@ module GraphQL
9
9
  def visible_type?(t); true; end
10
10
  end
11
11
 
12
- attr_reader :schema, :query, :warden
12
+ attr_reader :schema, :query, :warden, :dataloader
13
13
 
14
14
  def initialize
15
15
  @query = nil
16
+ @dataloader = GraphQL::Dataloader::NullDataloader.new
16
17
  @schema = GraphQL::Schema.new
17
18
  @warden = NullWarden.new(
18
19
  GraphQL::Filter.new,
@@ -36,7 +37,7 @@ module GraphQL
36
37
  @instance = self.new
37
38
  end
38
39
 
39
- def_delegators :instance, :query, :schema, :warden, :interpreter?
40
+ def_delegators :instance, :query, :schema, :warden, :interpreter?, :dataloader
40
41
  end
41
42
  end
42
43
  end
@@ -16,6 +16,7 @@ module GraphQL
16
16
  # @param query_object [GraphQL::Query] the query object for this execution
17
17
  # @return [Hash] a spec-compliant GraphQL result, as a hash
18
18
  def execute(ast_operation, root_type, query_object)
19
+ GraphQL::Deprecation.warn "#{self.class} will be removed in GraphQL-Ruby 2.0, please upgrade to the Interpreter: https://graphql-ruby.org/queries/interpreter.html"
19
20
  operation_resolution.resolve(
20
21
  query_object.irep_selection,
21
22
  root_type,
@@ -23,7 +23,7 @@ module GraphQL
23
23
  # a one level deep merge explicitly. However beyond that only show the
24
24
  # latest value and problems.
25
25
  super.merge({ "extensions" => { "value" => value, "problems" => validation_result.problems }}) do |key, oldValue, newValue|
26
- if oldValue.respond_to? merge
26
+ if oldValue.respond_to?(:merge)
27
27
  oldValue.merge(newValue)
28
28
  else
29
29
  newValue
@@ -59,6 +59,13 @@ module GraphQL
59
59
  # @param parent [Object] The object which this collection belongs to
60
60
  # @param context [GraphQL::Query::Context] The context from the field being resolved
61
61
  def initialize(nodes, arguments, field: nil, max_page_size: nil, parent: nil, context: nil)
62
+ GraphQL::Deprecation.warn "GraphQL::Relay::BaseConnection (used for #{self.class}) will be removed from GraphQL-Ruby 2.0, use GraphQL::Pagination::Connections instead: https://graphql-ruby.org/pagination/overview.html"
63
+
64
+ deprecated_caller = caller(0, 10).find { |c| !c.include?("lib/graphql") }
65
+ if deprecated_caller
66
+ GraphQL::Deprecation.warn " -> called from #{deprecated_caller}"
67
+ end
68
+
62
69
  @context = context
63
70
  @nodes = nodes
64
71
  @arguments = arguments
@@ -10,10 +10,10 @@ module GraphQL
10
10
  def self.default_arguments
11
11
  @default_arguments ||= begin
12
12
  argument_definitions = [
13
- ["first", GraphQL::INT_TYPE, "Returns the first _n_ elements from the list."],
14
- ["after", GraphQL::STRING_TYPE, "Returns the elements in the list that come after the specified cursor."],
15
- ["last", GraphQL::INT_TYPE, "Returns the last _n_ elements from the list."],
16
- ["before", GraphQL::STRING_TYPE, "Returns the elements in the list that come before the specified cursor."],
13
+ ["first", GraphQL::DEPRECATED_INT_TYPE, "Returns the first _n_ elements from the list."],
14
+ ["after", GraphQL::DEPRECATED_STRING_TYPE, "Returns the elements in the list that come after the specified cursor."],
15
+ ["last", GraphQL::DEPRECATED_INT_TYPE, "Returns the last _n_ elements from the list."],
16
+ ["before", GraphQL::DEPRECATED_STRING_TYPE, "Returns the elements in the list that come before the specified cursor."],
17
17
  ]
18
18
 
19
19
  argument_definitions.reduce({}) do |memo, arg_defn|
@@ -20,7 +20,7 @@ module GraphQL
20
20
  # Any call that would trigger `wrapped_type.ensure_defined`
21
21
  # must be inside this lazy block, otherwise we get weird
22
22
  # cyclical dependency errors :S
23
- ObjectType.define do
23
+ ObjectType.deprecated_define do
24
24
  type_name = wrapped_type.is_a?(GraphQL::BaseType) ? wrapped_type.name : wrapped_type.graphql_name
25
25
  edge_type ||= wrapped_type.edge_type
26
26
  name("#{type_name}Connection")
@@ -30,6 +30,7 @@ module GraphQL
30
30
  alias :input_fields :arguments
31
31
 
32
32
  def initialize
33
+ GraphQL::Deprecation.warn "GraphQL::Relay::Mutation will be removed from GraphQL-Ruby 2.0, use GraphQL::Schema::RelayClassicMutation instead: https://graphql-ruby.org/mutations/mutation_classes"
33
34
  @fields = {}
34
35
  @arguments = {}
35
36
  @has_generated_return_type = false
@@ -5,6 +5,7 @@ module GraphQL
5
5
  module Node
6
6
  # @return [GraphQL::Field] a field for finding objects by their global ID.
7
7
  def self.field(**kwargs, &block)
8
+ GraphQL::Deprecation.warn "GraphQL::Relay::Node.field will be removed from GraphQL-Ruby 2.0, use GraphQL::Types::Relay::NodeField instead"
8
9
  # We have to define it fresh each time because
9
10
  # its name will be modified and its description
10
11
  # _may_ be modified.
@@ -18,6 +19,7 @@ module GraphQL
18
19
  end
19
20
 
20
21
  def self.plural_field(**kwargs, &block)
22
+ GraphQL::Deprecation.warn "GraphQL::Relay::Nodes.field will be removed from GraphQL-Ruby 2.0, use GraphQL::Types::Relay::NodesField instead"
21
23
  field = GraphQL::Types::Relay::NodesField.graphql_definition
22
24
 
23
25
  if kwargs.any? || block
@@ -29,6 +31,7 @@ module GraphQL
29
31
 
30
32
  # @return [GraphQL::InterfaceType] The interface which all Relay types must implement
31
33
  def self.interface
34
+ GraphQL::Deprecation.warn "GraphQL::Relay::Node.interface will be removed from GraphQL-Ruby 2.0, use GraphQL::Types::Relay::Node instead"
32
35
  @interface ||= GraphQL::Types::Relay::Node.graphql_definition
33
36
  end
34
37
  end
@@ -12,6 +12,7 @@ module GraphQL
12
12
  # Define a custom connection type for this object type
13
13
  # @return [GraphQL::ObjectType]
14
14
  def define_connection(**kwargs, &block)
15
+ GraphQL::Deprecation.warn ".connection_type and .define_connection will be removed from GraphQL-Ruby 2.0, use class-based type definitions instead: https://graphql-ruby.org/schema/class_based_api.html"
15
16
  GraphQL::Relay::ConnectionType.create_type(self, **kwargs, &block)
16
17
  end
17
18
 
@@ -23,6 +24,7 @@ module GraphQL
23
24
  # Define a custom edge type for this object type
24
25
  # @return [GraphQL::ObjectType]
25
26
  def define_edge(**kwargs, &block)
27
+ GraphQL::Deprecation.warn ".edge_type and .define_edge will be removed from GraphQL-Ruby 2.0, use class-based type definitions instead: https://graphql-ruby.org/schema/class_based_api.html"
26
28
  GraphQL::Relay::EdgeType.create_type(self, **kwargs, &block)
27
29
  end
28
30
  end
@@ -2,6 +2,8 @@
2
2
  module GraphQL
3
3
  # @api deprecated
4
4
  class ScalarType < GraphQL::BaseType
5
+ extend Define::InstanceDefinable::DeprecatedDefine
6
+
5
7
  accepts_definitions :coerce, :coerce_input, :coerce_result
6
8
  ensure_defined :coerce_non_null_input, :coerce_result
7
9
 
@@ -21,6 +21,7 @@ require "graphql/schema/validation"
21
21
  require "graphql/schema/warden"
22
22
  require "graphql/schema/build_from_definition"
23
23
 
24
+ require "graphql/schema/validator"
24
25
  require "graphql/schema/member"
25
26
  require "graphql/schema/wrapper"
26
27
  require "graphql/schema/list"
@@ -40,6 +41,7 @@ require "graphql/schema/directive/deprecated"
40
41
  require "graphql/schema/directive/include"
41
42
  require "graphql/schema/directive/skip"
42
43
  require "graphql/schema/directive/feature"
44
+ require "graphql/schema/directive/flagged"
43
45
  require "graphql/schema/directive/transform"
44
46
  require "graphql/schema/type_membership"
45
47
 
@@ -80,6 +82,7 @@ module GraphQL
80
82
  extend GraphQL::Schema::Member::AcceptsDefinition
81
83
  extend GraphQL::Schema::Member::HasAstNode
82
84
  include GraphQL::Define::InstanceDefinable
85
+ extend GraphQL::Define::InstanceDefinable::DeprecatedDefine
83
86
  extend GraphQL::Schema::FindInheritedValue
84
87
 
85
88
  class DuplicateTypeNamesError < GraphQL::Error
@@ -181,7 +184,7 @@ module GraphQL
181
184
  },
182
185
  query_analyzer: ->(schema, analyzer) {
183
186
  if analyzer == GraphQL::Authorization::Analyzer
184
- warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
187
+ GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
185
188
  end
186
189
  schema.query_analyzers << analyzer
187
190
  },
@@ -281,11 +284,11 @@ module GraphQL
281
284
  @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
282
285
  @lazy_methods.set(GraphQL::Execution::Lazy, :value)
283
286
  @cursor_encoder = Base64Encoder
284
- # Default to the built-in execution strategy:
287
+ # For schema instances, default to legacy runtime modules
285
288
  @analysis_engine = GraphQL::Analysis
286
- @query_execution_strategy = self.class.default_execution_strategy
287
- @mutation_execution_strategy = self.class.default_execution_strategy
288
- @subscription_execution_strategy = self.class.default_execution_strategy
289
+ @query_execution_strategy = GraphQL::Execution::Execute
290
+ @mutation_execution_strategy = GraphQL::Execution::Execute
291
+ @subscription_execution_strategy = GraphQL::Execution::Execute
289
292
  @default_mask = GraphQL::Schema::NullMask
290
293
  @rebuilding_artifacts = false
291
294
  @context_class = GraphQL::Query::Context
@@ -300,12 +303,11 @@ module GraphQL
300
303
 
301
304
  # @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
302
305
  def interpreter?
303
- @interpreter
306
+ query_execution_strategy == GraphQL::Execution::Interpreter &&
307
+ mutation_execution_strategy == GraphQL::Execution::Interpreter &&
308
+ subscription_execution_strategy == GraphQL::Execution::Interpreter
304
309
  end
305
310
 
306
- # @api private
307
- attr_writer :interpreter
308
-
309
311
  def inspect
310
312
  "#<#{self.class.name} ...>"
311
313
  end
@@ -370,7 +372,7 @@ module GraphQL
370
372
  res[:errors]
371
373
  end
372
374
 
373
- def define(**kwargs, &block)
375
+ def deprecated_define(**kwargs, &block)
374
376
  super
375
377
  ensure_defined
376
378
  # Assert that all necessary configs are present:
@@ -709,7 +711,7 @@ module GraphQL
709
711
  alias :_schema_class :class
710
712
  def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
711
713
  def_delegators :_schema_class, :directive
712
- def_delegators :_schema_class, :error_handler
714
+ def_delegators :_schema_class, :error_handler, :rescues
713
715
 
714
716
 
715
717
  # Given this schema member, find the class-based definition object
@@ -787,9 +789,8 @@ module GraphQL
787
789
  # @param default_resolve [<#call(type, field, obj, args, ctx)>] A callable for handling field resolution
788
790
  # @param parser [Object] An object for handling definition string parsing (must respond to `parse`)
789
791
  # @param using [Hash] Plugins to attach to the created schema with `use(key, value)`
790
- # @param interpreter [Boolean] If false, the legacy {Execution::Execute} runtime will be used
791
792
  # @return [Class] the schema described by `document`
792
- def self.from_definition(definition_or_path, default_resolve: nil, interpreter: true, parser: GraphQL.default_parser, using: {})
793
+ def self.from_definition(definition_or_path, default_resolve: nil, parser: GraphQL.default_parser, using: {})
793
794
  # If the file ends in `.graphql`, treat it like a filepath
794
795
  if definition_or_path.end_with?(".graphql")
795
796
  GraphQL::Schema::BuildFromDefinition.from_definition_path(
@@ -797,7 +798,6 @@ module GraphQL
797
798
  default_resolve: default_resolve,
798
799
  parser: parser,
799
800
  using: using,
800
- interpreter: interpreter,
801
801
  )
802
802
  else
803
803
  GraphQL::Schema::BuildFromDefinition.from_definition(
@@ -805,7 +805,6 @@ module GraphQL
805
805
  default_resolve: default_resolve,
806
806
  parser: parser,
807
807
  using: using,
808
- interpreter: interpreter,
809
808
  )
810
809
  end
811
810
  end
@@ -1157,6 +1156,14 @@ module GraphQL
1157
1156
  end
1158
1157
  end
1159
1158
 
1159
+ # @api private
1160
+ # @see GraphQL::Dataloader
1161
+ def dataloader_class
1162
+ @dataloader_class || GraphQL::Dataloader::NullDataloader
1163
+ end
1164
+
1165
+ attr_writer :dataloader_class
1166
+
1160
1167
  def references_to(to_type = nil, from: nil)
1161
1168
  @own_references_to ||= Hash.new { |h, k| h[k] = [] }
1162
1169
  if to_type
@@ -1300,7 +1307,7 @@ module GraphQL
1300
1307
  attr_writer :analysis_engine
1301
1308
 
1302
1309
  def analysis_engine
1303
- @analysis_engine || find_inherited_value(:analysis_engine, GraphQL::Analysis)
1310
+ @analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
1304
1311
  end
1305
1312
 
1306
1313
  def using_ast_analysis?
@@ -1308,11 +1315,9 @@ module GraphQL
1308
1315
  end
1309
1316
 
1310
1317
  def interpreter?
1311
- if defined?(@interpreter)
1312
- @interpreter
1313
- else
1314
- find_inherited_value(:interpreter?, false)
1315
- end
1318
+ query_execution_strategy == GraphQL::Execution::Interpreter &&
1319
+ mutation_execution_strategy == GraphQL::Execution::Interpreter &&
1320
+ subscription_execution_strategy == GraphQL::Execution::Interpreter
1316
1321
  end
1317
1322
 
1318
1323
  attr_writer :interpreter
@@ -1396,7 +1401,15 @@ module GraphQL
1396
1401
  if superclass <= GraphQL::Schema
1397
1402
  superclass.default_execution_strategy
1398
1403
  else
1399
- @default_execution_strategy ||= GraphQL::Execution::Execute
1404
+ @default_execution_strategy ||= GraphQL::Execution::Interpreter
1405
+ end
1406
+ end
1407
+
1408
+ def default_analysis_engine
1409
+ if superclass <= GraphQL::Schema
1410
+ superclass.default_analysis_engine
1411
+ else
1412
+ @default_analysis_engine ||= GraphQL::Analysis::AST
1400
1413
  end
1401
1414
  end
1402
1415
 
@@ -1550,6 +1563,10 @@ module GraphQL
1550
1563
  end
1551
1564
 
1552
1565
  def instrument(instrument_step, instrumenter, options = {})
1566
+ if instrument_step == :field
1567
+ GraphQL::Deprecation.warn "Field instrumentation (#{instrumenter.inspect}) will be removed in GraphQL-Ruby 2.0, please upgrade to field extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
1568
+ end
1569
+
1553
1570
  step = if instrument_step == :field && options[:after_built_ins]
1554
1571
  :field_after_built_ins
1555
1572
  else
@@ -1571,9 +1588,12 @@ module GraphQL
1571
1588
 
1572
1589
  # Attach a single directive to this schema
1573
1590
  # @param new_directive [Class]
1591
+ # @return void
1574
1592
  def directive(new_directive)
1575
- add_type_and_traverse(new_directive, root: false)
1576
- own_directives[new_directive.graphql_name] = new_directive
1593
+ own_directives[new_directive.graphql_name] ||= begin
1594
+ add_type_and_traverse(new_directive, root: false)
1595
+ new_directive
1596
+ end
1577
1597
  end
1578
1598
 
1579
1599
  def default_directives
@@ -1594,7 +1614,7 @@ module GraphQL
1594
1614
 
1595
1615
  def query_analyzer(new_analyzer)
1596
1616
  if new_analyzer == GraphQL::Authorization::Analyzer
1597
- warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
1617
+ GraphQL::Deprecation.warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
1598
1618
  end
1599
1619
  own_query_analyzers << new_analyzer
1600
1620
  end
@@ -1605,6 +1625,7 @@ module GraphQL
1605
1625
 
1606
1626
  def middleware(new_middleware = nil)
1607
1627
  if new_middleware
1628
+ GraphQL::Deprecation.warn "Middleware will be removed in GraphQL-Ruby 2.0, please upgrade to Field Extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
1608
1629
  own_middleware << new_middleware
1609
1630
  else
1610
1631
  # TODO make sure this is cached when running a query
@@ -1681,7 +1702,7 @@ module GraphQL
1681
1702
  if interpreter? && !defined?(@subscription_extension_added) && subscription && self.subscriptions
1682
1703
  @subscription_extension_added = true
1683
1704
  if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
1684
- warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
1705
+ GraphQL::Deprecation.warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
1685
1706
  else
1686
1707
  subscription.fields.each do |name, field|
1687
1708
  field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
@@ -1704,6 +1725,7 @@ module GraphQL
1704
1725
  else
1705
1726
  @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
1706
1727
  @lazy_methods.set(GraphQL::Execution::Lazy, :value)
1728
+ @lazy_methods.set(GraphQL::Dataloader::Request, :load)
1707
1729
  end
1708
1730
  end
1709
1731
  @lazy_methods
@@ -1900,13 +1922,16 @@ module GraphQL
1900
1922
  end
1901
1923
  else
1902
1924
  own_types[type.graphql_name] = type
1925
+ add_directives_from(type)
1903
1926
  if type.kind.fields?
1904
1927
  type.fields.each do |name, field|
1905
1928
  field_type = field.type.unwrap
1906
1929
  references_to(field_type, from: field)
1907
1930
  field_path = path + [name]
1908
1931
  add_type(field_type, owner: field, late_types: late_types, path: field_path)
1932
+ add_directives_from(field)
1909
1933
  field.arguments.each do |arg_name, arg|
1934
+ add_directives_from(arg)
1910
1935
  arg_type = arg.type.unwrap
1911
1936
  references_to(arg_type, from: arg)
1912
1937
  add_type(arg_type, owner: arg, late_types: late_types, path: field_path + [arg_name])
@@ -1915,6 +1940,7 @@ module GraphQL
1915
1940
  end
1916
1941
  if type.kind.input_object?
1917
1942
  type.arguments.each do |arg_name, arg|
1943
+ add_directives_from(arg)
1918
1944
  arg_type = arg.type.unwrap
1919
1945
  references_to(arg_type, from: arg)
1920
1946
  add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg_name])
@@ -1952,8 +1978,20 @@ module GraphQL
1952
1978
  end
1953
1979
  end
1954
1980
  end
1981
+
1982
+ def add_directives_from(owner)
1983
+ owner.directives.each { |dir| directive(dir.class) }
1984
+ end
1955
1985
  end
1956
1986
 
1987
+ def dataloader_class
1988
+ self.class.dataloader_class
1989
+ end
1990
+
1991
+ # Install these here so that subclasses will also install it.
1992
+ use(GraphQL::Execution::Errors)
1993
+ use(GraphQL::Pagination::Connections)
1994
+
1957
1995
  protected
1958
1996
 
1959
1997
  def rescues?
@@ -10,6 +10,10 @@ module GraphQL
10
10
  include GraphQL::Schema::Member::AcceptsDefinition
11
11
  include GraphQL::Schema::Member::HasPath
12
12
  include GraphQL::Schema::Member::HasAstNode
13
+ include GraphQL::Schema::Member::HasDirectives
14
+ include GraphQL::Schema::Member::HasDeprecationReason
15
+ include GraphQL::Schema::Member::HasValidators
16
+ include GraphQL::Schema::FindInheritedValue::EmptyObjects
13
17
 
14
18
  NO_DEFAULT = :__no_default__
15
19
 
@@ -45,8 +49,10 @@ module GraphQL
45
49
  # @param camelize [Boolean] if true, the name will be camelized when building the schema
46
50
  # @param from_resolver [Boolean] if true, a Resolver class defined this argument
47
51
  # @param method_access [Boolean] If false, don't build method access on legacy {Query::Arguments} instances.
52
+ # @param directives [Hash{Class => Hash}]
48
53
  # @param deprecation_reason [String]
49
- def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, deprecation_reason: nil, &definition_block)
54
+ # @param validates [Hash, nil] Options for building validators, if any should be applied
55
+ def initialize(arg_name = nil, type_expr = nil, desc = nil, required:, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NO_DEFAULT, as: nil, from_resolver: false, camelize: true, prepare: nil, method_access: true, owner:, validates: nil, directives: nil, deprecation_reason: nil, &definition_block)
50
56
  arg_name ||= name
51
57
  @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
52
58
  @type_expr = type_expr || type
@@ -63,6 +69,14 @@ module GraphQL
63
69
  @method_access = method_access
64
70
  self.deprecation_reason = deprecation_reason
65
71
 
72
+ if directives
73
+ directives.each do |dir_class, dir_options|
74
+ directive(dir_class, **dir_options)
75
+ end
76
+ end
77
+
78
+ self.validates(validates)
79
+
66
80
  if definition_block
67
81
  if definition_block.arity == 1
68
82
  instance_exec(self, &definition_block)
@@ -94,14 +108,16 @@ module GraphQL
94
108
  # @return [String] Deprecation reason for this argument
95
109
  def deprecation_reason(text = nil)
96
110
  if text
97
- validate_deprecated_or_optional(null: @null, deprecation_reason: text)
98
- @deprecation_reason = text
111
+ self.deprecation_reason = text
99
112
  else
100
- @deprecation_reason
113
+ super()
101
114
  end
102
115
  end
103
116
 
104
- alias_method :deprecation_reason=, :deprecation_reason
117
+ def deprecation_reason=(new_reason)
118
+ validate_deprecated_or_optional(null: @null, deprecation_reason: new_reason)
119
+ super
120
+ end
105
121
 
106
122
  def visible?(context)
107
123
  true
@@ -157,8 +173,8 @@ module GraphQL
157
173
  if NO_DEFAULT != @default_value
158
174
  argument.default_value = @default_value
159
175
  end
160
- if @deprecation_reason
161
- argument.deprecation_reason = @deprecation_reason
176
+ if self.deprecation_reason
177
+ argument.deprecation_reason = self.deprecation_reason
162
178
  end
163
179
  argument
164
180
  end
@@ -199,6 +215,8 @@ module GraphQL
199
215
  value = value.prepare
200
216
  end
201
217
 
218
+ Schema::Validator.validate!(validators, obj, context, value)
219
+
202
220
  if @prepare.nil?
203
221
  value
204
222
  elsif @prepare.is_a?(String) || @prepare.is_a?(Symbol)
@@ -218,6 +236,67 @@ module GraphQL
218
236
  end
219
237
  end
220
238
 
239
+ # @api private
240
+ def coerce_into_values(parent_object, values, context, argument_values)
241
+ arg_name = graphql_name
242
+ arg_key = keyword
243
+ has_value = false
244
+ default_used = false
245
+ if values.key?(arg_name)
246
+ has_value = true
247
+ value = values[arg_name]
248
+ elsif values.key?(arg_key)
249
+ has_value = true
250
+ value = values[arg_key]
251
+ elsif default_value?
252
+ has_value = true
253
+ value = default_value
254
+ default_used = true
255
+ end
256
+
257
+ if has_value
258
+ loaded_value = nil
259
+ coerced_value = context.schema.error_handler.with_error_handling(context) do
260
+ type.coerce_input(value, context)
261
+ end
262
+
263
+ # TODO this should probably be inside after_lazy
264
+ if loads && !from_resolver?
265
+ loaded_value = if type.list?
266
+ loaded_values = coerced_value.map { |val| owner.load_application_object(self, loads, val, context) }
267
+ context.schema.after_any_lazies(loaded_values) { |result| result }
268
+ else
269
+ owner.load_application_object(self, loads, coerced_value, context)
270
+ end
271
+ end
272
+
273
+ coerced_value = if loaded_value
274
+ loaded_value
275
+ else
276
+ coerced_value
277
+ end
278
+
279
+ # If this isn't lazy, then the block returns eagerly and assigns the result here
280
+ # If it _is_ lazy, then we write the lazy to the hash, then update it later
281
+ argument_values[arg_key] = context.schema.after_lazy(coerced_value) do |coerced_value|
282
+ owner.validate_directive_argument(self, coerced_value)
283
+ prepared_value = context.schema.error_handler.with_error_handling(context) do
284
+ prepare_value(parent_object, coerced_value, context: context)
285
+ end
286
+
287
+ # TODO code smell to access such a deeply-nested constant in a distant module
288
+ argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
289
+ value: prepared_value,
290
+ definition: self,
291
+ default_used: default_used,
292
+ )
293
+ end
294
+ else
295
+ # has_value is false
296
+ owner.validate_directive_argument(self, nil)
297
+ end
298
+ end
299
+
221
300
  private
222
301
 
223
302
  def validate_input_type(input_type)