graphql 1.12.10 → 1.13.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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -1
  3. data/lib/generators/graphql/install_generator.rb +9 -2
  4. data/lib/generators/graphql/mutation_generator.rb +1 -1
  5. data/lib/generators/graphql/object_generator.rb +2 -1
  6. data/lib/generators/graphql/relay.rb +19 -11
  7. data/lib/generators/graphql/templates/schema.erb +14 -2
  8. data/lib/generators/graphql/type_generator.rb +0 -1
  9. data/lib/graphql/analysis/ast/field_usage.rb +28 -1
  10. data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
  11. data/lib/graphql/analysis/ast/visitor.rb +4 -4
  12. data/lib/graphql/backtrace/table.rb +15 -3
  13. data/lib/graphql/backtrace/tracer.rb +7 -4
  14. data/lib/graphql/base_type.rb +4 -2
  15. data/lib/graphql/boolean_type.rb +1 -1
  16. data/lib/graphql/dataloader/null_dataloader.rb +1 -0
  17. data/lib/graphql/dataloader/source.rb +50 -2
  18. data/lib/graphql/dataloader.rb +110 -41
  19. data/lib/graphql/define/instance_definable.rb +1 -1
  20. data/lib/graphql/deprecated_dsl.rb +11 -3
  21. data/lib/graphql/deprecation.rb +1 -5
  22. data/lib/graphql/directive/deprecated_directive.rb +1 -1
  23. data/lib/graphql/directive/include_directive.rb +1 -1
  24. data/lib/graphql/directive/skip_directive.rb +1 -1
  25. data/lib/graphql/directive.rb +0 -4
  26. data/lib/graphql/enum_type.rb +5 -1
  27. data/lib/graphql/execution/errors.rb +1 -0
  28. data/lib/graphql/execution/execute.rb +1 -1
  29. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  30. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -4
  31. data/lib/graphql/execution/interpreter/resolve.rb +6 -2
  32. data/lib/graphql/execution/interpreter/runtime.rb +513 -213
  33. data/lib/graphql/execution/interpreter.rb +4 -8
  34. data/lib/graphql/execution/lazy.rb +5 -1
  35. data/lib/graphql/execution/lookahead.rb +2 -2
  36. data/lib/graphql/execution/multiplex.rb +4 -1
  37. data/lib/graphql/float_type.rb +1 -1
  38. data/lib/graphql/id_type.rb +1 -1
  39. data/lib/graphql/int_type.rb +1 -1
  40. data/lib/graphql/integer_encoding_error.rb +18 -2
  41. data/lib/graphql/introspection/directive_type.rb +1 -1
  42. data/lib/graphql/introspection/entry_points.rb +2 -2
  43. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  44. data/lib/graphql/introspection/field_type.rb +2 -2
  45. data/lib/graphql/introspection/input_value_type.rb +10 -4
  46. data/lib/graphql/introspection/schema_type.rb +3 -3
  47. data/lib/graphql/introspection/type_type.rb +10 -10
  48. data/lib/graphql/language/block_string.rb +2 -6
  49. data/lib/graphql/language/document_from_schema_definition.rb +10 -4
  50. data/lib/graphql/language/lexer.rb +0 -3
  51. data/lib/graphql/language/lexer.rl +0 -4
  52. data/lib/graphql/language/nodes.rb +13 -3
  53. data/lib/graphql/language/parser.rb +442 -434
  54. data/lib/graphql/language/parser.y +5 -4
  55. data/lib/graphql/language/printer.rb +6 -1
  56. data/lib/graphql/language/sanitized_printer.rb +5 -5
  57. data/lib/graphql/language/token.rb +0 -4
  58. data/lib/graphql/name_validator.rb +0 -4
  59. data/lib/graphql/pagination/active_record_relation_connection.rb +43 -6
  60. data/lib/graphql/pagination/connections.rb +40 -16
  61. data/lib/graphql/pagination/relation_connection.rb +57 -27
  62. data/lib/graphql/query/arguments.rb +1 -1
  63. data/lib/graphql/query/arguments_cache.rb +1 -1
  64. data/lib/graphql/query/context.rb +15 -2
  65. data/lib/graphql/query/literal_input.rb +1 -1
  66. data/lib/graphql/query/null_context.rb +12 -7
  67. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  68. data/lib/graphql/query/validation_pipeline.rb +1 -1
  69. data/lib/graphql/query/variables.rb +5 -1
  70. data/lib/graphql/query.rb +5 -1
  71. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  72. data/lib/graphql/relay/global_id_resolve.rb +1 -1
  73. data/lib/graphql/relay/page_info.rb +1 -1
  74. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  75. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  76. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  77. data/lib/graphql/rubocop.rb +4 -0
  78. data/lib/graphql/schema/addition.rb +247 -0
  79. data/lib/graphql/schema/argument.rb +103 -45
  80. data/lib/graphql/schema/build_from_definition.rb +13 -7
  81. data/lib/graphql/schema/directive/feature.rb +1 -1
  82. data/lib/graphql/schema/directive/flagged.rb +2 -2
  83. data/lib/graphql/schema/directive/include.rb +1 -1
  84. data/lib/graphql/schema/directive/skip.rb +1 -1
  85. data/lib/graphql/schema/directive/transform.rb +14 -2
  86. data/lib/graphql/schema/directive.rb +7 -3
  87. data/lib/graphql/schema/enum.rb +70 -11
  88. data/lib/graphql/schema/enum_value.rb +6 -0
  89. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  90. data/lib/graphql/schema/field.rb +243 -81
  91. data/lib/graphql/schema/field_extension.rb +89 -2
  92. data/lib/graphql/schema/find_inherited_value.rb +1 -0
  93. data/lib/graphql/schema/finder.rb +5 -5
  94. data/lib/graphql/schema/input_object.rb +39 -29
  95. data/lib/graphql/schema/interface.rb +11 -20
  96. data/lib/graphql/schema/introspection_system.rb +1 -1
  97. data/lib/graphql/schema/list.rb +3 -1
  98. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  99. data/lib/graphql/schema/member/build_type.rb +1 -4
  100. data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
  101. data/lib/graphql/schema/member/has_arguments.rb +145 -57
  102. data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
  103. data/lib/graphql/schema/member/has_fields.rb +76 -18
  104. data/lib/graphql/schema/member/has_interfaces.rb +90 -0
  105. data/lib/graphql/schema/member.rb +1 -0
  106. data/lib/graphql/schema/non_null.rb +7 -1
  107. data/lib/graphql/schema/object.rb +10 -75
  108. data/lib/graphql/schema/printer.rb +12 -17
  109. data/lib/graphql/schema/relay_classic_mutation.rb +37 -3
  110. data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
  111. data/lib/graphql/schema/resolver.rb +75 -65
  112. data/lib/graphql/schema/scalar.rb +2 -0
  113. data/lib/graphql/schema/subscription.rb +36 -8
  114. data/lib/graphql/schema/traversal.rb +1 -1
  115. data/lib/graphql/schema/type_expression.rb +1 -1
  116. data/lib/graphql/schema/type_membership.rb +18 -4
  117. data/lib/graphql/schema/union.rb +8 -1
  118. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  119. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  120. data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
  121. data/lib/graphql/schema/validator/format_validator.rb +4 -5
  122. data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
  123. data/lib/graphql/schema/validator/length_validator.rb +5 -3
  124. data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
  125. data/lib/graphql/schema/validator/required_validator.rb +29 -15
  126. data/lib/graphql/schema/validator.rb +33 -25
  127. data/lib/graphql/schema/warden.rb +116 -52
  128. data/lib/graphql/schema.rb +162 -227
  129. data/lib/graphql/static_validation/all_rules.rb +1 -0
  130. data/lib/graphql/static_validation/base_visitor.rb +8 -5
  131. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  132. data/lib/graphql/static_validation/error.rb +3 -1
  133. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  134. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  135. data/lib/graphql/static_validation/rules/fields_will_merge.rb +52 -26
  136. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  137. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  138. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  139. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  140. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -1
  141. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
  142. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
  143. data/lib/graphql/static_validation/validation_context.rb +8 -2
  144. data/lib/graphql/static_validation/validator.rb +15 -12
  145. data/lib/graphql/string_encoding_error.rb +13 -3
  146. data/lib/graphql/string_type.rb +1 -1
  147. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +36 -6
  148. data/lib/graphql/subscriptions/event.rb +68 -31
  149. data/lib/graphql/subscriptions/serialize.rb +23 -3
  150. data/lib/graphql/subscriptions.rb +17 -19
  151. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  152. data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
  153. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  154. data/lib/graphql/types/big_int.rb +5 -1
  155. data/lib/graphql/types/int.rb +1 -1
  156. data/lib/graphql/types/relay/connection_behaviors.rb +26 -9
  157. data/lib/graphql/types/relay/default_relay.rb +5 -1
  158. data/lib/graphql/types/relay/edge_behaviors.rb +13 -2
  159. data/lib/graphql/types/relay/has_node_field.rb +2 -2
  160. data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
  161. data/lib/graphql/types/relay/node_field.rb +15 -4
  162. data/lib/graphql/types/relay/nodes_field.rb +14 -4
  163. data/lib/graphql/types/string.rb +1 -1
  164. data/lib/graphql/unauthorized_error.rb +1 -1
  165. data/lib/graphql/version.rb +1 -1
  166. data/lib/graphql.rb +10 -28
  167. data/readme.md +1 -4
  168. metadata +17 -21
  169. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/schema/addition"
