que-schema 0.1.1 → 0.1.3

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: 4438db2533fe5a222835a08cb3ba75791ee157b1b87753fcd304dc1c70bf4749
4
- data.tar.gz: 2c4136d7b17cf7905b87b8496b609e0d79b6e510c0f3c32ea19076e8f1961aa1
3
+ metadata.gz: 2dd48b725a6da899c882691afa3af22e3b4e1a6a5253f69eded20bbfe52c59e7
4
+ data.tar.gz: 8f2fdde04cebaa445a54b7281674257a414de7a1ad26077f61a6c85db481b3b0
5
5
  SHA512:
6
- metadata.gz: 6f42bf02fd3c6de18f3110ebc8315b053d78ee693861d3debd750ad6a6e2387536f4168c63fb6c509a517d36b5ae506bf6e0c746b94f96db8d598bfe34e63efd
7
- data.tar.gz: 39e649e71e5d217345bb29e078c020d8c3f63da926dd587ee1ede1f310a6f93435bd889854efa69504837741abd4c716b46fa850570bd28a0e32fa9d015dff99
6
+ metadata.gz: 26cb3c0d957a76c85d7d66cc66f4c72f1dd9c0244e1a58626ab309f658381451e044daf49364b775dfa5e9696c6eb9b06fe9baf0b27295c1d354fa6408f18d35
7
+ data.tar.gz: c41c48b31d14db35ea739c888c5dd424f19f1d4f24a2dbd4778ac97144f8482e178b3f7e86384304df84f2e975b1831ba621b5d3d23447a46fca971a6784bcab
data/CHANGELOG.md CHANGED
@@ -2,14 +2,22 @@
2
2
 
3
3
 
4
4
 
5
- ## [0.1.1] - 2026-03-09
5
+ ## [0.1.3] - 2026-04-01
6
6
 
7
- ### Fixed
7
+ ### Added
8
8
 
9
- - Schema dumper suppressing que_scheduler_* tables (1669e0d)
9
+ - Automatic que-scheduler schema management when que-scheduler gem is present (2bf5b3b)
10
10
 
11
- ## [0.1.0] - 2026-03-09
11
+ ## [0.1.2] - 2026-03-09
12
12
 
13
13
  ### Added
14
14
 
15
- - Schema dump/load support for Que via ActiveRecord integration (0aa34d1)
15
+ - Suppress Que-managed functions and triggers in schema dump (629c074)
16
+
17
+ ### Fixed
18
+
19
+ - Duplicate trigger errors during db:schema:load (629c074)
20
+
21
+ ### Changed
22
+
23
+ - SchemaDumper prepend timing for correct ancestor order (629c074)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- que-schema (0.1.1)
4
+ que-schema (0.1.3)
5
5
  activerecord (>= 6.0)
6
6
  que
7
7
  railties (>= 6.0)
@@ -7,8 +7,14 @@ module QueSchema
7
7
  ActiveRecord::Migration.include(QueSchema::SchemaStatements)
8
8
  ActiveRecord::Migration.include(QueSchema::MigrationHelpers)
9
9
  ActiveRecord::Schema.include(QueSchema::SchemaStatements)
10
- ActiveRecord::SchemaDumper.prepend(QueSchema::SchemaDumper)
11
10
  end
12
11
  end
12
+
13
+ # Prepend SchemaDumper after initialization so it sits
14
+ # above Fx/Scenic in the ancestor chain and can filter
15
+ # out Que-managed functions and triggers.
16
+ config.after_initialize do
17
+ ActiveRecord::SchemaDumper.prepend(QueSchema::SchemaDumper)
18
+ end
13
19
  end
14
20
  end
@@ -7,13 +7,15 @@ module QueSchema
7
7
  private
8
8
 
9
9
  def tables(stream)
10
- super
11
-
10
+ # Emit que_define_schema before tables so Que objects
11
+ # exist when later functions/triggers reference them.
12
12
  if postgresql? && (version = que_schema_version) && version > 0
13
13
  stream.puts " # Que internal schema — emitted by que-schema gem"
14
14
  stream.puts " que_define_schema(version: #{version})"
15
15
  stream.puts
16
16
  end
17
+
18
+ super
17
19
  end
18
20
 
19
21
  # Suppress Que-managed tables — Que.migrate! recreates them during
@@ -41,12 +43,78 @@ module QueSchema
41
43
  @connection.respond_to?(:adapter_name) && @connection.adapter_name.match?(/postgresql/i)
42
44
  end
43
45
 
