graphql 1.11.4 → 1.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +5 -5
  3. data/lib/generators/graphql/object_generator.rb +2 -0
  4. data/lib/generators/graphql/relay_generator.rb +63 -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/generators/graphql/templates/union.erb +1 -1
  12. data/lib/graphql.rb +55 -4
  13. data/lib/graphql/analysis/analyze_query.rb +7 -0
  14. data/lib/graphql/analysis/ast.rb +11 -2
  15. data/lib/graphql/analysis/ast/visitor.rb +9 -1
  16. data/lib/graphql/argument.rb +3 -3
  17. data/lib/graphql/backtrace.rb +28 -19
  18. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  19. data/lib/graphql/backtrace/table.rb +22 -2
  20. data/lib/graphql/backtrace/tracer.rb +40 -8
  21. data/lib/graphql/backwards_compatibility.rb +1 -0
  22. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  23. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  24. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  25. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  26. data/lib/graphql/dataloader.rb +198 -0
  27. data/lib/graphql/dataloader/null_dataloader.rb +21 -0
  28. data/lib/graphql/dataloader/request.rb +24 -0
  29. data/lib/graphql/dataloader/request_all.rb +22 -0
  30. data/lib/graphql/dataloader/source.rb +93 -0
  31. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  32. data/lib/graphql/define/instance_definable.rb +32 -2
  33. data/lib/graphql/define/type_definer.rb +5 -5
  34. data/lib/graphql/deprecated_dsl.rb +5 -0
  35. data/lib/graphql/enum_type.rb +2 -0
  36. data/lib/graphql/execution/errors.rb +4 -0
  37. data/lib/graphql/execution/execute.rb +7 -0
  38. data/lib/graphql/execution/interpreter.rb +20 -6
  39. data/lib/graphql/execution/interpreter/arguments.rb +57 -5
  40. data/lib/graphql/execution/interpreter/arguments_cache.rb +8 -0
  41. data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
  42. data/lib/graphql/execution/interpreter/runtime.rb +236 -120
  43. data/lib/graphql/execution/multiplex.rb +20 -6
  44. data/lib/graphql/function.rb +4 -0
  45. data/lib/graphql/input_object_type.rb +2 -0
  46. data/lib/graphql/integer_decoding_error.rb +17 -0
  47. data/lib/graphql/interface_type.rb +3 -1
  48. data/lib/graphql/introspection.rb +96 -0
  49. data/lib/graphql/introspection/field_type.rb +7 -3
  50. data/lib/graphql/introspection/input_value_type.rb +6 -0
  51. data/lib/graphql/introspection/introspection_query.rb +6 -92
  52. data/lib/graphql/introspection/type_type.rb +7 -3
  53. data/lib/graphql/invalid_null_error.rb +1 -1
  54. data/lib/graphql/language/block_string.rb +24 -5
  55. data/lib/graphql/language/document_from_schema_definition.rb +50 -23
  56. data/lib/graphql/language/lexer.rb +7 -3
  57. data/lib/graphql/language/lexer.rl +7 -3
  58. data/lib/graphql/language/nodes.rb +1 -1
  59. data/lib/graphql/language/parser.rb +107 -103
  60. data/lib/graphql/language/parser.y +4 -0
  61. data/lib/graphql/language/sanitized_printer.rb +59 -26
  62. data/lib/graphql/name_validator.rb +6 -7
  63. data/lib/graphql/object_type.rb +2 -0
  64. data/lib/graphql/pagination/connection.rb +5 -1
  65. data/lib/graphql/pagination/connections.rb +15 -17
  66. data/lib/graphql/query.rb +8 -3
  67. data/lib/graphql/query/context.rb +18 -3
  68. data/lib/graphql/query/serial_execution.rb +1 -0
  69. data/lib/graphql/query/validation_pipeline.rb +1 -1
  70. data/lib/graphql/relay/array_connection.rb +2 -2
  71. data/lib/graphql/relay/base_connection.rb +7 -0
  72. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  73. data/lib/graphql/relay/connection_type.rb +1 -1
  74. data/lib/graphql/relay/mutation.rb +1 -0
  75. data/lib/graphql/relay/node.rb +3 -0
  76. data/lib/graphql/relay/range_add.rb +14 -5
  77. data/lib/graphql/relay/type_extensions.rb +2 -0
  78. data/lib/graphql/scalar_type.rb +2 -0
  79. data/lib/graphql/schema.rb +104 -39
  80. data/lib/graphql/schema/argument.rb +74 -5
  81. data/lib/graphql/schema/build_from_definition.rb +203 -86
  82. data/lib/graphql/schema/default_type_error.rb +2 -0
  83. data/lib/graphql/schema/directive.rb +76 -0
  84. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  85. data/lib/graphql/schema/directive/flagged.rb +57 -0
  86. data/lib/graphql/schema/enum.rb +3 -0
  87. data/lib/graphql/schema/enum_value.rb +12 -6
  88. data/lib/graphql/schema/field.rb +59 -24
  89. data/lib/graphql/schema/field/connection_extension.rb +10 -8
  90. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  91. data/lib/graphql/schema/input_object.rb +38 -25
  92. data/lib/graphql/schema/interface.rb +2 -1
  93. data/lib/graphql/schema/late_bound_type.rb +2 -2
  94. data/lib/graphql/schema/loader.rb +1 -0
  95. data/lib/graphql/schema/member.rb +4 -0
  96. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -0
  97. data/lib/graphql/schema/member/build_type.rb +17 -7
  98. data/lib/graphql/schema/member/has_arguments.rb +70 -51
  99. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  100. data/lib/graphql/schema/member/has_directives.rb +98 -0
  101. data/lib/graphql/schema/member/has_fields.rb +2 -2
  102. data/lib/graphql/schema/member/has_validators.rb +31 -0
  103. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  104. data/lib/graphql/schema/object.rb +11 -0
  105. data/lib/graphql/schema/printer.rb +5 -4
  106. data/lib/graphql/schema/relay_classic_mutation.rb +4 -2
  107. data/lib/graphql/schema/resolver.rb +7 -0
  108. data/lib/graphql/schema/resolver/has_payload_type.rb +2 -0
  109. data/lib/graphql/schema/subscription.rb +19 -1
  110. data/lib/graphql/schema/timeout.rb +29 -15
  111. data/lib/graphql/schema/timeout_middleware.rb +2 -0
  112. data/lib/graphql/schema/unique_within_type.rb +1 -2
  113. data/lib/graphql/schema/validation.rb +10 -0
  114. data/lib/graphql/schema/validator.rb +163 -0
  115. data/lib/graphql/schema/validator/exclusion_validator.rb +31 -0
  116. data/lib/graphql/schema/validator/format_validator.rb +49 -0
  117. data/lib/graphql/schema/validator/inclusion_validator.rb +33 -0
  118. data/lib/graphql/schema/validator/length_validator.rb +57 -0
  119. data/lib/graphql/schema/validator/numericality_validator.rb +71 -0
  120. data/lib/graphql/schema/validator/required_validator.rb +68 -0
  121. data/lib/graphql/static_validation.rb +1 -0
  122. data/lib/graphql/static_validation/all_rules.rb +1 -0
  123. data/lib/graphql/static_validation/rules/fields_will_merge.rb +25 -17
  124. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  125. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  126. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  127. data/lib/graphql/static_validation/validator.rb +33 -7
  128. data/lib/graphql/subscriptions.rb +18 -23
  129. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -7
  130. data/lib/graphql/tracing.rb +2 -2
  131. data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
  132. data/lib/graphql/tracing/platform_tracing.rb +4 -2
  133. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  134. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  135. data/lib/graphql/types/int.rb +9 -2
  136. data/lib/graphql/types/relay.rb +11 -3
  137. data/lib/graphql/types/relay/base_connection.rb +2 -91
  138. data/lib/graphql/types/relay/base_edge.rb +2 -34
  139. data/lib/graphql/types/relay/connection_behaviors.rb +123 -0
  140. data/lib/graphql/types/relay/default_relay.rb +27 -0
  141. data/lib/graphql/types/relay/edge_behaviors.rb +42 -0
  142. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  143. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  144. data/lib/graphql/types/relay/node.rb +2 -4
  145. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  146. data/lib/graphql/types/relay/node_field.rb +1 -19
  147. data/lib/graphql/types/relay/nodes_field.rb +1 -19
  148. data/lib/graphql/types/relay/page_info.rb +2 -14
  149. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  150. data/lib/graphql/types/string.rb +7 -1
  151. data/lib/graphql/unauthorized_error.rb +1 -1
  152. data/lib/graphql/union_type.rb +2 -0
  153. data/lib/graphql/upgrader/member.rb +1 -0
  154. data/lib/graphql/upgrader/schema.rb +1 -0
  155. data/lib/graphql/version.rb +1 -1
  156. data/readme.md +1 -1
  157. metadata +49 -6
  158. data/lib/graphql/types/relay/base_field.rb +0 -22
  159. data/lib/graphql/types/relay/base_interface.rb +0 -29
  160. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -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