2
3
  require "graphql/schema/base_64_encoder"
3
4
  require "graphql/schema/catchall_middleware"
4
5
  require "graphql/schema/default_parse_error"
@@ -91,6 +92,8 @@ module GraphQL
91
92
  end
92
93
  end
93
94
 
95
+ class DuplicateNamesError < GraphQL::Error; end
96
+
94
97
  class UnresolvedLateBoundTypeError < GraphQL::Error
95
98
  attr_reader :type
96
99
  def initialize(type:)
@@ -160,7 +163,7 @@ module GraphQL
160
163
 
161
164
  accepts_definitions \
162
165
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
163
- :validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
166
+ :validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
164
167
  :orphan_types, :resolve_type, :type_error, :parse_error,
165
168
  :error_bubbling,
166
169
  :raise_definition_error,
@@ -199,7 +202,7 @@ module GraphQL
199
202
  attr_accessor \
200
203
  :query, :mutation, :subscription,
201
204
  :query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
202
- :validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
205
+ :validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
203
206
  :orphan_types, :directives,
204
207
  :query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
205
208
  :cursor_encoder,
@@ -551,7 +554,7 @@ module GraphQL
551
554
  end
552
555
  end
553
556
 
554
- # @see [GraphQL::Schema::Warden] Resticted access to root types
557
+ # @see [GraphQL::Schema::Warden] Restricted access to root types
555
558
  # @return [GraphQL::ObjectType, nil]
