graphql 2.6.6 → 2.6.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3366525e188ac8b81b4dc7bdc8e34bb1839153fbec23d8e2a5faf07c02b56aa6
4
- data.tar.gz: 414d8f17cee8d40adf8c5923427e83d187efdbd08871c7b9d8bbd4fa13b0e550
3
+ metadata.gz: 75192ceea307d33645d2d511db98530f8021c8af45af33fc75e86dcd69f53952
4
+ data.tar.gz: ff3ee9e77876ad45fb67491fb5076df4614ab086ecfa15e476b3d35bca2e3b22
5
5
  SHA512:
6
- metadata.gz: f4423d53187dcf97e67ae1ba93cc9b5135c7db35cab04abc5533b96e97e3abd5d2c4bbbe683a64abc0117a022743a53df804d170e5fbd0fd7430a3987466531b
7
- data.tar.gz: c6093a9a53e554aed992da96b80007bbe10df7ac9552c4a1dc0cce19ae8a3f33fd3e2cb0858c117c1e061c4b996a4af8a7b161b31b4f3806ff3a30a84dfaddb2
6
+ metadata.gz: 50bc8591ece79fc8070b4c3a6a3611f29e9a4ad84a94e6f310a5fd2c00ac0d10b6db5ebe44474e1d5f002a76615d6a25dd4dbfc2a8f56ec1c2d0d88972ce95e2
7
+ data.tar.gz: b28b83923ac25bb605d7fe1e9b25a64e37aa8173a64c958849287cdd0c87cc419deea25f36b4d525a6ea17088b7a02cb0a51011750c568337a6274b0373ff43b
@@ -4,6 +4,11 @@ module GraphQL
4
4
  class Dataloader
5
5
  class AsyncDataloader < Dataloader
6
6
  def self.use(...)
7
+ install_graphql_methods
8
+ super
9
+ end
10
+
11
+ def self.install_graphql_methods
7
12
  if !Async::Task.method_defined?(:cancel)
8
13
  Async::Task.alias_method(:cancel, :stop)
9
14
  end
@@ -11,7 +16,6 @@ module GraphQL
11
16
  Async::Task.attr_accessor(:graphql_async_dataloader_run)
12
17
  Async::Task.attr_accessor(:graphql_async_dataloader_condition)
13
18
  end
14
- super
15
19
  end
16
20
 
17
21
  def initialize(...)
@@ -54,7 +58,10 @@ module GraphQL
54
58
  @running_tasks = nil
55
59
  @tasks_channel = nil
56
60
  @tasks_channel_task = nil
57
- @finished_all_tasks = nil
61
+ @activity = nil
62
+ @task_error = nil
63
+ @expected_resumes = 0
64
+ @mode = nil
58
65
 
59
66
  @snoozed_jobs_condition = Async::Condition.new
60
67
  @snoozed_sources_condition = Async::Condition.new
@@ -77,20 +84,41 @@ module GraphQL
77
84
  @tasks_channel_task.cancel
78
85
  end
79
86
 
80
- def wait_for_queues
81
- @finished_all_tasks.wait
82
- @finished_all_tasks = Async::Promise.new
87
+ def wait_for_activity
88
+ @activity.wait
89
+ end
90
+
91
+ def quiesced?
92
+ @running_tasks.empty? && @tasks_channel.empty? && @expected_resumes == 0
93
+ end
94
+
95
+ def has_pending_work?
96
+ @mode == :jobs ? @jobs.any? : @dataloader.pending_sources.any?(&:pending?) # rubocop:disable Development/NoneWithoutBlockCop
97
+ end
98
+
99
+ def has_bandwidth?
100
+ @mode == :jobs ? jobs_bandwidth? : sources_bandwidth?
101
+ end
102
+
103
+ # Signalled tasks don't appear in any accounting until their first slice
104
+ # pushes `:resumed_task`, so they have to be counted at signal time:
105
+ def expect_resumes(count)
106
+ @expected_resumes = count
83
107
  end
84
108
 
85
- def wait_for_no_running_tasks
86
- @no_running_tasks.wait
87
- @no_running_tasks = Async::Promise.new
109
+ def check_error!
110
+ if (err = @task_error)
111
+ @task_error = nil
112
+ raise err
113
+ end
88
114
  end
89
115
 
90
116
  def new_queues(mode)
117
+ @mode = mode
91
118
  @tasks_channel = Async::Queue.new(parent: @root_task)
92
- @no_running_tasks = Async::Promise.new
93
- @finished_all_tasks = Async::Promise.new
119
+ @activity = Async::Condition.new
120
+ @task_error = nil
121
+ @expected_resumes = 0
94
122
  @running_tasks = []
95
123
  @tasks_channel_task = @root_task.async do |_t|
96
124
  while ((msg, data) = @tasks_channel.wait)
@@ -99,23 +127,18 @@ module GraphQL
99
127
  @running_tasks.push(data)
100
128
  data.run
101
129
  when :resumed_task
130
+ if @expected_resumes > 0
131
+ @expected_resumes -= 1
132
+ end
102
133
  @running_tasks.push(data)
103
134
  when :finished_task, :paused_task
104
135
  @running_tasks.delete(data)