+ 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
+ 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
+ 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
@@ -33,12 +33,21 @@ module GraphQL
33
33
  # @param item [Object] The newly-added item (will be wrapped in `edge_class`)
34
34
  # @param parent [Object] The owner of `collection`, will be passed to the connection if provided
35
35
  # @param context [GraphQL::Query::Context] The surrounding `ctx`, will be passed to the connection if provided (this is required for cursor encoders)
36
- # @param edge_class [Class] The class to wrap `item` with
37
- def initialize(collection:, item:, parent: nil, context: nil, edge_class: Relay::Edge)
38
- connection_class = BaseConnection.connection_for_nodes(collection)
36
+ # @param edge_class [Class] The class to wrap `item` with (defaults to the connection's edge class)
37
+ def initialize(collection:, item:, parent: nil, context: nil, edge_class: nil)
38
+ if context && context.schema.new_connections?
39
+ conn_class = context.schema.connections.wrapper_for(collection)
40
+ # The rest will be added by ConnectionExtension
41
+ @connection = conn_class.new(collection, parent: parent, context: context, edge_class: edge_class)
42
+ @edge = @connection.edge_class.new(item, @connection)
43
+ else
44
+ connection_class = BaseConnection.connection_for_nodes(collection)
45
+ @connection = connection_class.new(collection, {}, parent: parent, context: context)
46
+ edge_class ||= Relay::Edge
47
+ @edge = edge_class.new(item, @connection)
48
+ end
49
+
39
50
  @parent = parent