556
559
  def root_type_for_operation(operation)
557
560
  case operation
@@ -842,7 +845,7 @@ module GraphQL
842
845
  # - Cause the Schema instance to be created, if it hasn't been created yet
843
846
  # - Delegate to that instance
844
847
  # Eventually, the methods will be moved into this class, removing the need for the singleton.
845
- def_delegators :graphql_definition,
848
+ def_delegators :deprecated_graphql_definition,
846
849
  # Execution
847
850
  :execution_strategy_for_operation,
848
851
  # Configuration
@@ -851,6 +854,10 @@ module GraphQL
851
854
  :id_from_object=, :object_from_id=,
852
855
  :remove_handler
853
856
 
857
+ def deprecated_graphql_definition
858
+ graphql_definition(silence_deprecation_warning: true)
859
+ end
860
+
854
861
  # @return [GraphQL::Subscriptions]
855
862
  attr_accessor :subscriptions
856
863
 
@@ -893,8 +900,15 @@ module GraphQL
893
900
  @find_cache[path] ||= @finder.find(path)
894
901
  end
895
902
 
896
- def graphql_definition
897
- @graphql_definition ||= to_graphql
903
+ def graphql_definition(silence_deprecation_warning: false)
904
+ @graphql_definition ||= begin
905
+ unless silence_deprecation_warning
906
+ message = "Legacy `.graphql_definition` objects are deprecated and will be removed in GraphQL-Ruby 2.0. Use a class-based definition instead."
907
+ caller_message = "\n\nCalled on #{self.inspect} from:\n #{caller(1, 25).map { |l| " #{l}" }.join("\n")}"
908
+ GraphQL::Deprecation.warn(message + caller_message)
909
+ end
910
+ to_graphql(silence_deprecation_warning: silence_deprecation_warning)
911
+ end
898
912
  end
899
913
 
900
914
  def default_filter
@@ -926,18 +940,20 @@ module GraphQL
926
940
  find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
927
941
  end
928
942
 
943
+ prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
929
944
  def to_graphql
930
945
  schema_defn = self.new
931
946
  schema_defn.raise_definition_error = true
932
- schema_defn.query = query && query.graphql_definition
933
- schema_defn.mutation = mutation && mutation.graphql_definition
934
- schema_defn.subscription = subscription && subscription.graphql_definition
947
+ schema_defn.query = query && query.graphql_definition(silence_deprecation_warning: true)
948
+ schema_defn.mutation = mutation && mutation.graphql_definition(silence_deprecation_warning: true)
949
+ schema_defn.subscription = subscription && subscription.graphql_definition(silence_deprecation_warning: true)
935
950
  schema_defn.validate_timeout = validate_timeout
