activerecord_views 0.0.17 → 0.0.18

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
- SHA256:
3
- metadata.gz: b2627c1dce47cf8e2c072dc3e47c36792dac3d2f1ff21271dc0c3268e502f386
4
- data.tar.gz: e7faba517dfd15a41741c87e7657dd9e190e8b5a1047c155e18f8bfd300de3be
2
+ SHA1:
3
+ metadata.gz: 3311e70b5371fad5e3e179b012cd73157503ba33
4
+ data.tar.gz: 570acd248425e41f312240c6ffd3f6ec76c4e99a
5
5
  SHA512:
6
- metadata.gz: d93b3071f407c190a08c52f8bc998600049971bd1751ecf1f1a1b05682061b4e75d1d5ec2aa46d32feb54b24ba2153045644a0c22e1e6a595e4e6b212b44f857
7
- data.tar.gz: f3df8e14207b91c5be93f40473ef63f4b3d56a52075d875c2e624edda16fe1594e9cb01bd9faa08ecf0408354cb7dd244c7d2dec1d0b14cb3635ce23aabe6c5f
6
+ metadata.gz: 32f32cc5728ec20db1b1342baaad6763c75116ce411fd59939449a71def61571405017654ffb8b47744b2ae0dbb394e0873b770bf1574a48ac626f716edf9355
7
+ data.tar.gz: c4f8fb9024b8bdcd0c540e520e4a5280d406b55879ff1ff438ff44b405fd59c10a6cbde8d217906bdcd8e76c3210a073b9be9a8c10edb2e7087f18c84a1134bd
data/.gitignore CHANGED
@@ -2,4 +2,5 @@
2
2
  Gemfile.lock