40
- @connection = connection_class.new(collection, {}, parent: parent, context: context)
41
- @edge = edge_class.new(item, @connection)
42
51
  end
43
52
  end
44
53
  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
+ 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
+ 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
@@ -157,7 +160,7 @@ module GraphQL
157
160
 
158
161
  accepts_definitions \
159
162
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
160
- :max_depth, :max_complexity, :default_max_page_size,
163
+ :validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
161
164
  :orphan_types, :resolve_type, :type_error, :parse_error,
162
165
  :error_bubbling,
163
166
  :raise_definition_error,
@@ -196,7 +199,7 @@ module GraphQL
196
199
  attr_accessor \
197
200
  :query, :mutation, :subscription,
198
201
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
199
- :max_depth, :max_complexity, :default_max_page_size,
202
+ :validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
200
203
  :orphan_types, :directives,
201
204
  :query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
202
205
  :cursor_encoder,
@@ -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
@@ -366,11 +368,11 @@ module GraphQL
366
368
  validator_opts = { schema: self }
367
369
  rules && (validator_opts[:rules] = rules)
368
370
  validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
369
- res = validator.validate(query)
371
+ res = validator.validate(query, timeout: validate_timeout)
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,22 +789,24 @@ 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: BuildFromDefinition::DefaultParser, 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
- definition = if definition_or_path.end_with?(".graphql")
795
- File.read(definition_or_path)
795
+ if definition_or_path.end_with?(".graphql")
796
+ GraphQL::Schema::BuildFromDefinition.from_definition_path(
797
+ definition_or_path,
798
+ default_resolve: default_resolve,
799
+ parser: parser,
800
+ using: using,
801
+ )
796
802
  else
797
- definition_or_path
798
- end
799
- GraphQL::Schema::BuildFromDefinition.from_definition(
800
- definition,
801
- default_resolve: default_resolve,
802
- parser: parser,
803
- using: using,
804
- interpreter: interpreter,
805
- )
803
+ GraphQL::Schema::BuildFromDefinition.from_definition(
804
+ definition_or_path,
805
+ default_resolve: default_resolve,
806
+ parser: parser,
807
+ using: using,
808
+ )
809
+ end
806
810
  end
