sequel_postgresql_triggers 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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