graphql 2.4.3 → 2.5.0
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/graphql/analysis/analyzer.rb +2 -1
- data/lib/graphql/analysis/visitor.rb +38 -41
- data/lib/graphql/analysis.rb +15 -12
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +6 -1
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +158 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +64 -0
- data/lib/graphql/dataloader/active_record_source.rb +26 -0
- data/lib/graphql/dataloader/async_dataloader.rb +21 -9
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/source.rb +3 -3
- data/lib/graphql/dataloader.rb +43 -14
- data/lib/graphql/execution/interpreter/resolve.rb +3 -3
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +11 -4
- data/lib/graphql/execution/interpreter/runtime.rb +78 -41
- data/lib/graphql/execution/interpreter.rb +16 -7
- data/lib/graphql/execution/multiplex.rb +1 -5
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +5 -15
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/document_from_schema_definition.rb +8 -7
- data/lib/graphql/language/lexer.rb +11 -4
- data/lib/graphql/language/nodes.rb +3 -0
- data/lib/graphql/language/parser.rb +15 -8
- data/lib/graphql/language/printer.rb +8 -8
- data/lib/graphql/language/static_visitor.rb +37 -33
- data/lib/graphql/language/visitor.rb +59 -55
- data/lib/graphql/pagination/connection.rb +1 -1
- data/lib/graphql/query/context/scoped_context.rb +1 -1
- data/lib/graphql/query/context.rb +6 -5
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query.rb +19 -23
- data/lib/graphql/railtie.rb +7 -0
- data/lib/graphql/schema/addition.rb +1 -1
- data/lib/graphql/schema/argument.rb +7 -8
- data/lib/graphql/schema/build_from_definition.rb +99 -53
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/directive.rb +2 -2
- data/lib/graphql/schema/enum.rb +36 -1
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +12 -12
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +3 -1
- data/lib/graphql/schema/input_object.rb +76 -39
- data/lib/graphql/schema/interface.rb +3 -2
- data/lib/graphql/schema/loader.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +25 -17
- data/lib/graphql/schema/member/has_dataloader.rb +60 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +19 -1
- data/lib/graphql/schema/member/has_interfaces.rb +5 -5
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/object.rb +25 -8
- data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +11 -10
- data/lib/graphql/schema/subscription.rb +52 -6
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/validator/required_validator.rb +23 -6
- data/lib/graphql/schema/validator.rb +1 -1
- data/lib/graphql/schema/visibility/migration.rb +1 -0
- data/lib/graphql/schema/visibility/profile.rb +69 -237
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +169 -28
- data/lib/graphql/schema/warden.rb +18 -5
- data/lib/graphql/schema.rb +93 -44
- data/lib/graphql/static_validation/all_rules.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +1 -0
- data/lib/graphql/static_validation/validator.rb +6 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +12 -1
- data/lib/graphql/subscriptions/serialize.rb +1 -1
- data/lib/graphql/subscriptions.rb +1 -1
- data/lib/graphql/testing/helpers.rb +7 -4
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +9 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
- data/lib/graphql/tracing/appsignal_trace.rb +32 -55
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +46 -158
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +93 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +285 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +182 -34
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +734 -0
- data/lib/graphql/tracing/platform_trace.rb +5 -0
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
- data/lib/graphql/tracing/prometheus_trace.rb +72 -68
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -55
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +63 -94
- data/lib/graphql/tracing/statsd_trace.rb +33 -41
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +111 -1
- data/lib/graphql/tracing.rb +31 -30
- data/lib/graphql/types/relay/connection_behaviors.rb +3 -3
- data/lib/graphql/types/relay/edge_behaviors.rb +2 -2
- data/lib/graphql/types.rb +18 -11
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +55 -47
- metadata +146 -11
- data/lib/graphql/backtrace/inspect_result.rb +0 -38
- data/lib/graphql/backtrace/trace.rb +0 -93
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
|
@@ -19,13 +19,22 @@ module GraphQL
|
|
|
19
19
|
# propagate null.
|
|
20
20
|
null false
|
|
21
21
|
|
|
22
|
+
# @api private
|
|
22
23
|
def initialize(object:, context:, field:)
|
|
23
24
|
super
|
|
24
25
|
# Figure out whether this is an update or an initial subscription
|
|
25
26
|
@mode = context.query.subscription_update? ? :update : :subscribe
|
|
27
|
+
@subscription_written = false
|
|
28
|
+
@original_arguments = nil
|
|
29
|
+
if (subs_ns = context.namespace(:subscriptions)) &&
|
|
30
|
+
(sub_insts = subs_ns[:subscriptions])
|
|
31
|
+
sub_insts[context.current_path] = self
|
|
32
|
+
end
|
|
26
33
|
end
|
|
27
34
|
|
|
35
|
+
# @api private
|
|
28
36
|
def resolve_with_support(**args)
|
|
37
|
+
@original_arguments = args # before `loads:` have been run
|
|
29
38
|
result = nil
|
|
30
39
|
unsubscribed = true
|
|
31
40
|
unsubscribed_result = catch :graphql_subscription_unsubscribed do
|
|
@@ -46,7 +55,9 @@ module GraphQL
|
|
|
46
55
|
end
|
|
47
56
|
end
|
|
48
57
|
|
|
49
|
-
# Implement the {Resolve} API
|
|
58
|
+
# Implement the {Resolve} API.
|
|
59
|
+
# You can implement this if you want code to run for _both_ the initial subscription
|
|
60
|
+
# and for later updates. Or, implement {#subscribe} and {#update}
|
|
50
61
|
def resolve(**args)
|
|
51
62
|
# Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
|
|
52
63
|
# have an unexpected `@mode`
|
|
@@ -54,8 +65,9 @@ module GraphQL
|
|
|
54
65
|
end
|
|
55
66
|
|
|
56
67
|
# Wrap the user-defined `#subscribe` hook
|
|
68
|
+
# @api private
|
|
57
69
|
def resolve_subscribe(**args)
|
|
58
|
-
ret_val = args.
|
|
70
|
+
ret_val = !args.empty? ? subscribe(**args) : subscribe
|
|
59
71
|
if ret_val == :no_response
|
|
60
72
|
context.skip
|
|
61
73
|
else
|
|
@@ -71,8 +83,9 @@ module GraphQL
|
|
|
71
83
|
end
|
|
72
84
|
|
|
73
85
|
# Wrap the user-provided `#update` hook
|
|
86
|
+
# @api private
|
|
74
87
|
def resolve_update(**args)
|
|
75
|
-
ret_val = args.
|
|
88
|
+
ret_val = !args.empty? ? update(**args) : update
|
|
76
89
|
if ret_val == NO_UPDATE
|
|
77
90
|
context.namespace(:subscriptions)[:no_update] = true
|
|
78
91
|
context.skip
|
|
@@ -106,14 +119,13 @@ module GraphQL
|
|
|
106
119
|
throw :graphql_subscription_unsubscribed, update_value
|
|
107
120
|
end
|
|
108
121
|
|
|
109
|
-
READING_SCOPE = ::Object.new
|
|
110
122
|
# Call this method to provide a new subscription_scope; OR
|
|
111
123
|
# call it without an argument to get the subscription_scope
|
|
112
124
|
# @param new_scope [Symbol]
|
|
113
125
|
# @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription.
|
|
114
126
|
# @return [Symbol]
|
|
115
|
-
def self.subscription_scope(new_scope =
|
|
116
|
-
if new_scope !=
|
|
127
|
+
def self.subscription_scope(new_scope = NOT_CONFIGURED, optional: false)
|
|
128
|
+
if new_scope != NOT_CONFIGURED
|
|
117
129
|
@subscription_scope = new_scope
|
|
118
130
|
@subscription_scope_optional = optional
|
|
119
131
|
elsif defined?(@subscription_scope)
|
|
@@ -150,6 +162,40 @@ module GraphQL
|
|
|
150
162
|
def self.topic_for(arguments:, field:, scope:)
|
|
151
163
|
Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
|
|
152
164
|
end
|
|
165
|
+
|
|
166
|
+
# Calls through to `schema.subscriptions` to register this subscription with the backend.
|
|
167
|
+
# This is automatically called by GraphQL-Ruby after a query finishes successfully,
|
|
168
|
+
# but if you need to commit the subscription during `#subscribe`, you can call it there.
|
|
169
|
+
# (This method also sets a flag showing that this subscription was already written.)
|
|
170
|
+
#
|
|
171
|
+
# If you call this method yourself, you may also need to {#unsubscribe}
|
|
172
|
+
# or call `subscriptions.delete_subscription` to clean up the database if the query crashes with an error
|
|
173
|
+
# later in execution.
|
|
174
|
+
# @return [void]
|
|
175
|
+
def write_subscription
|
|
176
|
+
if subscription_written?
|
|
177
|
+
raise GraphQL::Error, "`write_subscription` was called but `#{self.class}#subscription_written?` is already true. Remove a call to `write subscription`."
|
|
178
|
+
else
|
|
179
|
+
@subscription_written = true
|
|
180
|
+
context.schema.subscriptions.write_subscription(context.query, [event])
|
|
181
|
+
end
|
|
182
|
+
nil
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# @return [Boolean] `true` if {#write_subscription} was called already
|
|
186
|
+
def subscription_written?
|
|
187
|
+
@subscription_written
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# @return [Subscriptions::Event] This object is used as a representation of this subscription for the backend
|
|
191
|
+
def event
|
|
192
|
+
@event ||= Subscriptions::Event.new(
|
|
193
|
+
name: field.name,
|
|
194
|
+
arguments: @original_arguments,
|
|
195
|
+
context: context,
|
|
196
|
+
field: field,
|
|
197
|
+
)
|
|
198
|
+
end
|
|
153
199
|
end
|
|
154
200
|
end
|
|
155
201
|
end
|
data/lib/graphql/schema/union.rb
CHANGED
|
@@ -11,7 +11,7 @@ module GraphQL
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def possible_types(*types, context: GraphQL::Query::NullContext.instance, **options)
|
|
14
|
-
if types.
|
|
14
|
+
if !types.empty?
|
|
15
15
|
types.each do |t|
|
|
16
16
|
assert_valid_union_member(t)
|
|
17
17
|
type_memberships << type_membership_class.new(self, t, **options)
|
|
@@ -51,19 +51,36 @@ module GraphQL
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def validate(_object, context, value)
|
|
54
|
-
|
|
54
|
+
fully_matched_conditions = 0
|
|
55
|
+
partially_matched_conditions = 0
|
|
55
56
|
|
|
56
57
|
if !value.nil?
|
|
57
58
|
@one_of.each do |one_of_condition|
|
|
58
59
|
case one_of_condition
|
|
59
60
|
when Symbol
|
|
60
61
|
if value.key?(one_of_condition)
|
|
61
|
-
|
|
62
|
+
fully_matched_conditions += 1
|
|
62
63
|
end
|
|
63
64
|
when Array
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
any_match = false
|
|
66
|
+
full_match = true
|
|
67
|
+
|
|
68
|
+
one_of_condition.each do |k|
|
|
69
|
+
if value.key?(k)
|
|
70
|
+
any_match = true
|
|
71
|
+
else
|
|
72
|
+
full_match = false
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
partial_match = !full_match && any_match
|
|
77
|
+
|
|
78
|
+
if full_match
|
|
79
|
+
fully_matched_conditions += 1
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
if partial_match
|
|
83
|
+
partially_matched_conditions += 1
|
|
67
84
|
end
|
|
68
85
|
else
|
|
69
86
|
raise ArgumentError, "Unknown one_of condition: #{one_of_condition.inspect}"
|
|
@@ -71,7 +88,7 @@ module GraphQL
|
|
|
71
88
|
end
|
|
72
89
|
end
|
|
73
90
|
|
|
74
|
-
if
|
|
91
|
+
if fully_matched_conditions == 1 && partially_matched_conditions == 0
|
|
75
92
|
nil # OK
|
|
76
93
|
else
|
|
77
94
|
@message || build_message(context)
|
|
@@ -18,7 +18,7 @@ module GraphQL
|
|
|
18
18
|
if ctx.respond_to?(:types) && (types = ctx.types).is_a?(self)
|
|
19
19
|
types
|
|
20
20
|
else
|
|
21
|
-
schema.visibility.profile_for(ctx
|
|
21
|
+
schema.visibility.profile_for(ctx)
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -38,38 +38,17 @@ module GraphQL
|
|
|
38
38
|
@all_types = {}
|
|
39
39
|
@all_types_loaded = false
|
|
40
40
|
@unvisited_types = []
|
|
41
|
-
@referenced_types = Hash.new { |h, type_defn| h[type_defn] = [] }.compare_by_identity
|
|
42
|
-
@cached_directives = {}
|
|
43
41
|
@all_directives = nil
|
|
44
|
-
@cached_visible = Hash.new { |h, member|
|
|
45
|
-
h[member] = @schema.visible?(member, @context)
|
|
46
|
-
}.compare_by_identity
|
|
42
|
+
@cached_visible = Hash.new { |h, member| h[member] = @schema.visible?(member, @context) }.compare_by_identity
|
|
47
43
|
|
|
48
44
|
@cached_visible_fields = Hash.new { |h, owner|
|
|
49
45
|
h[owner] = Hash.new do |h2, field|
|
|
50
|
-
h2[field] =
|
|
51
|
-
(ret_type = field.type.unwrap) &&
|
|
52
|
-
@cached_visible[ret_type] &&
|
|
53
|
-
(owner == field.owner || (!owner.kind.object?) || field_on_visible_interface?(field, owner))
|
|
54
|
-
|
|
55
|
-
if !field.introspection?
|
|
56
|
-
# The problem is that some introspection fields may have references
|
|
57
|
-
# to non-custom introspection types.
|
|
58
|
-
# If those were added here, they'd cause a DuplicateNamesError.
|
|
59
|
-
# This is basically a bug -- those fields _should_ reference the custom types.
|
|
60
|
-
add_type(ret_type, field)
|
|
61
|
-
end
|
|
62
|
-
true
|
|
63
|
-
else
|
|
64
|
-
false
|
|
65
|
-
end
|
|
46
|
+
h2[field] = visible_field_for(owner, field)
|
|
66
47
|
end.compare_by_identity
|
|
67
48
|
}.compare_by_identity
|
|
68
49
|
|
|
69
50
|
@cached_visible_arguments = Hash.new do |h, arg|
|
|
70
51
|
h[arg] = if @cached_visible[arg] && (arg_type = arg.type.unwrap) && @cached_visible[arg_type]
|
|
71
|
-
add_type(arg_type, arg)
|
|
72
|
-
arg.validate_default_value
|
|
73
52
|
true
|
|
74
53
|
else
|
|
75
54
|
false
|
|
@@ -88,39 +67,7 @@ module GraphQL
|
|
|
88
67
|
end
|
|
89
68
|
end.compare_by_identity
|
|
90
69
|
|
|
91
|
-
@cached_possible_types = Hash.new
|
|
92
|
-
h[type] = case type.kind.name
|
|
93
|
-
when "INTERFACE"
|
|
94
|
-
load_all_types
|
|
95
|
-
pts = []
|
|
96
|
-
@unfiltered_interface_type_memberships[type].each { |itm|
|
|
97
|
-
if @cached_visible[itm] && (ot = itm.object_type) && @cached_visible[ot] && referenced?(ot)
|
|
98
|
-
pts << ot
|
|
99
|
-
end
|
|
100
|
-
}
|
|
101
|
-
pts
|
|
102
|
-
when "UNION"
|
|
103
|
-
pts = []
|
|
104
|
-
type.type_memberships.each { |tm|
|
|
105
|
-
if @cached_visible[tm] &&
|
|
106
|
-
(ot = tm.object_type) &&
|
|
107
|
-
@cached_visible[ot] &&
|
|
108
|
-
referenced?(ot)
|
|
109
|
-
pts << ot
|
|
110
|
-
end
|
|
111
|
-
}
|
|
112
|
-
pts
|
|
113
|
-
when "OBJECT"
|
|
114
|
-
load_all_types
|
|
115
|
-
if @all_types[type.graphql_name] == type
|
|
116
|
-
[type]
|
|
117
|
-
else
|
|
118
|
-
EmptyObjects::EMPTY_ARRAY
|
|
119
|
-
end
|
|
120
|
-
else
|
|
121
|
-
GraphQL::EmptyObjects::EMPTY_ARRAY
|
|
122
|
-
end
|
|
123
|
-
end.compare_by_identity
|
|
70
|
+
@cached_possible_types = Hash.new { |h, type| h[type] = possible_types_for(type) }.compare_by_identity
|
|
124
71
|
|
|
125
72
|
@cached_enum_values = Hash.new do |h, enum_t|
|
|
126
73
|
values = non_duplicate_items(enum_t.enum_values(@context), @cached_visible)
|
|
@@ -137,6 +84,8 @@ module GraphQL
|
|
|
137
84
|
@cached_arguments = Hash.new do |h, owner|
|
|
138
85
|
h[owner] = non_duplicate_items(owner.all_argument_definitions, @cached_visible_arguments)
|
|
139
86
|
end.compare_by_identity
|
|
87
|
+
|
|
88
|
+
@loadable_possible_types = Hash.new { |h, union_type| h[union_type] = union_type.possible_types }.compare_by_identity
|
|
140
89
|
end
|
|
141
90
|
|
|
142
91
|
def field_on_visible_interface?(field, owner)
|
|
@@ -164,17 +113,12 @@ module GraphQL
|
|
|
164
113
|
end
|
|
165
114
|
|
|
166
115
|
def type(type_name)
|
|
167
|
-
t =
|
|
168
|
-
loaded_t
|
|
169
|
-
elsif !@all_types_loaded
|
|
170
|
-
load_all_types
|
|
171
|
-
@all_types[type_name]
|
|
172
|
-
end
|
|
116
|
+
t = @schema.visibility.get_type(type_name) # rubocop:disable Development/ContextIsPassedCop
|
|
173
117
|
if t
|
|
174
118
|
if t.is_a?(Array)
|
|
175
119
|
vis_t = nil
|
|
176
120
|
t.each do |t_defn|
|
|
177
|
-
if @cached_visible[t_defn]
|
|
121
|
+
if @cached_visible[t_defn] && referenced?(t_defn)
|
|
178
122
|
if vis_t.nil?
|
|
179
123
|
vis_t = t_defn
|
|
180
124
|
else
|
|
@@ -184,7 +128,7 @@ module GraphQL
|
|
|
184
128
|
end
|
|
185
129
|
vis_t
|
|
186
130
|
else
|
|
187
|
-
if t && @cached_visible[t]
|
|
131
|
+
if t && @cached_visible[t] && referenced?(t)
|
|
188
132
|
t
|
|
189
133
|
else
|
|
190
134
|
nil
|
|
@@ -215,7 +159,7 @@ module GraphQL
|
|
|
215
159
|
end
|
|
216
160
|
end
|
|
217
161
|
end
|
|
218
|
-
visible_f
|
|
162
|
+
visible_f&.ensure_loaded
|
|
219
163
|
elsif f && @cached_visible_fields[owner][f.ensure_loaded]
|
|
220
164
|
f
|
|
221
165
|
else
|
|
@@ -267,15 +211,15 @@ module GraphQL
|
|
|
267
211
|
end
|
|
268
212
|
|
|
269
213
|
def query_root
|
|
270
|
-
|
|
214
|
+
((t = @schema.query) && @cached_visible[t]) ? t : nil
|
|
271
215
|
end
|
|
272
216
|
|
|
273
217
|
def mutation_root
|
|
274
|
-
|
|
218
|
+
((t = @schema.mutation) && @cached_visible[t]) ? t : nil
|
|
275
219
|
end
|
|
276
220
|
|
|
277
221
|
def subscription_root
|
|
278
|
-
|
|
222
|
+
((t = @schema.subscription) && @cached_visible[t]) ? t : nil
|
|
279
223
|
end
|
|
280
224
|
|
|
281
225
|
def all_types
|
|
@@ -293,38 +237,31 @@ module GraphQL
|
|
|
293
237
|
end
|
|
294
238
|
|
|
295
239
|
def directive_exists?(dir_name)
|
|
296
|
-
|
|
297
|
-
!!dir
|
|
298
|
-
else
|
|
299
|
-
load_all_types
|
|
300
|
-
!!@cached_directives[dir_name]
|
|
301
|
-
end
|
|
240
|
+
directives.any? { |d| d.graphql_name == dir_name }
|
|
302
241
|
end
|
|
303
242
|
|
|
304
243
|
def directives
|
|
305
|
-
@all_directives ||=
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
@schema.directives.each do |name, dir_defn|
|
|
309
|
-
if !@cached_directives[name] && @cached_visible[dir_defn]
|
|
310
|
-
dirs << dir_defn
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
dirs.concat(@cached_directives.values)
|
|
314
|
-
end
|
|
244
|
+
@all_directives ||= @schema.visibility.all_directives.select { |dir|
|
|
245
|
+
@cached_visible[dir] && @schema.visibility.all_references[dir].any? { |ref| ref == true || (@cached_visible[ref] && referenced?(ref)) }
|
|
246
|
+
}
|
|
315
247
|
end
|
|
316
248
|
|
|
317
249
|
def loadable?(t, _ctx)
|
|
250
|
+
load_all_types
|
|
318
251
|
!@all_types[t.graphql_name] && @cached_visible[t]
|
|
319
252
|
end
|
|
320
253
|
|
|
254
|
+
def loadable_possible_types(t, _ctx)
|
|
255
|
+
@loadable_possible_types[t]
|
|
256
|
+
end
|
|
257
|
+
|
|
321
258
|
def loaded_types
|
|
322
259
|
@all_types.values
|
|
323
260
|
end
|
|
324
261
|
|
|
325
|
-
def reachable_type?(
|
|
262
|
+
def reachable_type?(type_name)
|
|
326
263
|
load_all_types
|
|
327
|
-
!!@all_types[
|
|
264
|
+
!!@all_types[type_name]
|
|
328
265
|
end
|
|
329
266
|
|
|
330
267
|
def visible_enum_value?(enum_value, _ctx = nil)
|
|
@@ -333,29 +270,6 @@ module GraphQL
|
|
|
333
270
|
|
|
334
271
|
private
|
|
335
272
|
|
|
336
|
-
def add_if_visible(t)
|
|
337
|
-
(t && @cached_visible[t]) ? (add_type(t, true); t) : nil
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
def add_type(t, by_member)
|
|
341
|
-
if t && @cached_visible[t]
|
|
342
|
-
n = t.graphql_name
|
|
343
|
-
if (prev_t = @all_types[n])
|
|
344
|
-
if !prev_t.equal?(t)
|
|
345
|
-
raise_duplicate_definition(prev_t, t)
|
|
346
|
-
end
|
|
347
|
-
false
|
|
348
|
-
else
|
|
349
|
-
@referenced_types[t] << by_member
|
|
350
|
-
@all_types[n] = t
|
|
351
|
-
@unvisited_types << t
|
|
352
|
-
true
|
|
353
|
-
end
|
|
354
|
-
else
|
|
355
|
-
false
|
|
356
|
-
end
|
|
357
|
-
end
|
|
358
|
-
|
|
359
273
|
def non_duplicate_items(definitions, visibility_cache)
|
|
360
274
|
non_dups = []
|
|
361
275
|
definitions.each do |defn|
|
|
@@ -373,153 +287,71 @@ module GraphQL
|
|
|
373
287
|
raise DuplicateNamesError.new(duplicated_name: first_defn.path, duplicated_definition_1: first_defn.inspect, duplicated_definition_2: second_defn.inspect)
|
|
374
288
|
end
|
|
375
289
|
|
|
376
|
-
def referenced?(t)
|
|
377
|
-
load_all_types
|
|
378
|
-
@referenced_types[t].any? { |reference| (reference == true) || @cached_visible[reference] }
|
|
379
|
-
end
|
|
380
|
-
|
|
381
290
|
def load_all_types
|
|
382
291
|
return if @all_types_loaded
|
|
383
292
|
@all_types_loaded = true
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
# Don't include any orphan_types whose interfaces aren't visible.
|
|
392
|
-
@schema.orphan_types.each do |orphan_type|
|
|
393
|
-
if @cached_visible[orphan_type] &&
|
|
394
|
-
orphan_type.interface_type_memberships.any? { |tm| @cached_visible[tm] && @cached_visible[tm.abstract_type] }
|
|
395
|
-
entry_point_types << orphan_type
|
|
396
|
-
end
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
@schema.directives.each do |_dir_name, dir_class|
|
|
400
|
-
if @cached_visible[dir_class]
|
|
401
|
-
arguments(dir_class).each do |arg|
|
|
402
|
-
entry_point_types << arg.type.unwrap
|
|
403
|
-
end
|
|
404
|
-
end
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
entry_point_types.compact! # Root types might be nil
|
|
408
|
-
entry_point_types.flatten! # handle multiple defns
|
|
409
|
-
entry_point_types.each { |t| add_type(t, true) }
|
|
410
|
-
|
|
411
|
-
@unfiltered_interface_type_memberships = Hash.new { |h, k| h[k] = [] }.compare_by_identity
|
|
412
|
-
@add_possible_types = Set.new
|
|
413
|
-
@late_types = []
|
|
414
|
-
|
|
415
|
-
while @unvisited_types.any? || @late_types.any?
|
|
416
|
-
while t = @unvisited_types.pop
|
|
417
|
-
# These have already been checked for `.visible?`
|
|
418
|
-
visit_type(t)
|
|
419
|
-
end
|
|
420
|
-
@add_possible_types.each do |int_t|
|
|
421
|
-
itms = @unfiltered_interface_type_memberships[int_t]
|
|
422
|
-
itms.each do |itm|
|
|
423
|
-
if @cached_visible[itm] && (obj_type = itm.object_type) && @cached_visible[obj_type]
|
|
424
|
-
add_type(obj_type, itm)
|
|
293
|
+
visit = Visibility::Visit.new(@schema) do |member|
|
|
294
|
+
if member.is_a?(Module) && member.respond_to?(:kind)
|
|
295
|
+
if @cached_visible[member]
|
|
296
|
+
type_name = member.graphql_name
|
|
297
|
+
if (prev_t = @all_types[type_name]) && !prev_t.equal?(member)
|
|
298
|
+
raise_duplicate_definition(member, prev_t)
|
|
425
299
|
end
|
|
300
|
+
@all_types[type_name] = member
|
|
301
|
+
true
|
|
302
|
+
else
|
|
303
|
+
false
|
|
426
304
|
end
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
while (union_tm = @late_types.shift)
|
|
431
|
-
late_obj_t = union_tm.object_type
|
|
432
|
-
obj_t = @all_types[late_obj_t.graphql_name] || raise("Failed to resolve #{late_obj_t.graphql_name.inspect} from #{union_tm.inspect}")
|
|
433
|
-
union_tm.abstract_type.assign_type_membership_object_type(obj_t)
|
|
305
|
+
else
|
|
306
|
+
@cached_visible[member]
|
|
434
307
|
end
|
|
435
308
|
end
|
|
436
|
-
|
|
309
|
+
visit.visit_each
|
|
437
310
|
@all_types.delete_if { |type_name, type_defn| !referenced?(type_defn) }
|
|
438
311
|
nil
|
|
439
312
|
end
|
|
440
313
|
|
|
441
|
-
def
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
when "OBJECT", "INTERFACE"
|
|
445
|
-
if type.kind.object?
|
|
446
|
-
type.interface_type_memberships.each do |itm|
|
|
447
|
-
@unfiltered_interface_type_memberships[itm.abstract_type] << itm
|
|
448
|
-
end
|
|
449
|
-
# recurse into visible implemented interfaces
|
|
450
|
-
interfaces(type).each do |interface|
|
|
451
|
-
add_type(interface, type)
|
|
452
|
-
end
|
|
453
|
-
else
|
|
454
|
-
type.orphan_types.each { |t| add_type(t, type)}
|
|
455
|
-
end
|
|
456
|
-
|
|
457
|
-
# recurse into visible fields
|
|
458
|
-
t_f = type.all_field_definitions
|
|
459
|
-
t_f.each do |field|
|
|
460
|
-
field.ensure_loaded
|
|
461
|
-
if @cached_visible[field]
|
|
462
|
-
visit_directives(field)
|
|
463
|
-
field_type = field.type.unwrap
|
|
464
|
-
if field_type.kind.interface?
|
|
465
|
-
@add_possible_types.add(field_type)
|
|
466
|
-
end
|
|
467
|
-
add_type(field_type, field)
|
|
314
|
+
def referenced?(type_defn)
|
|
315
|
+
@schema.visibility.all_references[type_defn].any? { |r| r == true || @cached_visible[r] }
|
|
316
|
+
end
|
|
468
317
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
318
|
+
def possible_types_for(type)
|
|
319
|
+
case type.kind.name
|
|
320
|
+
when "INTERFACE"
|
|
321
|
+
pts = []
|
|
322
|
+
@schema.visibility.all_interface_type_memberships[type].each do |(itm, impl_type)|
|
|
323
|
+
if @cached_visible[itm] && @cached_visible[impl_type] && referenced?(impl_type)
|
|
324
|
+
pts << impl_type
|
|
474
325
|
end
|
|
475
326
|
end
|
|
476
|
-
|
|
477
|
-
# recurse into visible arguments
|
|
478
|
-
arguments(type).each do |argument|
|
|
479
|
-
visit_directives(argument)
|
|
480
|
-
add_type(argument.type.unwrap, argument)
|
|
481
|
-
end
|
|
327
|
+
pts
|
|
482
328
|
when "UNION"
|
|
483
|
-
|
|
484
|
-
type.type_memberships.each
|
|
485
|
-
if @cached_visible[tm]
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
if obj_t.is_a?(String)
|
|
491
|
-
obj_t = Member::BuildType.constantize(obj_t)
|
|
492
|
-
tm.object_type = obj_t
|
|
493
|
-
end
|
|
494
|
-
if @cached_visible[obj_t]
|
|
495
|
-
add_type(obj_t, tm)
|
|
496
|
-
end
|
|
497
|
-
end
|
|
329
|
+
pts = []
|
|
330
|
+
type.type_memberships.each { |tm|
|
|
331
|
+
if @cached_visible[tm] &&
|
|
332
|
+
(ot = tm.object_type) &&
|
|
333
|
+
@cached_visible[ot] &&
|
|
334
|
+
referenced?(ot)
|
|
335
|
+
pts << ot
|
|
498
336
|
end
|
|
337
|
+
}
|
|
338
|
+
pts
|
|
339
|
+
when "OBJECT"
|
|
340
|
+
if @cached_visible[type]
|
|
341
|
+
[type]
|
|
342
|
+
else
|
|
343
|
+
EmptyObjects::EMPTY_ARRAY
|
|
499
344
|
end
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
visit_directives(val)
|
|
503
|
-
end
|
|
504
|
-
when "SCALAR"
|
|
505
|
-
# pass
|
|
345
|
+
else
|
|
346
|
+
GraphQL::EmptyObjects::EMPTY_ARRAY
|
|
506
347
|
end
|
|
507
348
|
end
|
|
508
349
|
|
|
509
|
-
def
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
if (existing_dir = @cached_directives[dir_name])
|
|
515
|
-
if existing_dir != dir_class
|
|
516
|
-
raise ArgumentError, "Two directives for `@#{dir_name}`: #{existing_dir}, #{dir.class}"
|
|
517
|
-
end
|
|
518
|
-
else
|
|
519
|
-
@cached_directives[dir.graphql_name] = dir_class
|
|
520
|
-
end
|
|
521
|
-
end
|
|
522
|
-
}
|
|
350
|
+
def visible_field_for(owner, field)
|
|
351
|
+
@cached_visible[field] &&
|
|
352
|
+
(ret_type = field.type.unwrap) &&
|
|
353
|
+
@cached_visible[ret_type] &&
|
|
354
|
+
(owner == field.owner || (!owner.kind.object?) || field_on_visible_interface?(field, owner))
|
|
523
355
|
end
|
|
524
356
|
end
|
|
525
357
|
end
|