807
811
 
808
812
  # Error that is raised when [#Schema#from_definition] is passed an invalid schema definition string.
@@ -832,7 +836,7 @@ module GraphQL
832
836
  # @param except [<#call(member, ctx)>]
833
837
  # @return [Hash] GraphQL result
834
838
  def as_json(only: nil, except: nil, context: {})
835
- execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
839
+ execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
836
840
  end
837
841
 
838
842
  # Returns the JSON response of {Introspection::INTROSPECTION_QUERY}.
@@ -880,7 +884,7 @@ module GraphQL
880
884
  # @param except [<#call(member, ctx)>]
881
885
  # @return [Hash] GraphQL result
882
886
  def as_json(only: nil, except: nil, context: {})
883
- execute(Introspection::INTROSPECTION_QUERY, only: only, except: except, context: context).to_h
887
+ execute(Introspection.query(include_deprecated_args: true), only: only, except: except, context: context).to_h
884
888
  end
885
889
 
886
890
  # Return the GraphQL IDL for the schema
@@ -945,6 +949,7 @@ module GraphQL
945
949
  schema_defn.query = query && query.graphql_definition
946
950
  schema_defn.mutation = mutation && mutation.graphql_definition
947
951
  schema_defn.subscription = subscription && subscription.graphql_definition
952
+ schema_defn.validate_timeout = validate_timeout
948
953
  schema_defn.max_complexity = max_complexity
949
954
  schema_defn.error_bubbling = error_bubbling
950
955
  schema_defn.max_depth = max_depth
@@ -1112,7 +1117,16 @@ module GraphQL
1112
1117
  if type.kind.union?
1113
1118
  type.possible_types(context: context)
1114
1119
  else
1115
- own_possible_types[type.graphql_name] ||
1120
+ stored_possible_types = own_possible_types[type.graphql_name]
1121
+ visible_possible_types = stored_possible_types.select do |possible_type|
1122
+ next true unless type.kind.interface?
1123
+ next true unless possible_type.kind.object?
1124
+
1125
+ # Use `.graphql_name` comparison to match legacy vs class-based types.
1126
+ # When we don't need to support legacy `.define` types, use `.include?(type)` instead.
1127
+ possible_type.interfaces(context).any? { |interface| interface.graphql_name == type.graphql_name }
1128
+ end if stored_possible_types
1129
+ visible_possible_types ||
1116
1130
  introspection_system.possible_types[type.graphql_name] ||