44
- # Only tables created by Que.migrate! — other que_* tables
45
- # (e.g. que_scheduler_*) belong to separate gems.
46
- QUE_MANAGED_TABLES = %w[que_jobs que_lockers que_values].freeze
46
+ # Only objects created by Que.migrate! — other que_*
47
+ # objects (e.g. que_scheduler_*) belong to separate gems
48
+ # unless que-schema manages them too.
49
+ QUE_MANAGED_TABLES = %w[
50
+ que_jobs que_lockers que_values
51
+ ].freeze
52
+
53
+ QUE_MANAGED_FUNCTIONS = %w[
54
+ que_validate_tags que_determine_job_state
55
+ que_job_notify que_state_notify
56
+ ].freeze
57
+
58
+ QUE_MANAGED_TRIGGERS = %w[
59
+ que_job_notify que_state_notify
60
+ ].freeze
61
+
62
+ QUE_SCHEDULER_TABLES = %w[
63
+ que_scheduler_audit que_scheduler_audit_enqueued
64
+ ].freeze
65
+
66
+ QUE_SCHEDULER_FUNCTIONS = %w[
67
+ que_scheduler_check_job_exists
68
+ que_scheduler_prevent_job_deletion
69
+ ].freeze
70
+
71
+ QUE_SCHEDULER_TRIGGERS = %w[
72
+ que_scheduler_prevent_job_deletion_trigger
73
+ ].freeze
74
+
75
+ def que_scheduler?
76
+ defined?(Que::Scheduler::Migrations)
77
+ end
47
78
 
48
79
  def que_table?(table_name)
49
- QUE_MANAGED_TABLES.include?(table_name)
80
+ return true if QUE_MANAGED_TABLES.include?(table_name)
81
+ return true if que_scheduler? && QUE_SCHEDULER_TABLES.include?(table_name)
82
+
83
+ false
84
+ end
85
+
86
+ def que_function?(name)
87
+ return true if QUE_MANAGED_FUNCTIONS.include?(name.to_s)
88
+ return true if que_scheduler? && QUE_SCHEDULER_FUNCTIONS.include?(name.to_s)
89
+
90
+ false
91
+ end
92
+
93
+ def que_trigger?(name)
94
+ return true if QUE_MANAGED_TRIGGERS.include?(name.to_s)
95
+ return true if que_scheduler? && QUE_SCHEDULER_TRIGGERS.include?(name.to_s)
96
+
97
+ false
98
+ end
99
+
100
+ # Override Fx::SchemaDumper methods to filter out
101
+ # Que-managed objects when Fx is present.
102
+ def functions(stream)
103
+ return super unless postgresql? && defined?(::Fx)
104
+
105
+ dumpable = Fx.database.functions
106
+ .reject { |f| que_function?(f.name) }
107
+ dumpable.each { |f| stream.puts(f.to_schema) }
108
+ stream.puts if dumpable.any?
109
+ end
110
+
111
+ def triggers(stream)
112
+ return super unless postgresql? && defined?(::Fx)
113
+
114
+ dumpable = Fx.database.triggers
115
+ .reject { |t| que_trigger?(t.name) }
116
+ stream.puts if dumpable.any?
117
+ dumpable.each { |t| stream.puts(t.to_schema) }
50
118
  end
51
119
  end
52
120
  end
@@ -14,6 +14,14 @@ module QueSchema
14
14
 
15
15
  Que.connection_proc = proc { |&block| block.call(connection.raw_connection) }
16
16
  Que.migrate!(version: version.to_i)
17
+ apply_que_scheduler_schema
18
+ end
19
+
20
+ def apply_que_scheduler_schema
21
+ return unless defined?(Que::Scheduler::Migrations)
22
+
23
+ Que::Scheduler::Migrations.migrate!(version: Que::Scheduler::Migrations::MAX_VERSION)
24
+ Que::Scheduler::Migrations.reenqueue_scheduler_if_missing
17
25
  end
18
26
 
19
27
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QueSchema
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.3"
5
5
  end
@@ -45,14 +45,14 @@ RSpec.describe QueSchema::SchemaDumper do
45
45
  allow(connection).to receive(:execute).and_return([{"comment" => "7"}])
46
46
  end
47
47
 
48
- it "emits que_define_schema after tables" do
48
+ it "emits que_define_schema before tables" do
49
49
  stream = StringIO.new
50
50
  dumper.send(:tables, stream)
51
51
  output = stream.string
52
52
 
53
53
  expect(output).to include("que_define_schema(version: 7)")
54
54
  expect(output).to include("# original tables output")
55
- expect(output.index("que_define_schema")).to be > output.index("original tables")
55
+ expect(output.index("que_define_schema")).to be < output.index("original tables")
56
56
  end
57
57
  end
58
58
 
