activerecord_views 0.0.17 → 0.0.18

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
- 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