951
+ schema_defn.validate_max_errors = validate_max_errors
936
952
  schema_defn.max_complexity = max_complexity
937
953
  schema_defn.error_bubbling = error_bubbling
938
954
  schema_defn.max_depth = max_depth
939
955
  schema_defn.default_max_page_size = default_max_page_size
940
- schema_defn.orphan_types = orphan_types.map(&:graphql_definition)
956
+ schema_defn.orphan_types = orphan_types.map { |t| t.graphql_definition(silence_deprecation_warning: true) }
941
957
  schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
942
958
  schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
943
959
  schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
@@ -994,16 +1010,58 @@ module GraphQL
994
1010
  # Build a map of `{ name => type }` and return it
995
1011
  # @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
996
1012
  # @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
997
- def types
998
- non_introspection_types.merge(introspection_system.types)
1013
+ def types(context = GraphQL::Query::NullContext)
1014
+ all_types = non_introspection_types.merge(introspection_system.types)
1015
+ visible_types = {}
1016
+ all_types.each do |k, v|
1017
+ visible_types[k] =if v.is_a?(Array)
1018
+ visible_t = nil
1019
+ v.each do |t|
1020
+ if t.visible?(context)
1021
+ if visible_t.nil?
1022
+ visible_t = t
1023
+ else
1024
+ raise DuplicateNamesError, "Found two visible type definitions for `#{k}`: #{visible_t.inspect}, #{t.inspect}"
1025
+ end
1026
+ end
1027
+ end
1028
+ visible_t
1029
+ else
1030
+ v
1031
+ end
1032
+ end
1033
+ visible_types
999
1034
  end
1000
1035
 
1001
1036
  # @param type_name [String]
1002
1037
  # @return [Module, nil] A type, or nil if there's no type called `type_name`
1003
- def get_type(type_name)
1004
- own_types[type_name] ||
1005
- introspection_system.types[type_name] ||
1006
- find_inherited_value(:types, EMPTY_HASH)[type_name]
1038
+ def get_type(type_name, context = GraphQL::Query::NullContext)
1039
+ local_entry = own_types[type_name]
1040
+ type_defn = case local_entry
1041
+ when nil
1042
+ nil
1043
+ when Array
1044
+ visible_t = nil
1045
+ warden = Warden.from_context(context)
1046
+ local_entry.each do |t|
1047
+ if warden.visible_type?(t, context)
1048
+ if visible_t.nil?
1049
+ visible_t = t
1050
+ else
1051
+ raise DuplicateNamesError, "Found two visible type definitions for `#{type_name}`: #{visible_t.inspect}, #{t.inspect}"
1052
+ end
1053
+ end
1054
+ end
1055
+ visible_t
1056
+ when Module
1057
+ local_entry
1058
+ else
1059
+ raise "Invariant: unexpected own_types[#{type_name.inspect}]: #{local_entry.inspect}"
1060
+ end
1061
+
1062
+ type_defn ||
1063
+ introspection_system.types[type_name] || # todo context-specific introspection?
1064
+ (superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
1007
1065
  end
1008
1066
 
1009
1067
  # @api private
@@ -1072,7 +1130,7 @@ module GraphQL
1072
1130
  end
1073
1131
  end
1074
1132
 
1075
- # @see [GraphQL::Schema::Warden] Resticted access to root types
1133
+ # @see [GraphQL::Schema::Warden] Restricted access to root types
1076
1134
  # @return [GraphQL::ObjectType, nil]
1077
1135
  def root_type_for_operation(operation)
1078
1136
  case operation
@@ -1180,19 +1238,23 @@ module GraphQL
1180
1238
  GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
1181
1239
  end
1182
1240
 
1183
- def get_field(type_or_name, field_name)
1241
+ def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
1184
1242
  parent_type = case type_or_name
1185
1243
  when LateBoundType
1186
- get_type(type_or_name.name)
1244
+ get_type(type_or_name.name, context)
1187
1245
  when String
1188
- get_type(type_or_name)
1246
+ get_type(type_or_name, context)
1189
1247
  when Module
1190
1248
  type_or_name
1191
1249
  else
1192
- raise ArgumentError, "unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
1250
+ raise ArgumentError, <<-ERR
1251
+ Invariant: unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})
1252
+
1253
+ This is probably a bug in GraphQL-Ruby, please report this error on GitHub: https://github.com/rmosolgo/graphql-ruby/issues/new?template=bug_report.md
1254
+ ERR
1193
1255
  end