@@ -146,6 +146,70 @@ RSpec.describe QueSchema::SchemaDumper do
146
146
  end
147
147
  end
148
148
 
149
+ describe "#que_function? (private)" do
150
+ it "returns true for Que-managed functions" do
151
+ %w[que_validate_tags que_determine_job_state que_job_notify que_state_notify].each do |name|
152
+ expect(dumper.send(:que_function?, name)).to be true
153
+ end
154
+ end
155
+
156
+ it "returns false for functions from other que_* gems" do
157
+ expect(dumper.send(:que_function?, "que_scheduler_check_job_exists")).to be false
158
+ expect(dumper.send(:que_function?, "que_scheduler_prevent_job_deletion")).to be false
159
+ end
160
+ end
161
+
162
+ describe "#que_trigger? (private)" do
163
+ it "returns true for Que-managed triggers" do
164
+ expect(dumper.send(:que_trigger?, "que_job_notify")).to be true
165
+ expect(dumper.send(:que_trigger?, "que_state_notify")).to be true
166
+ end
167
+
168
+ it "returns false for triggers from other que_* gems" do
169
+ expect(dumper.send(:que_trigger?, "que_scheduler_prevent_job_deletion_trigger")).to be false
170
+ end
171
+ end
172
+
173
+ describe "#functions (private)" do
174
+ let(:que_fn) { double("function", name: "que_job_notify", to_schema: ' create_function :que_job_notify') }
175
+ let(:app_fn) { double("function", name: "my_app_function", to_schema: ' create_function :my_app_function') }
176
+ let(:scheduler_fn) { double("function", name: "que_scheduler_check_job_exists", to_schema: ' create_function :que_scheduler_check_job_exists') }
177
+
178
+ before do
179
+ stub_postgresql!
180
+ stub_const("Fx", double("Fx", database: double(functions: [que_fn, app_fn, scheduler_fn])))
181
+ end
182
+
183
+ it "filters out Que-managed functions" do
184
+ stream = StringIO.new
185
+ dumper.send(:functions, stream)
186
+ output = stream.string
187
+
188
+ expect(output).not_to include("que_job_notify")
189
+ expect(output).to include("my_app_function")
190
+ expect(output).to include("que_scheduler_check_job_exists")
191
+ end
192
+ end
193
+
194
+ describe "#triggers (private)" do
195
+ let(:que_trigger) { double("trigger", name: "que_job_notify", to_schema: ' create_trigger :que_job_notify') }
196
+ let(:app_trigger) { double("trigger", name: "que_scheduler_prevent_job_deletion_trigger", to_schema: ' create_trigger :que_scheduler_prevent_job_deletion_trigger') }
197
+
198
+ before do
199
+ stub_postgresql!
200
+ stub_const("Fx", double("Fx", database: double(triggers: [que_trigger, app_trigger])))
201
+ end
202
+
203
+ it "filters out Que-managed triggers" do
204
+ stream = StringIO.new
205
+ dumper.send(:triggers, stream)
206
+ output = stream.string
207
+
208
+ expect(output).not_to include("que_job_notify")
209
+ expect(output).to include("que_scheduler_prevent_job_deletion_trigger")
210
+ end
211
+ end
212
+
149
213
  describe "#que_table? (private)" do
150
214
  it "returns true for Que-managed tables" do
151
215
  expect(dumper.send(:que_table?, "que_jobs")).to be true
@@ -164,6 +228,96 @@ RSpec.describe QueSchema::SchemaDumper do
164
228
  end
165
229
  end
166
230
 
