sequel_postgresql_triggers 1.0.8 → 1.1.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
  SHA1:
3
- metadata.gz: 12a05702b972f0adb894a4c5e678400debab6f7a
4
- data.tar.gz: cd51e2bf9105506ed4d992a2eafa231c45346ad4
3
+ metadata.gz: c908ae3d087271626842952b60bc22365793a3d9
4
+ data.tar.gz: 1cf7c4c70437c36ab0852d566d600756314c90d5
5
5
  SHA512:
6
- metadata.gz: cfcd7fe87e24a790f79c1158fabd01f38f0411ad4632e5b4c2a18cce5e27dab8cb32832f8b3a8edd14d879f6427e6bd00c231409db5f2740b8dd9104cc5be833
7
- data.tar.gz: ff1c7f9c541f44e00217e65ed434a16b45e1418517f47e76c1df84590a548fc021f5d3a54454ddca403256c1dc80c2f55b4d0b8ebf202097eceb4d475a8829aa
6
+ metadata.gz: 6f10299a3e24a54147217af11e85317484b02b43a0f9faba1120f5f1bfdd402b8f281c4b403f0f785175c94196d6079a9719667965383102e5732f6e0ca1c9b9
7
+ data.tar.gz: 06f7baa57db107b2fec9d169ebe03f87b737f611adbc302e8af3f0dda2695d0c96d74dd68b50be4b1c7cb0715c4f40b1b17318f41bdf1ed2755defdf94e70ea2
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008-2014 Jeremy Evans
1
+ Copyright (c) 2008-2016 Jeremy Evans
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
data/README CHANGED
@@ -37,13 +37,21 @@ differs that upon update, the column is also set to CURRENT_TIMESTAMP.
37
37
  This takes quite a few arguments (see the RDoc) and sets up a
38
38
  counter cache so that when the counted table is inserted to
39
39
  or deleted from, records in the main table are updated with the
40
- count of the corresponding records in the counted table.
40
+ count of the corresponding records in the counted table. The counter
41
+ cache column must have a default of 0 for this to work correctly.
41
42
 
42
43
  === Sum Cache - pgt_sum_cache
43
44
 
44
45
  Similar to pgt_counter_cache, except instead of storing a count
45
46
  of records in the main table, it stores the sum on one of the
46
- columns in summed table.
47
+ columns in summed table. The sum cache column must have a default
48
+ of 0 for this to work correctly.
49
+
50
+ === Sum Through Many Cache - pgt_sum_through_many_cache
51
+
52
+ Similar to pgt_sum_cache, except instead of a one-to-many relationship,
53
+ it supports a many-to-many relationship with a single join table. The
54
+ sum cache column must have a default of 0 for this to work correctly.
47
55
 
48
56
  === Immutable Columns - pgt_immutable
49
57
 
@@ -137,6 +137,89 @@ module Sequel
137
137
  SQL
138
138
  end
139
139
 