1117
1131
  (
1118
1132
  superclass.respond_to?(:possible_types) ?
@@ -1142,6 +1156,14 @@ module GraphQL
1142
1156
  end
1143
1157
  end
1144
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
+
1145
1167
  def references_to(to_type = nil, from: nil)
1146
1168
  @own_references_to ||= Hash.new { |h, k| h[k] = [] }
1147
1169
  if to_type
@@ -1258,6 +1280,18 @@ module GraphQL
1258
1280
  end
1259
1281
  end
1260
1282
 
1283
+ attr_writer :validate_timeout
1284
+
1285
+ def validate_timeout(new_validate_timeout = nil)
1286
+ if new_validate_timeout
1287
+ @validate_timeout = new_validate_timeout
1288
+ elsif defined?(@validate_timeout)
1289
+ @validate_timeout
1290
+ else
1291
+ find_inherited_value(:validate_timeout)
1292
+ end
1293
+ end
1294
+
1261
1295
  attr_writer :max_complexity
1262
1296
 
1263
1297
  def max_complexity(max_complexity = nil)
@@ -1273,7 +1307,7 @@ module GraphQL
1273
1307
  attr_writer :analysis_engine
1274
1308
 
1275
1309
  def analysis_engine
1276
- @analysis_engine || find_inherited_value(:analysis_engine, GraphQL::Analysis)
1310
+ @analysis_engine || find_inherited_value(:analysis_engine, self.default_analysis_engine)
1277
1311
  end
1278
1312
 
1279
1313
  def using_ast_analysis?
@@ -1281,11 +1315,9 @@ module GraphQL
1281
1315
  end
1282
1316
 
1283
1317
  def interpreter?
1284
- if defined?(@interpreter)
1285
- @interpreter
1286
- else
1287
- find_inherited_value(:interpreter?, false)
1288
- end
1318
+ query_execution_strategy == GraphQL::Execution::Interpreter &&
1319
+ mutation_execution_strategy == GraphQL::Execution::Interpreter &&
1320
+ subscription_execution_strategy == GraphQL::Execution::Interpreter
1289
1321
  end
1290
1322
 
1291
1323
  attr_writer :interpreter
@@ -1369,7 +1401,15 @@ module GraphQL
1369
1401
  if superclass <= GraphQL::Schema
1370
1402
  superclass.default_execution_strategy
1371
1403
  else
1372
- @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
1373
1413
  end
1374
1414
  end
1375
1415
 
@@ -1523,6 +1563,10 @@ module GraphQL
1523
1563
  end
1524
1564
 
1525
1565
  def instrument(instrument_step, instrumenter, options = {})
1566
+ if instrument_step == :field
1567
+ 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
+
1526
1570
  step = if instrument_step == :field && options[:after_built_ins]
1527
1571
  :field_after_built_ins
1528
1572
  else
@@ -1544,9 +1588,12 @@ module GraphQL
1544
1588
 
1545
1589
  # Attach a single directive to this schema
1546
1590
  # @param new_directive [Class]
1591
+ # @return void
1547
1592
  def directive(new_directive)
1548
- add_type_and_traverse(new_directive, root: false)
1549
- 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
1550
1597
  end
1551
1598
 
1552
1599
  def default_directives
@@ -1578,6 +1625,7 @@ module GraphQL
1578
1625
 
1579
1626
  def middleware(new_middleware = nil)
1580
1627
  if new_middleware
1628
+ warn "Middleware will be removed in GraphQL-Ruby 2.0, please upgrade to Field Extensions: https://graphql-ruby.org/type_definitions/field_extensions.html"
1581
1629
  own_middleware << new_middleware
1582
1630
  else
1583
1631
  # TODO make sure this is cached when running a query
@@ -1664,7 +1712,7 @@ module GraphQL
1664
1712
  end
1665
1713
 
1666
1714
  def query_stack_error(query, err)
1667
- query.analysis_errors.push(GraphQL::AnalysisError.new("This query is too large to execute."))
1715
+ query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
1668
1716
  end
1669
1717
 
1670
1718
  private
@@ -1677,6 +1725,7 @@ module GraphQL
1677
1725
  else
1678
1726
  @lazy_methods = GraphQL::Execution::Lazy::LazyMethodMap.new
1679
1727
  @lazy_methods.set(GraphQL::Execution::Lazy, :value)
1728
+ @lazy_methods.set(GraphQL::Dataloader::Request, :load)
1680
1729
  end
1681
1730
  end
1682
1731
  @lazy_methods
@@ -1873,13 +1922,16 @@ module GraphQL
1873
1922
  end
1874
1923
  else
1875
1924
  own_types[type.graphql_name] = type
1925
+ add_directives_from(type)
1876
1926
  if type.kind.fields?
1877
1927
  type.fields.each do |name, field|
1878
1928
  field_type = field.type.unwrap
1879
1929
  references_to(field_type, from: field)
1880
1930
  field_path = path + [name]
1881
1931
  add_type(field_type, owner: field, late_types: late_types, path: field_path)
1932
+ add_directives_from(field)
1882
1933
  field.arguments.each do |arg_name, arg|
1934
+ add_directives_from(arg)
1883
1935
  arg_type = arg.type.unwrap
1884
1936
  references_to(arg_type, from: arg)
1885
1937
  add_type(arg_type, owner: arg, late_types: late_types, path: field_path + [arg_name])
@@ -1888,6 +1940,7 @@ module GraphQL
1888
1940
  end
1889
1941
  if type.kind.input_object?
1890
1942
  type.arguments.each do |arg_name, arg|
1943
+ add_directives_from(arg)
1891
1944
  arg_type = arg.type.unwrap
1892
1945
  references_to(arg_type, from: arg)
1893
1946
  add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg_name])
@@ -1925,8 +1978,20 @@ module GraphQL
1925
1978
  end
1926
1979
  end
1927
1980
  end
