graphql 2.0.27 → 2.2.6
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.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +3 -0
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +6 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +2 -0
- data/lib/graphql/analysis/ast/analyzer.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +32 -7
- data/lib/graphql/analysis/ast/query_complexity.rb +80 -128
- data/lib/graphql/analysis/ast/query_depth.rb +7 -2
- data/lib/graphql/analysis/ast/visitor.rb +2 -2
- data/lib/graphql/analysis/ast.rb +21 -11
- data/lib/graphql/backtrace/trace.rb +12 -15
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +85 -0
- data/lib/graphql/dataloader/source.rb +11 -3
- data/lib/graphql/dataloader.rb +109 -142
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
- data/lib/graphql/execution/interpreter/runtime.rb +70 -248
- data/lib/graphql/execution/interpreter.rb +91 -157
- data/lib/graphql/execution/lookahead.rb +88 -21
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/schema_type.rb +3 -1
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +37 -37
- data/lib/graphql/language/lexer.rb +271 -177
- data/lib/graphql/language/nodes.rb +74 -56
- data/lib/graphql/language/parser.rb +697 -1986
- data/lib/graphql/language/printer.rb +299 -146
- data/lib/graphql/language/sanitized_printer.rb +20 -22
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +20 -81
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +3 -3
- data/lib/graphql/pagination/connection.rb +28 -1
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +3 -3
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +36 -98
- data/lib/graphql/query/null_context.rb +4 -11
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +13 -22
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/schema/argument.rb +6 -1
- data/lib/graphql/schema/build_from_definition.rb +0 -11
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive.rb +1 -1
- data/lib/graphql/schema/enum.rb +3 -3
- data/lib/graphql/schema/field/connection_extension.rb +1 -15
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +8 -5
- data/lib/graphql/schema/has_single_input_argument.rb +156 -0
- data/lib/graphql/schema/input_object.rb +2 -2
- data/lib/graphql/schema/interface.rb +10 -10
- data/lib/graphql/schema/introspection_system.rb +2 -0
- data/lib/graphql/schema/loader.rb +0 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +61 -38
- data/lib/graphql/schema/member/has_fields.rb +8 -5
- data/lib/graphql/schema/member/has_interfaces.rb +23 -9
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/object.rb +8 -0
- data/lib/graphql/schema/printer.rb +8 -7
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -128
- data/lib/graphql/schema/resolver.rb +7 -3
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/warden.rb +96 -94
- data/lib/graphql/schema.rb +219 -72
- data/lib/graphql/static_validation/all_rules.rb +1 -1
- data/lib/graphql/static_validation/base_visitor.rb +1 -1
- data/lib/graphql/static_validation/literal_validator.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +3 -2
- data/lib/graphql/subscriptions/event.rb +8 -2
- data/lib/graphql/subscriptions.rb +14 -12
- data/lib/graphql/testing/helpers.rb +125 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/appoptics_trace.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/data_dog_trace.rb +21 -34
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +2 -0
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/sentry_trace.rb +94 -0
- data/lib/graphql/tracing/trace.rb +1 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +32 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +7 -0
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -3
- data/readme.md +12 -2
- metadata +33 -25
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
|
@@ -21,6 +21,10 @@ module GraphQL
|
|
|
21
21
|
# @see {GraphQL::Schema::Mutation} for an example, it's basically the same.
|
|
22
22
|
#
|
|
23
23
|
class RelayClassicMutation < GraphQL::Schema::Mutation
|
|
24
|
+
include GraphQL::Schema::HasSingleInputArgument
|
|
25
|
+
|
|
26
|
+
argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
|
|
27
|
+
|
|
24
28
|
# The payload should always include this field
|
|
25
29
|
field(:client_mutation_id, String, "A unique identifier for the client performing the mutation.")
|
|
26
30
|
# Relay classic default:
|
|
@@ -31,34 +35,14 @@ module GraphQL
|
|
|
31
35
|
def resolve_with_support(**inputs)
|
|
32
36
|
input = inputs[:input].to_kwargs
|
|
33
37
|
|
|
34
|
-
new_extras = field ? field.extras : []
|
|
35
|
-
all_extras = self.class.extras + new_extras
|
|
36
|
-
|
|
37
|
-
# Transfer these from the top-level hash to the
|
|
38
|
-
# shortcutted `input:` object
|
|
39
|
-
all_extras.each do |ext|
|
|
40
|
-
# It's possible that the `extra` was not passed along by this point,
|
|
41
|
-
# don't re-add it if it wasn't given here.
|
|
42
|
-
if inputs.key?(ext)
|
|
43
|
-
input[ext] = inputs[ext]
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
38
|
if input
|
|
48
39
|
# This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
|
|
49
40
|
input_kwargs = input.to_h
|
|
50
41
|
client_mutation_id = input_kwargs.delete(:client_mutation_id)
|
|
51
|
-
|
|
52
|
-
# Relay Classic Mutations with no `argument`s
|
|
53
|
-
# don't require `input:`
|
|
54
|
-
input_kwargs = {}
|
|
42
|
+
inputs[:input] = input_kwargs
|
|
55
43
|
end
|
|
56
44
|
|
|
57
|
-
return_value =
|
|
58
|
-
super(**input_kwargs)
|
|
59
|
-
else
|
|
60
|
-
super()
|
|
61
|
-
end
|
|
45
|
+
return_value = super(**inputs)
|
|
62
46
|
|
|
63
47
|
context.query.after_lazy(return_value) do |return_hash|
|
|
64
48
|
# It might be an error
|
|
@@ -68,112 +52,6 @@ module GraphQL
|
|
|
68
52
|
return_hash
|
|
69
53
|
end
|
|
70
54
|
end
|
|
71
|
-
|
|
72
|
-
class << self
|
|
73
|
-
def dummy
|
|
74
|
-
@dummy ||= begin
|
|
75
|
-
d = Class.new(GraphQL::Schema::Resolver)
|
|
76
|
-
d.argument_class(self.argument_class)
|
|
77
|
-
# TODO make this lazier?
|
|
78
|
-
d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
|
|
79
|
-
d
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def field_arguments(context = GraphQL::Query::NullContext)
|
|
84
|
-
dummy.arguments(context)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def get_field_argument(name, context = GraphQL::Query::NullContext)
|
|
88
|
-
dummy.get_argument(name, context)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def own_field_arguments
|
|
92
|
-
dummy.own_arguments
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def all_field_argument_definitions
|
|
96
|
-
dummy.all_argument_definitions
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Also apply this argument to the input type:
|
|
100
|
-
def argument(*args, own_argument: false, **kwargs, &block)
|
|
101
|
-
it = input_type # make sure any inherited arguments are already added to it
|
|
102
|
-
arg = super(*args, **kwargs, &block)
|
|
103
|
-
|
|
104
|
-
# This definition might be overriding something inherited;
|
|
105
|
-
# if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
|
|
106
|
-
prev_args = it.own_arguments[arg.graphql_name]
|
|
107
|
-
case prev_args
|
|
108
|
-
when GraphQL::Schema::Argument
|
|
109
|
-
if prev_args.owner != self
|
|
110
|
-
it.own_arguments.delete(arg.graphql_name)
|
|
111
|
-
end
|
|
112
|
-
when Array
|
|
113
|
-
prev_args.reject! { |a| a.owner != self }
|
|
114
|
-
if prev_args.empty?
|
|
115
|
-
it.own_arguments.delete(arg.graphql_name)
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it.add_argument(arg)
|
|
120
|
-
arg
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# The base class for generated input object types
|
|
124
|
-
# @param new_class [Class] The base class to use for generating input object definitions
|
|
125
|
-
# @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})
|
|
126
|
-
def input_object_class(new_class = nil)
|
|
127
|
-
if new_class
|
|
128
|
-
@input_object_class = new_class
|
|
129
|
-
end
|
|
130
|
-
@input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# @param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
|
|
134
|
-
# @return [Class] The generated {Schema::InputObject} class for this mutation's `input`
|
|
135
|
-
def input_type(new_input_type = nil)
|
|
136
|
-
if new_input_type
|
|
137
|
-
@input_type = new_input_type
|
|
138
|
-
end
|
|
139
|
-
@input_type ||= generate_input_type
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
private
|
|
143
|
-
|
|
144
|
-
# Generate the input type for the `input:` argument
|
|
145
|
-
# To customize how input objects are generated, override this method
|
|
146
|
-
# @return [Class] a subclass of {.input_object_class}
|
|
147
|
-
def generate_input_type
|
|
148
|
-
mutation_args = all_argument_definitions
|
|
149
|
-
mutation_class = self
|
|
150
|
-
Class.new(input_object_class) do
|
|
151
|
-
class << self
|
|
152
|
-
def default_graphql_name
|
|
153
|
-
"#{self.mutation.graphql_name}Input"
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def description(new_desc = nil)
|
|
157
|
-
super || "Autogenerated input type of #{self.mutation.graphql_name}"
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
mutation(mutation_class)
|
|
161
|
-
# these might be inherited:
|
|
162
|
-
mutation_args.each do |arg|
|
|
163
|
-
add_argument(arg)
|
|
164
|
-
end
|
|
165
|
-
argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
private
|
|
171
|
-
|
|
172
|
-
def authorize_arguments(args, values)
|
|
173
|
-
# remove the `input` wrapper to match values
|
|
174
|
-
input_args = args["input"].type.unwrap.arguments(context)
|
|
175
|
-
super(input_args, values)
|
|
176
|
-
end
|
|
177
55
|
end
|
|
178
56
|
end
|
|
179
57
|
end
|
|
@@ -205,16 +205,20 @@ module GraphQL
|
|
|
205
205
|
end
|
|
206
206
|
end
|
|
207
207
|
|
|
208
|
-
def get_argument(name, context = GraphQL::Query::NullContext)
|
|
208
|
+
def get_argument(name, context = GraphQL::Query::NullContext.instance)
|
|
209
209
|
self.class.get_argument(name, context)
|
|
210
210
|
end
|
|
211
211
|
|
|
212
212
|
class << self
|
|
213
|
-
def field_arguments(context = GraphQL::Query::NullContext)
|
|
213
|
+
def field_arguments(context = GraphQL::Query::NullContext.instance)
|
|
214
214
|
arguments(context)
|
|
215
215
|
end
|
|
216
216
|
|
|
217
|
-
def
|
|
217
|
+
def any_field_arguments?
|
|
218
|
+
any_arguments?
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
|
|
218
222
|
get_argument(name, context)
|
|
219
223
|
end
|
|
220
224
|
|
|
@@ -19,9 +19,9 @@ module GraphQL
|
|
|
19
19
|
|
|
20
20
|
def specified_by_url(new_url = nil)
|
|
21
21
|
if new_url
|
|
22
|
-
|
|
23
|
-
elsif
|
|
24
|
-
|
|
22
|
+
directive(GraphQL::Schema::Directive::SpecifiedBy, url: new_url)
|
|
23
|
+
elsif (directive = directives.find { |dir| dir.graphql_name == "specifiedBy" })
|
|
24
|
+
directive.arguments[:url] # rubocop:disable Development/ContextIsPassedCop
|
|
25
25
|
elsif superclass.respond_to?(:specified_by_url)
|
|
26
26
|
superclass.specified_by_url
|
|
27
27
|
else
|
|
@@ -28,14 +28,19 @@ module GraphQL
|
|
|
28
28
|
def resolve_with_support(**args)
|
|
29
29
|
result = nil
|
|
30
30
|
unsubscribed = true
|
|
31
|
-
catch :graphql_subscription_unsubscribed do
|
|
31
|
+
unsubscribed_result = catch :graphql_subscription_unsubscribed do
|
|
32
32
|
result = super
|
|
33
33
|
unsubscribed = false
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
if unsubscribed
|
|
38
|
-
|
|
38
|
+
if unsubscribed_result
|
|
39
|
+
context.namespace(:subscriptions)[:final_update] = true
|
|
40
|
+
unsubscribed_result
|
|
41
|
+
else
|
|
42
|
+
context.skip
|
|
43
|
+
end
|
|
39
44
|
else
|
|
40
45
|
result
|
|
41
46
|
end
|
|
@@ -94,9 +99,11 @@ module GraphQL
|
|
|
94
99
|
end
|
|
95
100
|
|
|
96
101
|
# Call this to halt execution and remove this subscription from the system
|
|
97
|
-
|
|
102
|
+
# @param update_value [Object] if present, deliver this update before unsubscribing
|
|
103
|
+
# @return [void]
|
|
104
|
+
def unsubscribe(update_value = nil)
|
|
98
105
|
context.namespace(:subscriptions)[:unsubscribed] = true
|
|
99
|
-
throw :graphql_subscription_unsubscribed
|
|
106
|
+
throw :graphql_subscription_unsubscribed, update_value
|
|
100
107
|
end
|
|
101
108
|
|
|
102
109
|
READING_SCOPE = ::Object.new
|
data/lib/graphql/schema/union.rb
CHANGED
|
@@ -10,7 +10,7 @@ module GraphQL
|
|
|
10
10
|
super
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def possible_types(*types, context: GraphQL::Query::NullContext, **options)
|
|
13
|
+
def possible_types(*types, context: GraphQL::Query::NullContext.instance, **options)
|
|
14
14
|
if types.any?
|
|
15
15
|
types.each do |t|
|
|
16
16
|
assert_valid_union_member(t)
|
|
@@ -4,37 +4,12 @@ require 'set'
|
|
|
4
4
|
|
|
5
5
|
module GraphQL
|
|
6
6
|
class Schema
|
|
7
|
-
# Restrict access to a {GraphQL::Schema} with a user-defined
|
|
7
|
+
# Restrict access to a {GraphQL::Schema} with a user-defined `visible?` implementations.
|
|
8
8
|
#
|
|
9
9
|
# When validating and executing a query, all access to schema members
|
|
10
10
|
# should go through a warden. If you access the schema directly,
|
|
11
11
|
# you may show a client something that it shouldn't be allowed to see.
|
|
12
12
|
#
|
|
13
|
-
# @example Hiding private fields
|
|
14
|
-
# private_members = -> (member, ctx) { member.metadata[:private] }
|
|
15
|
-
# result = Schema.execute(query_string, except: private_members)
|
|
16
|
-
#
|
|
17
|
-
# @example Custom filter implementation
|
|
18
|
-
# # It must respond to `#call(member)`.
|
|
19
|
-
# class MissingRequiredFlags
|
|
20
|
-
# def initialize(user)
|
|
21
|
-
# @user = user
|
|
22
|
-
# end
|
|
23
|
-
#
|
|
24
|
-
# # Return `false` if any required flags are missing
|
|
25
|
-
# def call(member, ctx)
|
|
26
|
-
# member.metadata[:required_flags].any? do |flag|
|
|
27
|
-
# !@user.has_flag?(flag)
|
|
28
|
-
# end
|
|
29
|
-
# end
|
|
30
|
-
# end
|
|
31
|
-
#
|
|
32
|
-
# # Then, use the custom filter in query:
|
|
33
|
-
# missing_required_flags = MissingRequiredFlags.new(current_user)
|
|
34
|
-
#
|
|
35
|
-
# # This query can only access members which match the user's flags
|
|
36
|
-
# result = Schema.execute(query_string, except: missing_required_flags)
|
|
37
|
-
#
|
|
38
13
|
# @api private
|
|
39
14
|
class Warden
|
|
40
15
|
def self.from_context(context)
|
|
@@ -85,6 +60,7 @@ module GraphQL
|
|
|
85
60
|
def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
|
|
86
61
|
def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
|
|
87
62
|
def arguments(owner, ctx); owner.arguments(ctx); end
|
|
63
|
+
def loadable?(type, ctx); type.visible?(ctx); end
|
|
88
64
|
end
|
|
89
65
|
end
|
|
90
66
|
|
|
@@ -109,33 +85,28 @@ module GraphQL
|
|
|
109
85
|
def fields(type_defn); type_defn.all_field_definitions; end # rubocop:disable Development/ContextIsPassedCop
|
|
110
86
|
def get_field(parent_type, field_name); @schema.get_field(parent_type, field_name); end
|
|
111
87
|
def reachable_type?(type_name); true; end
|
|
88
|
+
def loadable?(type, _ctx); true; end
|
|
112
89
|
def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
|
|
113
90
|
def possible_types(type_defn); @schema.possible_types(type_defn); end
|
|
114
91
|
def interfaces(obj_type); obj_type.interfaces; end
|
|
115
92
|
end
|
|
116
93
|
|
|
117
|
-
# @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
|
|
118
94
|
# @param context [GraphQL::Query::Context]
|
|
119
95
|
# @param schema [GraphQL::Schema]
|
|
120
|
-
def initialize(
|
|
96
|
+
def initialize(context:, schema:)
|
|
121
97
|
@schema = schema
|
|
122
98
|
# Cache these to avoid repeated hits to the inheritance chain when one isn't present
|
|
123
99
|
@query = @schema.query
|
|
124
100
|
@mutation = @schema.mutation
|
|
125
101
|
@subscription = @schema.subscription
|
|
126
102
|
@context = context
|
|
127
|
-
@visibility_cache =
|
|
128
|
-
read_through { |m| filter.call(m, context) }
|
|
129
|
-
else
|
|
130
|
-
read_through { |m| schema.visible?(m, context) }
|
|
131
|
-
end
|
|
132
|
-
|
|
103
|
+
@visibility_cache = read_through { |m| schema.visible?(m, context) }
|
|
133
104
|
@visibility_cache.compare_by_identity
|
|
134
105
|
# Initialize all ivars to improve object shape consistency:
|
|
135
106
|
@types = @visible_types = @reachable_types = @visible_parent_fields =
|
|
136
107
|
@visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
|
|
137
108
|
@visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
|
|
138
|
-
@visible_and_reachable_type = @unions = @unfiltered_interfaces =
|
|
109
|
+
@visible_and_reachable_type = @unions = @unfiltered_interfaces =
|
|
139
110
|
@reachable_type_set =
|
|
140
111
|
nil
|
|
141
112
|
end
|
|
@@ -153,6 +124,11 @@ module GraphQL
|
|
|
153
124
|
end
|
|
154
125
|
end
|
|
155
126
|
|
|
127
|
+
# @return [Boolean] True if this type is used for `loads:` but not in the schema otherwise and not _explicitly_ hidden.
|
|
128
|
+
def loadable?(type, _ctx)
|
|
129
|
+
!reachable_type_set.include?(type) && visible_type?(type)
|
|
130
|
+
end
|
|
131
|
+
|
|
156
132
|
# @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
|
|
157
133
|
def get_type(type_name)
|
|
158
134
|
@visible_types ||= read_through do |name|
|
|
@@ -219,7 +195,16 @@ module GraphQL
|
|
|
219
195
|
# @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
|
|
220
196
|
# @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
|
|
221
197
|
def arguments(argument_owner, ctx = nil)
|
|
222
|
-
@visible_arguments ||= read_through { |o|
|
|
198
|
+
@visible_arguments ||= read_through { |o|
|
|
199
|
+
args = o.arguments(@context)
|
|
200
|
+
if args.any?
|
|
201
|
+
args = args.values
|
|
202
|
+
args.select! { |a| visible_argument?(a, @context) }
|
|
203
|
+
args
|
|
204
|
+
else
|
|
205
|
+
EmptyObjects::EMPTY_ARRAY
|
|
206
|
+
end
|
|
207
|
+
}
|
|
223
208
|
@visible_arguments[argument_owner]
|
|
224
209
|
end
|
|
225
210
|
|
|
@@ -242,7 +227,13 @@ module GraphQL
|
|
|
242
227
|
|
|
243
228
|
# @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
|
|
244
229
|
def interfaces(obj_type)
|
|
245
|
-
@visible_interfaces ||= read_through { |t|
|
|
230
|
+
@visible_interfaces ||= read_through { |t|
|
|
231
|
+
ints = t.interfaces(@context)
|
|
232
|
+
if ints.any?
|
|
233
|
+
ints.select! { |i| visible_type?(i) }
|
|
234
|
+
end
|
|
235
|
+
ints
|
|
236
|
+
}
|
|
246
237
|
@visible_interfaces[obj_type]
|
|
247
238
|
end
|
|
248
239
|
|
|
@@ -298,11 +289,26 @@ module GraphQL
|
|
|
298
289
|
next true if root_type?(type_defn) || type_defn.introspection?
|
|
299
290
|
|
|
300
291
|
if type_defn.kind.union?
|
|
301
|
-
|
|
292
|
+
possible_types(type_defn).any? && (referenced?(type_defn) || orphan_type?(type_defn))
|
|
302
293
|
elsif type_defn.kind.interface?
|
|
303
|
-
|
|
294
|
+
if possible_types(type_defn).any?
|
|
295
|
+
true
|
|
296
|
+
else
|
|
297
|
+
if @context.respond_to?(:logger) && (logger = @context.logger)
|
|
298
|
+
logger.debug { "Interface `#{type_defn.graphql_name}` hidden because it has no visible implementors" }
|
|
299
|
+
end
|
|
300
|
+
false
|
|
301
|
+
end
|
|
304
302
|
else
|
|
305
|
-
referenced?(type_defn)
|
|
303
|
+
if referenced?(type_defn)
|
|
304
|
+
true
|
|
305
|
+
elsif type_defn.kind.object?
|
|
306
|
+
# Show this object if it belongs to ...
|
|
307
|
+
interfaces(type_defn).any? { |t| referenced?(t) } || # an interface which is referenced in the schema
|
|
308
|
+
union_memberships(type_defn).any? { |t| referenced?(t) || orphan_type?(t) } # or a union which is referenced or added via orphan_types
|
|
309
|
+
else
|
|
310
|
+
false
|
|
311
|
+
end
|
|
306
312
|
end
|
|
307
313
|
end
|
|
308
314
|
|
|
@@ -357,35 +363,23 @@ module GraphQL
|
|
|
357
363
|
end
|
|
358
364
|
|
|
359
365
|
def referenced?(type_defn)
|
|
360
|
-
@references_to ||= @schema.references_to
|
|
361
366
|
graphql_name = type_defn.unwrap.graphql_name
|
|
362
|
-
members = @references_to
|
|
367
|
+
members = @schema.references_to(graphql_name)
|
|
363
368
|
members.any? { |m| visible?(m) }
|
|
364
369
|
end
|
|
365
370
|
|
|
366
|
-
NO_REFERENCES = [].freeze
|
|
367
|
-
|
|
368
371
|
def orphan_type?(type_defn)
|
|
369
372
|
@schema.orphan_types.include?(type_defn)
|
|
370
373
|
end
|
|
371
374
|
|
|
372
|
-
def visible_abstract_type?(type_defn)
|
|
373
|
-
type_defn.kind.object? && (
|
|
374
|
-
interfaces(type_defn).any? ||
|
|
375
|
-
union_memberships(type_defn).any?
|
|
376
|
-
)
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
def visible_possible_types?(type_defn)
|
|
380
|
-
possible_types(type_defn).any? { |t| visible_and_reachable_type?(t) }
|
|
381
|
-
end
|
|
382
|
-
|
|
383
375
|
def visible?(member)
|
|
384
376
|
@visibility_cache[member]
|
|
385
377
|
end
|
|
386
378
|
|
|
387
379
|
def read_through
|
|
388
|
-
Hash.new { |h, k| h[k] = yield(k) }
|
|
380
|
+
h = Hash.new { |h, k| h[k] = yield(k) }
|
|
381
|
+
h.compare_by_identity
|
|
382
|
+
h
|
|
389
383
|
end
|
|
390
384
|
|
|
391
385
|
def reachable_type_set
|
|
@@ -416,54 +410,62 @@ module GraphQL
|
|
|
416
410
|
end
|
|
417
411
|
end
|
|
418
412
|
|
|
413
|
+
included_interface_possible_types_set = Set.new
|
|
414
|
+
|
|
419
415
|
until unvisited_types.empty?
|
|
420
416
|
type = unvisited_types.pop
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
417
|
+
visit_type(type, unvisited_types, @reachable_type_set, rt_hash, included_interface_possible_types_set, include_interface_possible_types: false)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
@reachable_type_set
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def visit_type(type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types:)
|
|
424
|
+
if visited_type_set.add?(type) || (include_interface_possible_types && type.kind.interface? && included_interface_possible_types_set.add?(type))
|
|
425
|
+
type_by_name = type_by_name_hash[type.graphql_name] ||= type
|
|
426
|
+
if type_by_name != type
|
|
427
|
+
name_1, name_2 = [type.inspect, type_by_name.inspect].sort
|
|
428
|
+
raise DuplicateNamesError.new(
|
|
429
|
+
duplicated_name: type.graphql_name, duplicated_definition_1: name_1, duplicated_definition_2: name_2
|
|
430
|
+
)
|
|
431
|
+
end
|
|
432
|
+
if type.kind.input_object?
|
|
433
|
+
# recurse into visible arguments
|
|
434
|
+
arguments(type).each do |argument|
|
|
435
|
+
argument_type = argument.type.unwrap
|
|
436
|
+
unvisited_types << argument_type
|
|
427
437
|
end
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
# recurse into visible
|
|
436
|
-
|
|
437
|
-
unvisited_types <<
|
|
438
|
+
elsif type.kind.union?
|
|
439
|
+
# recurse into visible possible types
|
|
440
|
+
possible_types(type).each do |possible_type|
|
|
441
|
+
unvisited_types << possible_type
|
|
442
|
+
end
|
|
443
|
+
elsif type.kind.fields?
|
|
444
|
+
if type.kind.object?
|
|
445
|
+
# recurse into visible implemented interfaces
|
|
446
|
+
interfaces(type).each do |interface|
|
|
447
|
+
unvisited_types << interface
|
|
438
448
|
end
|
|
439
|
-
elsif
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
possible_types(type).each do |possible_type|
|
|
443
|
-
unvisited_types << possible_type
|
|
444
|
-
end
|
|
445
|
-
elsif type.kind.object?
|
|
446
|
-
# recurse into visible implemented interfaces
|
|
447
|
-
interfaces(type).each do |interface|
|
|
448
|
-
unvisited_types << interface
|
|
449
|
-
end
|
|
449
|
+
elsif include_interface_possible_types
|
|
450
|
+
possible_types(type).each do |pt|
|
|
451
|
+
unvisited_types << pt
|
|
450
452
|
end
|
|
453
|
+
end
|
|
454
|
+
# Don't visit interface possible types -- it's not enough to justify visibility
|
|
451
455
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
456
|
+
# recurse into visible fields
|
|
457
|
+
fields(type).each do |field|
|
|
458
|
+
field_type = field.type.unwrap
|
|
459
|
+
# In this case, if it's an interface, we want to include
|
|
460
|
+
visit_type(field_type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types: true)
|
|
461
|
+
# recurse into visible arguments
|
|
462
|
+
arguments(field).each do |argument|
|
|
463
|
+
argument_type = argument.type.unwrap
|
|
464
|
+
unvisited_types << argument_type
|
|
461
465
|
end
|
|
462
466
|
end
|
|
463
467
|
end
|
|
464
468
|
end
|
|
465
|
-
|
|
466
|
-
@reachable_type_set
|
|
467
469
|
end
|
|
468
470
|
end
|
|
469
471
|
end
|