graphql 1.12.16 → 1.13.2
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.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +3 -1
- data/lib/generators/graphql/install_generator.rb +9 -2
- data/lib/generators/graphql/mutation_generator.rb +1 -1
- data/lib/generators/graphql/object_generator.rb +2 -1
- data/lib/generators/graphql/relay.rb +19 -11
- data/lib/generators/graphql/templates/schema.erb +14 -2
- data/lib/generators/graphql/type_generator.rb +0 -1
- data/lib/graphql/analysis/ast/field_usage.rb +3 -3
- data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
- data/lib/graphql/analysis/ast/visitor.rb +4 -4
- data/lib/graphql/backtrace/table.rb +1 -1
- data/lib/graphql/base_type.rb +4 -2
- data/lib/graphql/boolean_type.rb +1 -1
- data/lib/graphql/dataloader/source.rb +50 -2
- data/lib/graphql/dataloader.rb +93 -37
- data/lib/graphql/define/instance_definable.rb +1 -1
- data/lib/graphql/deprecated_dsl.rb +11 -3
- data/lib/graphql/deprecation.rb +1 -5
- data/lib/graphql/directive/deprecated_directive.rb +1 -1
- data/lib/graphql/directive/include_directive.rb +1 -1
- data/lib/graphql/directive/skip_directive.rb +1 -1
- data/lib/graphql/directive.rb +0 -4
- data/lib/graphql/enum_type.rb +5 -1
- data/lib/graphql/execution/errors.rb +1 -0
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -2
- data/lib/graphql/execution/interpreter/runtime.rb +39 -23
- data/lib/graphql/execution/lookahead.rb +2 -2
- data/lib/graphql/execution/multiplex.rb +4 -1
- data/lib/graphql/float_type.rb +1 -1
- data/lib/graphql/id_type.rb +1 -1
- data/lib/graphql/int_type.rb +1 -1
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +2 -2
- data/lib/graphql/introspection/input_value_type.rb +10 -4
- data/lib/graphql/introspection/schema_type.rb +2 -2
- data/lib/graphql/introspection/type_type.rb +10 -10
- data/lib/graphql/language/block_string.rb +2 -6
- data/lib/graphql/language/document_from_schema_definition.rb +4 -2
- data/lib/graphql/language/lexer.rb +0 -3
- data/lib/graphql/language/lexer.rl +0 -4
- data/lib/graphql/language/nodes.rb +12 -2
- data/lib/graphql/language/parser.rb +442 -434
- data/lib/graphql/language/parser.y +5 -4
- data/lib/graphql/language/printer.rb +6 -1
- data/lib/graphql/language/sanitized_printer.rb +5 -5
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/pagination/connections.rb +35 -16
- data/lib/graphql/query/arguments.rb +1 -1
- data/lib/graphql/query/arguments_cache.rb +1 -1
- data/lib/graphql/query/context.rb +15 -2
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/query/null_context.rb +12 -7
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/query/variables.rb +5 -1
- data/lib/graphql/query.rb +4 -0
- data/lib/graphql/relay/edges_instrumentation.rb +0 -1
- data/lib/graphql/relay/global_id_resolve.rb +1 -1
- data/lib/graphql/relay/page_info.rb +1 -1
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/schema/addition.rb +37 -28
- data/lib/graphql/schema/argument.rb +79 -34
- data/lib/graphql/schema/build_from_definition.rb +5 -5
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +2 -2
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +7 -3
- data/lib/graphql/schema/enum.rb +60 -10
- data/lib/graphql/schema/enum_value.rb +6 -0
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +140 -42
- data/lib/graphql/schema/field_extension.rb +52 -2
- data/lib/graphql/schema/find_inherited_value.rb +1 -0
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/input_object.rb +13 -14
- data/lib/graphql/schema/interface.rb +11 -20
- data/lib/graphql/schema/introspection_system.rb +1 -1
- data/lib/graphql/schema/list.rb +3 -1
- data/lib/graphql/schema/member/accepts_definition.rb +15 -3
- data/lib/graphql/schema/member/build_type.rb +0 -4
- data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
- data/lib/graphql/schema/member/has_arguments.rb +145 -57
- data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +76 -18
- data/lib/graphql/schema/member/has_interfaces.rb +90 -0
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/non_null.rb +3 -1
- data/lib/graphql/schema/object.rb +10 -75
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/schema/relay_classic_mutation.rb +37 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
- data/lib/graphql/schema/resolver.rb +49 -64
- data/lib/graphql/schema/scalar.rb +2 -0
- data/lib/graphql/schema/subscription.rb +17 -9
- data/lib/graphql/schema/traversal.rb +1 -1
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +18 -4
- data/lib/graphql/schema/union.rb +8 -1
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/format_validator.rb +4 -5
- data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/length_validator.rb +5 -3
- data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
- data/lib/graphql/schema/validator.rb +33 -25
- data/lib/graphql/schema/warden.rb +116 -52
- data/lib/graphql/schema.rb +124 -27
- data/lib/graphql/static_validation/base_visitor.rb +8 -5
- data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +52 -26
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -1
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +7 -7
- data/lib/graphql/static_validation/validation_context.rb +8 -2
- data/lib/graphql/static_validation/validator.rb +15 -12
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/string_type.rb +1 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +15 -5
- data/lib/graphql/subscriptions/event.rb +66 -13
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +17 -19
- data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
- data/lib/graphql/types/int.rb +1 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +26 -9
- data/lib/graphql/types/relay/default_relay.rb +5 -1
- data/lib/graphql/types/relay/edge_behaviors.rb +13 -2
- data/lib/graphql/types/relay/has_node_field.rb +1 -1
- data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +10 -32
- data/readme.md +1 -1
- metadata +13 -6
data/lib/graphql/schema.rb
CHANGED
@@ -92,6 +92,8 @@ module GraphQL
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
+
class DuplicateNamesError < GraphQL::Error; end
|
96
|
+
|
95
97
|
class UnresolvedLateBoundTypeError < GraphQL::Error
|
96
98
|
attr_reader :type
|
97
99
|
def initialize(type:)
|
@@ -161,7 +163,7 @@ module GraphQL
|
|
161
163
|
|
162
164
|
accepts_definitions \
|
163
165
|
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
164
|
-
:validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
|
166
|
+
:validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
|
165
167
|
:orphan_types, :resolve_type, :type_error, :parse_error,
|
166
168
|
:error_bubbling,
|
167
169
|
:raise_definition_error,
|
@@ -200,7 +202,7 @@ module GraphQL
|
|
200
202
|
attr_accessor \
|
201
203
|
:query, :mutation, :subscription,
|
202
204
|
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
203
|
-
:validate_timeout, :max_depth, :max_complexity, :default_max_page_size,
|
205
|
+
:validate_timeout, :validate_max_errors, :max_depth, :max_complexity, :default_max_page_size,
|
204
206
|
:orphan_types, :directives,
|
205
207
|
:query_analyzers, :multiplex_analyzers, :instrumenters, :lazy_methods,
|
206
208
|
:cursor_encoder,
|
@@ -552,7 +554,7 @@ module GraphQL
|
|
552
554
|
end
|
553
555
|
end
|
554
556
|
|
555
|
-
# @see [GraphQL::Schema::Warden]
|
557
|
+
# @see [GraphQL::Schema::Warden] Restricted access to root types
|
556
558
|
# @return [GraphQL::ObjectType, nil]
|
557
559
|
def root_type_for_operation(operation)
|
558
560
|
case operation
|
@@ -843,7 +845,7 @@ module GraphQL
|
|
843
845
|
# - Cause the Schema instance to be created, if it hasn't been created yet
|
844
846
|
# - Delegate to that instance
|
845
847
|
# Eventually, the methods will be moved into this class, removing the need for the singleton.
|
846
|
-
def_delegators :
|
848
|
+
def_delegators :deprecated_graphql_definition,
|
847
849
|
# Execution
|
848
850
|
:execution_strategy_for_operation,
|
849
851
|
# Configuration
|
@@ -852,6 +854,10 @@ module GraphQL
|
|
852
854
|
:id_from_object=, :object_from_id=,
|
853
855
|
:remove_handler
|
854
856
|
|
857
|
+
def deprecated_graphql_definition
|
858
|
+
graphql_definition(silence_deprecation_warning: true)
|
859
|
+
end
|
860
|
+
|
855
861
|
# @return [GraphQL::Subscriptions]
|
856
862
|
attr_accessor :subscriptions
|
857
863
|
|
@@ -894,8 +900,15 @@ module GraphQL
|
|
894
900
|
@find_cache[path] ||= @finder.find(path)
|
895
901
|
end
|
896
902
|
|
897
|
-
def graphql_definition
|
898
|
-
@graphql_definition ||=
|
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
|
899
912
|
end
|
900
913
|
|
901
914
|
def default_filter
|
@@ -927,18 +940,20 @@ module GraphQL
|
|
927
940
|
find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
|
928
941
|
end
|
929
942
|
|
943
|
+
prepend Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
|
930
944
|
def to_graphql
|
931
945
|
schema_defn = self.new
|
932
946
|
schema_defn.raise_definition_error = true
|
933
|
-
schema_defn.query = query && query.graphql_definition
|
934
|
-
schema_defn.mutation = mutation && mutation.graphql_definition
|
935
|
-
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)
|
936
950
|
schema_defn.validate_timeout = validate_timeout
|
951
|
+
schema_defn.validate_max_errors = validate_max_errors
|
937
952
|
schema_defn.max_complexity = max_complexity
|
938
953
|
schema_defn.error_bubbling = error_bubbling
|
939
954
|
schema_defn.max_depth = max_depth
|
940
955
|
schema_defn.default_max_page_size = default_max_page_size
|
941
|
-
schema_defn.orphan_types = orphan_types.map(
|
956
|
+
schema_defn.orphan_types = orphan_types.map { |t| t.graphql_definition(silence_deprecation_warning: true) }
|
942
957
|
schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
|
943
958
|
schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
|
944
959
|
schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
|
@@ -995,16 +1010,58 @@ module GraphQL
|
|
995
1010
|
# Build a map of `{ name => type }` and return it
|
996
1011
|
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
997
1012
|
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
998
|
-
def types
|
999
|
-
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
|
1000
1034
|
end
|
1001
1035
|
|
1002
1036
|
# @param type_name [String]
|
1003
1037
|
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
1004
|
-
def get_type(type_name)
|
1005
|
-
own_types[type_name]
|
1006
|
-
|
1007
|
-
|
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)
|
1008
1065
|
end
|
1009
1066
|
|
1010
1067
|
# @api private
|
@@ -1073,7 +1130,7 @@ module GraphQL
|
|
1073
1130
|
end
|
1074
1131
|
end
|
1075
1132
|
|
1076
|
-
# @see [GraphQL::Schema::Warden]
|
1133
|
+
# @see [GraphQL::Schema::Warden] Restricted access to root types
|
1077
1134
|
# @return [GraphQL::ObjectType, nil]
|
1078
1135
|
def root_type_for_operation(operation)
|
1079
1136
|
case operation
|
@@ -1181,19 +1238,19 @@ module GraphQL
|
|
1181
1238
|
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
1182
1239
|
end
|
1183
1240
|
|
1184
|
-
def get_field(type_or_name, field_name)
|
1241
|
+
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
|
1185
1242
|
parent_type = case type_or_name
|
1186
1243
|
when LateBoundType
|
1187
|
-
get_type(type_or_name.name)
|
1244
|
+
get_type(type_or_name.name, context)
|
1188
1245
|
when String
|
1189
|
-
get_type(type_or_name)
|
1246
|
+
get_type(type_or_name, context)
|
1190
1247
|
when Module
|
1191
1248
|
type_or_name
|
1192
1249
|
else
|
1193
1250
|
raise ArgumentError, "unexpected field owner for #{field_name.inspect}: #{type_or_name.inspect} (#{type_or_name.class})"
|
1194
1251
|
end
|
1195
1252
|
|
1196
|
-
if parent_type.kind.fields? && (field = parent_type.get_field(field_name))
|
1253
|
+
if parent_type.kind.fields? && (field = parent_type.get_field(field_name, context))
|
1197
1254
|
field
|
1198
1255
|
elsif parent_type == query && (entry_point_field = introspection_system.entry_point(name: field_name))
|
1199
1256
|
entry_point_field
|
@@ -1204,8 +1261,8 @@ module GraphQL
|
|
1204
1261
|
end
|
1205
1262
|
end
|
1206
1263
|
|
1207
|
-
def get_fields(type)
|
1208
|
-
type.fields
|
1264
|
+
def get_fields(type, context = GraphQL::Query::NullContext)
|
1265
|
+
type.fields(context)
|
1209
1266
|
end
|
1210
1267
|
|
1211
1268
|
def introspection(new_introspection_namespace = nil)
|
@@ -1290,10 +1347,22 @@ module GraphQL
|
|
1290
1347
|
validator_opts = { schema: self }
|
1291
1348
|
rules && (validator_opts[:rules] = rules)
|
1292
1349
|
validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
|
1293
|
-
res = validator.validate(query, timeout: validate_timeout)
|
1350
|
+
res = validator.validate(query, timeout: validate_timeout, max_errors: validate_max_errors)
|
1294
1351
|
res[:errors]
|
1295
1352
|
end
|
1296
1353
|
|
1354
|
+
attr_writer :validate_max_errors
|
1355
|
+
|
1356
|
+
def validate_max_errors(new_validate_max_errors = nil)
|
1357
|
+
if new_validate_max_errors
|
1358
|
+
@validate_max_errors = new_validate_max_errors
|
1359
|
+
elsif defined?(@validate_max_errors)
|
1360
|
+
@validate_max_errors
|
1361
|
+
else
|
1362
|
+
find_inherited_value(:validate_max_errors)
|
1363
|
+
end
|
1364
|
+
end
|
1365
|
+
|
1297
1366
|
attr_writer :max_complexity
|
1298
1367
|
|
1299
1368
|
def max_complexity(max_complexity = nil)
|
@@ -1392,7 +1461,6 @@ module GraphQL
|
|
1392
1461
|
if new_orphan_types.any?
|
1393
1462
|
new_orphan_types = new_orphan_types.flatten
|
1394
1463
|
add_type_and_traverse(new_orphan_types, root: false)
|
1395
|
-
@orphan_types = new_orphan_types
|
1396
1464
|
own_orphan_types.concat(new_orphan_types.flatten)
|
1397
1465
|
end
|
1398
1466
|
|
@@ -1702,7 +1770,7 @@ module GraphQL
|
|
1702
1770
|
if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
|
1703
1771
|
GraphQL::Deprecation.warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
|
1704
1772
|
else
|
1705
|
-
subscription.
|
1773
|
+
subscription.all_field_definitions.each do |field|
|
1706
1774
|
field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
|
1707
1775
|
end
|
1708
1776
|
end
|
@@ -1724,7 +1792,36 @@ module GraphQL
|
|
1724
1792
|
end
|
1725
1793
|
new_types = Array(t)
|
1726
1794
|
addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
|
1727
|
-
|
1795
|
+
addition.types.each do |name, types_entry| # rubocop:disable Development/ContextIsPassedCop -- build-time, not query-time
|
1796
|
+
if (prev_entry = own_types[name])
|
1797
|
+
prev_entries = case prev_entry
|
1798
|
+
when Array
|
1799
|
+
prev_entry
|
1800
|
+
when Module
|
1801
|
+
own_types[name] = [prev_entry]
|
1802
|
+
else
|
1803
|
+
raise "Invariant: unexpected prev_entry at #{name.inspect} when adding #{t.inspect}"
|
1804
|
+
end
|
1805
|
+
|
1806
|
+
case types_entry
|
1807
|
+
when Array
|
1808
|
+
prev_entries.concat(types_entry)
|
1809
|
+
prev_entries.uniq! # in case any are being re-visited
|
1810
|
+
when Module
|
1811
|
+
if !prev_entries.include?(types_entry)
|
1812
|
+
prev_entries << types_entry
|
1813
|
+
end
|
1814
|
+
else
|
1815
|
+
raise "Invariant: unexpected types_entry at #{name} when adding #{t.inspect}"
|
1816
|
+
end
|
1817
|
+
else
|
1818
|
+
if types_entry.is_a?(Array)
|
1819
|
+
types_entry.uniq!
|
1820
|
+
end
|
1821
|
+
own_types[name] = types_entry
|
1822
|
+
end
|
1823
|
+
end
|
1824
|
+
|
1728
1825
|
own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
|
1729
1826
|
own_union_memberships.merge!(addition.union_memberships)
|
1730
1827
|
|
@@ -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
|
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
|
128
|
+
@context.warden.get_argument(directive_defn, node.name)
|
129
129
|
elsif (field_defn = @field_definitions.last)
|
130
|
-
field_defn
|
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
|
-
@
|
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
|
@@ -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 =
|
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
|
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)
|
@@ -10,6 +10,7 @@ module GraphQL
|
|
10
10
|
#
|
11
11
|
# Original Algorithm: https://github.com/graphql/graphql-js/blob/master/src/validation/rules/OverlappingFieldsCanBeMerged.js
|
12
12
|
NO_ARGS = {}.freeze
|
13
|
+
|
13
14
|
Field = Struct.new(:node, :definition, :owner_type, :parents)
|
14
15
|
FragmentSpread = Struct.new(:name, :parents)
|
15
16
|
|
@@ -17,24 +18,47 @@ module GraphQL
|
|
17
18
|
super
|
18
19
|
@visited_fragments = {}
|
19
20
|
@compared_fragments = {}
|
21
|
+
@conflict_count = 0
|
20
22
|
end
|
21
23
|
|
22
24
|
def on_operation_definition(node, _parent)
|
23
|
-
conflicts_within_selection_set(node, type_definition)
|
25
|
+
setting_errors { conflicts_within_selection_set(node, type_definition) }
|
24
26
|
super
|
25
27
|
end
|
26
28
|
|
27
29
|
def on_field(node, _parent)
|
28
|
-
conflicts_within_selection_set(node, type_definition)
|
30
|
+
setting_errors { conflicts_within_selection_set(node, type_definition) }
|
29
31
|
super
|
30
32
|
end
|
31
33
|
|
32
34
|
private
|
33
35
|
|
36
|
+
def field_conflicts
|
37
|
+
@field_conflicts ||= Hash.new do |errors, field|
|
38
|
+
errors[field] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: :field, field_name: field)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def arg_conflicts
|
43
|
+
@arg_conflicts ||= Hash.new do |errors, field|
|
44
|
+
errors[field] = GraphQL::StaticValidation::FieldsWillMergeError.new(kind: :argument, field_name: field)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def setting_errors
|
49
|
+
@field_conflicts = nil
|
50
|
+
@arg_conflicts = nil
|
51
|
+
|
52
|
+
yield
|
53
|
+
# don't initialize these if they weren't initialized in the block:
|
54
|
+
@field_conflicts && @field_conflicts.each_value { |error| add_error(error) }
|
55
|
+
@arg_conflicts && @arg_conflicts.each_value { |error| add_error(error) }
|
56
|
+
end
|
57
|
+
|
34
58
|
def conflicts_within_selection_set(node, parent_type)
|
35
59
|
return if parent_type.nil?
|
36
60
|
|
37
|
-
fields, fragment_spreads = fields_and_fragments_from_selection(node, owner_type: parent_type, parents:
|
61
|
+
fields, fragment_spreads = fields_and_fragments_from_selection(node, owner_type: parent_type, parents: nil)
|
38
62
|
|
39
63
|
# (A) Find find all conflicts "within" the fields of this selection set.
|
40
64
|
find_conflicts_within(fields)
|
@@ -174,15 +198,21 @@ module GraphQL
|
|
174
198
|
response_keys.each do |key, fields|
|
175
199
|
next if fields.size < 2
|
176
200
|
# find conflicts within nodes
|
177
|
-
|
178
|
-
|
201
|
+
i = 0
|
202
|
+
while i < fields.size
|
203
|
+
j = i + 1
|
204
|
+
while j < fields.size
|
179
205
|
find_conflict(key, fields[i], fields[j])
|
206
|
+
j += 1
|
180
207
|
end
|
208
|
+
i += 1
|
181
209
|
end
|
182
210
|
end
|
183
211
|
end
|
184
212
|
|
185
213
|
def find_conflict(response_key, field1, field2, mutually_exclusive: false)
|
214
|
+
return if @conflict_count >= context.max_errors
|
215
|
+
|
186
216
|
node1 = field1.node
|
187
217
|
node2 = field2.node
|
188
218
|
|
@@ -191,28 +221,21 @@ module GraphQL
|
|
191
221
|
|
192
222
|
if !are_mutually_exclusive
|
193
223
|
if node1.name != node2.name
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
field_name: response_key,
|
201
|
-
conflicts: errored_nodes
|
202
|
-
)
|
224
|
+
conflict = field_conflicts[response_key]
|
225
|
+
|
226
|
+
conflict.add_conflict(node1, node1.name)
|
227
|
+
conflict.add_conflict(node2, node2.name)
|
228
|
+
|
229
|
+
@conflict_count += 1
|
203
230
|
end
|
204
231
|
|
205
232
|
if !same_arguments?(node1, node2)
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
path: [],
|
213
|
-
field_name: response_key,
|
214
|
-
conflicts: conflicts
|
215
|
-
)
|
233
|
+
conflict = arg_conflicts[response_key]
|
234
|
+
|
235
|
+
conflict.add_conflict(node1, GraphQL::Language.serialize(serialize_field_args(node1)))
|
236
|
+
conflict.add_conflict(node2, GraphQL::Language.serialize(serialize_field_args(node2)))
|
237
|
+
|
238
|
+
@conflict_count += 1
|
216
239
|
end
|
217
240
|
end
|
218
241
|
|
@@ -224,7 +247,9 @@ module GraphQL
|
|
224
247
|
end
|
225
248
|
|
226
249
|
def find_conflicts_between_sub_selection_sets(field1, field2, mutually_exclusive:)
|
227
|
-
return if field1.definition.nil? ||
|
250
|
+
return if field1.definition.nil? ||
|
251
|
+
field2.definition.nil? ||
|
252
|
+
(field1.node.selections.empty? && field2.node.selections.empty?)
|
228
253
|
|
229
254
|
return_type1 = field1.definition.type.unwrap
|
230
255
|
return_type2 = field2.definition.type.unwrap
|
@@ -304,6 +329,7 @@ module GraphQL
|
|
304
329
|
if node.selections.empty?
|
305
330
|
NO_SELECTIONS
|
306
331
|
else
|
332
|
+
parents ||= []
|
307
333
|
fields, fragment_spreads = find_fields_and_fragments(node.selections, owner_type: owner_type, parents: parents, fields: [], fragment_spreads: [])
|
308
334
|
response_keys = fields.group_by { |f| f.node.alias || f.node.name }
|
309
335
|
[response_keys, fragment_spreads]
|
@@ -314,7 +340,7 @@ module GraphQL
|
|
314
340
|
selections.each do |node|
|
315
341
|
case node
|
316
342
|
when GraphQL::Language::Nodes::Field
|
317
|
-
definition = context.
|
343
|
+
definition = context.query.get_field(owner_type, node.name)
|
318
344
|
fields << Field.new(node, definition, owner_type, parents)
|
319
345
|
when GraphQL::Language::Nodes::InlineFragment
|
320
346
|
fragment_type = node.type ? context.warden.get_type(node.type.name) : owner_type
|
@@ -3,12 +3,33 @@ module GraphQL
|
|
3
3
|
module StaticValidation
|
4
4
|
class FieldsWillMergeError < StaticValidation::Error
|
5
5
|
attr_reader :field_name
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :kind
|
7
|
+
|
8
|
+
def initialize(kind:, field_name:)
|
9
|
+
super(nil)
|
7
10
|
|
8
|
-
def initialize(message, path: nil, nodes: [], field_name:, conflicts:)
|
9
|
-
super(message, path: path, nodes: nodes)
|
10
11
|
@field_name = field_name
|
11
|
-
@
|
12
|
+
@kind = kind
|
13
|
+
@conflicts = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def message
|
17
|
+
"Field '#{field_name}' has #{kind == :argument ? 'an' : 'a'} #{kind} conflict: #{conflicts}?"
|
18
|
+
end
|
19
|
+
|
20
|
+
def path
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
|
24
|
+
def conflicts
|
25
|
+
@conflicts.join(' or ')
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_conflict(node, conflict_str)
|
29
|
+
return if nodes.include?(node)
|
30
|
+
|
31
|
+
@nodes << node
|
32
|
+
@conflicts << conflict_str
|
12
33
|
end
|
13
34
|
|
14
35
|
# A hash representation of this Message
|
@@ -7,12 +7,12 @@ module GraphQL
|
|
7
7
|
dependency_map = context.dependencies
|
8
8
|
dependency_map.cyclical_definitions.each do |defn|
|
9
9
|
if defn.node.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
|
10
|
-
|
10
|
+
add_error(GraphQL::StaticValidation::FragmentsAreFiniteError.new(
|
11
11
|
"Fragment #{defn.name} contains an infinite loop",
|
12
12
|
nodes: defn.node,
|
13
13
|
path: defn.path,
|
14
14
|
name: defn.name
|
15
|
-
)
|
15
|
+
))
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -16,8 +16,10 @@ module GraphQL
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def assert_required_args(ast_node, defn)
|
19
|
+
args = defn.arguments(context.query.context)
|
20
|
+
return if args.empty?
|
19
21
|
present_argument_names = ast_node.arguments.map(&:name)
|
20
|
-
required_argument_names =
|
22
|
+
required_argument_names = context.warden.arguments(defn)
|
21
23
|
.select { |a| a.type.kind.non_null? && !a.default_value? && context.warden.get_argument(defn, a.name) }
|
22
24
|
.map(&:name)
|
23
25
|
|
@@ -34,16 +34,16 @@ module GraphQL
|
|
34
34
|
parent_type = get_parent_type(context, parent)
|
35
35
|
return unless parent_type && parent_type.kind.input_object?
|
36
36
|
|
37
|
-
required_fields =
|
38
|
-
.select{|
|
39
|
-
.
|
37
|
+
required_fields = context.warden.arguments(parent_type)
|
38
|
+
.select{|arg| arg.type.kind.non_null?}
|
39
|
+
.map(&:graphql_name)
|
40
40
|
|
41
41
|
present_fields = ast_node.arguments.map(&:name)
|
42
42
|
missing_fields = required_fields - present_fields
|
43
43
|
|
44
44
|
missing_fields.each do |missing_field|
|
45
45
|
path = [*context.path, missing_field]
|
46
|
-
missing_field_type = parent_type
|
46
|
+
missing_field_type = context.warden.get_argument(parent_type, missing_field).type
|
47
47
|
add_error(RequiredInputObjectAttributesArePresentError.new(
|
48
48
|
"Argument '#{missing_field}' on InputObject '#{parent_type.to_type_signature}' is required. Expected type #{missing_field_type.to_type_signature}",
|
49
49
|
argument_name: missing_field,
|
@@ -22,15 +22,15 @@ module GraphQL
|
|
22
22
|
node_values = node_values.select { |value| value.is_a? GraphQL::Language::Nodes::VariableIdentifier }
|
23
23
|
|
24
24
|
if node_values.any?
|
25
|
-
|
25
|
+
argument_owner = case parent
|
26
26
|
when GraphQL::Language::Nodes::Field
|
27
|
-
context.field_definition
|
27
|
+
context.field_definition
|
28
28
|
when GraphQL::Language::Nodes::Directive
|
29
|
-
context.directive_definition
|
29
|
+
context.directive_definition
|
30
30
|
when GraphQL::Language::Nodes::InputObject
|
31
31
|
arg_type = context.argument_definition.type.unwrap
|
32
32
|
if arg_type.kind.input_object?
|
33
|
-
|
33
|
+
arg_type
|
34
34
|
else
|
35
35
|
# This is some kind of error
|
36
36
|
nil
|
@@ -43,7 +43,7 @@ module GraphQL
|
|
43
43
|
var_defn_ast = @declared_variables[node_value.name]
|
44
44
|
# Might be undefined :(
|
45
45
|
# VariablesAreUsedAndDefined can't finalize its search until the end of the document.
|
46
|
-
var_defn_ast &&
|
46
|
+
var_defn_ast && argument_owner && validate_usage(argument_owner, node, var_defn_ast)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
super
|
@@ -51,7 +51,7 @@ module GraphQL
|
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
|
-
def validate_usage(
|
54
|
+
def validate_usage(argument_owner, arg_node, ast_var)
|
55
55
|
var_type = context.schema.type_from_ast(ast_var.type, context: context)
|
56
56
|
if var_type.nil?
|
57
57
|
return
|
@@ -65,7 +65,7 @@ module GraphQL
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
arg_defn =
|
68
|
+
arg_defn = context.warden.get_argument(argument_owner, arg_node.name)
|
69
69
|
arg_defn_type = arg_defn.type
|
70
70
|
|
71
71
|
var_inner_type = var_type.unwrap
|