sequel_postgresql_triggers 1.5.0 → 1.6.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/README.rdoc +13 -1
- data/lib/sequel/extensions/pg_triggers.rb +4 -4
- data/spec/sequel_postgresql_triggers_spec.rb +71 -5
- metadata +35 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a985c677d8d3b87630378feee9b80dda40ef2ba95147ec525f2df8feff18b38
|
4
|
+
data.tar.gz: 8c6b9526bbedb13a72fd3edc44c2da56041fc985c0e41187613914bae9163230
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39bd5f9c742aeed9331e59b521d571e5631c1b3dcd0804dd959e010a2a6c2bcd110ad8752eac92b1f9d0a768d0a9925f67cf59cdc5a34b718bc4e15e07ba996e
|
7
|
+
data.tar.gz: e5304e315766b8059adc6d29e48b6eb60af4ead1662a70d0eb5d7a87daa541a3b5068385a0b3a302bddaf23fd35f88637c6c3cf762b8308d5f2b5c27f9db682e
|
data/README.rdoc
CHANGED
@@ -126,7 +126,7 @@ sum cache that sums the length of a string column.
|
|
126
126
|
|
127
127
|
Arguments:
|
128
128
|
main_table :: name of table holding counter cache column
|
129
|
-
main_table_id_column :: column in main table matching
|
129
|
+
main_table_id_column :: column in main table matching summed_table_id_column in summed_table
|
130
130
|
sum_column :: column in main table containing the sum cache
|
131
131
|
summed_table :: name of table being summed
|
132
132
|
summed_table_id_column :: column in summed_table matching main_table_id_column in main_table
|
@@ -254,6 +254,18 @@ function :: The name of the trigger function to call to log changes
|
|
254
254
|
Note that it is probably a bad idea to use the same table argument
|
255
255
|
to both +pgt_json_audit_log_setup+ and +pgt_json_audit_log+.
|
256
256
|
|
257
|
+
== Caveats
|
258
|
+
|
259
|
+
If you have defined counter or sum cache triggers using this library
|
260
|
+
before version 1.6.0, you should drop them and regenerate them if
|
261
|
+
you want the triggers to work correctly with queries that use
|
262
|
+
<tt>INSERT ... ON CONFLICT DO NOTHING</tt>.
|
263
|
+
|
264
|
+
When restoring a data-only migration with +pg_dump+, you may need to
|
265
|
+
use <tt>--disable-triggers</tt> for it to restore correctly, and you
|
266
|
+
will need to manually enforce data integrity if you are doing
|
267
|
+
partial restores and not full restores.
|
268
|
+
|
257
269
|
== License
|
258
270
|
|
259
271
|
This library is released under the MIT License. See the MIT-LICENSE
|
@@ -14,7 +14,7 @@ module Sequel
|
|
14
14
|
main_column = quote_identifier(main_table_id_column)
|
15
15
|
count_column = quote_identifier(counter_column)
|
16
16
|
|
17
|
-
pgt_trigger(counted_table, trigger_name, function_name, [:insert, :update, :delete], <<-SQL)
|
17
|
+
pgt_trigger(counted_table, trigger_name, function_name, [:insert, :update, :delete], <<-SQL, :after=>true)
|
18
18
|
BEGIN
|
19
19
|
IF (TG_OP = 'UPDATE' AND (NEW.#{id_column} = OLD.#{id_column} OR (OLD.#{id_column} IS NULL AND NEW.#{id_column} IS NULL))) THEN
|
20
20
|
RETURN NEW;
|
@@ -122,7 +122,7 @@ module Sequel
|
|
122
122
|
main_column = quote_identifier(main_table_id_column)
|
123
123
|
sum_column = quote_identifier(sum_column)
|
124
124
|
|
125
|
-
pgt_trigger(summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL)
|
125
|
+
pgt_trigger(summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL, :after=>true)
|
126
126
|
BEGIN
|
127
127
|
IF (TG_OP = 'UPDATE' AND NEW.#{id_column} = OLD.#{id_column}) THEN
|
128
128
|
UPDATE #{table} SET #{sum_column} = #{sum_column} + #{new_table_summed_column} - #{old_table_summed_column} WHERE #{main_column} = NEW.#{id_column};
|
@@ -176,7 +176,7 @@ module Sequel
|
|
176
176
|
main_table_fk_column = quote_schema_table(main_table_fk_column)
|
177
177
|
summed_table_fk_column = quote_schema_table(summed_table_fk_column)
|
178
178
|
|
179
|
-
pgt_trigger(orig_summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL)
|
179
|
+
pgt_trigger(orig_summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL, :after=>true)
|
180
180
|
BEGIN
|
181
181
|
IF (TG_OP = 'UPDATE' AND NEW.#{summed_table_id_column} = OLD.#{summed_table_id_column}) THEN
|
182
182
|
UPDATE #{main_table} SET #{sum_column} = #{sum_column} + #{new_table_summed_column} - #{old_table_summed_column} WHERE #{main_table_id_column} IN (SELECT #{main_table_fk_column} FROM #{join_table} WHERE #{summed_table_fk_column} = NEW.#{summed_table_id_column});
|
@@ -195,7 +195,7 @@ module Sequel
|
|
195
195
|
END;
|
196
196
|
SQL
|
197
197
|
|
198
|
-
pgt_trigger(orig_join_table, join_trigger_name, join_function_name, [:insert, :delete, :update], <<-SQL)
|
198
|
+
pgt_trigger(orig_join_table, join_trigger_name, join_function_name, [:insert, :delete, :update], <<-SQL, :after=>true)
|
199
199
|
BEGIN
|
200
200
|
IF (NOT (TG_OP = 'UPDATE' AND NEW.#{main_table_fk_column} = OLD.#{main_table_fk_column} AND NEW.#{summed_table_fk_column} = OLD.#{summed_table_fk_column})) THEN
|
201
201
|
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
|
@@ -1,10 +1,21 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require 'rubygems'
|
3
2
|
require 'sequel'
|
4
3
|
|
4
|
+
if coverage = ENV.delete('COVERAGE')
|
5
|
+
require 'simplecov'
|
6
|
+
|
7
|
+
SimpleCov.start do
|
8
|
+
enable_coverage :branch
|
9
|
+
command_name coverage
|
10
|
+
add_filter "/spec/"
|
11
|
+
add_group('Missing'){|src| src.covered_percent < 100}
|
12
|
+
add_group('Covered'){|src| src.covered_percent == 100}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
5
16
|
ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
|
6
17
|
gem 'minitest'
|
7
|
-
require 'minitest/autorun'
|
18
|
+
require 'minitest/global_expectations/autorun'
|
8
19
|
|
9
20
|
DB = Sequel.connect(ENV['PGT_SPEC_DB']||'postgres:///spgt_test?user=postgres')
|
10
21
|
|
@@ -32,6 +43,14 @@ describe "PostgreSQL Counter Cache Trigger" do
|
|
32
43
|
DB.drop_function(:spgt_counter_cache)
|
33
44
|
end
|
34
45
|
|
46
|
+
it "should not modify counter cache if adding/removing records fails due to ON CONFLICT DO NOTHING" do
|
47
|
+
DB.alter_table(:entries){add_unique_constraint :account_id}
|
48
|
+
DB[:entries].insert(:id=>1, :account_id=>1)
|
49
|
+
DB[:accounts].order(:id).select_map(:num_entries).must_equal [1, 0]
|
50
|
+
DB[:entries].insert_conflict.insert(:id=>1, :account_id=>1)
|
51
|
+
DB[:accounts].order(:id).select_map(:num_entries).must_equal [1, 0]
|
52
|
+
end
|
53
|
+
|
35
54
|
it "should modify counter cache when adding or removing records" do
|
36
55
|
DB[:accounts].order(:id).select_map(:num_entries).must_equal [0, 0]
|
37
56
|
|
@@ -129,6 +148,23 @@ describe "PostgreSQL Immutable Trigger" do
|
|
129
148
|
end
|
130
149
|
end
|
131
150
|
|
151
|
+
describe "PostgreSQL Immutable Trigger" do
|
152
|
+
before do
|
153
|
+
DB.create_table(:accounts){integer :id; integer :balance, :default=>0}
|
154
|
+
DB.pgt_immutable(:accounts, :balance)
|
155
|
+
DB[:accounts].insert(:id=>1)
|
156
|
+
end
|
157
|
+
|
158
|
+
after do
|
159
|
+
DB.drop_table(:accounts)
|
160
|
+
DB.drop_function(:pgt_im_balance)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should work when called without options" do
|
164
|
+
DB[:accounts].update(:id=>2)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
132
168
|
describe "PostgreSQL Sum Cache Trigger" do
|
133
169
|
before do
|
134
170
|
DB.create_table(:accounts){integer :id; integer :balance, :default=>0}
|
@@ -143,6 +179,14 @@ describe "PostgreSQL Sum Cache Trigger" do
|
|
143
179
|
DB.drop_function(:spgt_sum_cache)
|
144
180
|
end
|
145
181
|
|
182
|
+
it "should not modify sum cache if adding/removing records fails due to ON CONFLICT DO NOTHING" do
|
183
|
+
DB.alter_table(:entries){add_unique_constraint :account_id}
|
184
|
+
DB[:entries].insert(:id=>1, :account_id=>1, :amount=>5)
|
185
|
+
DB[:accounts].order(:id).select_map(:balance).must_equal [5, 0]
|
186
|
+
DB[:entries].insert_conflict.insert(:id=>1, :account_id=>1, :amount=>10)
|
187
|
+
DB[:accounts].order(:id).select_map(:balance).must_equal [5, 0]
|
188
|
+
end
|
189
|
+
|
146
190
|
it "should modify sum cache when adding, updating, or removing records" do
|
147
191
|
DB[:accounts].order(:id).select_map(:balance).must_equal [0, 0]
|
148
192
|
|
@@ -266,6 +310,17 @@ describe "PostgreSQL Sum Through Many Cache Trigger" do
|
|
266
310
|
DB.drop_function(:spgt_stm_cache_join)
|
267
311
|
end
|
268
312
|
|
313
|
+
it "should not modify sum cache if adding/removing records fails due to ON CONFLICT DO NOTHING" do
|
314
|
+
DB.alter_table(:children){add_unique_constraint :amount}
|
315
|
+
DB[:children].insert(:id=>1, :amount=>5)
|
316
|
+
DB[:links].insert(:parent_id=>1, :child_id=>1)
|
317
|
+
DB[:parents].order(:id).select_map(:balance).must_equal [5, 0]
|
318
|
+
DB[:children].insert_conflict.insert(:id=>1, :amount=>5)
|
319
|
+
DB[:parents].order(:id).select_map(:balance).must_equal [5, 0]
|
320
|
+
DB[:links].insert_conflict.insert(:parent_id=>1, :child_id=>1)
|
321
|
+
DB[:parents].order(:id).select_map(:balance).must_equal [5, 0]
|
322
|
+
end
|
323
|
+
|
269
324
|
it "should modify sum cache when adding, updating, or removing records" do
|
270
325
|
DB[:parents].order(:id).select_map(:balance).must_equal [0, 0]
|
271
326
|
|
@@ -461,6 +516,17 @@ describe "PostgreSQL Touch Trigger" do
|
|
461
516
|
DB.drop_function(:spgt_touch2) if @spgt_touch2
|
462
517
|
end
|
463
518
|
|
519
|
+
it "should not modify timestamp column of related table if adding/removing records fails due to ON CONFLICT DO NOTHING" do
|
520
|
+
DB.pgt_touch(:children, :parents, :changed_on, {:id1=>:parent_id1}, :function_name=>:spgt_touch)
|
521
|
+
DB.alter_table(:children){add_unique_constraint :parent_id1}
|
522
|
+
d30 = Date.today - 30
|
523
|
+
DB[:children].insert(:id=>1, :parent_id1=>1)
|
524
|
+
DB[:parents].insert(:id1=>1, :changed_on=>d30)
|
525
|
+
DB[:parents].get(:changed_on).to_date.must_equal d30
|
526
|
+
DB[:children].insert_conflict.insert(:id=>1, :parent_id1=>1)
|
527
|
+
DB[:parents].get(:changed_on).to_date.must_equal d30
|
528
|
+
end
|
529
|
+
|
464
530
|
it "should update the timestamp column of the related table when adding, updating or removing records" do
|
465
531
|
DB.pgt_touch(:children, :parents, :changed_on, {:id1=>:parent_id1}, :function_name=>:spgt_touch)
|
466
532
|
d = Date.today
|
@@ -624,13 +690,13 @@ describe "PostgreSQL JSON Audit Logging" do
|
|
624
690
|
DB.drop_function(:spgt_audit_log)
|
625
691
|
end
|
626
692
|
|
627
|
-
it "should previous values in JSON format for
|
693
|
+
it "should store previous values in JSON format in audit table for updates and deletes on main table" do
|
628
694
|
@logs.first.must_be_nil
|
629
695
|
|
630
696
|
@ds.update(:id=>2, :a=>3)
|
631
697
|
@ds.all.must_equal [{:id=>2, :a=>3}]
|
632
698
|
h = @logs.first
|
633
|
-
h.delete(:at).to_i.
|
699
|
+
h.delete(:at).to_i.must_be_close_to(10, DB.get(Sequel::CURRENT_TIMESTAMP).to_i)
|
634
700
|
h.delete(:user).must_be_kind_of(String)
|
635
701
|
txid1 = h.delete(:txid)
|
636
702
|
txid1.must_be_kind_of(Integer)
|
@@ -639,7 +705,7 @@ describe "PostgreSQL JSON Audit Logging" do
|
|
639
705
|
@ds.delete
|
640
706
|
@ds.all.must_equal []
|
641
707
|
h = @logs.first
|
642
|
-
h.delete(:at).to_i.
|
708
|
+
h.delete(:at).to_i.must_be_close_to(10, DB.get(Sequel::CURRENT_TIMESTAMP).to_i)
|
643
709
|
h.delete(:user).must_be_kind_of(String)
|
644
710
|
txid2 = h.delete(:txid)
|
645
711
|
txid2.must_be_kind_of(Integer)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel_postgresql_triggers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -24,7 +24,35 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest-global_expectations
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
28
56
|
email: code@jeremyevans.net
|
29
57
|
executables: []
|
30
58
|
extensions: []
|
@@ -39,7 +67,7 @@ homepage: https://github.com/jeremyevans/sequel_postgresql_triggers
|
|
39
67
|
licenses:
|
40
68
|
- MIT
|
41
69
|
metadata: {}
|
42
|
-
post_install_message:
|
70
|
+
post_install_message:
|
43
71
|
rdoc_options:
|
44
72
|
- "--inline-source"
|
45
73
|
- "--line-numbers"
|
@@ -62,9 +90,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
90
|
- !ruby/object:Gem::Version
|
63
91
|
version: '0'
|
64
92
|
requirements: []
|
65
|
-
|
66
|
-
|
67
|
-
signing_key:
|
93
|
+
rubygems_version: 3.5.3
|
94
|
+
signing_key:
|
68
95
|
specification_version: 4
|
69
96
|
summary: Database enforced timestamps, immutable columns, counter/sum caches, and
|
70
97
|
touch propogation
|