graphql 2.4.3 → 2.4.13
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 +95 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/current.rb +6 -1
- 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/dashboard.css +3 -0
- data/lib/graphql/dashboard/statics/dashboard.js +78 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/traces/index.html.erb +63 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +60 -0
- data/lib/graphql/dashboard.rb +142 -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 +67 -40
- data/lib/graphql/execution/interpreter.rb +16 -6
- data/lib/graphql/execution/multiplex.rb +0 -4
- 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 +2 -2
- 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 +20 -22
- data/lib/graphql/railtie.rb +7 -0
- data/lib/graphql/schema/addition.rb +1 -1
- data/lib/graphql/schema/argument.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +8 -7
- 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 +70 -34
- 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 +90 -43
- 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/required_arguments_are_present.rb +1 -1
- 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 +2 -2
- data/lib/graphql/tracing/active_support_notifications_trace.rb +7 -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 +2 -0
- data/lib/graphql/tracing/appsignal_trace.rb +12 -0
- 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 +11 -0
- 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/new_relic_trace.rb +164 -41
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +4 -0
- 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 +737 -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 +31 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +11 -0
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +11 -0
- data/lib/graphql/tracing/statsd_trace.rb +15 -0
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +128 -1
- data/lib/graphql/tracing.rb +30 -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 +152 -10
- 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
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "graphql/dataloader/source"
|
3
|
+
require "graphql/dataloader/active_record_source"
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
class Dataloader
|
7
|
+
class ActiveRecordAssociationSource < GraphQL::Dataloader::Source
|
8
|
+
RECORD_SOURCE_CLASS = ActiveRecordSource
|
9
|
+
|
10
|
+
def initialize(association, scope = nil)
|
11
|
+
@association = association
|
12
|
+
@scope = scope
|
13
|
+
end
|
14
|
+
|
15
|
+
def load(record)
|
16
|
+
if (assoc = record.association(@association)).loaded?
|
17
|
+
assoc.target
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch(records)
|
24
|
+
record_classes = Set.new.compare_by_identity
|
25
|
+
associated_classes = Set.new.compare_by_identity
|
26
|
+
records.each do |record|
|
27
|
+
if record_classes.add?(record.class)
|
28
|
+
reflection = record.class.reflect_on_association(@association)
|
29
|
+
if !reflection.polymorphic? && reflection.klass
|
30
|
+
associated_classes.add(reflection.klass)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
available_records = []
|
36
|
+
associated_classes.each do |assoc_class|
|
37
|
+
already_loaded_records = dataloader.with(RECORD_SOURCE_CLASS, assoc_class).results.values
|
38
|
+
available_records.concat(already_loaded_records)
|
39
|
+
end
|
40
|
+
|
41
|
+
::ActiveRecord::Associations::Preloader.new(records: records, associations: @association, available_records: available_records, scope: @scope).call
|
42
|
+
|
43
|
+
loaded_associated_records = records.map { |r| r.public_send(@association) }
|
44
|
+
records_by_model = {}
|
45
|
+
loaded_associated_records.each do |record|
|
46
|
+
if record
|
47
|
+
updates = records_by_model[record.class] ||= {}
|
48
|
+
updates[record.id] = record
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if @scope.nil?
|
53
|
+
# Don't cache records loaded via scope because they might have reduced `SELECT`s
|
54
|
+
# Could check .select_values here?
|
55
|
+
records_by_model.each do |model_class, updates|
|
56
|
+
dataloader.with(RECORD_SOURCE_CLASS, model_class).merge(updates)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
loaded_associated_records
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "graphql/dataloader/source"
|
3
|
+
|
4
|
+
module GraphQL
|
5
|
+
class Dataloader
|
6
|
+
class ActiveRecordSource < GraphQL::Dataloader::Source
|
7
|
+
def initialize(model_class, find_by: model_class.primary_key)
|
8
|
+
@model_class = model_class
|
9
|
+
@find_by = find_by
|
10
|
+
@type_for_column = @model_class.type_for_attribute(@find_by)
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(requested_key)
|
14
|
+
casted_key = @type_for_column.cast(requested_key)
|
15
|
+
super(casted_key)
|
16
|
+
end
|
17
|
+
|
18
|
+
def fetch(record_ids)
|
19
|
+
records = @model_class.where(@find_by => record_ids)
|
20
|
+
record_lookup = {}
|
21
|
+
records.each { |r| record_lookup[r.public_send(@find_by)] = r }
|
22
|
+
record_ids.map { |id| record_lookup[id] }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -2,16 +2,20 @@
|
|
2
2
|
module GraphQL
|
3
3
|
class Dataloader
|
4
4
|
class AsyncDataloader < Dataloader
|
5
|
-
def yield
|
6
|
-
|
5
|
+
def yield(source = Fiber[:__graphql_current_dataloader_source])
|
6
|
+
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
7
|
+
trace&.dataloader_fiber_yield(source)
|
8
|
+
if (condition = Fiber[:graphql_dataloader_next_tick])
|
7
9
|
condition.wait
|
8
10
|
else
|
9
11
|
Fiber.yield
|
10
12
|
end
|
13
|
+
trace&.dataloader_fiber_resume(source)
|
11
14
|
nil
|
12
15
|
end
|
13
16
|
|
14
17
|
def run
|
18
|
+
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
15
19
|
jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
|
16
20
|
job_fibers = []
|
17
21
|
next_job_fibers = []
|
@@ -20,11 +24,12 @@ module GraphQL
|
|
20
24
|
first_pass = true
|
21
25
|
sources_condition = Async::Condition.new
|
22
26
|
manager = spawn_fiber do
|
23
|
-
|
27
|
+
trace&.begin_dataloader(self)
|
28
|
+
while first_pass || !job_fibers.empty?
|
24
29
|
first_pass = false
|
25
30
|
fiber_vars = get_fiber_variables
|
26
31
|
|
27
|
-
while (f = (job_fibers.shift || (((job_fibers.size + next_job_fibers.size + source_tasks.size) < jobs_fiber_limit) && spawn_job_fiber)))
|
32
|
+
while (f = (job_fibers.shift || (((job_fibers.size + next_job_fibers.size + source_tasks.size) < jobs_fiber_limit) && spawn_job_fiber(trace))))
|
28
33
|
if f.alive?
|
29
34
|
finished = run_fiber(f)
|
30
35
|
if !finished
|
@@ -37,8 +42,8 @@ module GraphQL
|
|
37
42
|
|
38
43
|
Sync do |root_task|
|
39
44
|
set_fiber_variables(fiber_vars)
|
40
|
-
while source_tasks.
|
41
|
-
while (task = (source_tasks.shift || (((job_fibers.size + next_job_fibers.size + source_tasks.size + next_source_tasks.size) < total_fiber_limit) && spawn_source_task(root_task, sources_condition))))
|
45
|
+
while !source_tasks.empty? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) }
|
46
|
+
while (task = (source_tasks.shift || (((job_fibers.size + next_job_fibers.size + source_tasks.size + next_source_tasks.size) < total_fiber_limit) && spawn_source_task(root_task, sources_condition, trace))))
|
42
47
|
if task.alive?
|
43
48
|
root_task.yield # give the source task a chance to run
|
44
49
|
next_source_tasks << task
|
@@ -50,6 +55,7 @@ module GraphQL
|
|
50
55
|
end
|
51
56
|
end
|
52
57
|
end
|
58
|
+
trace&.end_dataloader(self)
|
53
59
|
end
|
54
60
|
|
55
61
|
manager.resume
|
@@ -63,7 +69,7 @@ module GraphQL
|
|
63
69
|
|
64
70
|
private
|
65
71
|
|
66
|
-
def spawn_source_task(parent_task, condition)
|
72
|
+
def spawn_source_task(parent_task, condition, trace)
|
67
73
|
pending_sources = nil
|
68
74
|
@source_cache.each_value do |source_by_batch_params|
|
69
75
|
source_by_batch_params.each_value do |source|
|
@@ -77,10 +83,16 @@ module GraphQL
|
|
77
83
|
if pending_sources
|
78
84
|
fiber_vars = get_fiber_variables
|
79
85
|
parent_task.async do
|
86
|
+
trace&.dataloader_spawn_source_fiber(pending_sources)
|
80
87
|
set_fiber_variables(fiber_vars)
|
81
|
-
|
82
|
-
pending_sources.each
|
88
|
+
Fiber[:graphql_dataloader_next_tick] = condition
|
89
|
+
pending_sources.each do |s|
|
90
|
+
trace&.begin_dataloader_source(s)
|
91
|
+
s.run_pending_keys
|
92
|
+
trace&.end_dataloader_source(s)
|
93
|
+
end
|
83
94
|
cleanup_fiber
|
95
|
+
trace&.dataloader_fiber_exit
|
84
96
|
end
|
85
97
|
end
|
86
98
|
end
|
@@ -11,7 +11,7 @@ module GraphQL
|
|
11
11
|
# executed synchronously.
|
12
12
|
def run; end
|
13
13
|
def run_isolated; yield; end
|
14
|
-
def yield
|
14
|
+
def yield(_source)
|
15
15
|
raise GraphQL::Error, "GraphQL::Dataloader is not running -- add `use GraphQL::Dataloader` to your schema to use Dataloader sources."
|
16
16
|
end
|
17
17
|
|
@@ -73,7 +73,7 @@ module GraphQL
|
|
73
73
|
end
|
74
74
|
}
|
75
75
|
|
76
|
-
if pending_keys.
|
76
|
+
if !pending_keys.empty?
|
77
77
|
sync(pending_keys)
|
78
78
|
end
|
79
79
|
|
@@ -93,14 +93,14 @@ module GraphQL
|
|
93
93
|
# Then run the batch and update the cache.
|
94
94
|
# @return [void]
|
95
95
|
def sync(pending_result_keys)
|
96
|
-
@dataloader.yield
|
96
|
+
@dataloader.yield(self)
|
97
97
|
iterations = 0
|
98
98
|
while pending_result_keys.any? { |key| !@results.key?(key) }
|
99
99
|
iterations += 1
|
100
100
|
if iterations > MAX_ITERATIONS
|
101
101
|
raise "#{self.class}#sync tried #{MAX_ITERATIONS} times to load pending keys (#{pending_result_keys}), but they still weren't loaded. There is likely a circular dependency#{@dataloader.fiber_limit ? " or `fiber_limit: #{@dataloader.fiber_limit}` is set too low" : ""}."
|
102
102
|
end
|
103
|
-
@dataloader.yield
|
103
|
+
@dataloader.yield(self)
|
104
104
|
end
|
105
105
|
nil
|
106
106
|
end
|
data/lib/graphql/dataloader.rb
CHANGED
@@ -4,6 +4,8 @@ require "graphql/dataloader/null_dataloader"
|
|
4
4
|
require "graphql/dataloader/request"
|
5
5
|
require "graphql/dataloader/request_all"
|
6
6
|
require "graphql/dataloader/source"
|
7
|
+
require "graphql/dataloader/active_record_association_source"
|
8
|
+
require "graphql/dataloader/active_record_source"
|
7
9
|
|
8
10
|
module GraphQL
|
9
11
|
# This plugin supports Fiber-based concurrency, along with {GraphQL::Dataloader::Source}.
|
@@ -78,10 +80,7 @@ module GraphQL
|
|
78
80
|
def get_fiber_variables
|
79
81
|
fiber_vars = {}
|
80
82
|
Thread.current.keys.each do |fiber_var_key|
|
81
|
-
|
82
|
-
if fiber_var_key != :__graphql_runtime_info
|
83
|
-
fiber_vars[fiber_var_key] = Thread.current[fiber_var_key]
|
84
|
-
end
|
83
|
+
fiber_vars[fiber_var_key] = Thread.current[fiber_var_key]
|
85
84
|
end
|
86
85
|
fiber_vars
|
87
86
|
end
|
@@ -132,8 +131,11 @@ module GraphQL
|
|
132
131
|
# Dataloader will resume the fiber after the requested data has been loaded (by another Fiber).
|
133
132
|
#
|
134
133
|
# @return [void]
|
135
|
-
def yield
|
134
|
+
def yield(source = Fiber[:__graphql_current_dataloader_source])
|
135
|
+
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
136
|
+
trace&.dataloader_fiber_yield(source)
|
136
137
|
Fiber.yield
|
138
|
+
trace&.dataloader_fiber_resume(source)
|
137
139
|
nil
|
138
140
|
end
|
139
141
|
|
@@ -187,6 +189,7 @@ module GraphQL
|
|
187
189
|
end
|
188
190
|
|
189
191
|
def run
|
192
|
+
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
190
193
|
jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
|
191
194
|
job_fibers = []
|
192
195
|
next_job_fibers = []
|
@@ -194,10 +197,11 @@ module GraphQL
|
|
194
197
|
next_source_fibers = []
|
195
198
|
first_pass = true
|
196
199
|
manager = spawn_fiber do
|
197
|
-
|
200
|
+
trace&.begin_dataloader(self)
|
201
|
+
while first_pass || !job_fibers.empty?
|
198
202
|
first_pass = false
|
199
203
|
|
200
|
-
while (f = (job_fibers.shift || (((next_job_fibers.size + job_fibers.size) < jobs_fiber_limit) && spawn_job_fiber)))
|
204
|
+
while (f = (job_fibers.shift || (((next_job_fibers.size + job_fibers.size) < jobs_fiber_limit) && spawn_job_fiber(trace))))
|
201
205
|
if f.alive?
|
202
206
|
finished = run_fiber(f)
|
203
207
|
if !finished
|
@@ -207,8 +211,8 @@ module GraphQL
|
|
207
211
|
end
|
208
212
|
join_queues(job_fibers, next_job_fibers)
|
209
213
|
|
210
|
-
while (source_fibers.
|
211
|
-
while (f = source_fibers.shift || (((job_fibers.size + source_fibers.size + next_source_fibers.size + next_job_fibers.size) < total_fiber_limit) && spawn_source_fiber))
|
214
|
+
while (!source_fibers.empty? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) })
|
215
|
+
while (f = source_fibers.shift || (((job_fibers.size + source_fibers.size + next_source_fibers.size + next_job_fibers.size) < total_fiber_limit) && spawn_source_fiber(trace)))
|
212
216
|
if f.alive?
|
213
217
|
finished = run_fiber(f)
|
214
218
|
if !finished
|
@@ -219,6 +223,8 @@ module GraphQL
|
|
219
223
|
join_queues(source_fibers, next_source_fibers)
|
220
224
|
end
|
221
225
|
end
|
226
|
+
|
227
|
+
trace&.end_dataloader(self)
|
222
228
|
end
|
223
229
|
|
224
230
|
run_fiber(manager)
|
@@ -227,12 +233,13 @@ module GraphQL
|
|
227
233
|
raise "Invariant: Manager fiber didn't terminate properly."
|
228
234
|
end
|
229
235
|
|
230
|
-
if job_fibers.
|
236
|
+
if !job_fibers.empty?
|
231
237
|
raise "Invariant: job fibers should have exited but #{job_fibers.size} remained"
|
232
238
|
end
|
233
|
-
if source_fibers.
|
239
|
+
if !source_fibers.empty?
|
234
240
|
raise "Invariant: source fibers should have exited but #{source_fibers.size} remained"
|
235
241
|
end
|
242
|
+
|
236
243
|
rescue UncaughtThrowError => e
|
237
244
|
throw e.tag, e.value
|
238
245
|
end
|
@@ -250,6 +257,22 @@ module GraphQL
|
|
250
257
|
}
|
251
258
|
end
|
252
259
|
|
260
|
+
# Pre-warm the Dataloader cache with ActiveRecord objects which were loaded elsewhere.
|
261
|
+
# These will be used by {Dataloader::ActiveRecordSource}, {Dataloader::ActiveRecordAssociationSource} and their helper
|
262
|
+
# methods, `dataload_record` and `dataload_association`.
|
263
|
+
# @param records [Array<ActiveRecord::Base>] Already-loaded records to warm the cache with
|
264
|
+
# @param index_by [Symbol] The attribute to use as the cache key. (Should match `find_by:` when using {ActiveRecordSource})
|
265
|
+
# @return [void]
|
266
|
+
def merge_records(records, index_by: :id)
|
267
|
+
records_by_class = Hash.new { |h, k| h[k] = {} }
|
268
|
+
records.each do |r|
|
269
|
+
records_by_class[r.class][r.public_send(index_by)] = r
|
270
|
+
end
|
271
|
+
records_by_class.each do |r_class, records|
|
272
|
+
with(ActiveRecordSource, r_class).merge(records)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
253
276
|
private
|
254
277
|
|
255
278
|
def calculate_fiber_limit
|
@@ -269,17 +292,19 @@ module GraphQL
|
|
269
292
|
new_queue.clear
|
270
293
|
end
|
271
294
|
|
272
|
-
def spawn_job_fiber
|
273
|
-
if
|
295
|
+
def spawn_job_fiber(trace)
|
296
|
+
if !@pending_jobs.empty?
|
274
297
|
spawn_fiber do
|
298
|
+
trace&.dataloader_spawn_execution_fiber(@pending_jobs)
|
275
299
|
while job = @pending_jobs.shift
|
276
300
|
job.call
|
277
301
|
end
|
302
|
+
trace&.dataloader_fiber_exit
|
278
303
|
end
|
279
304
|
end
|
280
305
|
end
|
281
306
|
|
282
|
-
def spawn_source_fiber
|
307
|
+
def spawn_source_fiber(trace)
|
283
308
|
pending_sources = nil
|
284
309
|
@source_cache.each_value do |source_by_batch_params|
|
285
310
|
source_by_batch_params.each_value do |source|
|
@@ -292,10 +317,14 @@ module GraphQL
|
|
292
317
|
|
293
318
|
if pending_sources
|
294
319
|
spawn_fiber do
|
320
|
+
trace&.dataloader_spawn_source_fiber(pending_sources)
|
295
321
|
pending_sources.each do |source|
|
296
322
|
Fiber[:__graphql_current_dataloader_source] = source
|
323
|
+
trace&.begin_dataloader_source(source)
|
297
324
|
source.run_pending_keys
|
325
|
+
trace&.end_dataloader_source(source)
|
298
326
|
end
|
327
|
+
trace&.dataloader_fiber_exit
|
299
328
|
end
|
300
329
|
end
|
301
330
|
end
|
@@ -22,7 +22,7 @@ module GraphQL
|
|
22
22
|
|
23
23
|
if smallest_depth
|
24
24
|
lazies = lazies_at_depth.delete(smallest_depth)
|
25
|
-
if lazies.
|
25
|
+
if !lazies.empty?
|
26
26
|
dataloader.append_job {
|
27
27
|
lazies.each(&:value) # resolve these Lazy instances
|
28
28
|
}
|
@@ -55,7 +55,7 @@ module GraphQL
|
|
55
55
|
# these approaches.
|
56
56
|
dataloader.run
|
57
57
|
next_results = []
|
58
|
-
while results.
|
58
|
+
while !results.empty?
|
59
59
|
result_value = results.shift
|
60
60
|
if result_value.is_a?(Runtime::GraphQLResultHash) || result_value.is_a?(Hash)
|
61
61
|
results.concat(result_value.values)
|
@@ -81,7 +81,7 @@ module GraphQL
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
if next_results.
|
84
|
+
if !next_results.empty?
|
85
85
|
# Any pending data loader jobs may populate the
|
86
86
|
# resutl arrays or result hashes accumulated in
|
87
87
|
# `next_results``. Run those **to completion**
|
@@ -5,7 +5,10 @@ module GraphQL
|
|
5
5
|
class Interpreter
|
6
6
|
class Runtime
|
7
7
|
module GraphQLResult
|
8
|
-
def initialize(result_name, result_type, application_value, parent_result, is_non_null_in_parent, selections, is_eager)
|
8
|
+
def initialize(result_name, result_type, application_value, parent_result, is_non_null_in_parent, selections, is_eager, ast_node, graphql_arguments, graphql_field) # rubocop:disable Metrics/ParameterLists
|
9
|
+
@ast_node = ast_node
|
10
|
+
@graphql_arguments = graphql_arguments
|
11
|
+
@graphql_field = graphql_field
|
9
12
|
@graphql_parent = parent_result
|
10
13
|
@graphql_application_value = application_value
|
11
14
|
@graphql_result_type = result_type
|
@@ -31,14 +34,14 @@ module GraphQL
|
|
31
34
|
|
32
35
|
attr_accessor :graphql_dead
|
33
36
|
attr_reader :graphql_parent, :graphql_result_name, :graphql_is_non_null_in_parent,
|
34
|
-
:graphql_application_value, :graphql_result_type, :graphql_selections, :graphql_is_eager
|
37
|
+
:graphql_application_value, :graphql_result_type, :graphql_selections, :graphql_is_eager, :ast_node, :graphql_arguments, :graphql_field
|
35
38
|
|
36
39
|
# @return [Hash] Plain-Ruby result data (`@graphql_metadata` contains Result wrapper objects)
|
37
40
|
attr_accessor :graphql_result_data
|
38
41
|
end
|
39
42
|
|
40
43
|
class GraphQLResultHash
|
41
|
-
def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager)
|
44
|
+
def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager, _ast_node, _graphql_arguments, graphql_field) # rubocop:disable Metrics/ParameterLists
|
42
45
|
super
|
43
46
|
@graphql_result_data = {}
|
44
47
|
end
|
@@ -126,7 +129,7 @@ module GraphQL
|
|
126
129
|
class GraphQLResultArray
|
127
130
|
include GraphQLResult
|
128
131
|
|
129
|
-
def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager)
|
132
|
+
def initialize(_result_name, _result_type, _application_value, _parent_result, _is_non_null_in_parent, _selections, _is_eager, _ast_node, _graphql_arguments, graphql_field) # rubocop:disable Metrics/ParameterLists
|
130
133
|
super
|
131
134
|
@graphql_result_data = []
|
132
135
|
end
|
@@ -168,6 +171,10 @@ module GraphQL
|
|
168
171
|
def values
|
169
172
|
(@graphql_metadata || @graphql_result_data)
|
170
173
|
end
|
174
|
+
|
175
|
+
def [](idx)
|
176
|
+
(@graphql_metadata || @graphql_result_data)[idx]
|
177
|
+
end
|
171
178
|
end
|
172
179
|
end
|
173
180
|
end
|