1194
1256
 
1195
- if parent_type.kind.fields? && (field = parent_type.get_field(field_name))
1257
+ if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
1196
1258
  field
1197
1259
  elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
1198
1260
  entry_point_field
@@ -1203,8 +1265,8 @@ module GraphQL
1203
1265
  end
1204
1266
  end
1205
1267
 
1206
- def get_fields(type)
1207
- type.fields
1268
+ def get_fields(type, context = GraphQL::Query::NullContext)
1269
+ type.fields(context)
1208
1270
  end
1209
1271
 
1210
1272
  def introspection(new_introspection_namespace = nil)
@@ -1289,10 +1351,22 @@ module GraphQL
1289
1351
  validator_opts = { schema: self }
1290
1352
  rules && (validator_opts[:rules] = rules)
1291
1353
  validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
1292
- res = validator.validate(query, timeout: validate_timeout)
1354
+ res = validator.validate(query, timeout: validate_timeout, max_errors: validate_max_errors)
1293
1355
  res[:errors]
1294
1356
  end
1295
1357
 
1358
+ attr_writer :validate_max_errors
1359
+
1360
+ def validate_max_errors(new_validate_max_errors = nil)
1361
+ if new_validate_max_errors
1362
+ @validate_max_errors = new_validate_max_errors
1363
+ elsif defined?(@validate_max_errors)
1364
+ @validate_max_errors
1365
+ else
1366
+ find_inherited_value(:validate_max_errors)
1367
+ end
1368
+ end
1369
+
1296
1370
  attr_writer :max_complexity
1297
1371
 
1298
1372
  def max_complexity(max_complexity = nil)
@@ -1391,7 +1465,6 @@ module GraphQL
1391
1465
  if new_orphan_types.any?
1392
1466
  new_orphan_types = new_orphan_types.flatten
1393
1467
  add_type_and_traverse(new_orphan_types, root: false)
1394
- @orphan_types = new_orphan_types
1395
1468
  own_orphan_types.concat(new_orphan_types.flatten)
1396
1469
  end
1397
1470
 
@@ -1582,10 +1655,7 @@ module GraphQL
1582
1655
  # @param new_directive [Class]
1583
1656
  # @return void
1584
1657
  def directive(new_directive)
1585
- own_directives[new_directive.graphql_name] ||= begin
1586
- add_type_and_traverse(new_directive, root: false)
1587
- new_directive
1588
- end
1658
+ add_type_and_traverse(new_directive, root: false)
1589
1659
  end
1590
1660
 
1591
1661
  def default_directives
@@ -1633,6 +1703,14 @@ module GraphQL
1633
1703
  find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
1634
1704
  end
1635
1705
 
1706
+ def sanitized_printer(new_sanitized_printer = nil)
1707
+ if new_sanitized_printer
1708
+ @own_sanitized_printer = new_sanitized_printer
1709
+ else
1710
+ @own_sanitized_printer || GraphQL::Language::SanitizedPrinter
1711
+ end
1712
+ end
1713
+
1636
1714
  # Execute a query on itself.
1637
1715
  # @see {Query#initialize} for arguments.
1638
1716
  # @return [Hash] query result, ready to be serialized as JSON
@@ -1696,7 +1774,7 @@ module GraphQL
1696
1774
  if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
1697
1775
  GraphQL::Deprecation.warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
1698
1776
  else
1699
- subscription.fields.each do |name, field|
1777
+ subscription.all_field_definitions.each do |field|
1700
1778
  field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
1701
1779
  end
1702
1780
  end
@@ -1709,6 +1787,59 @@ module GraphQL
1709
1787
 
1710
1788
  private
1711
1789
 
