activerecord_views 0.0.12 → 0.0.13

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
  SHA1:
3
- metadata.gz: 1bc9898154793aaeadd3252f3ae9f691dd43669f
4
- data.tar.gz: fdea9d04caa3e922a45725436532f9db48d175d8
3
+ metadata.gz: f3c9db1b593bf137570cde8f2e4fcaf6837aa414
4
+ data.tar.gz: 81143c5d6e77cfe47971b9bca74dde2f8a1c3847
5
5
  SHA512:
6
- metadata.gz: 4658c236510c130b3f197beaf66d04f569c7b8fae0861e4ea32e4205172ea6c2213ea30ce13750025745dbe287bf714900e1b5e426ce5c439ad9a2ec3540933e
7
- data.tar.gz: 47f78f0aaafcddf3186f1c3f7574d141e74955e2d211a1cdb406cf0e1382b8609f8214f2e1769ac84ac0562d781a01cad752073870f29fb9c3443e4498ef1e87
6
+ metadata.gz: fcf258e4d370ee70ad3a96488271d206ec7e8fe27dce4c123b9a176a10d12cd06cf2c1f3d7f2c21446a98045015967cbc4130d8414e48db0b9d1081e8afb6691
7
+ data.tar.gz: 684a7373b1167ab08a20f565e7f33c93cc5420e85ec34186488af74f36772672927dcaa993198273d83f568fd05ffae05eaf2c8a40d55096a80af1ea9785ac8d
data/README.markdown CHANGED
@@ -121,6 +121,8 @@ AccountBalance.refresh_view!
121
121
  AccountBalance.view_populated? # => true
122
122
  ```
123
123
 
124
+ ActiveRecordViews records when a view was last refreshed. This is often useful for giving users an idea of how stale data. To retrieve this timestamp, call `.refreshed_at` on the model:
125
+
124
126
  PostgreSQL 9.4 supports refreshing materialized views concurrently. This allows other processes to continue reading old cached data while the view is being updated. To use this feature you must have define a unique index on the materialized view:
125
127
 
126
128
  ```sql
@@ -22,8 +22,12 @@ module ActiveRecordViews
22
22
  @connection.execute "ALTER TABLE active_record_views ADD COLUMN options json NOT NULL DEFAULT '{}';"
23
23
  end
24
24
 
25
+ if table_exists && !@connection.column_exists?('active_record_views', 'refreshed_at')
26
+ @connection.execute "ALTER TABLE active_record_views ADD COLUMN refreshed_at timestamp;"
27
+ end
28
+
25
29
  unless table_exists
26
- @connection.execute "CREATE TABLE active_record_views(name text PRIMARY KEY, class_name text NOT NULL UNIQUE, checksum text NOT NULL, options json NOT NULL DEFAULT '{}');"
30
+ @connection.execute "CREATE TABLE active_record_views(name text PRIMARY KEY, class_name text NOT NULL UNIQUE, checksum text NOT NULL, options json NOT NULL DEFAULT '{}', refreshed_at timestamp);"
27
31
  end
28
32
  end
29
33
 
@@ -48,7 +48,10 @@ module ActiveRecordViews
48
48
  raise ArgumentError, 'invalid concurrent option'
49
49
  end
50
50
 
51
- connection.execute "REFRESH MATERIALIZED VIEW#{' CONCURRENTLY' if concurrent} #{connection.quote_table_name self.table_name};"
51
+ connection.transaction do
52
+ connection.execute "REFRESH MATERIALIZED VIEW#{' CONCURRENTLY' if concurrent} #{connection.quote_table_name self.table_name};"
53
+ connection.execute "UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = #{connection.quote self.table_name};"
54
+ end
52
55
  end
53
56
 
54
57
  def view_populated?
@@ -64,6 +67,18 @@ module ActiveRecordViews
64
67
 
65
68
  ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(value)
66
69
  end
70
+
71
+ def refreshed_at
72
+ value = connection.select_value(<<-SQL.squish)
73
+ SELECT refreshed_at
74
+ FROM active_record_views
75
+ WHERE name = #{connection.quote self.table_name};
76
+ SQL
77
+
78
+ if value
79
+ ActiveSupport::TimeZone['UTC'].parse(value)
80
+ end
81
+ end
67
82
  end
68
83
  end
69
84
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordViews
2
- VERSION = '0.0.12'
2
+ VERSION = '0.0.13'
3
3
  end
@@ -62,7 +62,7 @@ describe ActiveRecordViews::ChecksumCache do
62
62
  end
63
63
  end
64
64
 
65
- context 'existing table without options' do
65
+ context 'existing table without options or refreshed at timestamp' do
66
66
  before do
67
67
  connection.execute 'CREATE TABLE active_record_views(name text PRIMARY KEY, class_name text NOT NULL UNIQUE, checksum text NOT NULL);'
68
68
 
@@ -71,14 +71,17 @@ describe ActiveRecordViews::ChecksumCache do
71
71
  end
72
72
 
73
73
  it 'upgrades the table without losing data' do
74
- expect(ActiveRecord::Base.connection).to receive(:execute).with("ALTER TABLE active_record_views ADD COLUMN options json NOT NULL DEFAULT '{}';").once.and_call_original
75
-
76
74
  expect(connection.column_exists?('active_record_views', 'options')).to eq false
75
+ expect(connection.column_exists?('active_record_views', 'refreshed_at')).to eq false
77
76
  expect(ActiveRecordViews.view_exists?(connection, 'test_view')).to eq true
78
77
 