231
+ context "when que-scheduler is present" do
232
+ before do
233
+ stub_const("Que::Scheduler::Migrations", double("Migrations"))
234
+ end
235
+
236
+ describe "#que_table?" do
237
+ it "suppresses que_scheduler tables" do
238
+ expect(dumper.send(:que_table?, "que_scheduler_audit")).to be true
239
+ expect(dumper.send(:que_table?, "que_scheduler_audit_enqueued")).to be true
240
+ end
241
+
242
+ it "still suppresses core que tables" do
243
+ expect(dumper.send(:que_table?, "que_jobs")).to be true
244
+ end
245
+
246
+ it "does not suppress non-que tables" do
247
+ expect(dumper.send(:que_table?, "users")).to be false
248
+ end
249
+ end
250
+
251
+ describe "#que_function?" do
252
+ it "suppresses que_scheduler functions" do
253
+ expect(dumper.send(:que_function?, "que_scheduler_check_job_exists")).to be true
254
+ expect(dumper.send(:que_function?, "que_scheduler_prevent_job_deletion")).to be true
255
+ end
256
+
257
+ it "still suppresses core que functions" do
258
+ expect(dumper.send(:que_function?, "que_job_notify")).to be true
259
+ end
260
+ end
261
+
262
+ describe "#que_trigger?" do
263
+ it "suppresses que_scheduler triggers" do
264
+ expect(dumper.send(:que_trigger?, "que_scheduler_prevent_job_deletion_trigger")).to be true
265
+ end
266
+
267
+ it "still suppresses core que triggers" do
268
+ expect(dumper.send(:que_trigger?, "que_job_notify")).to be true
269
+ end
270
+ end
271
+
272
+ describe "#table" do
273
+ before { stub_postgresql! }
274
+
275
+ it "suppresses que_scheduler_audit" do
276
+ stream = StringIO.new
277
+ dumper.send(:table, "que_scheduler_audit", stream)
278
+ expect(stream.string).to be_empty
279
+ end
280
+ end
281
+
282
+ describe "#functions" do
283
+ before do
284
+ stub_postgresql!
285
+ stub_const("Fx", double("Fx", database: double(functions: [
286
+ double("function", name: "que_scheduler_check_job_exists", to_schema: " create_function :que_scheduler_check_job_exists"),
287
+ double("function", name: "my_app_function", to_schema: " create_function :my_app_function")
288
+ ])))
289
+ end
290
+
291
+ it "filters out que_scheduler functions" do
292
+ stream = StringIO.new
293
+ dumper.send(:functions, stream)
294
+ output = stream.string
295
+
296
+ expect(output).not_to include("que_scheduler_check_job_exists")
297
+ expect(output).to include("my_app_function")
298
+ end
299
+ end
300
+
301
+ describe "#triggers" do
302
+ before do
303
+ stub_postgresql!
304
+ stub_const("Fx", double("Fx", database: double(triggers: [
305
+ double("trigger", name: "que_scheduler_prevent_job_deletion_trigger", to_schema: " create_trigger :que_scheduler_prevent_job_deletion_trigger"),
306
+ double("trigger", name: "my_app_trigger", to_schema: " create_trigger :my_app_trigger")
307
+ ])))
308
+ end
309
+
310
+ it "filters out que_scheduler triggers" do
311
+ stream = StringIO.new
312
+ dumper.send(:triggers, stream)
313
+ output = stream.string
314
+
315
+ expect(output).not_to include("que_scheduler_prevent_job_deletion_trigger")
316
+ expect(output).to include("my_app_trigger")
317
+ end
318
+ end
319
+ end
320
+
167
321
  describe "#que_schema_version (private)" do
168
322
  it "returns the version from the table comment" do
169
323
  allow(connection).to receive(:table_exists?).with("que_jobs").and_return(true)
@@ -64,6 +64,46 @@ RSpec.describe QueSchema::SchemaStatements do
64
64
  end
65
65
  end
66
66
 
67
+ describe "que-scheduler integration" do
68
+ context "when Que::Scheduler::Migrations is defined" do
69
+ before do
70
+ scheduler_mod = Module.new do
71
+ class << self
72
+ attr_accessor :migrate_called_with, :reenqueue_called
73
+
74
+ def migrate!(version:)
75
+ self.migrate_called_with = version
76
+ end
77
+
78
+ def reenqueue_scheduler_if_missing
79
+ self.reenqueue_called = true
80
+ end
81
+ end
82
+ end
83
+ scheduler_mod.const_set(:MAX_VERSION, 8)
84
+ stub_const("Que::Scheduler::Migrations", scheduler_mod)
85
+ end
86
+
87
+ it "calls Que::Scheduler::Migrations.migrate! with MAX_VERSION" do
88
+ instance.que_define_schema(version: 7)
89
+
90
+ expect(Que::Scheduler::Migrations.migrate_called_with).to eq(8)
91
+ end
92
+
93
+ it "calls reenqueue_scheduler_if_missing" do
94
+ instance.que_define_schema(version: 7)
95
+
96
+ expect(Que::Scheduler::Migrations.reenqueue_called).to be true
97
+ end
98
+ end
99
+
100
+ context "when Que::Scheduler::Migrations is not defined" do
101
+ it "does not raise an error" do
102
+ expect { instance.que_define_schema(version: 7) }.not_to raise_error
103
+ end
104
+ end
105
+ end
106
+
67
107
  describe "#postgresql? (private)" do
68
108
  it "returns false when no connection method exists" do
69
109
  obj = Object.new
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: que-schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Gay
@@ -102,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  requirements: []
105
- rubygems_version: 4.0.3
105
+ rubygems_version: 4.0.6
106
106
  specification_version: 4
107
107
  summary: Enables schema.rb compatibility for the que job queue gem
108
108
  test_files: []