graphql 1.12.24 → 1.13.19
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 -8
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/install_generator.rb +10 -3
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +5 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +8 -37
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- data/lib/generators/graphql/templates/enum.erb +5 -1
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +4 -2
- data/lib/generators/graphql/templates/mutation.erb +1 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/object.erb +4 -2
- data/lib/generators/graphql/templates/scalar.erb +3 -1
- data/lib/generators/graphql/templates/union.erb +4 -2
- data/lib/generators/graphql/type_generator.rb +46 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/ast/field_usage.rb +2 -2
- data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
- data/lib/graphql/analysis/ast/visitor.rb +5 -4
- data/lib/graphql/argument.rb +1 -1
- data/lib/graphql/backtrace/table.rb +1 -1
- data/lib/graphql/base_type.rb +5 -3
- data/lib/graphql/boolean_type.rb +1 -1
- data/lib/graphql/dataloader/source.rb +2 -2
- data/lib/graphql/dataloader.rb +55 -22
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/define/instance_definable.rb +15 -0
- 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 +1 -5
- data/lib/graphql/enum_type.rb +7 -3
- 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 +6 -4
- data/lib/graphql/execution/interpreter/runtime.rb +66 -38
- data/lib/graphql/execution/lookahead.rb +2 -2
- data/lib/graphql/execution/multiplex.rb +4 -1
- data/lib/graphql/field.rb +1 -1
- data/lib/graphql/float_type.rb +1 -1
- data/lib/graphql/id_type.rb +1 -1
- data/lib/graphql/input_object_type.rb +1 -1
- data/lib/graphql/int_type.rb +1 -1
- data/lib/graphql/interface_type.rb +1 -1
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +5 -3
- 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 +3 -3
- data/lib/graphql/introspection/input_value_type.rb +4 -4
- data/lib/graphql/introspection/schema_type.rb +9 -4
- data/lib/graphql/introspection/type_type.rb +18 -12
- data/lib/graphql/introspection.rb +4 -1
- data/lib/graphql/language/block_string.rb +2 -6
- data/lib/graphql/language/document_from_schema_definition.rb +11 -4
- data/lib/graphql/language/lexer.rb +50 -28
- data/lib/graphql/language/lexer.rl +2 -4
- data/lib/graphql/language/nodes.rb +4 -3
- data/lib/graphql/language/parser.rb +841 -820
- data/lib/graphql/language/parser.y +13 -6
- data/lib/graphql/language/printer.rb +10 -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/object_type.rb +2 -2
- data/lib/graphql/pagination/active_record_relation_connection.rb +43 -6
- data/lib/graphql/pagination/relation_connection.rb +59 -29
- 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/input_validation_result.rb +9 -0
- 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 +2 -3
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +35 -4
- data/lib/graphql/query.rb +0 -1
- data/lib/graphql/relay/connection_type.rb +15 -2
- data/lib/graphql/relay/edges_instrumentation.rb +0 -1
- data/lib/graphql/relay/global_id_resolve.rb +1 -2
- data/lib/graphql/relay/mutation.rb +1 -1
- data/lib/graphql/relay/page_info.rb +1 -1
- data/lib/graphql/relay/range_add.rb +4 -0
- 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/scalar_type.rb +1 -1
- data/lib/graphql/schema/addition.rb +37 -28
- data/lib/graphql/schema/argument.rb +30 -15
- data/lib/graphql/schema/build_from_definition.rb +6 -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 +23 -4
- data/lib/graphql/schema/enum.rb +61 -12
- 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 +261 -83
- data/lib/graphql/schema/field_extension.rb +89 -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 +24 -7
- data/lib/graphql/schema/interface.rb +11 -20
- data/lib/graphql/schema/introspection_system.rb +1 -1
- data/lib/graphql/schema/list.rb +21 -4
- data/lib/graphql/schema/loader.rb +3 -0
- data/lib/graphql/schema/member/accepts_definition.rb +15 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
- 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 +56 -14
- 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 +100 -0
- data/lib/graphql/schema/member/validates_input.rb +2 -2
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/non_null.rb +9 -3
- 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 +37 -17
- data/lib/graphql/schema/scalar.rb +15 -1
- data/lib/graphql/schema/subscription.rb +11 -1
- 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/format_validator.rb +0 -4
- data/lib/graphql/schema/validator/numericality_validator.rb +1 -0
- data/lib/graphql/schema/validator/required_validator.rb +29 -15
- data/lib/graphql/schema/validator.rb +4 -7
- data/lib/graphql/schema/warden.rb +126 -53
- data/lib/graphql/schema.rb +120 -24
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/base_visitor.rb +6 -6
- data/lib/graphql/static_validation/definition_dependencies.rb +0 -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/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
- data/lib/graphql/static_validation/validation_context.rb +4 -0
- data/lib/graphql/string_type.rb +1 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -4
- data/lib/graphql/subscriptions/event.rb +20 -12
- data/lib/graphql/subscriptions/serialize.rb +22 -2
- data/lib/graphql/subscriptions.rb +17 -19
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
- data/lib/graphql/tracing/data_dog_tracing.rb +24 -2
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_tracing.rb +20 -10
- data/lib/graphql/types/iso_8601_date.rb +13 -5
- data/lib/graphql/types/iso_8601_date_time.rb +8 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +28 -10
- 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/relay/node_field.rb +2 -3
- data/lib/graphql/types/relay/nodes_field.rb +19 -3
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/union_type.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +22 -32
- metadata +31 -11
- /data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +0 -0
- /data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +0 -0
@@ -103,10 +103,12 @@ module GraphQL
|
|
103
103
|
# Call this method to provide a new subscription_scope; OR
|
104
104
|
# call it without an argument to get the subscription_scope
|
105
105
|
# @param new_scope [Symbol]
|
106
|
+
# @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription.
|
106
107
|
# @return [Symbol]
|
107
|
-
def self.subscription_scope(new_scope = READING_SCOPE)
|
108
|
+
def self.subscription_scope(new_scope = READING_SCOPE, optional: false)
|
108
109
|
if new_scope != READING_SCOPE
|
109
110
|
@subscription_scope = new_scope
|
111
|
+
@subscription_scope_optional = optional
|
110
112
|
elsif defined?(@subscription_scope)
|
111
113
|
@subscription_scope
|
112
114
|
else
|
@@ -114,6 +116,14 @@ module GraphQL
|
|
114
116
|
end
|
115
117
|
end
|
116
118
|
|
119
|
+
def self.subscription_scope_optional?
|
120
|
+
if defined?(@subscription_scope_optional)
|
121
|
+
@subscription_scope_optional
|
122
|
+
else
|
123
|
+
find_inherited_value(:subscription_scope_optional, false)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
117
127
|
# This is called during initial subscription to get a "name" for this subscription.
|
118
128
|
# Later, when `.trigger` is called, this will be called again to build another "name".
|
119
129
|
# Any subscribers with matching topic will begin the update flow.
|
@@ -173,7 +173,7 @@ Some late-bound types couldn't be resolved:
|
|
173
173
|
end
|
174
174
|
when Class
|
175
175
|
if member.respond_to?(:graphql_definition)
|
176
|
-
graphql_member = member.graphql_definition
|
176
|
+
graphql_member = member.graphql_definition(silence_deprecation_warning: true)
|
177
177
|
visit(schema, graphql_member, context_description)
|
178
178
|
else
|
179
179
|
raise GraphQL::Schema::InvalidTypeError.new("Unexpected traversal member: #{member} (#{member.class.name})")
|
@@ -11,7 +11,7 @@ module GraphQL
|
|
11
11
|
def self.build_type(type_owner, ast_node)
|
12
12
|
case ast_node
|
13
13
|
when GraphQL::Language::Nodes::TypeName
|
14
|
-
type_owner.get_type(ast_node.name)
|
14
|
+
type_owner.get_type(ast_node.name) # rubocop:disable Development/ContextIsPassedCop -- this is a `context` or `warden`, it's already query-aware
|
15
15
|
when GraphQL::Language::Nodes::NonNullType
|
16
16
|
ast_inner_type = ast_node.of_type
|
17
17
|
inner_type = build_type(type_owner, ast_inner_type)
|
@@ -4,8 +4,6 @@ module GraphQL
|
|
4
4
|
class Schema
|
5
5
|
# This class joins an object type to an abstract type (interface or union) of which
|
6
6
|
# it is a member.
|
7
|
-
#
|
8
|
-
# TODO: Not yet implemented for interfaces.
|
9
7
|
class TypeMembership
|
10
8
|
# @return [Class<GraphQL::Schema::Object>]
|
11
9
|
attr_accessor :object_type
|
@@ -26,9 +24,25 @@ module GraphQL
|
|
26
24
|
end
|
27
25
|
|
28
26
|
# @return [Boolean] if false, {#object_type} will be treated as _not_ a member of {#abstract_type}
|
29
|
-
def visible?(
|
30
|
-
|
27
|
+
def visible?(ctx)
|
28
|
+
warden = Warden.from_context(ctx)
|
29
|
+
(@object_type.respond_to?(:visible?) ? warden.visible_type?(@object_type, ctx) : true) &&
|
30
|
+
(@abstract_type.respond_to?(:visible?) ? warden.visible_type?(@abstract_type, ctx) : true)
|
31
31
|
end
|
32
|
+
|
33
|
+
def graphql_name
|
34
|
+
"#{@object_type.graphql_name}.#{@abstract_type.kind.interface? ? "implements" : "belongsTo" }.#{@abstract_type.graphql_name}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def path
|
38
|
+
graphql_name
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
"#<#{self.class} #{@object_type.inspect} => #{@abstract_type.inspect}>"
|
43
|
+
end
|
44
|
+
|
45
|
+
alias :type_class :itself
|
32
46
|
end
|
33
47
|
end
|
34
48
|
end
|
data/lib/graphql/schema/union.rb
CHANGED
@@ -19,8 +19,9 @@ module GraphQL
|
|
19
19
|
end
|
20
20
|
else
|
21
21
|
visible_types = []
|
22
|
+
warden = Warden.from_context(context)
|
22
23
|
type_memberships.each do |type_membership|
|
23
|
-
if
|
24
|
+
if warden.visible_type_membership?(type_membership, context)
|
24
25
|
visible_types << type_membership.object_type
|
25
26
|
end
|
26
27
|
end
|
@@ -28,6 +29,12 @@ module GraphQL
|
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
32
|
+
def all_possible_types
|
33
|
+
type_memberships.map(&:object_type)
|
34
|
+
end
|
35
|
+
|
36
|
+
prepend GraphQL::Schema::Member::CachedGraphQLDefinition::DeprecatedToGraphQL
|
37
|
+
|
31
38
|
def to_graphql
|
32
39
|
type_defn = GraphQL::UnionType.new
|
33
40
|
type_defn.name = graphql_name
|
@@ -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]
|
@@ -14,7 +14,7 @@ module GraphQL
|
|
14
14
|
# argument :ingredient_id, ID, required: true
|
15
15
|
# argument :cups, Integer, required: false
|
16
16
|
# argument :tablespoons, Integer, required: false
|
17
|
-
# argument :teaspoons, Integer, required:
|
17
|
+
# argument :teaspoons, Integer, required: false
|
18
18
|
# validates required: { one_of: [:cups, :tablespoons, :teaspoons] }
|
19
19
|
# end
|
20
20
|
#
|
@@ -28,11 +28,23 @@ module GraphQL
|
|
28
28
|
# validates required: { one_of: [:node_id, [:object_type, :object_id]] }
|
29
29
|
# end
|
30
30
|
#
|
31
|
+
# @example require _some_ value for an argument, even if it's null
|
32
|
+
# field :update_settings, AccountSettings do
|
33
|
+
# # `required: :nullable` means this argument must be given, but may be `null`
|
34
|
+
# argument :age, Integer, required: :nullable
|
35
|
+
# end
|
36
|
+
#
|
31
37
|
class RequiredValidator < Validator
|
32
38
|
# @param one_of [Symbol, Array<Symbol>] An argument, or a list of arguments, that represents a valid set of inputs for this field
|
33
39
|
# @param message [String]
|
34
|
-
def initialize(one_of
|
35
|
-
@one_of = one_of
|
40
|
+
def initialize(one_of: nil, argument: nil, message: "%{validated} has the wrong arguments", **default_options)
|
41
|
+
@one_of = if one_of
|
42
|
+
one_of
|
43
|
+
elsif argument
|
44
|
+
[argument]
|
45
|
+
else
|
46
|
+
raise ArgumentError, "`one_of:` or `argument:` must be given in `validates required: {...}`"
|
47
|
+
end
|
36
48
|
@message = message
|
37
49
|
super(**default_options)
|
38
50
|
end
|
@@ -40,19 +52,21 @@ module GraphQL
|
|
40
52
|
def validate(_object, _context, value)
|
41
53
|
matched_conditions = 0
|
42
54
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
if !value.nil?
|
56
|
+
@one_of.each do |one_of_condition|
|
57
|
+
case one_of_condition
|
58
|
+
when Symbol
|
59
|
+
if value.key?(one_of_condition)
|
60
|
+
matched_conditions += 1
|
61
|
+
end
|
62
|
+
when Array
|
63
|
+
if one_of_condition.all? { |k| value.key?(k) }
|
64
|
+
matched_conditions += 1
|
65
|
+
break
|
66
|
+
end
|
67
|
+
else
|
68
|
+
raise ArgumentError, "Unknown one_of condition: #{one_of_condition.inspect}"
|
53
69
|
end
|
54
|
-
else
|
55
|
-
raise ArgumentError, "Unknown one_of condition: #{one_of_condition.inspect}"
|
56
70
|
end
|
57
71
|
end
|
58
72
|
|
@@ -48,16 +48,13 @@ module GraphQL
|
|
48
48
|
EMPTY_ARRAY
|
49
49
|
else
|
50
50
|
validates_hash = validates_hash.dup
|
51
|
-
allow_null = validates_hash.delete(:allow_null)
|
52
|
-
allow_blank = validates_hash.delete(:allow_blank)
|
53
51
|
|
54
|
-
# This could be {...}.compact on Ruby 2.4+
|
55
52
|
default_options = {}
|
56
|
-
if
|
57
|
-
default_options[:allow_null] = allow_null
|
53
|
+
if validates_hash[:allow_null]
|
54
|
+
default_options[:allow_null] = validates_hash.delete(:allow_null)
|
58
55
|
end
|
59
|
-
if
|
60
|
-
default_options[:allow_blank] = allow_blank
|
56
|
+
if validates_hash[:allow_blank]
|
57
|
+
default_options[:allow_blank] = validates_hash.delete(:allow_blank)
|
61
58
|
end
|
62
59
|
|
63
60
|
# allow_nil or allow_blank are the _only_ validations:
|
@@ -37,6 +37,52 @@ 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
|
+
def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
|
82
|
+
def arguments(owner, ctx); owner.arguments(ctx); end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
40
86
|
# @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
|
41
87
|
# @param context [GraphQL::Query::Context]
|
42
88
|
# @param schema [GraphQL::Schema]
|
@@ -54,8 +100,8 @@ module GraphQL
|
|
54
100
|
def types
|
55
101
|
@types ||= begin
|
56
102
|
vis_types = {}
|
57
|
-
@schema.types.each do |n, t|
|
58
|
-
if
|
103
|
+
@schema.types(@context).each do |n, t|
|
104
|
+
if visible_and_reachable_type?(t)
|
59
105
|
vis_types[n] = t
|
60
106
|
end
|
61
107
|
end
|
@@ -66,8 +112,8 @@ module GraphQL
|
|
66
112
|
# @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
|
67
113
|
def get_type(type_name)
|
68
114
|
@visible_types ||= read_through do |name|
|
69
|
-
type_defn = @schema.get_type(name)
|
70
|
-
if type_defn &&
|
115
|
+
type_defn = @schema.get_type(name, @context)
|
116
|
+
if type_defn && visible_and_reachable_type?(type_defn)
|
71
117
|
type_defn
|
72
118
|
else
|
73
119
|
nil
|
@@ -84,7 +130,7 @@ module GraphQL
|
|
84
130
|
|
85
131
|
# @return Boolean True if the type is visible and reachable in the schema
|
86
132
|
def reachable_type?(type_name)
|
87
|
-
type = get_type(type_name)
|
133
|
+
type = get_type(type_name) # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
|
88
134
|
type && reachable_type_set.include?(type)
|
89
135
|
end
|
90
136
|
|
@@ -92,8 +138,8 @@ module GraphQL
|
|
92
138
|
def get_field(parent_type, field_name)
|
93
139
|
@visible_parent_fields ||= read_through do |type|
|
94
140
|
read_through do |f_name|
|
95
|
-
field_defn = @schema.get_field(type, f_name)
|
96
|
-
if field_defn && visible_field?(
|
141
|
+
field_defn = @schema.get_field(type, f_name, @context)
|
142
|
+
if field_defn && visible_field?(field_defn, nil, type)
|
97
143
|
field_defn
|
98
144
|
else
|
99
145
|
nil
|
@@ -106,15 +152,15 @@ module GraphQL
|
|
106
152
|
|
107
153
|
# @return [GraphQL::Argument, nil] The argument named `argument_name` on `parent_type`, if it exists and is visible
|
108
154
|
def get_argument(parent_type, argument_name)
|
109
|
-
argument = parent_type.get_argument(argument_name)
|
110
|
-
return argument if argument && visible_argument?(argument)
|
155
|
+
argument = parent_type.get_argument(argument_name, @context)
|
156
|
+
return argument if argument && visible_argument?(argument, @context)
|
111
157
|
end
|
112
158
|
|
113
159
|
# @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
|
114
160
|
def possible_types(type_defn)
|
115
161
|
@visible_possible_types ||= read_through { |type_defn|
|
116
162
|
pt = @schema.possible_types(type_defn, @context)
|
117
|
-
pt.select { |t|
|
163
|
+
pt.select { |t| visible_and_reachable_type?(t) }
|
118
164
|
}
|
119
165
|
@visible_possible_types[type_defn]
|
120
166
|
end
|
@@ -122,26 +168,31 @@ module GraphQL
|
|
122
168
|
# @param type_defn [GraphQL::ObjectType, GraphQL::InterfaceType]
|
123
169
|
# @return [Array<GraphQL::Field>] Fields on `type_defn`
|
124
170
|
def fields(type_defn)
|
125
|
-
@visible_fields ||= read_through { |t| @schema.get_fields(t
|
171
|
+
@visible_fields ||= read_through { |t| @schema.get_fields(t, @context).values }
|
126
172
|
@visible_fields[type_defn]
|
127
173
|
end
|
128
174
|
|
129
175
|
# @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
|
130
176
|
# @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
|
131
|
-
def arguments(argument_owner)
|
132
|
-
@visible_arguments ||= read_through { |o| o.arguments.each_value.select { |a| visible_argument?(a) } }
|
177
|
+
def arguments(argument_owner, ctx = nil)
|
178
|
+
@visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a, @context) } }
|
133
179
|
@visible_arguments[argument_owner]
|
134
180
|
end
|
135
181
|
|
136
182
|
# @return [Array<GraphQL::EnumType::EnumValue>] Visible members of `enum_defn`
|
137
183
|
def enum_values(enum_defn)
|
138
|
-
@
|
139
|
-
@
|
184
|
+
@visible_enum_arrays ||= read_through { |e| e.enum_values(@context) }
|
185
|
+
@visible_enum_arrays[enum_defn]
|
186
|
+
end
|
187
|
+
|
188
|
+
def visible_enum_value?(enum_value, _ctx = nil)
|
189
|
+
@visible_enum_values ||= read_through { |ev| visible?(ev) }
|
190
|
+
@visible_enum_values[enum_value]
|
140
191
|
end
|
141
192
|
|
142
193
|
# @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
|
143
194
|
def interfaces(obj_type)
|
144
|
-
@visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i|
|
195
|
+
@visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i| visible_type?(i) } }
|
145
196
|
@visible_interfaces[obj_type]
|
146
197
|
end
|
147
198
|
|
@@ -158,25 +209,59 @@ module GraphQL
|
|
158
209
|
end
|
159
210
|
end
|
160
211
|
|
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)
|
212
|
+
# @param owner [Class, Module] If provided, confirm that field has the given owner.
|
213
|
+
def visible_field?(field_defn, _ctx = nil, owner = field_defn.owner)
|
173
214
|
# This field is visible in its own right
|
174
215
|
visible?(field_defn) &&
|
175
216
|
# This field's return type is visible
|
176
|
-
|
217
|
+
visible_and_reachable_type?(field_defn.type.unwrap) &&
|
177
218
|
# This field is either defined on this object type,
|
178
219
|
# or the interface it's inherited from is also visible
|
179
|
-
((field_defn.respond_to?(:owner) && field_defn.owner ==
|
220
|
+
((field_defn.respond_to?(:owner) && field_defn.owner == owner) || field_on_visible_interface?(field_defn, owner))
|
221
|
+
end
|
222
|
+
|
223
|
+
def visible_argument?(arg_defn, _ctx = nil)
|
224
|
+
visible?(arg_defn) && visible_and_reachable_type?(arg_defn.type.unwrap)
|
225
|
+
end
|
226
|
+
|
227
|
+
def visible_type?(type_defn, _ctx = nil)
|
228
|
+
@type_visibility ||= read_through { |type_defn| visible?(type_defn) }
|
229
|
+
@type_visibility[type_defn]
|
230
|
+
end
|
231
|
+
|
232
|
+
def visible_type_membership?(type_membership, _ctx = nil)
|
233
|
+
visible?(type_membership)
|
234
|
+
end
|
235
|
+
|
236
|
+
def interface_type_memberships(obj_type, _ctx = nil)
|
237
|
+
@type_memberships ||= read_through do |obj_t|
|
238
|
+
obj_t.interface_type_memberships
|
239
|
+
end
|
240
|
+
@type_memberships[obj_type]
|
241
|
+
end
|
242
|
+
|
243
|
+
private
|
244
|
+
|
245
|
+
def visible_and_reachable_type?(type_defn)
|
246
|
+
@visible_and_reachable_type ||= read_through do |type_defn|
|
247
|
+
next false unless visible_type?(type_defn)
|
248
|
+
next true if root_type?(type_defn) || type_defn.introspection?
|
249
|
+
|
250
|
+
if type_defn.kind.union?
|
251
|
+
visible_possible_types?(type_defn) && (referenced?(type_defn) || orphan_type?(type_defn))
|
252
|
+
elsif type_defn.kind.interface?
|
253
|
+
visible_possible_types?(type_defn)
|
254
|
+
else
|
255
|
+
referenced?(type_defn) || visible_abstract_type?(type_defn)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
@visible_and_reachable_type[type_defn]
|
260
|
+
end
|
261
|
+
|
262
|
+
def union_memberships(obj_type)
|
263
|
+
@unions ||= read_through { |obj_type| @schema.union_memberships(obj_type).select { |u| visible?(u) } }
|
264
|
+
@unions[obj_type]
|
180
265
|
end
|
181
266
|
|
182
267
|
# We need this to tell whether a field was inherited by an interface
|
@@ -195,10 +280,10 @@ module GraphQL
|
|
195
280
|
any_interface_has_visible_field = false
|
196
281
|
ints = unfiltered_interfaces(type_defn)
|
197
282
|
ints.each do |interface_type|
|
198
|
-
if (iface_field_defn = interface_type.get_field(field_defn.graphql_name))
|
283
|
+
if (iface_field_defn = interface_type.get_field(field_defn.graphql_name, @context))
|
199
284
|
any_interface_has_field = true
|
200
285
|
|
201
|
-
if interfaces(type_defn).include?(interface_type) && visible_field?(
|
286
|
+
if interfaces(type_defn).include?(interface_type) && visible_field?(iface_field_defn, nil, interface_type)
|
202
287
|
any_interface_has_visible_field = true
|
203
288
|
end
|
204
289
|
end
|
@@ -215,23 +300,6 @@ module GraphQL
|
|
215
300
|
end
|
216
301
|
end
|
217
302
|
|
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
303
|
def root_type?(type_defn)
|
236
304
|
@query == type_defn ||
|
237
305
|
@mutation == type_defn ||
|
@@ -259,7 +327,7 @@ module GraphQL
|
|
259
327
|
end
|
260
328
|
|
261
329
|
def visible_possible_types?(type_defn)
|
262
|
-
possible_types(type_defn).any? { |t|
|
330
|
+
possible_types(type_defn).any? { |t| visible_and_reachable_type?(t) }
|
263
331
|
end
|
264
332
|
|
265
333
|
def visible?(member)
|
@@ -274,6 +342,7 @@ module GraphQL
|
|
274
342
|
return @reachable_type_set if defined?(@reachable_type_set)
|
275
343
|
|
276
344
|
@reachable_type_set = Set.new
|
345
|
+
rt_hash = {}
|
277
346
|
|
278
347
|
unvisited_types = []
|
279
348
|
['query', 'mutation', 'subscription'].each do |op_name|
|
@@ -283,16 +352,16 @@ module GraphQL
|
|
283
352
|
unvisited_types.concat(@schema.introspection_system.types.values)
|
284
353
|
|
285
354
|
directives.each do |dir_class|
|
286
|
-
dir_class.
|
355
|
+
arguments(dir_class).each do |arg_defn|
|
287
356
|
arg_t = arg_defn.type.unwrap
|
288
|
-
if get_type(arg_t.graphql_name)
|
357
|
+
if get_type(arg_t.graphql_name) # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
|
289
358
|
unvisited_types << arg_t
|
290
359
|
end
|
291
360
|
end
|
292
361
|
end
|
293
362
|
|
294
363
|
@schema.orphan_types.each do |orphan_type|
|
295
|
-
if get_type(orphan_type.graphql_name)
|
364
|
+
if get_type(orphan_type.graphql_name) == orphan_type # rubocop:disable Development/ContextIsPassedCop -- `self` is query-aware
|
296
365
|
unvisited_types << orphan_type
|
297
366
|
end
|
298
367
|
end
|
@@ -300,6 +369,10 @@ module GraphQL
|
|
300
369
|
until unvisited_types.empty?
|
301
370
|
type = unvisited_types.pop
|
302
371
|
if @reachable_type_set.add?(type)
|
372
|
+
type_by_name = rt_hash[type.graphql_name] ||= type
|
373
|
+
if type_by_name != type
|
374
|
+
raise DuplicateNamesError, "Found two visible type definitions for `#{type.graphql_name}`: #{type.inspect}, #{type_by_name.inspect}"
|
375
|
+
end
|
303
376
|
if type.kind.input_object?
|
304
377
|
# recurse into visible arguments
|
305
378
|
arguments(type).each do |argument|
|