1790
+ # @param t [Module, Array<Module>]
1791
+ # @return [void]
1792
+ def add_type_and_traverse(t, root:)
1793
+ if root
1794
+ @root_types ||= []
1795
+ @root_types << t
1796
+ end
1797
+ new_types = Array(t)
1798
+ addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
1799
+ addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
1800
+ if (prev_entry = own_types[name])
1801
+ prev_entries = case prev_entry
1802
+ when Array
1803
+ prev_entry
1804
+ when Module
1805
+ own_types[name] = [prev_entry]
1806
+ else
1807
+ raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
1808
+ end
1809
+
1810
+ case types_entry
1811
+ when Array
1812
+ prev_entries.concat(types_entry)
1813
+ prev_entries.uniq! # in case any are being re-visited
1814
+ when Module
1815
+ if !prev_entries.include?(types_entry)
1816
+ prev_entries << types_entry
1817
+ end
1818
+ else
1819
+ raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
1820
+ end
1821
+ else
1822
+ if types_entry.is_a?(Array)
1823
+ types_entry.uniq!
1824
+ end
1825
+ own_types[name] = types_entry
1826
+ end
1827
+ end
1828
+
1829
+ own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
1830
+ own_union_memberships.merge!(addition.union_memberships)
1831
+
1832
+ addition.references.each { |thing, pointers|
1833
+ pointers.each { |pointer| references_to(thing, from: pointer) }
1834
+ }
1835
+
1836
+ addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
1837
+
1838
+ addition.arguments_with_default_values.each do |arg|
1839
+ arg.validate_default_value
1840
+ end
1841
+ end
1842
+
1712
1843
  def lazy_methods
1713
1844
  if !defined?(@lazy_methods)
1714
1845
  if inherited_map = find_inherited_value(:lazy_methods)
@@ -1774,202 +1905,6 @@ module GraphQL
1774
1905
  def own_multiplex_analyzers
1775
1906
  @own_multiplex_analyzers ||= []
1776
1907
  end