3
3
  gemfiles/*.gemfile.lock
4
4
  pkg
5
+ spec/internal/db/schema.rb
5
6
  spec/internal/log/*.log
data/Appraisals CHANGED
@@ -1,15 +1,15 @@
1
- appraise 'rails3_2' do
2
- gem 'rails', '~> 3.2.0'
1
+ appraise 'rails4_2' do
2
+ gem 'rails', '~> 4.2.0'
3
3
  end
4
4
 
5
- appraise 'rails4_0' do
6
- gem 'rails', '~> 4.0.0'
5
+ appraise 'rails5_0' do
6
+ gem 'rails', '~> 5.0.0'
7
7
  end
8
8
 
9
- appraise 'rails4_1' do
10
- gem 'rails', '~> 4.1.0'
9
+ appraise 'rails5_1' do
10
+ gem 'rails', '~> 5.1.0'
11
11
  end
12
12
 
13
- appraise 'rails4_2' do
14
- gem 'rails', '~> 4.2.0'
13
+ appraise 'rails5_2' do
14
+ gem 'rails', '~> 5.2.0'
15
15
  end
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ['lib']
19
19
 
20
- gem.add_dependency 'activerecord', ['>= 3.2', '< 4.3']
20
+ gem.add_dependency 'activerecord', ['>= 4.2', '< 5.3']
21
21
 
22
22
  gem.add_development_dependency 'appraisal'
23
23
  gem.add_development_dependency 'rspec-rails', '>= 2.14'
@@ -4,4 +4,4 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "rails", "~> 4.2.0"
6
6
 
7
- gemspec :path => "../"
7
+ gemspec path: "../"
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 3.2.0"
5
+ gem "rails", "~> 5.0.0"
6
6
 
7
- gemspec :path => "../"
7
+ gemspec path: "../"
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 4.0.0"
5
+ gem "rails", "~> 5.1.0"
6
6
 
7
- gemspec :path => "../"
7
+ gemspec path: "../"
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 4.1.0"
5
+ gem "rails", "~> 5.2.0"
6
6
 
7
- gemspec :path => "../"
7
+ gemspec path: "../"
@@ -320,4 +320,12 @@ module ActiveRecordViews
320
320
  end
321
321
  end
322
322
  end
323
+
324
+ def self.drop_unregistered_views!
325
+ connection = ActiveRecord::Base.connection
326
+
327
+ connection.select_rows('SELECT name, class_name FROM active_record_views')
328
+ .reject { |name, class_name| Object.const_defined? class_name }
329
+ .each { |name, class_name| ActiveRecordViews.drop_view connection, name }
330
+ end
323
331
  end
@@ -6,7 +6,11 @@ module ActiveRecordViews
6
6
  end
7
7
 
8
8
  def init_state_table!
9
- table_exists = @connection.table_exists?('active_record_views')
9
+ table_exists = if Rails::VERSION::MAJOR >= 5
10
+ @connection.data_source_exists?('active_record_views')
11
+ else
12
+ @connection.table_exists?('active_record_views')
13
+ end
10
14
 
11
15
  if table_exists && !@connection.column_exists?('active_record_views', 'class_name')
12
16
  @connection.transaction :requires_new => true do
@@ -4,6 +4,18 @@ module ActiveRecordViews
4
4
  module Extension
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ mattr_accessor :create_enabled
8
+ self.create_enabled = true
9
+
10
+ mattr_accessor :create_queue
11
+ self.create_queue = []
12
+
13
+ def self.process_create_queue!
14
+ while create_args = create_queue.shift
15
+ ActiveRecordViews.create_view ActiveRecord::Base.connection, *create_args
16
+ end
17
+ end
18
+
7
19
  def self.currently_migrating?
8
20
  if defined?(Rake) && Rake.respond_to?(:application)
9
21
  Rake.application.top_level_tasks.any? { |task_name| task_name =~ /^db:migrate($|:)/ }
@@ -12,8 +24,6 @@ module ActiveRecordViews
12
24
 
13
25
  module ClassMethods
14
26
  def is_view(*args)
15
- return if ActiveRecordViews::Extension.currently_migrating?
16
-
17
27
  cattr_accessor :view_options
18
28
  self.view_options = args.extract_options!
19
29
 
@@ -26,7 +36,12 @@ module ActiveRecordViews
26
36
  ActiveRecordViews.read_sql_file(sql_path)
27
37
  end
28
38
 
29
- ActiveRecordViews.create_view self.connection, self.table_name, self.name, sql, self.view_options
39
+ create_args = [self.table_name, self.name, sql, self.view_options]
40
+ if ActiveRecordViews::Extension.create_enabled && !ActiveRecordViews::Extension.currently_migrating?
41
+ ActiveRecordViews.create_view self.connection, *create_args
42
+ else
43
+ ActiveRecordViews::Extension.create_queue << create_args
44
+ end
30
45
  end
31
46
 
32
47
  def refresh_view!(options = {})
@@ -60,7 +75,11 @@ module ActiveRecordViews
60
75
  raise ArgumentError, 'not a materialized view'
61
76
  end
62
77
 
63
- ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(value)
78
+ if Rails::VERSION::MAJOR < 5
79
+ value = ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(value)
80
+ end
81
+
82
+ value
64
83
  end
65
84
 
66
85
  def refreshed_at
@@ -7,6 +7,7 @@ module ActiveRecordViews
7
7
  end
8
8
 
9
9
  ActiveSupport.on_load :action_controller do
10
+ ActiveRecordViews::Extension.create_enabled = !app.config.cache_classes
10
11
  unless app.config.cache_classes
11
12
  ActionDispatch::Callbacks.before do
12
13
  ActiveRecordViews.reload_stale_views!
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordViews
2
- VERSION = '0.0.17'
2
+ VERSION = '0.0.18'
3
3
  end
@@ -1,5 +1,19 @@
1
+ Rake::Task['db:migrate'].enhance do
2
+ if Rails.application.config.cache_classes
3
+ Rails.application.eager_load!
4
+ ActiveRecordViews::Extension.process_create_queue!
5
+ ActiveRecordViews.drop_unregistered_views!
6
+ end
7
+ end
8
+
1
9
  Rake::Task['db:structure:dump'].enhance do
2
- if ActiveRecord::Base.connection.table_exists?('active_record_views')
10
+ table_exists = if Rails::VERSION::MAJOR >= 5
11
+ ActiveRecord::Base.connection.data_source_exists?('active_record_views')
12
+ else
13
+ ActiveRecord::Base.connection.table_exists?('active_record_views')
14
+ end
15
+
16
+ if table_exists
3
17
  filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
4
18
 
5
19
  if defined? ActiveRecord::Tasks::DatabaseTasks
@@ -4,13 +4,21 @@ describe ActiveRecordViews::ChecksumCache do
4
4
  let(:connection) { ActiveRecord::Base.connection }
5
5
 
6
6
  describe 'initialisation' do
7
+ def metadata_table_exists?
8
+ if Rails::VERSION::MAJOR >= 5
9
+ connection.data_source_exists?('active_record_views')
10
+ else
11
+ connection.table_exists?('active_record_views')
12
+ end
13
+ end
14
+
7
15
  context 'no existing table' do
8
16
  it 'creates the table' do
9
17
  expect(ActiveRecord::Base.connection).to receive(:execute).with(/\ACREATE TABLE active_record_views/).once.and_call_original
10
18
 
11
- expect(connection.table_exists?('active_record_views')).to eq false
19
+ expect(metadata_table_exists?).to eq false
12
20
  ActiveRecordViews::ChecksumCache.new(connection)
13
- expect(connection.table_exists?('active_record_views')).to eq true
21
+ expect(metadata_table_exists?).to eq true
14
22
 
15
23
  expect(connection.column_exists?('active_record_views', 'class_name')).to eq true
16
24
  expect(connection.column_exists?('active_record_views', 'options')).to eq true
@@ -20,7 +28,7 @@ describe ActiveRecordViews::ChecksumCache do
20
28
  context 'existing table with current structure' do
21
29
  before do
22
30
  ActiveRecordViews::ChecksumCache.new(connection)
23
- expect(connection.table_exists?('active_record_views')).to eq true
31
+ expect(metadata_table_exists?).to eq true
24
32
  end
25
33
 
26
34
  it 'does not recreate the table' do
@@ -42,9 +50,6 @@ describe ActiveRecordViews::ChecksumCache do
42
50
 
43
51
  it 'drops existing managed views recreates the table' do
44
52
  expect(ActiveRecord::Base.connection).to receive(:execute).with(/\ABEGIN\z/).once.and_call_original
45
- if Rails::VERSION::MAJOR < 4
46
- expect(ActiveRecord::Base.connection).to receive(:execute).with('SELECT name FROM active_record_views;', nil).once.and_call_original
47
- end
48
53
  expect(ActiveRecord::Base.connection).to receive(:execute).with(/\ADROP VIEW IF EXISTS test_view CASCADE;\z/).once.and_call_original
49
54
  expect(ActiveRecord::Base.connection).to receive(:execute).with(/\ADROP TABLE active_record_views;\z/).once.and_call_original
50
55
  expect(ActiveRecord::Base.connection).to receive(:execute).with(/\ACREATE TABLE active_record_views/).once.and_call_original
@@ -353,5 +353,32 @@ describe ActiveRecordViews::Extension do
353
353
  dependency_check_good_unmanageds
354
354
  ]
355
355
  end
356
+
357
+ context 'without create_enabled' do
358
+ around do |example|
359
+ without_create_enabled(&example)
360
+ end
361
+
362
+ it 'delays create_view until process_create_queue! is called' do
363
+ allow(ActiveRecordViews).to receive(:create_view).and_call_original
364
+
365
+ expect(ActiveRecordViews::Extension.create_queue.size).to eq 0
366
+ expect(ActiveRecordViews).to_not have_received(:create_view)
367
+
368
+ expect {
369
+ expect(HeredocTestModel.first.name).to eq 'Here document'
370
+ }.to raise_error ActiveRecord::StatementInvalid
371
+
372
+ expect(ActiveRecordViews::Extension.create_queue.size).to eq 1
373
+ expect(ActiveRecordViews).to_not have_received(:create_view)
374
+
375
+ ActiveRecordViews::Extension.process_create_queue!
376
+
377
+ expect(ActiveRecordViews::Extension.create_queue.size).to eq 0
378
+ expect(ActiveRecordViews).to have_received(:create_view)
379
+
380
+ expect(HeredocTestModel.first.name).to eq 'Here document'
381
+ end
382
+ end
356
383
  end
357
384
  end
@@ -92,14 +92,14 @@ describe ActiveRecordViews do
92
92
  it 'updates view with compatible change' do
93
93
  create_test_view 'select 2 as id'
94
94
  expect(test_view_sql).to eq 'SELECT 2 AS id;'
95
- expect(connection.select_value('SELECT id2 FROM dependant2a')).to eq '4'
95
+ expect(Integer(connection.select_value('SELECT id2 FROM dependant2a'))).to eq 4
96
96
  end
97
97
 
98
98
  describe 'changes incompatible with CREATE OR REPLACE' do
99
99
  it 'updates view with new column added before existing' do
100
100
  create_test_view "select 'foo'::text as name, 3 as id"
101
101
  expect(test_view_sql).to eq "SELECT 'foo'::text AS name, 3 AS id;"
102
- expect(connection.select_value('SELECT id2 FROM dependant2a')).to eq '6'
102
+ expect(Integer(connection.select_value('SELECT id2 FROM dependant2a'))).to eq 6
103
103
  end
104
104
 
105
105
  it 'fails to update view if column used by dependant view is removed' do
@@ -107,7 +107,7 @@ describe ActiveRecordViews do
107
107
  create_test_view "select 'foo'::text as name"
108
108
  }.to raise_error ActiveRecord::StatementInvalid, /column test.id does not exist/
109
109
  expect(test_view_sql).to eq 'SELECT 1 AS id;'
110
- expect(connection.select_value('SELECT id2 FROM dependant2a')).to eq '2'
110
+ expect(Integer(connection.select_value('SELECT id2 FROM dependant2a'))).to eq 2
111
111
  end
112
112
  end
113
113
 
@@ -8,8 +8,7 @@ Combustion::Database.instance_eval do
8
8
  end
9
9
 
10
10
  Combustion.initialize! :active_record, :action_controller do
11
- config.cache_classes = false
12
- config.active_record.whitelist_attributes = true if Rails::VERSION::MAJOR < 4
11
+ config.cache_classes = ENV['CACHE_CLASSES'] == 'true'
13
12
  end
14
13
 
15
14
  load 'active_record/railties/databases.rake'
@@ -1,3 +1,5 @@
1
- class MissingFileTestModel < ActiveRecord::Base
2
- is_view
1
+ unless ActiveRecordViews::Extension.currently_migrating?
2
+ class MissingFileTestModel < ActiveRecord::Base
3
+ is_view
4
+ end
3
5
  end
data/spec/spec_helper.rb CHANGED
@@ -2,13 +2,16 @@ require 'bundler'
2
2
  Bundler.setup
3
3
 
4
4
  require 'rails/version'
5
- $VERBOSE = true unless Rails::VERSION::MAJOR < 4
5
+ $VERBOSE = true
6
6
 
7
7
  require 'combustion'
8
8
  require 'active_record_views'
9
+
10
+ FileUtils.mkdir_p 'spec/internal/db'
11
+ File.write 'spec/internal/db/schema.rb', ''
12
+
9
13
  Combustion.initialize! :active_record, :action_controller do
10
14
  config.cache_classes = false
11
- config.active_record.whitelist_attributes = true if Rails::VERSION::MAJOR < 4
12
15
  end
13
16
  require 'rspec/rails'
14
17
 
@@ -16,8 +19,12 @@ RSpec.configure do |config|
16
19
  config.use_transactional_fixtures = false
17
20
 
18
21
  config.before do
19
- ActionDispatch::Reloader.cleanup!
20
- ActionDispatch::Reloader.prepare!
22
+ if Rails::VERSION::MAJOR >= 5
23
+ Rails.application.reloader.reload!
24
+ else
25
+ ActionDispatch::Reloader.cleanup!
26
+ ActionDispatch::Reloader.prepare!
27
+ end
21
28
 
22
29
  connection = ActiveRecord::Base.connection
23
30
 
@@ -41,7 +48,6 @@ RSpec.configure do |config|
41
48
  connection.execute "DROP MATERIALIZED VIEW IF EXISTS #{connection.quote_table_name view_name} CASCADE"
42
49
  end
43
50
  end
44
-
45
51
  end
46
52
 
47
53
  def test_request
@@ -92,3 +98,11 @@ def without_dependency_checks
92
98
  ensure
93
99
  allow(ActiveRecordViews).to receive(:check_dependencies).and_call_original
94
100
  end
101
+
102
+ def without_create_enabled
103
+ old_enabled = ActiveRecordViews::Extension.create_enabled
104
+ ActiveRecordViews::Extension.create_enabled = false
105
+ yield
106
+ ensure
107
+ ActiveRecordViews::Extension.create_enabled = old_enabled
108
+ end
data/spec/tasks_spec.rb CHANGED
@@ -1,17 +1,68 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'rake db:structure:dump' do
4
- it 'copies over activerecord_views data' do
5
- ActiveRecordViews.create_view ActiveRecord::Base.connection, 'test_view', 'TestView', 'SELECT 1'
6
-
7
- FileUtils.rm_f 'spec/internal/db/structure.sql'
8
- system("rake -f spec/internal/Rakefile db:structure:dump")
3
+ describe 'rake tasks' do
4
+ def rake(task_name, cache_classes: false)
5
+ system(*%W[
6
+ rake
7
+ -f spec/internal/Rakefile
8
+ #{task_name}
9
+ CACHE_CLASSES=#{cache_classes}
10
+ ])
9
11
  raise unless $?.success?
12
+ end
13
+
14
+ describe 'db:migrate' do
15
+ def view_names
16
+ ActiveRecord::Base.connection.select_values(<<~SQL.squish)
17
+ SELECT table_name
18
+ FROM information_schema.views
19
+ WHERE table_schema = 'public'
20
+ SQL
21
+ end
22
+
23
+ it 'does not create any database views' do
24
+ expect(view_names).to be_empty
25
+ rake 'db:migrate'
26
+ expect(view_names).to be_empty
27
+ end
28
+
29
+ it 'creates database views when classes are cached (production mode)' do
30
+ expect(view_names).to be_empty
31
+ rake 'db:migrate', cache_classes: true
32
+ expect(view_names).to_not be_empty
33
+ end
34
+
35
+ context 'with unregistered view' do
36
+ before do
37
+ ActiveRecordViews.create_view ActiveRecord::Base.connection, 'old_view', 'OldView', 'SELECT 42 AS id'
38
+ end
39
+
40
+ it 'does not drop unregistered views' do
41
+ expect(view_names).to include 'old_view'
42
+ rake 'db:migrate'
43
+ expect(view_names).to include 'old_view'
44
+ end
45
+
46
+ it 'drops unregistered views when classes are cached (production mode)' do
47
+ expect(view_names).to include 'old_view'
48
+ rake 'db:migrate', cache_classes: true
49
+ expect(view_names).to_not include 'old_view'
50
+ end
51
+ end
52
+ end
53
+
54
+ describe 'db:structure:dump' do
55
+ it 'copies over activerecord_views data' do
56
+ ActiveRecordViews.create_view ActiveRecord::Base.connection, 'test_view', 'TestView', 'SELECT 1'
57
+
58
+ FileUtils.rm_f 'spec/internal/db/structure.sql'
59
+ rake 'db:structure:dump'
10
60
 
11
- sql = File.read('spec/internal/db/structure.sql')
12
- FileUtils.rm_f 'spec/internal/db/structure.sql'
61
+ sql = File.read('spec/internal/db/structure.sql')
62
+ FileUtils.rm_f 'spec/internal/db/structure.sql'
13
63
 
14
- expect(sql).to match(/COPY public\.active_record_views.+test_view\tTestView/m)
15
- expect(sql).to match(/UPDATE public\.active_record_views SET refreshed_at = NULL/)
64
+ expect(sql).to match(/COPY public\.active_record_views.+test_view\tTestView/m)
65
+ expect(sql).to match(/UPDATE public\.active_record_views SET refreshed_at = NULL/)
66
+ end
16
67
  end
17
68
  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.17
4
+ version: 0.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Weathered
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-02 00:00:00.000000000 Z
11
+ date: 2018-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.2'
19
+ version: '4.2'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '4.3'
22
+ version: '5.3'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '3.2'
29
+ version: '4.2'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '4.3'
32
+ version: '5.3'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: appraisal
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -101,10 +101,10 @@ files:
101
101
  - README.markdown
102
102
  - Rakefile
103
103
  - activerecord_views.gemspec
104
- - gemfiles/rails3_2.gemfile
105
- - gemfiles/rails4_0.gemfile
106
- - gemfiles/rails4_1.gemfile
107
104
  - gemfiles/rails4_2.gemfile
105
+ - gemfiles/rails5_0.gemfile
106
+ - gemfiles/rails5_1.gemfile
107
+ - gemfiles/rails5_2.gemfile
108
108
  - lib/active_record_views.rb
109
109
  - lib/active_record_views/checksum_cache.rb
110
110
  - lib/active_record_views/database_cleaner/truncation_extension.rb
@@ -132,7 +132,6 @@ files:
132
132
  - spec/internal/app/models/namespace/test_model.rb
133
133
  - spec/internal/app/models/namespace/test_model.sql
134
134
  - spec/internal/config/database.yml
135
- - spec/internal/db/schema.rb
136
135
  - spec/spec_helper.rb
137
136
  - spec/tasks_spec.rb
138
137
  homepage: http://github.com/jasoncodes/activerecord_views
@@ -155,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
154
  version: '0'
156
155
  requirements: []
157
156
  rubyforge_project:
158
- rubygems_version: 2.7.6
157
+ rubygems_version: 2.6.14.3
159
158
  signing_key:
160
159
  specification_version: 4
161
160
  summary: Automatic database view creation for ActiveRecord
@@ -178,6 +177,5 @@ test_files:
178
177
  - spec/internal/app/models/namespace/test_model.rb
179
178
  - spec/internal/app/models/namespace/test_model.sql
180
179
  - spec/internal/config/database.yml
181
- - spec/internal/db/schema.rb
182
180
  - spec/spec_helper.rb
183
181
  - spec/tasks_spec.rb
@@ -1,2 +0,0 @@
1
- ActiveRecord::Schema.define do
2
- end