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
@@ -18,10 +18,6 @@ module GraphQL
|
|
18
18
|
# # It's pretty hard to come up with a legitimate use case for `without:`
|
19
19
|
#
|
20
20
|
class FormatValidator < Validator
|
21
|
-
if !String.method_defined?(:match?)
|
22
|
-
using GraphQL::StringMatchBackport
|
23
|
-
end
|
24
|
-
|
25
21
|
# @param with [RegExp, nil]
|
26
22
|
# @param without [Regexp, nil]
|
27
23
|
# @param message [String]
|
@@ -38,7 +34,10 @@ module GraphQL
|
|
38
34
|
end
|
39
35
|
|
40
36
|
def validate(_object, _context, value)
|
41
|
-
if (
|
37
|
+
if permitted_empty_value?(value)
|
38
|
+
# Do nothing
|
39
|
+
elsif value.nil? ||
|
40
|
+
(@with_pattern && !value.match?(@with_pattern)) ||
|
42
41
|
(@without_pattern && value.match?(@without_pattern))
|
43
42
|
@message
|
44
43
|
end
|
@@ -43,11 +43,13 @@ module GraphQL
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def validate(_object, _context, value)
|
46
|
-
if
|
46
|
+
return if permitted_empty_value?(value) # pass in this case
|
47
|
+
length = value.nil? ? 0 : value.length
|
48
|
+
if @maximum && length > @maximum
|
47
49
|
partial_format(@too_long, { count: @maximum })
|
48
|
-
elsif @minimum &&
|
50
|
+
elsif @minimum && length < @minimum
|
49
51
|
partial_format(@too_short, { count: @minimum })
|
50
|
-
elsif @is &&
|
52
|
+
elsif @is && length != @is
|
51
53
|
partial_format(@wrong_length, { count: @is })
|
52
54
|
end
|
53
55
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module GraphQL
|
2
3
|
class Schema
|
3
4
|
class Validator
|
@@ -24,13 +25,15 @@ module GraphQL
|
|
24
25
|
# @param other_than [Integer]
|
25
26
|
# @param odd [Boolean]
|
26
27
|
# @param even [Boolean]
|
28
|
+
# @param within [Range]
|
27
29
|
# @param message [String] used for all validation failures
|
28
30
|
def initialize(
|
29
31
|
greater_than: nil, greater_than_or_equal_to: nil,
|
30
32
|
less_than: nil, less_than_or_equal_to: nil,
|
31
33
|
equal_to: nil, other_than: nil,
|
32
|
-
odd: nil, even: nil,
|
34
|
+
odd: nil, even: nil, within: nil,
|
33
35
|
message: "%{validated} must be %{comparison} %{target}",
|
36
|
+
null_message: Validator::AllowNullValidator::MESSAGE,
|
34
37
|
**default_options
|
35
38
|
)
|
36
39
|
|
@@ -42,12 +45,18 @@ module GraphQL
|
|
42
45
|
@other_than = other_than
|
43
46
|
@odd = odd
|
44
47
|
@even = even
|
48
|
+
@within = within
|
45
49
|
@message = message
|
50
|
+
@null_message = null_message
|
46
51
|
super(**default_options)
|
47
52
|
end
|
48
53
|
|
49
54
|
def validate(object, context, value)
|
50
|
-
if
|
55
|
+
if permitted_empty_value?(value)
|
56
|
+
# pass in this case
|
57
|
+
elsif value.nil? # @allow_null is handled in the parent class
|
58
|
+
@null_message
|
59
|
+
elsif @greater_than && value <= @greater_than
|
51
60
|
partial_format(@message, { comparison: "greater than", target: @greater_than })
|
52
61
|
elsif @greater_than_or_equal_to && value < @greater_than_or_equal_to
|
53
62
|
partial_format(@message, { comparison: "greater than or equal to", target: @greater_than_or_equal_to })
|
@@ -63,6 +72,8 @@ module GraphQL
|
|
63
72
|
(partial_format(@message, { comparison: "even", target: "" })).strip
|
64
73
|
elsif @odd && !value.odd?
|
65
74
|
(partial_format(@message, { comparison: "odd", target: "" })).strip
|
75
|
+
elsif @within && !@within.include?(value)
|
76
|
+
partial_format(@message, { comparison: "within", target: @within })
|
66
77
|
end
|
67
78
|
end
|
68
79
|
end
|
@@ -7,7 +7,6 @@ module GraphQL
|
|
7
7
|
# @return [GraphQL::Schema::Argument, GraphQL::Schema::Field, GraphQL::Schema::Resolver, Class<GraphQL::Schema::InputObject>]
|
8
8
|
attr_reader :validated
|
9
9
|
|
10
|
-
# TODO should this implement `if:` and `unless:` ?
|
11
10
|
# @param validated [GraphQL::Schema::Argument, GraphQL::Schema::Field, GraphQL::Schema::Resolver, Class<GraphQL::Schema::InputObject>] The argument or argument owner this validator is attached to
|
12
11
|
# @param allow_blank [Boolean] if `true`, then objects that respond to `.blank?` and return true for `.blank?` will skip this validation
|
13
12
|
# @param allow_null [Boolean] if `true`, then incoming `null`s will skip this validation
|
@@ -25,26 +24,6 @@ module GraphQL
|
|
25
24
|
raise GraphQL::RequiredImplementationMissingError, "Validator classes should implement #validate"
|
26
25
|
end
|
27
26
|
|
28
|
-
# This is called by the validation system and eventually calls {#validate}.
|
29
|
-
# @api private
|
30
|
-
def apply(object, context, value)
|
31
|
-
if value.nil?
|
32
|
-
if @allow_null
|
33
|
-
nil # skip this
|
34
|
-
else
|
35
|
-
"%{validated} can't be null"
|
36
|
-
end
|
37
|
-
elsif value.respond_to?(:blank?) && value.blank?
|
38
|
-
if @allow_blank
|
39
|
-
nil # skip this
|
40
|
-
else
|
41
|
-
"%{validated} can't be blank"
|
42
|
-
end
|
43
|
-
else
|
44
|
-
validate(object, context, value)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
27
|
# This is like `String#%`, but it supports the case that only some of `string`'s
|
49
28
|
# values are present in `substitutions`
|
50
29
|
def partial_format(string, substitutions)
|
@@ -55,6 +34,12 @@ module GraphQL
|
|
55
34
|
string
|
56
35
|
end
|
57
36
|
|
37
|
+
# @return [Boolean] `true` if `value` is `nil` and this validator has `allow_null: true` or if value is `.blank?` and this validator has `allow_blank: true`
|
38
|
+
def permitted_empty_value?(value)
|
39
|
+
(value.nil? && @allow_null) ||
|
40
|
+
(@allow_blank && value.respond_to?(:blank?) && value.blank?)
|
41
|
+
end
|
42
|
+
|
58
43
|
# @param schema_member [GraphQL::Schema::Field, GraphQL::Schema::Argument, Class<GraphQL::Schema::InputObject>]
|
59
44
|
# @param validates_hash [Hash{Symbol => Hash}, Hash{Class => Hash} nil] A configuration passed as `validates:`
|
60
45
|
# @return [Array<Validator>]
|
@@ -62,6 +47,21 @@ module GraphQL
|
|
62
47
|
if validates_hash.nil? || validates_hash.empty?
|
63
48
|
EMPTY_ARRAY
|
64
49
|
else
|
50
|
+
validates_hash = validates_hash.dup
|
51
|
+
|
52
|
+
default_options = {}
|
53
|
+
if validates_hash[:allow_null]
|
54
|
+
default_options[:allow_null] = validates_hash.delete(:allow_null)
|
55
|
+
end
|
56
|
+
if validates_hash[:allow_blank]
|
57
|
+
default_options[:allow_blank] = validates_hash.delete(:allow_blank)
|
58
|
+
end
|
59
|
+
|
60
|
+
# allow_nil or allow_blank are the _only_ validations:
|
61
|
+
if validates_hash.empty?
|
62
|
+
validates_hash = default_options
|
63
|
+
end
|
64
|
+
|
65
65
|
validates_hash.map do |validator_name, options|
|
66
66
|
validator_class = case validator_name
|
67
67
|
when Class
|
@@ -69,7 +69,11 @@ module GraphQL
|
|
69
69
|
else
|
70
70
|
all_validators[validator_name] || raise(ArgumentError, "unknown validation: #{validator_name.inspect}")
|
71
71
|
end
|
72
|
-
|
72
|
+
if options.is_a?(Hash)
|
73
|
+
validator_class.new(validated: schema_member, **(default_options.merge(options)))
|
74
|
+
else
|
75
|
+
validator_class.new(options, validated: schema_member, **default_options)
|
76
|
+
end
|
73
77
|
end
|
74
78
|
end
|
75
79
|
end
|
@@ -122,10 +126,10 @@ module GraphQL
|
|
122
126
|
|
123
127
|
validators.each do |validator|
|
124
128
|
validated = as || validator.validated
|
125
|
-
errors = validator.
|
129
|
+
errors = validator.validate(object, context, value)
|
126
130
|
if errors &&
|
127
|
-
|
128
|
-
|
131
|
+
(errors.is_a?(Array) && errors != EMPTY_ARRAY) ||
|
132
|
+
(errors.is_a?(String))
|
129
133
|
if all_errors.frozen? # It's empty
|
130
134
|
all_errors = []
|
131
135
|
end
|
@@ -161,3 +165,7 @@ require "graphql/schema/validator/exclusion_validator"
|
|
161
165
|
GraphQL::Schema::Validator.install(:exclusion, GraphQL::Schema::Validator::ExclusionValidator)
|
162
166
|
require "graphql/schema/validator/required_validator"
|
163
167
|
GraphQL::Schema::Validator.install(:required, GraphQL::Schema::Validator::RequiredValidator)
|
168
|
+
require "graphql/schema/validator/allow_null_validator"
|
169
|
+
GraphQL::Schema::Validator.install(:allow_null, GraphQL::Schema::Validator::AllowNullValidator)
|
170
|
+
require "graphql/schema/validator/allow_blank_validator"
|
171
|
+
GraphQL::Schema::Validator.install(:allow_blank, GraphQL::Schema::Validator::AllowBlankValidator)
|
@@ -37,6 +37,50 @@ module GraphQL
|
|
37
37
|
#
|
38
38
|
# @api private
|
39
39
|
class Warden
|
40
|
+
def self.from_context(context)
|
41
|
+
(context.respond_to?(:warden) && context.warden) || PassThruWarden
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param visibility_method [Symbol] a Warden method to call for this entry
|
45
|
+
# @param entry [Object, Array<Object>] One or more definitions for a given name in a GraphQL Schema
|
46
|
+
# @param context [GraphQL::Query::Context]
|
47
|
+
# @param warden [Warden]
|
48
|
+
# @return [Object] `entry` or one of `entry`'s items if exactly one of them is visible for this context
|
49
|
+
# @return [nil] If neither `entry` nor any of `entry`'s items are visible for this context
|
50
|
+
def self.visible_entry?(visibility_method, entry, context, warden = Warden.from_context(context))
|
51
|
+
if entry.is_a?(Array)
|
52
|
+
visible_item = nil
|
53
|
+
entry.each do |item|
|
54
|
+
if warden.public_send(visibility_method, item, context)
|
55
|
+
if visible_item.nil?
|
56
|
+
visible_item = item
|
57
|
+
else
|
58
|
+
raise Schema::DuplicateNamesError, "Found two visible definitions for `#{item.path}`: #{visible_item.inspect}, #{item.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
visible_item
|
63
|
+
elsif warden.public_send(visibility_method, entry, context)
|
64
|
+
entry
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# This is used when a caller provides a Hash for context.
|
71
|
+
# We want to call the schema's hooks, but we don't have a full-blown warden.
|
72
|
+
# The `context` arguments to these methods exist purely to simplify the code that
|
73
|
+
# calls methods on this object, so it will have everything it needs.
|
74
|
+
class PassThruWarden
|
75
|
+
class << self
|
76
|
+
def visible_field?(field, ctx); field.visible?(ctx); end
|
77
|
+
def visible_argument?(arg, ctx); arg.visible?(ctx); end
|
78
|
+
def visible_type?(type, ctx); type.visible?(ctx); end
|
79
|
+
def visible_enum_value?(ev, ctx); ev.visible?(ctx); end
|
80
|
+
def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
40
84
|
# @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
|
41
85
|
# @param context [GraphQL::Query::Context]
|
42
86
|
# @param schema [GraphQL::Schema]
|
@@ -54,8 +98,8 @@ module GraphQL
|
|
54
98
|
def types
|
55
99
|
@types ||= begin
|
56
100
|
vis_types = {}
|
57
|
-
@schema.types.each do |n, t|
|
58
|
-
if
|
101
|
+
@schema.types(@context).each do |n, t|
|
102
|
+
if visible_and_reachable_type?(t)
|
59
103
|
vis_types[n] = t
|
60
104
|
end
|
61
105
|
end
|
@@ -66,8 +110,8 @@ module GraphQL
|
|
66
110
|
# @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
|
67
111
|
def get_type(type_name)
|
68
112
|
@visible_types ||= read_through do |name|
|
69
|
-
type_defn = @schema.get_type(name)
|
70
|
-
if type_defn &&
|
113
|
+
type_defn = @schema.get_type(name, @context)
|
114
|
+
if type_defn && visible_and_reachable_type?(type_defn)
|
71
115
|
type_defn
|
72
116
|
else
|
73
117
|
nil
|
@@ -84,7 +128,7 @@ module GraphQL
|
|
84
128
|
|
85
129
|
# @return Boolean True if the type is visible and reachable in the schema
|
86
130
|
def reachable_type?(type_name)
|
87
|
-
type = get_type(type_name)
|
131
|
+
type = get_type(type_name) # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
|
88
132
|
type && reachable_type_set.include?(type)
|
89
133
|
end
|
90
134
|
|
@@ -92,8 +136,8 @@ module GraphQL
|
|
92
136
|
def get_field(parent_type, field_name)
|
93
137
|
@visible_parent_fields ||= read_through do |type|
|
94
138
|
read_through do |f_name|
|
95
|
-
field_defn = @schema.get_field(type, f_name)
|
96
|
-
if field_defn && visible_field?(
|
139
|
+
field_defn = @schema.get_field(type, f_name, @context)
|
140
|
+
if field_defn && visible_field?(field_defn, nil, type)
|
97
141
|
field_defn
|
98
142
|
else
|
99
143
|
nil
|
@@ -106,15 +150,15 @@ module GraphQL
|
|
106
150
|
|
107
151
|
# @return [GraphQL::Argument, nil] The argument named `argument_name` on `parent_type`, if it exists and is visible
|
108
152
|
def get_argument(parent_type, argument_name)
|
109
|
-
argument = parent_type.get_argument(argument_name)
|
110
|
-
return argument if argument && visible_argument?(argument)
|
153
|
+
argument = parent_type.get_argument(argument_name, @context)
|
154
|
+
return argument if argument && visible_argument?(argument, @context)
|
111
155
|
end
|
112
156
|
|
113
157
|
# @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
|
114
158
|
def possible_types(type_defn)
|
115
159
|
@visible_possible_types ||= read_through { |type_defn|
|
116
160
|
pt = @schema.possible_types(type_defn, @context)
|
117
|
-
pt.select { |t|
|
161
|
+
pt.select { |t| visible_and_reachable_type?(t) }
|
118
162
|
}
|
119
163
|
@visible_possible_types[type_defn]
|
120
164
|
end
|
@@ -122,26 +166,31 @@ module GraphQL
|
|
122
166
|
# @param type_defn [GraphQL::ObjectType, GraphQL::InterfaceType]
|
123
167
|
# @return [Array<GraphQL::Field>] Fields on `type_defn`
|
124
168
|
def fields(type_defn)
|
125
|
-
@visible_fields ||= read_through { |t| @schema.get_fields(t
|
169
|
+
@visible_fields ||= read_through { |t| @schema.get_fields(t, @context).values }
|
126
170
|
@visible_fields[type_defn]
|
127
171
|
end
|
128
172
|
|
129
173
|
# @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
|
130
174
|
# @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
|
131
175
|
def arguments(argument_owner)
|
132
|
-
@visible_arguments ||= read_through { |o| o.arguments.each_value.select { |a| visible_argument?(a) } }
|
176
|
+
@visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a) } }
|
133
177
|
@visible_arguments[argument_owner]
|
134
178
|
end
|
135
179
|
|
136
180
|
# @return [Array<GraphQL::EnumType::EnumValue>] Visible members of `enum_defn`
|
137
181
|
def enum_values(enum_defn)
|
138
|
-
@
|
139
|
-
@
|
182
|
+
@visible_enum_arrays ||= read_through { |e| e.enum_values(@context) }
|
183
|
+
@visible_enum_arrays[enum_defn]
|
184
|
+
end
|
185
|
+
|
186
|
+
def visible_enum_value?(enum_value, _ctx = nil)
|
187
|
+
@visible_enum_values ||= read_through { |ev| visible?(ev) }
|
188
|
+
@visible_enum_values[enum_value]
|
140
189
|
end
|
141
190
|
|
142
191
|
# @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
|
143
192
|
def interfaces(obj_type)
|
144
|
-
@visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i|
|
193
|
+
@visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i| visible_type?(i) } }
|
145
194
|
@visible_interfaces[obj_type]
|
146
195
|
end
|
147
196
|
|
@@ -158,25 +207,52 @@ module GraphQL
|
|
158
207
|
end
|
159
208
|
end
|
160
209
|
|
161
|
-
|
162
|
-
|
163
|
-
def union_memberships(obj_type)
|
164
|
-
@unions ||= read_through { |obj_type| @schema.union_memberships(obj_type).select { |u| visible?(u) } }
|
165
|
-
@unions[obj_type]
|
166
|
-
end
|
167
|
-
|
168
|
-
def visible_argument?(arg_defn)
|
169
|
-
visible?(arg_defn) && visible_type?(arg_defn.type.unwrap)
|
170
|
-
end
|
171
|
-
|
172
|
-
def visible_field?(owner_type, field_defn)
|
210
|
+
# @param owner [Class, Module] If provided, confirm that field has the given owner.
|
211
|
+
def visible_field?(field_defn, _ctx = nil, owner = field_defn.owner)
|
173
212
|
# This field is visible in its own right
|
174
213
|
visible?(field_defn) &&
|
175
214
|
# This field's return type is visible
|
176
|
-
|
215
|
+
visible_and_reachable_type?(field_defn.type.unwrap) &&
|
177
216
|
# This field is either defined on this object type,
|
178
217
|
# or the interface it's inherited from is also visible
|
179
|
-
((field_defn.respond_to?(:owner) && field_defn.owner ==
|
218
|
+
((field_defn.respond_to?(:owner) && field_defn.owner == owner) || field_on_visible_interface?(field_defn, owner))
|
219
|
+
end
|
220
|
+
|
221
|
+
def visible_argument?(arg_defn, _ctx = nil)
|
222
|
+
visible?(arg_defn) && visible_and_reachable_type?(arg_defn.type.unwrap)
|
223
|
+
end
|
224
|
+
|
225
|
+
def visible_type?(type_defn, _ctx = nil)
|
226
|
+
@type_visibility ||= read_through { |type_defn| visible?(type_defn) }
|
227
|
+
@type_visibility[type_defn]
|
228
|
+
end
|
229
|
+
|
230
|
+
def visible_type_membership?(type_membership, _ctx = nil)
|
231
|
+
visible?(type_membership)
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def visible_and_reachable_type?(type_defn)
|
237
|
+
@visible_and_reachable_type ||= read_through do |type_defn|
|
238
|
+
next false unless visible_type?(type_defn)
|
239
|
+
next true if root_type?(type_defn) || type_defn.introspection?
|
240
|
+
|
241
|
+
if type_defn.kind.union?
|
242
|
+
visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
|
243
|
+
elsif type_defn.kind.interface?
|
244
|
+
visible_possible_types?(type_defn)
|
245
|
+
else
|
246
|
+
referenced?(type_defn) || visible_abstract_type?(type_defn)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
@visible_and_reachable_type[type_defn]
|
251
|
+
end
|
252
|
+
|
253
|
+
def union_memberships(obj_type)
|
254
|
+
@unions ||= read_through { |obj_type| @schema.union_memberships(obj_type).select { |u| visible?(u) } }
|
255
|
+
@unions[obj_type]
|
180
256
|
end
|
181
257
|
|
182
258
|
# We need this to tell whether a field was inherited by an interface
|
@@ -195,10 +271,10 @@ module GraphQL
|
|
195
271
|
any_interface_has_visible_field = false
|
196
272
|
ints = unfiltered_interfaces(type_defn)
|
197
273
|
ints.each do |interface_type|
|
198
|
-
if (iface_field_defn = interface_type.get_field(field_defn.graphql_name))
|
274
|
+
if (iface_field_defn = interface_type.get_field(field_defn.graphql_name, @context))
|
199
275
|
any_interface_has_field = true
|
200
276
|
|
201
|
-
if interfaces(type_defn).include?(interface_type) && visible_field?(
|
277
|
+
if interfaces(type_defn).include?(interface_type) && visible_field?(iface_field_defn, nil, interface_type)
|
202
278
|
any_interface_has_visible_field = true
|
203
279
|
end
|
204
280
|
end
|
@@ -215,23 +291,6 @@ module GraphQL
|
|
215
291
|
end
|
216
292
|
end
|
217
293
|
|
218
|
-
def visible_type?(type_defn)
|
219
|
-
@type_visibility ||= read_through do |type_defn|
|
220
|
-
next false unless visible?(type_defn)
|
221
|
-
next true if root_type?(type_defn) || type_defn.introspection?
|
222
|
-
|
223
|
-
if type_defn.kind.union?
|
224
|
-
visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
|
225
|
-
elsif type_defn.kind.interface?
|
226
|
-
visible_possible_types?(type_defn)
|
227
|
-
else
|
228
|
-
referenced?(type_defn) || visible_abstract_type?(type_defn)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
@type_visibility[type_defn]
|
233
|
-
end
|
234
|
-
|
235
294
|
def root_type?(type_defn)
|
236
295
|
@query == type_defn ||
|
237
296
|
@mutation == type_defn ||
|
@@ -259,7 +318,7 @@ module GraphQL
|
|
259
318
|
end
|
260
319
|
|
261
320
|
def visible_possible_types?(type_defn)
|
262
|
-
possible_types(type_defn).any? { |t|
|
321
|
+
possible_types(type_defn).any? { |t| visible_and_reachable_type?(t) }
|
263
322
|
end
|
264
323
|
|
265
324
|
def visible?(member)
|
@@ -274,6 +333,7 @@ module GraphQL
|
|
274
333
|
return @reachable_type_set if defined?(@reachable_type_set)
|
275
334
|
|
276
335
|
@reachable_type_set = Set.new
|
336
|
+
rt_hash = {}
|
277
337
|
|
278
338
|
unvisited_types = []
|
279
339
|
['query', 'mutation', 'subscription'].each do |op_name|
|
@@ -283,16 +343,16 @@ module GraphQL
|
|
283
343
|
unvisited_types.concat(@schema.introspection_system.types.values)
|
284
344
|
|
285
345
|
directives.each do |dir_class|
|
286
|
-
dir_class.
|
346
|
+
arguments(dir_class).each do |arg_defn|
|
287
347
|
arg_t = arg_defn.type.unwrap
|
288
|
-
if get_type(arg_t.graphql_name)
|
348
|
+
if get_type(arg_t.graphql_name) # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
|
289
349
|
unvisited_types << arg_t
|
290
350
|
end
|
291
351
|
end
|
292
352
|
end
|
293
353
|
|
294
354
|
@schema.orphan_types.each do |orphan_type|
|
295
|
-
if get_type(orphan_type.graphql_name)
|
355
|
+
if get_type(orphan_type.graphql_name) == orphan_type # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
|
296
356
|
unvisited_types << orphan_type
|
297
357
|
end
|
298
358
|
end
|
@@ -300,6 +360,10 @@ module GraphQL
|
|
300
360
|
until unvisited_types.empty?
|
301
361
|
type = unvisited_types.pop
|
302
362
|
if @reachable_type_set.add?(type)
|
363
|
+
type_by_name = rt_hash[type.graphql_name] ||= type
|
364
|
+
if type_by_name != type
|
365
|
+
raise DuplicateNamesError, "Found two visible type definitions for `#{type.graphql_name}`: #{type.inspect}, #{type_by_name.inspect}"
|
366
|
+
end
|
303
367
|
if type.kind.input_object?
|
304
368
|
# recurse into visible arguments
|
305
369
|
arguments(type).each do |argument|
|