105
- has_pending_work = mode == :jobs ? @jobs.any? : @dataloader.pending_sources.any?(&:pending?) # rubocop:disable Development/NoneWithoutBlockCop
106
- if @running_tasks.empty?
107
- @no_running_tasks.resolve(true)
108
- has_bandwidth = mode == :jobs ? jobs_bandwidth? : sources_bandwidth?
109
- if (!has_pending_work) || (!has_bandwidth)
110
- @finished_all_tasks.resolve(true)
111
- end
112
- end
113
136
  when :task_error
114
- @no_running_tasks.resolve(true)
115
- @finished_all_tasks.reject(data)
137
+ @task_error ||= data
116
138
  else
117
139
  raise ArgumentError, "Unknown tasks_channel action: #{msg.inspect}"
118
140
  end
141
+ @activity.signal
119
142
  end
120
143
  end
121
144
  end
@@ -240,19 +263,20 @@ module GraphQL
240
263
  private
241
264
 
242
265
  def run_queue(run, condition, mode)
243
- should_wait_for_all_tasks = false
266
+ opened_queues = false
244
267
 
245
- if (unsnoozed = condition.waiting?)
246
- should_wait_for_all_tasks = true
268
+ if condition.waiting?
269
+ opened_queues = true
247
270
  run.new_queues(mode)
271
+ run.expect_resumes(condition.instance_variable_get(:@ready).num_waiting)
248
272
  condition.signal
249
273
  end
250
274
 
251
- while (pending_work = (mode == :jobs) ? (!run.jobs.empty? && run.jobs_bandwidth? ? run.jobs : nil) : (drain_pending_sources)) || unsnoozed
252
- unsnoozed = false
275
+ loop do
276
+ pending_work = (mode == :jobs) ? (!run.jobs.empty? && run.jobs_bandwidth? ? run.jobs : nil) : (drain_pending_sources)
253
277
  if pending_work
254
- if should_wait_for_all_tasks == false
255
- should_wait_for_all_tasks = true
278
+ if opened_queues == false
279
+ opened_queues = true
256
280
  run.new_queues(mode)
257
281
  end
258
282
  num_tasks = mode == :sources ? run.current_sources_fiber_limit : 1
@@ -262,14 +286,23 @@ module GraphQL
262
286
  spawn_tasks(run, mode, condition, pending_work, num_tasks)
263
287
  end
264
288
 
265
- run.wait_for_no_running_tasks
266
- end
289
+ if !opened_queues
290
+ break
291
+ end
292
+
293
+ run.check_error!
267
294
 
268
- if should_wait_for_all_tasks
269
- run.wait_for_queues
295
+ if run.quiesced?
296
+ if !run.has_pending_work? || !run.has_bandwidth?
297
+ break
298
+ end
299
+ # Quiesced, but more work appeared - loop around to drain it.
300
+ else
301
+ run.wait_for_activity
302
+ end
270
303
  end
271
304
  ensure
272
- if should_wait_for_all_tasks
305
+ if opened_queues
273
306
  run.close_queues
274
307
  end
275
308
  end
@@ -83,12 +83,12 @@ module GraphQL
83
83
  end
84
84
  end
85
85
 
86
- continue_selections.each do |frs|
87
- @runner.add_step(frs)
88
- end
89
-
90
86
  i += 2
91
87
  end
88
+
89
+ continue_selections.each do |frs|
90
+ @runner.add_step(frs)
91
+ end
92
92
  end
93
93
  end
94
94
  end
@@ -82,6 +82,7 @@ module GraphQL
82
82
  replace_late_bound_types_with_built_in(types)
83
83
 
84
84
  schema_extensions = nil
85
+ definitions_by_name = nil
85
86
  document.definitions.each do |definition|
86
87
  case definition
87
88
  when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
@@ -101,9 +102,16 @@ module GraphQL
101
102
  if prev_type.nil? || prev_type.is_a?(Schema::LateBoundType)
102
103
  if definition.is_a?(GraphQL::Language::Nodes::ObjectTypeDefinition) || definition.is_a?(Language::Nodes::InterfaceTypeDefinition)
103
104
  interface_names = definition.interfaces.map(&:name)
104
- transitive_names = interface_names.map { |n| document.definitions.find { |d| d.respond_to?(:name) && d.name == n }&.interfaces&.map(&:name) }
105
- transitive_names.flatten!
106
- transitive_names.compact!
105
+ if !interface_names.empty?
106
+ definitions_by_name ||= document.definitions.each_with_object({}) do |d, by_name|
107
+ by_name[d.name] ||= d if d.respond_to?(:name)
108
+ end
109
+ transitive_names = interface_names.map { |n| definitions_by_name[n]&.interfaces&.map(&:name) }
110
+ transitive_names.flatten!
111
+ transitive_names.compact!
112
+ else
113
+ transitive_names = interface_names
114
+ end
107
115
  if !(missing_transitive_interfaces = transitive_names - interface_names).empty?
108
116
  raise GraphQL::Schema::InvalidDocumentError, "type #{definition.name} is missing one or more transitive interface names: #{missing_transitive_interfaces.join(", ")}. Add them to the type's `implements` list and try again."
109
117
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.6.6"
3
+ VERSION = "2.6.7"
4
4
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.6
4
+ version: 2.6.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-07-21 00:00:00.000000000 Z
10
+ date: 2026-07-28 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64