1981
+
1982
+ def add_directives_from(owner)
1983
+ owner.directives.each { |dir| directive(dir.class) }
1984
+ end
1928
1985
  end
1929
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
+
1930
1995
  protected
1931
1996
 
1932
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,7 +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.
48
- 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:, &definition_block)
52
+ # @param directives [Hash{Class => Hash}]
53
+ # @param deprecation_reason [String]
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)
49
56
  arg_name ||= name
50
57
  @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
51
58
  @type_expr = type_expr || type
@@ -60,6 +67,15 @@ module GraphQL
60
67
  @ast_node = ast_node
61
68
  @from_resolver = from_resolver
62
69
  @method_access = method_access
70
+ self.deprecation_reason = deprecation_reason
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)
63
79
 
64
80
  if definition_block
65
81
  if definition_block.arity == 1
@@ -89,6 +105,20 @@ module GraphQL
89
105
  end
90
106
  end
91
107
 
108
+ # @return [String] Deprecation reason for this argument
109
+ def deprecation_reason(text = nil)
110
+ if text
111
+ self.deprecation_reason = text
112
+ else
113
+ super()
114
+ end
115
+ end
116
+
117
+ def deprecation_reason=(new_reason)
118
+ validate_deprecated_or_optional(null: @null, deprecation_reason: new_reason)
119
+ super
120
+ end
121
+
92
122
  def visible?(context)
93
123
  true
94
124
  end
@@ -143,15 +173,32 @@ module GraphQL
143
173
  if NO_DEFAULT != @default_value
144
174
  argument.default_value = @default_value
145
175
  end
176
+ if self.deprecation_reason
177
+ argument.deprecation_reason = self.deprecation_reason
178
+ end
146
179
  argument
147
180
  end
148
181
 
149
- attr_writer :type
182
+ def type=(new_type)
183
+ validate_input_type(new_type)
184
+ # This isn't true for LateBoundTypes, but we can assume those will
185
+ # be updated via this codepath later in schema setup.
186
+ if new_type.respond_to?(:non_null?)
187
+ validate_deprecated_or_optional(null: !new_type.non_null?, deprecation_reason: deprecation_reason)
188
+ end
189
+ @type = new_type
190
+ end
150
191
 
151
192
  def type
152
- @type ||= Member::BuildType.parse_type(@type_expr, null: @null)
153
- rescue StandardError => err
154
- raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
193
+ @type ||= begin
194
+ parsed_type = begin
195
+ Member::BuildType.parse_type(@type_expr, null: @null)
196
+ rescue StandardError => err
197
+ raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
198
+ end
199
+ # Use the setter method to get validations
200
+ self.type = parsed_type
201
+ end
155
202
  end
156
203
 
157
204
  def statically_coercible?
@@ -168,6 +215,8 @@ module GraphQL
168
215
  value = value.prepare
169
216
  end
170
217
 
218
+ Schema::Validator.validate!(validators, obj, context, value)
219
+
171
220
  if @prepare.nil?
172
221
  value
173
222
  elsif @prepare.is_a?(String) || @prepare.is_a?(Symbol)
@@ -186,6 +235,26 @@ module GraphQL
186
235
  raise "Invalid prepare for #{@owner.name}.name: #{@prepare.inspect}"
187
236
  end
188
237
  end
238
+
239
+ private
240
+
241
+ def validate_input_type(input_type)
242
+ if input_type.is_a?(String) || input_type.is_a?(GraphQL::Schema::LateBoundType)
243
+ # Do nothing; assume this will be validated later
244
+ elsif input_type.kind.non_null? || input_type.kind.list?
245
+ validate_input_type(input_type.unwrap)
246
+ elsif !input_type.kind.input?
247
+ raise ArgumentError, "Invalid input type for #{path}: #{input_type.graphql_name}. Must be scalar, enum, or input object, not #{input_type.kind.name}."
248
+ else
249
+ # It's an input type, we're OK
250
+ end
251
+ end
252
+
253
+ def validate_deprecated_or_optional(null:, deprecation_reason:)
254
+ if deprecation_reason && !null
255
+ raise ArgumentError, "Required arguments cannot be deprecated: #{path}."
256
+ end
257
+ end
189
258
  end
190
259
  end
191
260
  end