78
+ expect(ActiveRecord::Base.connection).to receive(:execute).with("ALTER TABLE active_record_views ADD COLUMN options json NOT NULL DEFAULT '{}';").once.and_call_original
79
+ expect(ActiveRecord::Base.connection).to receive(:execute).with("ALTER TABLE active_record_views ADD COLUMN refreshed_at timestamp;").once.and_call_original
80
+
79
81
  ActiveRecordViews::ChecksumCache.new(connection)
80
82
 
81
83
  expect(connection.column_exists?('active_record_views', 'options')).to eq true
84
+ expect(connection.column_exists?('active_record_views', 'refreshed_at')).to eq true
82
85
  expect(ActiveRecordViews.view_exists?(connection, 'test_view')).to eq true
83
86
  end
84
87
  end
@@ -149,8 +149,14 @@ describe ActiveRecordViews::Extension do
149
149
  }.to raise_error ActiveRecord::StatementInvalid, /materialized view "materialized_view_test_models" has not been populated/
150
150
 
151
151
  expect(MaterializedViewTestModel.view_populated?).to eq false
152
+ expect(MaterializedViewTestModel.refreshed_at).to eq nil
153
+
152
154
  MaterializedViewTestModel.refresh_view!
155
+
153
156
  expect(MaterializedViewTestModel.view_populated?).to eq true
157
+ expect(MaterializedViewTestModel.refreshed_at).to be_a ActiveSupport::TimeWithZone
158
+ expect(MaterializedViewTestModel.refreshed_at.zone).to eq 'UTC'
159
+ expect(MaterializedViewTestModel.refreshed_at).to be_within(1.second).of Time.now
154
160
 
155
161
  expect(MaterializedViewTestModel.first!.id).to eq 123
156
162
 
@@ -182,8 +188,18 @@ describe ActiveRecordViews::Extension do
182
188
  end
183
189
  MaterializedViewConcurrentRefreshTestModel.refresh_view!
184
190
 
185
- expect(ActiveRecord::Base.connection).to receive(:execute).with('REFRESH MATERIALIZED VIEW "materialized_view_refresh_test_models";').once.and_call_original
186
- expect(ActiveRecord::Base.connection).to receive(:execute).with('REFRESH MATERIALIZED VIEW CONCURRENTLY "materialized_view_concurrent_refresh_test_models";').once.and_call_original
191
+ [
192
+ 'BEGIN',
193
+ 'REFRESH MATERIALIZED VIEW "materialized_view_refresh_test_models";',
194
+ "UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_refresh_test_models';",
195
+ 'COMMIT',
196
+ 'BEGIN',
197
+ 'REFRESH MATERIALIZED VIEW CONCURRENTLY "materialized_view_concurrent_refresh_test_models";',
198
+ "UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_concurrent_refresh_test_models';",
199
+ 'COMMIT',
200
+ ].each do |sql|
201
+ expect(ActiveRecord::Base.connection).to receive(:execute).with(sql).once.and_call_original
202
+ end
187
203
 
188
204
  MaterializedViewRefreshTestModel.refresh_view!
189
205
  MaterializedViewConcurrentRefreshTestModel.refresh_view! concurrent: true
@@ -194,8 +210,18 @@ describe ActiveRecordViews::Extension do
194
210
  is_view 'SELECT 1 AS id;', materialized: true, unique_columns: [:id]
195
211
  end
196
212
 
197
- expect(ActiveRecord::Base.connection).to receive(:execute).with('REFRESH MATERIALIZED VIEW "materialized_view_auto_refresh_test_models";').once.and_call_original
198
- expect(ActiveRecord::Base.connection).to receive(:execute).with('REFRESH MATERIALIZED VIEW CONCURRENTLY "materialized_view_auto_refresh_test_models";').once.and_call_original
213
+ [
214
+ 'BEGIN',
215
+ 'REFRESH MATERIALIZED VIEW "materialized_view_auto_refresh_test_models";',
216
+ "UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_auto_refresh_test_models';",
217
+ 'COMMIT',
218
+ 'BEGIN',
219
+ 'REFRESH MATERIALIZED VIEW CONCURRENTLY "materialized_view_auto_refresh_test_models";',
220
+ "UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_auto_refresh_test_models';",
221
+ 'COMMIT',
222
+ ].each do |sql|
223
+ expect(ActiveRecord::Base.connection).to receive(:execute).with(sql).once.and_call_original
224
+ end
199
225
 
200
226
  MaterializedViewAutoRefreshTestModel.refresh_view! concurrent: :auto
201
227
  MaterializedViewAutoRefreshTestModel.refresh_view! concurrent: :auto
@@ -42,6 +42,7 @@ describe ActiveRecordViews do
42
42
  'class_name' => 'Test',
43
43
  'checksum' => Digest::SHA1.hexdigest('select 1 as id'),
44
44
  'options' => '{"materialized":true,"dependencies":[]}',
45
+ 'refreshed_at' => nil,
45
46
  }
46
47
  ]
47
48
  end
data/spec/tasks_spec.rb CHANGED
@@ -11,6 +11,6 @@ describe 'rake db:structure:dump' do
11
11
  sql = File.read('spec/internal/db/structure.sql')
12
12
  FileUtils.rm_f 'spec/internal/db/structure.sql'
13
13
 
14
- expect(sql).to match /COPY active_record_views.+test_view\tTestView/m
14
+ expect(sql).to match(/COPY active_record_views.+test_view\tTestView/m)
15
15
  end
16
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord_views
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Weathered
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-24 00:00:00.000000000 Z
11
+ date: 2015-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -155,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
155
  version: '0'
156
156
  requirements: []
157
157
  rubyforge_project:
158
- rubygems_version: 2.2.2
158
+ rubygems_version: 2.4.7
159
159
  signing_key:
160
160
  specification_version: 4
161
161
  summary: Automatic database view creation for ActiveRecord