140
+ # Turns a column in the main table into a sum cache through a join table.
141
+ # A sum cache is a column in the main table with the sum of a column in the
142
+ # summed table for the matching id. The join table must have NOT NULL constraints
143
+ # on the foreign keys to the main table and summed table and a
144
+ # composite unique constraint on both foreign keys.
145
+ #
146
+ # Arguments:
147
+ # * opts : option hash, see module documentation, and below.
148
+ # * :main_table: name of table holding sum cache column
149
+ # * :main_table_id_column: primary key column in main table referenced by main_table_fk_column (default: :id)
150
+ # * :sum_column: column in main table containing the sum cache, must be NOT NULL and default to 0
151
+ # * :summed_table: name of table being summed
152
+ # * :summed_table_id_column: primary key column in summed_table referenced by summed_table_fk_column (default: ;id)
153
+ # * :summed_column: column in summed_table being summed, must be NOT NULL
154
+ # * :join_table: name of table which joins main_table with summed_table
155
+ # * :main_table_fk_column: column in join_table referencing main_table_id_column, must be NOT NULL
156
+ # * :summed_table_fk_column: column in join_table referencing summed_table_id_column, must be NOT NULL
157
+ def pgt_sum_through_many_cache(opts={})
158
+ main_table = opts.fetch(:main_table)
159
+ main_table_id_column = opts.fetch(:main_table_id_column, :id)
160
+ sum_column = opts.fetch(:sum_column)
161
+ summed_table = opts.fetch(:summed_table)
162
+ summed_table_id_column = opts.fetch(:summed_table_id_column, :id)
163
+ summed_column = opts.fetch(:summed_column)
164
+ join_table = opts.fetch(:join_table)
165
+ main_table_fk_column = opts.fetch(:main_table_fk_column)
166
+ summed_table_fk_column = opts.fetch(:summed_table_fk_column)
167
+
168
+ trigger_name = opts[:trigger_name] || "pgt_stmc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}__#{summed_column}__#{main_table_fk_column}__#{summed_table_fk_column}"
169
+ function_name = opts[:function_name] || "pgt_stmc_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table}__#{summed_table_id_column}__#{summed_column}__#{join_table}__#{main_table_fk_column}__#{summed_table_fk_column}"
170
+ join_trigger_name = opts[:join_trigger_name] || "pgt_stmc_join_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table_id_column}__#{summed_column}__#{main_table_fk_column}__#{summed_table_fk_column}"
171
+ join_function_name = opts[:join_function_name] || "pgt_stmc_join_#{main_table}__#{main_table_id_column}__#{sum_column}__#{summed_table}__#{summed_table_id_column}__#{summed_column}__#{join_table}__#{main_table_fk_column}__#{summed_table_fk_column}"
172
+
173
+ orig_summed_table = summed_table
174
+ orig_join_table = join_table
175
+
176
+ main_table = quote_schema_table(main_table)
177
+ main_table_id_column = quote_schema_table(main_table_id_column)
178
+ sum_column = quote_schema_table(sum_column)
179
+ summed_table = quote_schema_table(summed_table)
180
+ summed_table_id_column = quote_schema_table(summed_table_id_column)
181
+ summed_column = quote_schema_table(summed_column)
182
+ join_table = quote_schema_table(join_table)
183
+ main_table_fk_column = quote_schema_table(main_table_fk_column)
184
+ summed_table_fk_column = quote_schema_table(summed_table_fk_column)
185
+
186
+ pgt_trigger(orig_summed_table, trigger_name, function_name, [:insert, :delete, :update], <<-SQL)
187
+ BEGIN
188
+ IF (TG_OP = 'UPDATE' AND NEW.#{summed_table_id_column} = OLD.#{summed_table_id_column}) THEN
189
+ UPDATE #{main_table} SET #{sum_column} = #{sum_column} + NEW.#{summed_column} - OLD.#{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});
190
+ ELSE
191
+ IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
192
+ UPDATE #{main_table} SET #{sum_column} = #{sum_column} + NEW.#{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});
193
+ END IF;
194
+ IF (TG_OP = 'DELETE' OR TG_OP = 'UPDATE') THEN
195
+ UPDATE #{main_table} SET #{sum_column} = #{sum_column} - OLD.#{summed_column} WHERE #{main_table_id_column} IN (SELECT #{main_table_fk_column} FROM #{join_table} WHERE #{summed_table_fk_column} = OLD.#{summed_table_id_column});
196
+ END IF;
197
+ END IF;
198
+ IF (TG_OP = 'DELETE') THEN
199
+ RETURN OLD;
200
+ END IF;
201
+ RETURN NEW;
202
+ END;
203
+ SQL
204
+
205
+ pgt_trigger(orig_join_table, join_trigger_name, join_function_name, [:insert, :delete, :update], <<-SQL)
206
+ BEGIN
207
+ 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
208
+ IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
209
+ UPDATE #{main_table} SET #{sum_column} = #{sum_column} + (SELECT #{summed_column} FROM #{summed_table} WHERE #{summed_table_id_column} = NEW.#{summed_table_fk_column}) WHERE #{main_table_id_column} = NEW.#{main_table_fk_column};
210
+ END IF;
211
+ IF (TG_OP = 'DELETE' OR TG_OP = 'UPDATE') THEN
212
+ UPDATE #{main_table} SET #{sum_column} = #{sum_column} - (SELECT #{summed_column} FROM #{summed_table} WHERE #{summed_table_id_column} = OLD.#{summed_table_fk_column}) WHERE #{main_table_id_column} = OLD.#{main_table_fk_column};
213
+ END IF;
214
+ END IF;
215
+ IF (TG_OP = 'DELETE') THEN
216
+ RETURN OLD;
217
+ END IF;
218
+ RETURN NEW;
219
+ END;
220
+ SQL
221
+ end
222
+
140
223
  # When rows in a table are updated, touches a timestamp of related rows
141
224
  # in another table.
142
225
  # Arguments:
@@ -1,6 +1,8 @@
1
- #!/usr/bin/env spec
1
+ #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
3
  require 'sequel'
4
+ require 'minitest/spec'
5
+ require 'minitest/autorun'
4
6
 
5
7
  DB = Sequel.connect(ENV['PGT_SPEC_DB']||'postgres:///spgt_test?user=postgres')
6
8
 
@@ -26,7 +28,7 @@ describe "PostgreSQL Triggers" do
26
28
  DB.drop_language(:plpgsql, :cascade=>true) if DB.server_version < 90000
27
29
  end
28
30
 
29
- context "PostgreSQL Counter Cache Trigger" do
31
+ describe "PostgreSQL Counter Cache Trigger" do
30
32
  before do
31
33
  DB.create_table(:accounts){integer :id; integer :num_entries, :default=>0}
32
34
  DB.create_table(:entries){integer :id; integer :account_id}
@@ -39,45 +41,45 @@ describe "PostgreSQL Triggers" do
39
41
  DB.drop_table(:entries, :accounts)
40
42
  end
41
43
 
42
- specify "Should modify counter cache when adding or removing records" do
43
- DB[:accounts].order(:id).select_map(:num_entries).should == [0, 0]
44
+ it "Should modify counter cache when adding or removing records" do
45
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [0, 0]
44
46
 
45
47
  DB[:entries] << {:id=>1, :account_id=>1}
46
- DB[:accounts].order(:id).select_map(:num_entries).should == [1, 0]
48
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [1, 0]
47
49
 
48
50
  DB[:entries] << {:id=>2, :account_id=>1}
49
- DB[:accounts].order(:id).select_map(:num_entries).should == [2, 0]
51
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [2, 0]
50
52
 
51
53
  DB[:entries] << {:id=>3, :account_id=>nil}
52
- DB[:accounts].order(:id).select_map(:num_entries).should == [2, 0]
54
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [2, 0]
53
55
 
54
56
  DB[:entries].where(:id=>3).update(:account_id=>2)
55
- DB[:accounts].order(:id).select_map(:num_entries).should == [2, 1]
57
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [2, 1]
56
58
 
57
59
  DB[:entries].where(:id=>2).update(:account_id=>2)
58
- DB[:accounts].order(:id).select_map(:num_entries).should == [1, 2]
60
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [1, 2]
59
61
 
60
62
  DB[:entries].where(:id=>2).update(:account_id=>nil)
61
- DB[:accounts].order(:id).select_map(:num_entries).should == [1, 1]
63
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [1, 1]
62
64
 
63
65
  DB[:entries].where(:id=>2).update(:id=>4)
64
- DB[:accounts].order(:id).select_map(:num_entries).should == [1, 1]
66
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [1, 1]
65
67
 
66
68
  DB[:entries].where(:id=>4).update(:account_id=>2)
67
- DB[:accounts].order(:id).select_map(:num_entries).should == [1, 2]
69
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [1, 2]
68
70
 
69
71
  DB[:entries].where(:id=>4).update(:account_id=>nil)
70
- DB[:accounts].order(:id).select_map(:num_entries).should == [1, 1]
72
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [1, 1]
71
73
 
72
74
  DB[:entries].filter(:id=>4).delete
73
- DB[:accounts].order(:id).select_map(:num_entries).should == [1, 1]
75
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [1, 1]
74
76
 
75
77
  DB[:entries].delete
76
- DB[:accounts].order(:id).select_map(:num_entries).should == [0, 0]
78
+ DB[:accounts].order(:id).select_map(:num_entries).must_equal [0, 0]
77
79
  end
78
80
  end
79
81
 
80
- context "PostgreSQL Created At Trigger" do
82
+ describe "PostgreSQL Created At Trigger" do
81
83
  before do
82
84
  DB.create_table(:accounts){integer :id; timestamp :added_on}
83
85
  DB.pgt_created_at(:accounts, :added_on)
@@ -87,21 +89,21 @@ describe "PostgreSQL Triggers" do
87
89
  DB.drop_table(:accounts)
88
90
  end
89
91
 
90
- specify "Should set the column upon insertion and ignore modifications afterward" do
92
+ it "Should set the column upon insertion and ignore modifications afterward" do
91
93
  DB[:accounts] << {:id=>1}
92
94
  t = DB[:accounts].get(:added_on)
93
- t.strftime('%F').should == Date.today.strftime('%F')
95
+ t.strftime('%F').must_equal Date.today.strftime('%F')
94
96
  DB[:accounts].update(:added_on=>Date.today - 60)
95
- DB[:accounts].get(:added_on).should == t
97
+ DB[:accounts].get(:added_on).must_equal t
96
98
  DB[:accounts] << {:id=>2}
97
99
  ds = DB[:accounts].select(:added_on)
98
- DB[:accounts].select((Sequel::SQL::NumericExpression.new(:NOOP, ds.filter(:id=>2)) > ds.filter(:id=>1)).as(:x)).first[:x].should == true
100
+ DB[:accounts].select((Sequel::SQL::NumericExpression.new(:NOOP, ds.filter(:id=>2)) > ds.filter(:id=>1)).as(:x)).first[:x].must_equal true
99
101
  DB[:accounts].filter(:id=>1).update(:id=>3)
100
- DB[:accounts].select((Sequel::SQL::NumericExpression.new(:NOOP, ds.filter(:id=>2)) > ds.filter(:id=>3)).as(:x)).first[:x].should == true
102
+ DB[:accounts].select((Sequel::SQL::NumericExpression.new(:NOOP, ds.filter(:id=>2)) > ds.filter(:id=>3)).as(:x)).first[:x].must_equal true
101
103
  end
102
104
  end
103
105
 
104
- context "PostgreSQL Immutable Trigger" do
106
+ describe "PostgreSQL Immutable Trigger" do
105
107
  before do
106
108
  DB.create_table(:accounts){integer :id; integer :balance, :default=>0}
107
109
  DB.pgt_immutable(:accounts, :balance)
@@ -112,29 +114,29 @@ describe "PostgreSQL Triggers" do
112
114
  DB.drop_table(:accounts)
113
115
  end
114
116
 
115
- specify "Should allow modifying columns not marked as immutable" do
116
- proc{DB[:accounts].update(:id=>2)}.should_not raise_error
117
+ it "Should allow modifying columns not marked as immutable" do
118
+ DB[:accounts].update(:id=>2)
117
119
  end
118
120
 
119
- specify "Should allow updating a column to its existing value" do
120
- proc{DB[:accounts].update(:balance=>0)}.should_not raise_error
121
- proc{DB[:accounts].update(:balance=>Sequel.*(:balance, :balance))}.should_not raise_error
121
+ it "Should allow updating a column to its existing value" do
122
+ DB[:accounts].update(:balance=>0)
123
+ DB[:accounts].update(:balance=>Sequel.*(:balance, :balance))
122
124
  end
123
125
 
124
- specify "Should not allow modifying a column's value" do
125
- proc{DB[:accounts].update(:balance=>1)}.should raise_error(Sequel::DatabaseError)
126
+ it "Should not allow modifying a column's value" do
127
+ proc{DB[:accounts].update(:balance=>1)}.must_raise(Sequel::DatabaseError)
126
128
  end
127
129
 
128
- specify "Should handle NULL values correctly" do
129
- proc{DB[:accounts].update(:balance=>nil)}.should raise_error(Sequel::DatabaseError)
130
+ it "Should handle NULL values correctly" do
131
+ proc{DB[:accounts].update(:balance=>nil)}.must_raise(Sequel::DatabaseError)
130
132
  DB[:accounts].delete
131
133
  DB[:accounts] << {:id=>1, :balance=>nil}
132
- proc{DB[:accounts].update(:balance=>nil)}.should_not raise_error
133
- proc{DB[:accounts].update(:balance=>0)}.should raise_error(Sequel::DatabaseError)
134
+ DB[:accounts].update(:balance=>nil)
135
+ proc{DB[:accounts].update(:balance=>0)}.must_raise(Sequel::DatabaseError)
134
136
  end
135
137
  end
136
138
 
137
- context "PostgreSQL Sum Cache Trigger" do
139
+ describe "PostgreSQL Sum Cache Trigger" do
138
140
  before do
139
141
  DB.create_table(:accounts){integer :id; integer :balance, :default=>0}
140
142
  DB.create_table(:entries){integer :id; integer :account_id; integer :amount}
@@ -147,48 +149,137 @@ describe "PostgreSQL Triggers" do
147
149
  DB.drop_table(:entries, :accounts)
148
150
  end
149
151
 
150
- specify "Should modify sum cache when adding, updating, or removing records" do
151
- DB[:accounts].order(:id).select_map(:balance).should == [0, 0]
152
+ it "Should modify sum cache when adding, updating, or removing records" do
153
+ DB[:accounts].order(:id).select_map(:balance).must_equal [0, 0]
152
154
 
153
155
  DB[:entries] << {:id=>1, :account_id=>1, :amount=>100}
154
- DB[:accounts].order(:id).select_map(:balance).should == [100, 0]
156
+ DB[:accounts].order(:id).select_map(:balance).must_equal [100, 0]
155
157
 
156
158
  DB[:entries] << {:id=>2, :account_id=>1, :amount=>200}
157
- DB[:accounts].order(:id).select_map(:balance).should == [300, 0]
159
+ DB[:accounts].order(:id).select_map(:balance).must_equal [300, 0]
158
160
 
159
161
  DB[:entries] << {:id=>3, :account_id=>nil, :amount=>500}
160
- DB[:accounts].order(:id).select_map(:balance).should == [300, 0]
162
+ DB[:accounts].order(:id).select_map(:balance).must_equal [300, 0]
161
163
 
162
164
  DB[:entries].where(:id=>3).update(:account_id=>2)
163
- DB[:accounts].order(:id).select_map(:balance).should == [300, 500]
165
+ DB[:accounts].order(:id).select_map(:balance).must_equal [300, 500]
164
166
 
165
167
  DB[:entries].exclude(:id=>2).update(:amount=>Sequel.*(:amount, 2))
166
- DB[:accounts].order(:id).select_map(:balance).should == [400, 1000]
168
+ DB[:accounts].order(:id).select_map(:balance).must_equal [400, 1000]
167
169
 
168
170
  DB[:entries].where(:id=>2).update(:account_id=>2)
169
- DB[:accounts].order(:id).select_map(:balance).should == [200, 1200]
171
+ DB[:accounts].order(:id).select_map(:balance).must_equal [200, 1200]
170
172
 
171
173
  DB[:entries].where(:id=>2).update(:account_id=>nil)
172
- DB[:accounts].order(:id).select_map(:balance).should == [200, 1000]
174
+ DB[:accounts].order(:id).select_map(:balance).must_equal [200, 1000]
173
175
 
174
176
  DB[:entries].where(:id=>2).update(:id=>4)
175
- DB[:accounts].order(:id).select_map(:balance).should == [200, 1000]
177
+ DB[:accounts].order(:id).select_map(:balance).must_equal [200, 1000]
176
178
 
177
179
  DB[:entries].where(:id=>4).update(:account_id=>2)
178
- DB[:accounts].order(:id).select_map(:balance).should == [200, 1200]
180
+ DB[:accounts].order(:id).select_map(:balance).must_equal [200, 1200]
179
181
 
180
182
  DB[:entries].where(:id=>4).update(:account_id=>nil)
181
- DB[:accounts].order(:id).select_map(:balance).should == [200, 1000]
183
+ DB[:accounts].order(:id).select_map(:balance).must_equal [200, 1000]
182
184
 
183
185
  DB[:entries].filter(:id=>4).delete
184
- DB[:accounts].order(:id).select_map(:balance).should == [200, 1000]
186
+ DB[:accounts].order(:id).select_map(:balance).must_equal [200, 1000]
185
187
 
186
188
  DB[:entries].delete
187
- DB[:accounts].order(:id).select_map(:balance).should == [0, 0]
189
+ DB[:accounts].order(:id).select_map(:balance).must_equal [0, 0]
188
190
  end
189
191
  end
190
192
 
191
- context "PostgreSQL Updated At Trigger" do
193
+ describe "PostgreSQL Sum Through Many Cache Trigger" do
194
+ before do
195
+ DB.create_table(:parents){primary_key :id; integer :balance, :default=>0, :null=>false}
196
+ DB.create_table(:children){primary_key :id; integer :amount, :null=>false}
197
+ DB.create_table(:links){integer :parent_id, :null=>false; integer :child_id, :null=>false; unique [:parent_id, :child_id]}
198
+ DB.pgt_sum_through_many_cache(
199
+ :main_table=>:parents,
200
+ :sum_column=>:balance,
201
+ :summed_table=>:children,
202
+ :summed_column=>:amount,
203
+ :join_table=>:links,
204
+ :main_table_fk_column=>:parent_id,
205
+ :summed_table_fk_column=>:child_id
206
+ )
207
+ DB[:parents] << {:id=>1}
208
+ DB[:parents] << {:id=>2}
209
+ end
210
+
211
+ after do
212
+ DB.drop_table(:links, :parents, :children)
213
+ end
214
+
215
+ it "Should modify sum cache when adding, updating, or removing records" do
216
+ DB[:parents].order(:id).select_map(:balance).must_equal [0, 0]
217
+
218
+ DB[:children] << {:id=>1, :amount=>100}
219
+ DB[:links] << {:parent_id=>1, :child_id=>1}
220
+ DB[:parents].order(:id).select_map(:balance).must_equal [100, 0]
221
+
222
+ DB[:children] << {:id=>2, :amount=>200}
223
+ DB[:links] << {:parent_id=>1, :child_id=>2}
224
+ DB[:parents].order(:id).select_map(:balance).must_equal [300, 0]
225
+
226
+ DB[:children] << {:id=>3, :amount=>500}
227
+ DB[:parents].order(:id).select_map(:balance).must_equal [300, 0]
228
+ DB[:links] << {:parent_id=>2, :child_id=>3}
229
+ DB[:parents].order(:id).select_map(:balance).must_equal [300, 500]
230
+
231
+ DB[:links].where(:parent_id=>2, :child_id=>3).update(:parent_id=>1)
232
+ DB[:parents].order(:id).select_map(:balance).must_equal [800, 0]
233
+
234
+ DB[:children] << {:id=>4, :amount=>400}
235
+ DB[:links].where(:parent_id=>1, :child_id=>3).update(:child_id=>4)
236
+ DB[:parents].order(:id).select_map(:balance).must_equal [700, 0]
237
+
238
+ DB[:links].where(:parent_id=>1, :child_id=>4).update(:parent_id=>2, :child_id=>3)
239
+ DB[:parents].order(:id).select_map(:balance).must_equal [300, 500]
240
+
241
+ DB[:children].exclude(:id=>2).update(:amount=>Sequel.*(:amount, 2))
242
+ DB[:parents].order(:id).select_map(:balance).must_equal [400, 1000]
243
+
244
+ DB[:links].where(:parent_id=>1, :child_id=>2).update(:parent_id=>2)
245
+ DB[:parents].order(:id).select_map(:balance).must_equal [200, 1200]
246
+
247
+ DB[:links].where(:parent_id=>2, :child_id=>2).update(:parent_id=>1)
248
+ DB[:parents].order(:id).select_map(:balance).must_equal [400, 1000]
249
+
250
+ DB[:links].where(:parent_id=>1, :child_id=>2).update(:child_id=>3)
251
+ DB[:parents].order(:id).select_map(:balance).must_equal [1200, 1000]
252
+
253
+ DB[:links] << {:parent_id=>2, :child_id=>4}
254
+ DB[:parents].order(:id).select_map(:balance).must_equal [1200, 1800]
255
+
256
+ DB[:children].filter(:id=>4).delete
257
+ DB[:parents].order(:id).select_map(:balance).must_equal [1200, 1000]
258
+
259
+ DB[:links].filter(:parent_id=>1, :child_id=>1).delete
260
+ DB[:parents].order(:id).select_map(:balance).must_equal [1000, 1000]
261
+
262
+ DB[:children] << {:id=>4, :amount=>400}
263
+ DB[:parents].order(:id).select_map(:balance).must_equal [1000, 1400]
264
+
265
+ DB[:children].delete
266
+ DB[:parents].order(:id).select_map(:balance).must_equal [0, 0]
267
+
268
+ DB[:children].multi_insert([{:id=>2, :amount=>200}, {:id=>1, :amount=>200}, {:id=>3, :amount=>1000}, {:id=>4, :amount=>400}])
269
+ DB[:parents].order(:id).select_map(:balance).must_equal [1000, 1400]
270
+
271
+ DB[:links].where(:child_id=>3).update(:child_id=>2)
272
+ DB[:parents].order(:id).select_map(:balance).must_equal [200, 600]
273
+
274
+ DB[:children].update(:amount=>10)
275
+ DB[:parents].order(:id).select_map(:balance).must_equal [10, 20]
276
+
277
+ DB[:links].delete
278
+ DB[:parents].order(:id).select_map(:balance).must_equal [0, 0]
279
+ end
280
+ end
281
+
282
+ describe "PostgreSQL Updated At Trigger" do
192
283
  before do
193
284
  DB.create_table(:accounts){integer :id; timestamp :changed_on}
194
285
  DB.pgt_updated_at(:accounts, :changed_on)
@@ -198,19 +289,19 @@ describe "PostgreSQL Triggers" do
198
289
  DB.drop_table(:accounts)
199
290
  end
200
291
 
201
- specify "Should set the column always to the current timestamp" do
292
+ it "Should set the column always to the current timestamp" do
202
293
  DB[:accounts] << {:id=>1}
203
294
  t = DB[:accounts].get(:changed_on)
204
- t.strftime('%F').should == Date.today.strftime('%F')
295
+ t.strftime('%F').must_equal Date.today.strftime('%F')
205
296
  DB[:accounts] << {:id=>2}
206
297
  ds = DB[:accounts].select(:changed_on)
207
- DB[:accounts].select((Sequel::SQL::NumericExpression.new(:NOOP, ds.filter(:id=>2)) > ds.filter(:id=>1)).as(:x)).first[:x].should == true
298
+ DB[:accounts].select((Sequel::SQL::NumericExpression.new(:NOOP, ds.filter(:id=>2)) > ds.filter(:id=>1)).as(:x)).first[:x].must_equal true
208
299
  DB[:accounts].filter(:id=>1).update(:id=>3)
209
- DB[:accounts].select((Sequel::SQL::NumericExpression.new(:NOOP, ds.filter(:id=>3)) > ds.filter(:id=>2)).as(:x)).first[:x].should == true
300
+ DB[:accounts].select((Sequel::SQL::NumericExpression.new(:NOOP, ds.filter(:id=>3)) > ds.filter(:id=>2)).as(:x)).first[:x].must_equal true
210
301
  end
211
302
  end
212
303
 
213
- context "PostgreSQL Touch Trigger" do
304
+ describe "PostgreSQL Touch Trigger" do
214
305
  before do
215
306
  DB.create_table(:parents){integer :id1; integer :id2; integer :child_id; timestamp :changed_on}
216
307
  DB.create_table(:children){integer :id; integer :parent_id1; integer :parent_id2; timestamp :changed_on}
@@ -220,86 +311,86 @@ describe "PostgreSQL Triggers" do
220
311
  DB.drop_table(:children, :parents)
221
312
  end
222
313
 
223
- specify "Should update the timestamp column of the related table when adding, updating or removing records" do
314
+ it "Should update the timestamp column of the related table when adding, updating or removing records" do
224
315
  DB.pgt_touch(:children, :parents, :changed_on, :id1=>:parent_id1)
225
316
  d = Date.today
226
317
  d30 = Date.today - 30
227
318
  DB[:parents] << {:id1=>1, :changed_on=>d30}
228
319
  DB[:parents] << {:id1=>2, :changed_on=>d30}
229
320
  DB[:children] << {:id=>1, :parent_id1=>1}
230
- DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.should == [d.strftime('%F'), d30.strftime('%F')]
321
+ DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.must_equal [d.strftime('%F'), d30.strftime('%F')]
231
322
 
232
323
  DB[:parents].update(:changed_on=>d30)
233
324
  DB[:children].update(:id=>2)
234
- DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.should == [d.strftime('%F'), d30.strftime('%F')]
325
+ DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.must_equal [d.strftime('%F'), d30.strftime('%F')]
235
326
 
236
327
  DB[:parents].update(:changed_on=>d30)
237
328
  DB[:children].update(:parent_id1=>2)
238
- DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.should == [d.strftime('%F'), d.strftime('%F')]
329
+ DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.must_equal [d.strftime('%F'), d.strftime('%F')]
239
330
 
240
331
  DB[:parents].update(:changed_on=>d30)
241
332
  DB[:children].update(:parent_id1=>nil)
242
- DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.should == [d30.strftime('%F'), d.strftime('%F')]
333
+ DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.must_equal [d30.strftime('%F'), d.strftime('%F')]
243
334
 
244
335
  DB[:parents].update(:changed_on=>d30)
245
336
  DB[:children].update(:parent_id2=>1)
246
- DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.should == [d30.strftime('%F'), d30.strftime('%F')]
337
+ DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.must_equal [d30.strftime('%F'), d30.strftime('%F')]
247
338
 
248
339
  DB[:parents].update(:changed_on=>d30)
249
340
  DB[:children].update(:parent_id1=>2)
250
- DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.should == [d30.strftime('%F'), d.strftime('%F')]
341
+ DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.must_equal [d30.strftime('%F'), d.strftime('%F')]
251
342
 
252
343
  DB[:parents].update(:changed_on=>d30)
253
344
  DB[:children].delete
254
- DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.should == [d30.strftime('%F'), d.strftime('%F')]
345
+ DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.must_equal [d30.strftime('%F'), d.strftime('%F')]
255
346
 
256
347
  DB[:parents].update(:changed_on=>d30)
257
348
  DB[:children] << {:id=>2, :parent_id1=>nil}
258
- DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.should == [d30.strftime('%F'), d30.strftime('%F')]
349
+ DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.must_equal [d30.strftime('%F'), d30.strftime('%F')]
259
350
  DB[:children].where(:id=>2).delete
260
- DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.should == [d30.strftime('%F'), d30.strftime('%F')]
351
+ DB[:parents].order(:id1).select_map(:changed_on).map{|t| t.strftime('%F')}.must_equal [d30.strftime('%F'), d30.strftime('%F')]
261
352
  end
262
353
 
263
- specify "Should update the timestamp column of the related table when there is a composite foreign key" do
354
+ it "Should update the timestamp column of the related table when there is a composite foreign key" do
264
355
  DB.pgt_touch(:children, :parents, :changed_on, :id1=>:parent_id1, :id2=>:parent_id2)
265
356
  DB[:parents] << {:id1=>1, :id2=>2, :changed_on=>Date.today - 30}
266
357
  DB[:children] << {:id=>1, :parent_id1=>1, :parent_id2=>2}
267
- DB[:parents].get(:changed_on).strftime('%F').should == Date.today.strftime('%F')
358
+ DB[:parents].get(:changed_on).strftime('%F').must_equal Date.today.strftime('%F')
268
359
  DB[:parents].update(:changed_on=>Date.today - 30)
269
360
  DB[:children].update(:id=>2)
270
- DB[:parents].get(:changed_on).strftime('%F').should == Date.today.strftime('%F')
361
+ DB[:parents].get(:changed_on).strftime('%F').must_equal Date.today.strftime('%F')
271
362
  DB[:parents].update(:changed_on=>Date.today - 30)
272
363
  DB[:children].delete
273
- DB[:parents].get(:changed_on).strftime('%F').should == Date.today.strftime('%F')
364
+ DB[:parents].get(:changed_on).strftime('%F').must_equal Date.today.strftime('%F')
274
365
  end
275
366
 
276
- specify "Should update timestamps correctly when two tables touch each other" do
367
+ it "Should update timestamps correctly when two tables touch each other" do
277
368
  DB.pgt_touch(:children, :parents, :changed_on, :id1=>:parent_id1)
278
369
  DB.pgt_touch(:parents, :children, :changed_on, :id=>:child_id)
279
370
  DB[:parents] << {:id1=>1, :child_id=>1, :changed_on=>Date.today - 30}
280
371
  DB[:children] << {:id=>1, :parent_id1=>1, :changed_on=>Date.today - 30}
281
- DB[:parents].get(:changed_on).strftime('%F').should == Date.today.strftime('%F')
282
- DB[:children].get(:changed_on).strftime('%F').should == Date.today.strftime('%F')
372
+ DB[:parents].get(:changed_on).strftime('%F').must_equal Date.today.strftime('%F')
373
+ DB[:children].get(:changed_on).strftime('%F').must_equal Date.today.strftime('%F')
283
374
  time = DB[:parents].get(:changed_on)
284
375
  DB[:parents].update(:id2=>4)
285
- DB[:parents].get(:changed_on).should > time
286
- DB[:children].get(:changed_on).should > time
376
+ DB[:parents].get(:changed_on).must_be :>, time
377
+ DB[:children].get(:changed_on).must_be :>, time
287
378
  time = DB[:parents].get(:changed_on)
288
379
  DB[:children].update(:id=>1)
289
- DB[:parents].get(:changed_on).should > time
290
- DB[:children].get(:changed_on).should > time
380
+ DB[:parents].get(:changed_on).must_be :>, time
381
+ DB[:children].get(:changed_on).must_be :>, time
291
382
  time = DB[:parents].get(:changed_on)
292
383
  DB[:children].delete
293
- DB[:parents].get(:changed_on).should > time
384
+ DB[:parents].get(:changed_on).must_be :>, time
294
385
  end
295
386
 
296
- specify "Should update the timestamp on the related table if that timestamp is initially NULL" do
387
+ it "Should update the timestamp on the related table if that timestamp is initially NULL" do
297
388
  DB.pgt_touch(:children, :parents, :changed_on, :id1=>:parent_id1)
298
389
  DB[:parents] << {:id1=>1, :changed_on=>nil}
299
390
  DB[:children] << {:id=>1, :parent_id1=>1}
300
391
  changed_on = DB[:parents].get(:changed_on)
301
- changed_on.should_not == nil
302
- changed_on.strftime('%F').should == Date.today.strftime('%F')
392
+ changed_on.wont_equal nil
393
+ changed_on.strftime('%F').must_equal Date.today.strftime('%F')
303
394
  end
304
395
  end
305
396
  end
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.0.8
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-07 00:00:00.000000000 Z
11
+ date: 2016-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -62,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
62
  version: '0'
63
63
  requirements: []
64
64
  rubyforge_project:
65
- rubygems_version: 2.4.5
65
+ rubygems_version: 2.5.1
66
66
  signing_key:
67
67
  specification_version: 4
68
68
  summary: Database enforced timestamps, immutable columns, and counter/sum caches