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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0c46791ed8af6edc2e71f5e7964625fe66811eb76d7a99c085b5157336f2d43
4
- data.tar.gz: 0d3cae20446b2f4d334746077959d8415cb815c9afcb4212a57c35ff2bc8ab88
3
+ metadata.gz: 2a985c677d8d3b87630378feee9b80dda40ef2ba95147ec525f2df8feff18b38
4
+ data.tar.gz: 8c6b9526bbedb13a72fd3edc44c2da56041fc985c0e41187613914bae9163230
5
5
  SHA512:
6
- metadata.gz: 19e85c00deff747bd3d89bad0d3dfd5d64105cd9191d4a336e004f5a862b097734fa5fe81793ac5bb8f32c8b849f5d28e1c9ef0975f038679f66357689702408
7
- data.tar.gz: 1a59b39455c23b6e41af7825de4e6a9c53ba0c394ddb48296e4636f31b5a34bb86f13524562edb104050791d47fa4ac39a7ec665234dcb110ced6bf5c862798f
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 counted_table_id_column in counted_table
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 inserts and updates" do
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.must_be_within_delta(10, DB.get(Sequel::CURRENT_TIMESTAMP).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.must_be_within_delta(10, DB.get(Sequel::CURRENT_TIMESTAMP).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.5.0
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: 2018-11-16 00:00:00.000000000 Z
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
- description:
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
- rubyforge_project:
66
- rubygems_version: 2.7.6
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