activerecord_views 0.1.5 → 0.1.7
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/lib/active_record_views/database_tasks.rb +91 -0
- data/lib/active_record_views/railtie.rb +0 -4
- data/lib/active_record_views/version.rb +1 -1
- data/lib/active_record_views.rb +2 -0
- metadata +11 -65
- data/.gitignore +0 -8
- data/.rspec +0 -2
- data/.tool-versions +0 -1
- data/Appraisals +0 -15
- data/Gemfile +0 -3
- data/LICENSE.txt +0 -22
- data/Rakefile +0 -14
- data/activerecord_views.gemspec +0 -27
- data/gemfiles/rails5_2.gemfile +0 -7
- data/gemfiles/rails6_0.gemfile +0 -7
- data/gemfiles/rails6_1.gemfile +0 -7
- data/gemfiles/rails7_0.gemfile +0 -7
- data/lib/tasks/active_record_views.rake +0 -106
- data/spec/active_record_views_checksum_cache_spec.rb +0 -112
- data/spec/active_record_views_extension_spec.rb +0 -459
- data/spec/active_record_views_spec.rb +0 -344
- data/spec/internal/Rakefile +0 -24
- data/spec/internal/app/models/dependency_a.rb +0 -3
- data/spec/internal/app/models/dependency_b.rb +0 -3
- data/spec/internal/app/models/dependency_c.rb +0 -3
- data/spec/internal/app/models/erb_test_model.rb +0 -7
- data/spec/internal/app/models/erb_test_model.sql.erb +0 -1
- data/spec/internal/app/models/external_file_test_model.rb +0 -3
- data/spec/internal/app/models/external_file_test_model.sql +0 -1
- data/spec/internal/app/models/heredoc_test_model.rb +0 -5
- data/spec/internal/app/models/modified_a.rb +0 -3
- data/spec/internal/app/models/modified_b.rb +0 -3
- data/spec/internal/app/models/namespace/test_model.rb +0 -3
- data/spec/internal/app/models/namespace/test_model.sql +0 -1
- data/spec/internal/config/database.yml +0 -9
- data/spec/internal/config/routes.rb +0 -3
- data/spec/spec_helper.rb +0 -130
- data/spec/support/silence_warnings.rb +0 -6
- data/spec/tasks_spec.rb +0 -113
@@ -1,459 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ActiveRecordViews::Extension do
|
4
|
-
describe '.is_view' do
|
5
|
-
def registered_model_class_names
|
6
|
-
ActiveRecordViews.registered_views.map(&:model_class_name)
|
7
|
-
end
|
8
|
-
|
9
|
-
def view_exists?(name)
|
10
|
-
connection = ActiveRecord::Base.connection
|
11
|
-
connection.view_exists?(name)
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'creates database views from heredocs' do
|
15
|
-
expect(ActiveRecordViews).to receive(:create_view).once.and_call_original
|
16
|
-
expect(HeredocTestModel.first.name).to eq 'Here document'
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'creates database views from external SQL files' do
|
20
|
-
expect(ActiveRecordViews).to receive(:create_view).once.and_call_original
|
21
|
-
expect(ExternalFileTestModel.first.name).to eq 'External SQL file'
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'creates database views from namespaced external SQL files' do
|
25
|
-
expect(ActiveRecordViews).to receive(:create_view).once.and_call_original
|
26
|
-
expect(Namespace::TestModel.first.name).to eq 'Namespaced SQL file'
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'creates database views from external ERB files' do
|
30
|
-
expect(ActiveRecordViews).to receive(:create_view).once.and_call_original
|
31
|
-
expect(ErbTestModel.first.name).to eq 'ERB method file'
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'errors if external SQL file is missing' do
|
35
|
-
expect {
|
36
|
-
class MissingFileTestModel < ActiveRecord::Base
|
37
|
-
is_view
|
38
|
-
end
|
39
|
-
}.to raise_error RuntimeError, /could not find missing_file_test_model.sql/
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'reloads the database view when external SQL file is modified' do
|
43
|
-
sql_file = File.join(TEST_TEMP_MODEL_DIR, 'modified_file_test_model.sql')
|
44
|
-
update_file sql_file, "SELECT 'foo'::text AS test"
|
45
|
-
|
46
|
-
expect {
|
47
|
-
expect(ActiveRecordViews).to receive(:create_view).once.and_call_original
|
48
|
-
class ModifiedFileTestModel < ActiveRecord::Base
|
49
|
-
is_view
|
50
|
-
end
|
51
|
-
}.to change { begin; ModifiedFileTestModel.take!.test; rescue NameError; end }.from(nil).to('foo')
|
52
|
-
.and change { registered_model_class_names.include?('ModifiedFileTestModel') }.from(false).to(true)
|
53
|
-
|
54
|
-
expect {
|
55
|
-
update_file sql_file, "SELECT 'bar'::text AS test, 42::integer AS test2"
|
56
|
-
}.to_not change { ModifiedFileTestModel.take!.test }
|
57
|
-
|
58
|
-
expect {
|
59
|
-
expect(ActiveRecordViews).to receive(:create_view).once.and_call_original
|
60
|
-
test_request
|
61
|
-
test_request # second request does not `create_view` again
|
62
|
-
}.to change { ModifiedFileTestModel.take!.test }.to('bar')
|
63
|
-
.and change { ModifiedFileTestModel.column_names }.from(%w[test]).to(%w[test test2])
|
64
|
-
|
65
|
-
expect {
|
66
|
-
update_file sql_file, "SELECT 'baz'::text AS test"
|
67
|
-
}.to_not change { ModifiedFileTestModel.take!.test }
|
68
|
-
|
69
|
-
expect {
|
70
|
-
expect(ActiveRecordViews).to receive(:create_view).once.and_call_original
|
71
|
-
test_request
|
72
|
-
}.to change { ModifiedFileTestModel.take!.test }.to('baz')
|
73
|
-
|
74
|
-
File.unlink sql_file
|
75
|
-
test_request # trigger cleanup
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'reloads the database view when external ERB SQL file is modified' do
|
79
|
-
['foo 42', 'bar 42'].each do |sql|
|
80
|
-
expect(ActiveRecordViews).to receive(:create_view).with(
|
81
|
-
anything,
|
82
|
-
'modified_erb_file_test_models',
|
83
|
-
'ModifiedErbFileTestModel',
|
84
|
-
sql,
|
85
|
-
{}
|
86
|
-
).once.ordered
|
87
|
-
end
|
88
|
-
|
89
|
-
sql_file = File.join(TEST_TEMP_MODEL_DIR, 'modified_erb_file_test_model.sql.erb')
|
90
|
-
update_file sql_file, 'foo <%= test_erb_method %>'
|
91
|
-
|
92
|
-
class ModifiedErbFileTestModel < ActiveRecord::Base
|
93
|
-
def self.test_erb_method
|
94
|
-
2 * 3 * 7
|
95
|
-
end
|
96
|
-
|
97
|
-
is_view
|
98
|
-
end
|
99
|
-
|
100
|
-
update_file sql_file, 'bar <%= test_erb_method %>'
|
101
|
-
test_request
|
102
|
-
|
103
|
-
File.unlink sql_file
|
104
|
-
test_request # trigger cleanup
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'drops the view if the external SQL file is deleted' do
|
108
|
-
sql_file = File.join(TEST_TEMP_MODEL_DIR, 'deleted_file_test_model.sql')
|
109
|
-
File.write sql_file, "SELECT 1 AS id, 'delete test'::text AS name"
|
110
|
-
|
111
|
-
rb_file = 'spec/internal/app/models_temp/deleted_file_test_model.rb'
|
112
|
-
File.write rb_file, <<~RB
|
113
|
-
class DeletedFileTestModel < ActiveRecord::Base
|
114
|
-
is_view
|
115
|
-
end
|
116
|
-
RB
|
117
|
-
|
118
|
-
Rails.application.reloader.wrap do
|
119
|
-
expect(DeletedFileTestModel.first.name).to eq 'delete test'
|
120
|
-
end
|
121
|
-
|
122
|
-
File.unlink sql_file
|
123
|
-
File.unlink rb_file
|
124
|
-
|
125
|
-
expect(ActiveRecord::Base.connection).to receive(:execute).with(/\ADROP/).once.and_call_original
|
126
|
-
expect {
|
127
|
-
test_request
|
128
|
-
}.to change { registered_model_class_names.include?('DeletedFileTestModel') }.from(true).to(false)
|
129
|
-
.and change { view_exists?('deleted_file_test_models') }.from(true).to(false)
|
130
|
-
test_request # second request does not `drop_view` again
|
131
|
-
|
132
|
-
expect {
|
133
|
-
DeletedFileTestModel.first.name
|
134
|
-
}.to raise_error NameError, 'uninitialized constant DeletedFileTestModel'
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'does not create if database view is initially up to date' do
|
138
|
-
ActiveRecordViews.create_view ActiveRecord::Base.connection, 'initial_create_test_models', 'InitialCreateTestModel', 'SELECT 42 as id'
|
139
|
-
expect(ActiveRecord::Base.connection).to receive(:execute).with(/\ACREATE (?:OR REPLACE )?VIEW/).never
|
140
|
-
class InitialCreateTestModel < ActiveRecord::Base
|
141
|
-
is_view 'SELECT 42 as id'
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'successfully recreates modified paired views with incompatible changes' do
|
146
|
-
without_dependency_checks do
|
147
|
-
ActiveRecordViews.create_view ActiveRecord::Base.connection, 'modified_as', 'ModifiedA', 'SELECT 11 AS old_name;'
|
148
|
-
ActiveRecordViews.create_view ActiveRecord::Base.connection, 'modified_bs', 'ModifiedB', 'SELECT old_name FROM modified_as;'
|
149
|
-
end
|
150
|
-
|
151
|
-
expect(ModifiedB.first.attributes.except(nil)).to eq('new_name' => 22)
|
152
|
-
end
|
153
|
-
|
154
|
-
it 'successfully restores dependant view when temporarily dropping dependency' do
|
155
|
-
without_dependency_checks do
|
156
|
-
ActiveRecordViews.create_view ActiveRecord::Base.connection, 'dependency_as', 'DependencyA', 'SELECT 42 AS foo, 1 AS id;'
|
157
|
-
ActiveRecordViews.create_view ActiveRecord::Base.connection, 'dependency_bs', 'DependencyB', 'SELECT id FROM dependency_as;'
|
158
|
-
end
|
159
|
-
|
160
|
-
expect(DependencyA.first.id).to eq 2
|
161
|
-
expect(DependencyB.first.id).to eq 2
|
162
|
-
end
|
163
|
-
|
164
|
-
it 'sucessfully restore dependant view and dependency when loading from middle outwards' do
|
165
|
-
without_dependency_checks do
|
166
|
-
ActiveRecordViews.create_view ActiveRecord::Base.connection, 'dependency_as', 'DependencyA', 'SELECT 42 AS foo, 1 AS id;'
|
167
|
-
ActiveRecordViews.create_view ActiveRecord::Base.connection, 'dependency_bs', 'DependencyB', 'SELECT id FROM dependency_as;'
|
168
|
-
ActiveRecordViews.create_view ActiveRecord::Base.connection, 'dependency_cs', 'DependencyC', 'SELECT id FROM dependency_bs;'
|
169
|
-
end
|
170
|
-
|
171
|
-
expect(DependencyB.first.id).to eq 2
|
172
|
-
end
|
173
|
-
|
174
|
-
it 'errors if more than one argument is specified' do
|
175
|
-
expect {
|
176
|
-
class TooManyArguments < ActiveRecord::Base
|
177
|
-
is_view 'SELECT 1 AS ID;', 'SELECT 2 AS ID;'
|
178
|
-
end
|
179
|
-
}.to raise_error ArgumentError, 'wrong number of arguments (2 for 0..1)'
|
180
|
-
end
|
181
|
-
|
182
|
-
it 'errors if an invalid option is specified' do
|
183
|
-
expect {
|
184
|
-
class InvalidOption < ActiveRecord::Base
|
185
|
-
is_view 'SELECT 1 AS ID;', blargh: 123
|
186
|
-
end
|
187
|
-
}.to raise_error ArgumentError, /^Unknown key: :?blargh/
|
188
|
-
end
|
189
|
-
|
190
|
-
it 'creates/refreshes/drops materialized views' do
|
191
|
-
sql_file = File.join(TEST_TEMP_MODEL_DIR, 'materialized_view_test_model.sql')
|
192
|
-
File.write sql_file, 'SELECT 123 AS id;'
|
193
|
-
|
194
|
-
class MaterializedViewTestModel < ActiveRecord::Base
|
195
|
-
is_view materialized: true
|
196
|
-
end
|
197
|
-
|
198
|
-
expect {
|
199
|
-
MaterializedViewTestModel.first!
|
200
|
-
}.to raise_error ActiveRecord::StatementInvalid, /materialized view "materialized_view_test_models" has not been populated/
|
201
|
-
|
202
|
-
expect(MaterializedViewTestModel.view_populated?).to eq false
|
203
|
-
expect(MaterializedViewTestModel.refreshed_at).to eq nil
|
204
|
-
|
205
|
-
MaterializedViewTestModel.refresh_view!
|
206
|
-
|
207
|
-
expect(MaterializedViewTestModel.view_populated?).to eq true
|
208
|
-
expect(MaterializedViewTestModel.refreshed_at).to be_a Time
|
209
|
-
expect(MaterializedViewTestModel.refreshed_at.zone).to eq 'UTC'
|
210
|
-
expect(MaterializedViewTestModel.refreshed_at).to be_within(1.second).of Time.now
|
211
|
-
|
212
|
-
expect(MaterializedViewTestModel.first!.id).to eq 123
|
213
|
-
|
214
|
-
File.unlink sql_file
|
215
|
-
|
216
|
-
expect {
|
217
|
-
test_request
|
218
|
-
}.to change { view_exists?('materialized_view_test_models') }.from(true).to(false)
|
219
|
-
end
|
220
|
-
|
221
|
-
it 'raises an error for `view_populated?` if view is not materialized' do
|
222
|
-
class NonMaterializedViewPopulatedTestModel < ActiveRecord::Base
|
223
|
-
is_view 'SELECT 1 AS id;'
|
224
|
-
end
|
225
|
-
|
226
|
-
expect {
|
227
|
-
NonMaterializedViewPopulatedTestModel.view_populated?
|
228
|
-
}.to raise_error ArgumentError, 'not a materialized view'
|
229
|
-
end
|
230
|
-
|
231
|
-
it 'supports ensuring a view hierarchy has been populated' do
|
232
|
-
class EnsurePopulatedFoo < ActiveRecord::Base
|
233
|
-
is_view 'SELECT 1 AS id;', materialized: true
|
234
|
-
end
|
235
|
-
|
236
|
-
class EnsurePopulatedBar < ActiveRecord::Base
|
237
|
-
is_view "SELECT * FROM #{EnsurePopulatedFoo.table_name}", dependencies: [EnsurePopulatedFoo]
|
238
|
-
end
|
239
|
-
|
240
|
-
class EnsurePopulatedBaz < ActiveRecord::Base
|
241
|
-
is_view "SELECT * FROM #{EnsurePopulatedBar.table_name}", dependencies: [EnsurePopulatedBar]
|
242
|
-
end
|
243
|
-
|
244
|
-
expect(ActiveRecord::Base.connection).to receive(:execute).with('REFRESH MATERIALIZED VIEW "ensure_populated_foos";').once.and_call_original
|
245
|
-
allow(ActiveRecord::Base.connection).to receive(:execute).and_call_original
|
246
|
-
|
247
|
-
expect(EnsurePopulatedFoo.view_populated?).to eq false
|
248
|
-
EnsurePopulatedBaz.ensure_populated!
|
249
|
-
expect(EnsurePopulatedFoo.view_populated?).to eq true
|
250
|
-
EnsurePopulatedBaz.ensure_populated!
|
251
|
-
expect(EnsurePopulatedFoo.view_populated?).to eq true
|
252
|
-
end
|
253
|
-
|
254
|
-
it 'invalidates ActiveRecord query cache after populating' do
|
255
|
-
class EnsurePopulatedCache < ActiveRecord::Base
|
256
|
-
is_view 'SELECT 1 AS id;', materialized: true
|
257
|
-
end
|
258
|
-
|
259
|
-
expect(ActiveRecord::Base.connection).to receive(:execute).with('REFRESH MATERIALIZED VIEW "ensure_populated_caches";').once.and_call_original
|
260
|
-
allow(ActiveRecord::Base.connection).to receive(:execute).and_call_original
|
261
|
-
|
262
|
-
ActiveRecord::Base.connection.cache do
|
263
|
-
expect(EnsurePopulatedCache.view_populated?).to eq false
|
264
|
-
EnsurePopulatedCache.ensure_populated!
|
265
|
-
expect(EnsurePopulatedCache.view_populated?).to eq true
|
266
|
-
EnsurePopulatedCache.ensure_populated!
|
267
|
-
expect(EnsurePopulatedCache.view_populated?).to eq true
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
it 'supports refreshing materialized views concurrently' do
|
272
|
-
class MaterializedViewRefreshTestModel < ActiveRecord::Base
|
273
|
-
is_view 'SELECT 1 AS id;', materialized: true
|
274
|
-
end
|
275
|
-
class MaterializedViewConcurrentRefreshTestModel < ActiveRecord::Base
|
276
|
-
is_view 'SELECT 1 AS id;', materialized: true, unique_columns: [:id]
|
277
|
-
end
|
278
|
-
MaterializedViewRefreshTestModel.refresh_view!
|
279
|
-
MaterializedViewConcurrentRefreshTestModel.refresh_view!
|
280
|
-
|
281
|
-
sql_statements.clear
|
282
|
-
|
283
|
-
MaterializedViewRefreshTestModel.refresh_view!
|
284
|
-
MaterializedViewRefreshTestModel.refresh_view! concurrent: false
|
285
|
-
expect {
|
286
|
-
MaterializedViewRefreshTestModel.refresh_view! concurrent: true
|
287
|
-
}.to raise_error ActiveRecord::StatementInvalid, /^PG::ObjectNotInPrerequisiteState: ERROR: +cannot refresh/
|
288
|
-
MaterializedViewConcurrentRefreshTestModel.refresh_view!
|
289
|
-
MaterializedViewConcurrentRefreshTestModel.refresh_view! concurrent: false
|
290
|
-
MaterializedViewConcurrentRefreshTestModel.refresh_view! concurrent: true
|
291
|
-
|
292
|
-
expect(sql_statements.grep_v(/^SELECT/)).to eq [
|
293
|
-
'BEGIN',
|
294
|
-
'REFRESH MATERIALIZED VIEW "materialized_view_refresh_test_models";',
|
295
|
-
"UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_refresh_test_models';",
|
296
|
-
'COMMIT',
|
297
|
-
|
298
|
-
'BEGIN',
|
299
|
-
'REFRESH MATERIALIZED VIEW "materialized_view_refresh_test_models";',
|
300
|
-
"UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_refresh_test_models';",
|
301
|
-
'COMMIT',
|
302
|
-
|
303
|
-
'BEGIN',
|
304
|
-
'REFRESH MATERIALIZED VIEW CONCURRENTLY "materialized_view_refresh_test_models";',
|
305
|
-
'ROLLBACK',
|
306
|
-
|
307
|
-
'BEGIN',
|
308
|
-
'REFRESH MATERIALIZED VIEW CONCURRENTLY "materialized_view_concurrent_refresh_test_models";',
|
309
|
-
"UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_concurrent_refresh_test_models';",
|
310
|
-
'COMMIT',
|
311
|
-
|
312
|
-
'BEGIN',
|
313
|
-
'REFRESH MATERIALIZED VIEW "materialized_view_concurrent_refresh_test_models";',
|
314
|
-
"UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_concurrent_refresh_test_models';",
|
315
|
-
'COMMIT',
|
316
|
-
|
317
|
-
'BEGIN',
|
318
|
-
'REFRESH MATERIALIZED VIEW CONCURRENTLY "materialized_view_concurrent_refresh_test_models";',
|
319
|
-
"UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_concurrent_refresh_test_models';",
|
320
|
-
'COMMIT',
|
321
|
-
]
|
322
|
-
end
|
323
|
-
|
324
|
-
it 'supports opportunistically refreshing materialized views concurrently' do
|
325
|
-
class MaterializedViewAutoRefreshTestModel < ActiveRecord::Base
|
326
|
-
is_view 'SELECT 1 AS id;', materialized: true, unique_columns: [:id]
|
327
|
-
end
|
328
|
-
|
329
|
-
sql_statements.clear
|
330
|
-
|
331
|
-
MaterializedViewAutoRefreshTestModel.refresh_view! concurrent: :auto
|
332
|
-
MaterializedViewAutoRefreshTestModel.refresh_view! concurrent: :auto
|
333
|
-
MaterializedViewAutoRefreshTestModel.refresh_view! concurrent: :auto
|
334
|
-
|
335
|
-
expect(sql_statements.grep_v(/^SELECT/)).to eq [
|
336
|
-
'BEGIN',
|
337
|
-
'REFRESH MATERIALIZED VIEW "materialized_view_auto_refresh_test_models";',
|
338
|
-
"UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_auto_refresh_test_models';",
|
339
|
-
'COMMIT',
|
340
|
-
|
341
|
-
'BEGIN',
|
342
|
-
'REFRESH MATERIALIZED VIEW CONCURRENTLY "materialized_view_auto_refresh_test_models";',
|
343
|
-
"UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_auto_refresh_test_models';",
|
344
|
-
'COMMIT',
|
345
|
-
|
346
|
-
'BEGIN',
|
347
|
-
'REFRESH MATERIALIZED VIEW CONCURRENTLY "materialized_view_auto_refresh_test_models";',
|
348
|
-
"UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'materialized_view_auto_refresh_test_models';",
|
349
|
-
'COMMIT',
|
350
|
-
]
|
351
|
-
end
|
352
|
-
|
353
|
-
it 'raises an error when refreshing materialized views with invalid concurrent option' do
|
354
|
-
class MaterializedViewInvalidRefreshTestModel < ActiveRecord::Base
|
355
|
-
is_view 'SELECT 1 AS id;', materialized: true, unique_columns: [:id]
|
356
|
-
end
|
357
|
-
|
358
|
-
expect {
|
359
|
-
MaterializedViewAutoRefreshTestModel.refresh_view! concurrent: :blah
|
360
|
-
}.to raise_error ArgumentError, 'invalid concurrent option'
|
361
|
-
end
|
362
|
-
|
363
|
-
it 'errors if dependencies are not specified' do
|
364
|
-
class DependencyCheckBase1 < ActiveRecord::Base
|
365
|
-
self.table_name = 'dependency_check_base1'
|
366
|
-
is_view 'SELECT 1 AS ID;'
|
367
|
-
end
|
368
|
-
class DependencyCheckBase2 < ActiveRecord::Base
|
369
|
-
self.table_name = 'dependency_check_base2'
|
370
|
-
is_view 'SELECT 1 AS ID;'
|
371
|
-
end
|
372
|
-
ActiveRecord::Base.connection.execute 'CREATE VIEW dependency_check_base_unmanaged AS SELECT 1 AS ID;'
|
373
|
-
|
374
|
-
expect {
|
375
|
-
class DependencyCheckGood < ActiveRecord::Base
|
376
|
-
is_view 'SELECT * FROM dependency_check_base1;', dependencies: [DependencyCheckBase1]
|
377
|
-
end
|
378
|
-
}.to_not raise_error
|
379
|
-
|
380
|
-
expect {
|
381
|
-
class DependencyCheckGoodUnmanaged < ActiveRecord::Base
|
382
|
-
is_view 'SELECT * FROM dependency_check_base_unmanaged;'
|
383
|
-
end
|
384
|
-
}.to_not raise_error
|
385
|
-
|
386
|
-
expect {
|
387
|
-
class DependencyCheckMissing1 < ActiveRecord::Base
|
388
|
-
is_view 'SELECT * FROM dependency_check_base1 UNION ALL SELECT * FROM dependency_check_base2;', dependencies: [DependencyCheckBase1]
|
389
|
-
end
|
390
|
-
}.to raise_error ArgumentError, 'DependencyCheckBase2 must be specified as a dependency of DependencyCheckMissing1: `is_view dependencies: [DependencyCheckBase1, DependencyCheckBase2]`'
|
391
|
-
|
392
|
-
expect {
|
393
|
-
class DependencyCheckMissing2 < ActiveRecord::Base
|
394
|
-
is_view 'SELECT * FROM dependency_check_base1 UNION ALL SELECT * FROM dependency_check_base2;', dependencies: []
|
395
|
-
end
|
396
|
-
}.to raise_error ArgumentError, 'DependencyCheckBase1 and DependencyCheckBase2 must be specified as dependencies of DependencyCheckMissing2: `is_view dependencies: [DependencyCheckBase1, DependencyCheckBase2]`'
|
397
|
-
|
398
|
-
expect {
|
399
|
-
class DependencyCheckNested < ActiveRecord::Base
|
400
|
-
is_view 'SELECT 1 FROM dependency_check_goods'
|
401
|
-
end
|
402
|
-
}.to raise_error ArgumentError, 'DependencyCheckGood must be specified as a dependency of DependencyCheckNested: `is_view dependencies: [DependencyCheckGood]`'
|
403
|
-
|
404
|
-
expect {
|
405
|
-
class DependencyCheckExtra1 < ActiveRecord::Base
|
406
|
-
is_view 'SELECT * FROM dependency_check_base1;', dependencies: [DependencyCheckBase1, DependencyCheckBase2]
|
407
|
-
end
|
408
|
-
}.to raise_error ArgumentError, 'DependencyCheckBase2 is not a dependency of DependencyCheckExtra1'
|
409
|
-
|
410
|
-
expect {
|
411
|
-
class DependencyCheckExtra2 < ActiveRecord::Base
|
412
|
-
is_view 'SELECT 1 AS id;', dependencies: [DependencyCheckBase1, DependencyCheckBase2]
|
413
|
-
end
|
414
|
-
}.to raise_error ArgumentError, 'DependencyCheckBase1 and DependencyCheckBase2 are not dependencies of DependencyCheckExtra2'
|
415
|
-
|
416
|
-
expect {
|
417
|
-
class DependencyCheckWrongType < ActiveRecord::Base
|
418
|
-
is_view 'SELECT 1;', dependencies: %w[DependencyCheckBase1]
|
419
|
-
end
|
420
|
-
}.to raise_error ArgumentError, 'dependencies must be ActiveRecord classes'
|
421
|
-
|
422
|
-
expect(view_names).to match_array %w[
|
423
|
-
dependency_check_base1
|
424
|
-
dependency_check_base2
|
425
|
-
dependency_check_base_unmanaged
|
426
|
-
|
427
|
-
dependency_check_goods
|
428
|
-
dependency_check_good_unmanageds
|
429
|
-
]
|
430
|
-
end
|
431
|
-
|
432
|
-
context 'without create_enabled' do
|
433
|
-
around do |example|
|
434
|
-
without_create_enabled(&example)
|
435
|
-
end
|
436
|
-
|
437
|
-
it 'delays create_view until process_create_queue! is called' do
|
438
|
-
allow(ActiveRecordViews).to receive(:create_view).and_call_original
|
439
|
-
|
440
|
-
expect(ActiveRecordViews::Extension.create_queue.size).to eq 0
|
441
|
-
expect(ActiveRecordViews).to_not have_received(:create_view)
|
442
|
-
|
443
|
-
expect {
|
444
|
-
expect(HeredocTestModel.first.name).to eq 'Here document'
|
445
|
-
}.to raise_error ActiveRecord::StatementInvalid
|
446
|
-
|
447
|
-
expect(ActiveRecordViews::Extension.create_queue.size).to eq 1
|
448
|
-
expect(ActiveRecordViews).to_not have_received(:create_view)
|
449
|
-
|
450
|
-
ActiveRecordViews::Extension.process_create_queue!
|
451
|
-
|
452
|
-
expect(ActiveRecordViews::Extension.create_queue.size).to eq 0
|
453
|
-
expect(ActiveRecordViews).to have_received(:create_view)
|
454
|
-
|
455
|
-
expect(HeredocTestModel.first.name).to eq 'Here document'
|
456
|
-
end
|
457
|
-
end
|
458
|
-
end
|
459
|
-
end
|