1777
-
1778
- # @param t [Module, Array<Module>]
1779
- # @return [void]
1780
- def add_type_and_traverse(t, root:)
1781
- if root
1782
- @root_types ||= []
1783
- @root_types << t
1784
- end
1785
- late_types = []
1786
- new_types = Array(t)
1787
- new_types.each { |t| add_type(t, owner: nil, late_types: late_types, path: [t.graphql_name]) }
1788
- missed_late_types = 0
1789
- while (late_type_vals = late_types.shift)
1790
- type_owner, lt = late_type_vals
1791
- if lt.is_a?(String)
1792
- type = Member::BuildType.constantize(lt)
1793
- # Reset the counter, since we might succeed next go-round
1794
- missed_late_types = 0
1795
- update_type_owner(type_owner, type)
1796
- add_type(type, owner: type_owner, late_types: late_types, path: [type.graphql_name])
1797
- elsif lt.is_a?(LateBoundType)
1798
- if (type = get_type(lt.graphql_name))
1799
- # Reset the counter, since we might succeed next go-round
1800
- missed_late_types = 0
1801
- update_type_owner(type_owner, type)
1802
- add_type(type, owner: type_owner, late_types: late_types, path: [type.graphql_name])
1803
- else
1804
- missed_late_types += 1
1805
- # Add it back to the list, maybe we'll be able to resolve it later.
1806
- late_types << [type_owner, lt]
1807
- if missed_late_types == late_types.size
1808
- # We've looked at all of them and haven't resolved one.
1809
- raise UnresolvedLateBoundTypeError.new(type: lt)
1810
- else
1811
- # Try the next one
1812
- end
1813
- end
1814
- else
1815
- raise ArgumentError, "Unexpected late type: #{lt.inspect}"
1816
- end
1817
- end
1818
- nil
1819
- end
1820
-
1821
- def update_type_owner(owner, type)
1822
- case owner
1823
- when Class
1824
- if owner.kind.union?
1825
- # It's a union with possible_types
1826
- # Replace the item by class name
1827
- owner.assign_type_membership_object_type(type)
1828
- own_possible_types[owner.graphql_name] = owner.possible_types
1829
- elsif type.kind.interface? && owner.kind.object?
1830
- new_interfaces = []
1831
- owner.interfaces.each do |int_t|
1832
- if int_t.is_a?(String) && int_t == type.graphql_name
1833
- new_interfaces << type
1834
- elsif int_t.is_a?(LateBoundType) && int_t.graphql_name == type.graphql_name
1835
- new_interfaces << type
1836
- else
1837
- # Don't re-add proper interface definitions,
1838
- # they were probably already added, maybe with options.
1839
- end
1840
- end
1841
- owner.implements(*new_interfaces)
1842
- new_interfaces.each do |int|
1843
- pt = own_possible_types[int.graphql_name] ||= []
1844
- if !pt.include?(owner)
1845
- pt << owner
1846
- end
1847
- end
1848
- end
1849
-
1850
- when nil
1851
- # It's a root type
1852
- own_types[type.graphql_name] = type
1853
- when GraphQL::Schema::Field, GraphQL::Schema::Argument
1854
- orig_type = owner.type
1855
- # Apply list/non-null wrapper as needed
1856
- if orig_type.respond_to?(:of_type)
1857
- transforms = []
1858
- while (orig_type.respond_to?(:of_type))
1859
- if orig_type.kind.non_null?
1860
- transforms << :to_non_null_type
1861
- elsif orig_type.kind.list?
1862
- transforms << :to_list_type
1863
- else
1864
- raise "Invariant: :of_type isn't non-null or list"
1865
- end
1866
- orig_type = orig_type.of_type
1867
- end
1868
- transforms.reverse_each { |t| type = type.public_send(t) }
1869
- end
1870
- owner.type = type
1871
- else
1872
- raise "Unexpected update: #{owner.inspect} #{type.inspect}"
1873
- end
1874
- end
1875
-
1876
- def add_type(type, owner:, late_types:, path:)
1877
- if type.respond_to?(:metadata) && type.metadata.is_a?(Hash)
1878
- type_class = type.metadata[:type_class]
1879
- if type_class.nil?
1880
- raise ArgumentError, "Can't add legacy type: #{type} (#{type.class})"
1881
- else
1882
- type = type_class
1883
- end
1884
- elsif type.is_a?(String) || type.is_a?(GraphQL::Schema::LateBoundType)
1885
- late_types << [owner, type]
1886
- return
1887
- end
1888
-
1889
- if owner.is_a?(Class) && owner < GraphQL::Schema::Union
1890
- um = own_union_memberships[type.graphql_name] ||= []
1891
- um << owner
1892
- end
1893
-
1894
- if (prev_type = own_types[type.graphql_name])
1895
- if prev_type != type
1896
- raise DuplicateTypeNamesError.new(
1897
- type_name: type.graphql_name,
1898
- first_definition: prev_type,
1899
- second_definition: type,
1900
- path: path,
1901
- )
1902
- else
1903
- # This type was already added
1904
- end
1905
- elsif type.is_a?(Class) && type < GraphQL::Schema::Directive
1906
- type.arguments.each do |name, arg|
1907
- arg_type = arg.type.unwrap
1908
- references_to(arg_type, from: arg)
1909
- add_type(arg_type, owner: arg, late_types: late_types, path: path + [name])
1910
- end
1911
- else
1912
- own_types[type.graphql_name] = type
1913
- add_directives_from(type)
1914
- if type.kind.fields?
1915
- type.fields.each do |name, field|
1916
- field_type = field.type.unwrap
1917
- references_to(field_type, from: field)
1918
- field_path = path + [name]
1919
- add_type(field_type, owner: field, late_types: late_types, path: field_path)
1920
- add_directives_from(field)
1921
- field.arguments.each do |arg_name, arg|
1922
- add_directives_from(arg)
1923
- arg_type = arg.type.unwrap
1924
- references_to(arg_type, from: arg)
1925
- add_type(arg_type, owner: arg, late_types: late_types, path: field_path + [arg_name])
1926
- end
1927
- end
1928
- end
1929
- if type.kind.input_object?
1930
- type.arguments.each do |arg_name, arg|
1931
- add_directives_from(arg)
1932
- arg_type = arg.type.unwrap
1933
- references_to(arg_type, from: arg)
1934
- add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg_name])
1935
- end
1936
- end
1937
- if type.kind.union?
1938
- own_possible_types[type.graphql_name] = type.possible_types
1939
- type.possible_types.each do |t|
1940
- add_type(t, owner: type, late_types: late_types, path: path + ["possible_types"])
1941
- end
1942
- end
1943
- if type.kind.interface?
1944
- type.orphan_types.each do |t|
1945
- add_type(t, owner: type, late_types: late_types, path: path + ["orphan_types"])
1946
- end
1947
- end
1948
- if type.kind.object?
1949
- own_possible_types[type.graphql_name] = [type]
1950
- type.interface_type_memberships.each do |interface_type_membership|
1951
- case interface_type_membership
1952
- when Schema::TypeMembership
1953
- interface_type = interface_type_membership.abstract_type
1954
- # We can get these now; we'll have to get late-bound types later
1955
- if interface_type.is_a?(Module)
1956
- implementers = own_possible_types[interface_type.graphql_name] ||= []
1957
- implementers << type
1958
- end
1959
- when String, Schema::LateBoundType
1960
- interface_type = interface_type_membership
1961
- else
1962
- raise ArgumentError, "Invariant: unexpected type membership for #{type.graphql_name}: #{interface_type_membership.class} (#{interface_type_membership.inspect})"
1963
- end
1964
- add_type(interface_type, owner: type, late_types: late_types, path: path + ["implements"])
1965
- end
1966
- end
1967
- end
1968
- end
1969
-
1970
- def add_directives_from(owner)
1971
- owner.directives.each { |dir| directive(dir.class) }
1972
- end
1973
1908
  end
1974
1909
 
1975
1910
  def dataloader_class
@@ -33,6 +33,7 @@ module GraphQL
33
33
  GraphQL::StaticValidation::VariablesAreUsedAndDefined,
34
34
  GraphQL::StaticValidation::VariableUsagesAreAllowed,
35
35
  GraphQL::StaticValidation::MutationRootExists,
36
+ GraphQL::StaticValidation::QueryRootExists,
36
37
  GraphQL::StaticValidation::SubscriptionRootExists,
37
38
  GraphQL::StaticValidation::InputObjectNamesAreUnique,
38
39
  ]
@@ -94,7 +94,7 @@ module GraphQL
94
94
 
95
95
  def on_field(node, parent)
96
96
  parent_type = @object_types.last
97
- field_definition = @schema.get_field(parent_type, node.name)
97
+ field_definition = @schema.get_field(parent_type, node.name, @context.query.context)
98
98
  @field_definitions.push(field_definition)
99
99
  if !field_definition.nil?
100
100
  next_object_type = field_definition.type.unwrap
@@ -120,14 +120,14 @@ module GraphQL
120
120
  argument_defn = if (arg = @argument_definitions.last)
121
121
  arg_type = arg.type.unwrap
122
122
  if arg_type.kind.input_object?
123
- arg_type.arguments[node.name]
123
+ @context.warden.get_argument(arg_type, node.name)
124
124
  else
125
125
  nil
126
126
  end
127
127
  elsif (directive_defn = @directive_definitions.last)
128
- directive_defn.arguments[node.name]
128
+ @context.warden.get_argument(directive_defn, node.name)
129
129
  elsif (field_defn = @field_definitions.last)
130
- field_defn.arguments[node.name]
130
+ @context.warden.get_argument(field_defn, node.name)
131
131
  else
132
132
  nil
133
133
  end
@@ -187,7 +187,7 @@ module GraphQL
187
187
 
188
188
  def on_fragment_with_type(node)
189
189
  object_type = if node.type
190
- @schema.get_type(node.type.name)
190
+ @context.warden.get_type(node.type.name)
191
191
  else
192
192
  @object_types.last
193
193
  end
@@ -205,6 +205,9 @@ module GraphQL
205
205
  private
206
206
 
207
207
  def add_error(error, path: nil)
208
+ if @context.too_many_errors?
209
+ throw :too_many_validation_errors
210
+ end
208
211
  error.path ||= (path || @path.dup)
209
212
  context.errors << error
210
213
  end
@@ -70,7 +70,6 @@ module GraphQL
70
70
  @dependency_map ||= resolve_dependencies(&block)
71
71
  end
72
72
 
73
-
74
73
  # Map definition AST nodes to the definition AST nodes they depend on.
75
74
  # Expose circular dependencies.
76
75
  class DependencyMap
@@ -32,8 +32,10 @@ module GraphQL
32
32
 
33
33
  private
34
34
 
35
+ attr_reader :nodes
36
+
35
37
  def locations
36
- @nodes.map do |node|
38
+ nodes.map do |node|
37
39
  h = {"line" => node.line, "column" => node.col}
38
40
  h["filename"] = node.filename if node.filename
39
41
  h
@@ -95,7 +95,7 @@ module GraphQL
95
95
  def required_input_fields_are_present(type, ast_node)
96
96
  # TODO - would be nice to use these to create an error message so the caller knows
97
97
  # that required fields are missing
98
- required_field_names = type.arguments.each_value
98
+ required_field_names = @warden.arguments(type)
99
99
  .select { |argument| argument.type.kind.non_null? && @warden.get_argument(type, argument.name) }
100
100
  .map(&:name)
101
101
 
@@ -15,7 +15,7 @@ module GraphQL
15
15
  if @context.schema.error_bubbling || context.errors.none? { |err| err.path.take(@path.size) == @path }
16
16
  parent_defn = parent_definition(parent)
17
17
 
18
- if parent_defn && (arg_defn = parent_defn.arguments[node.name])
18
+ if parent_defn && (arg_defn = context.warden.get_argument(parent_defn, node.name))
19
19
  validation_result = context.validate_literal(node.value, arg_defn.type)
20
20
  if !validation_result.valid?
21
21
  kind_of_node = node_type(parent)