activerecord_views 0.1.0 → 0.1.4

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
  SHA256:
3
- metadata.gz: 846f267566c95c8e6adc3a7dc503e0aaefa83d48dcd5c27b865f6ff60dc70bc0
4
- data.tar.gz: be109db5a85a682c00244c2ff52d7f29cefb72d20b54ea03431937d04355bdcb
3
+ metadata.gz: e64bd87ba9a26795e83b579cc0047078b712c46f7e63be89f9ba7a5aad7de6d7
4
+ data.tar.gz: a7039933d362f05912e01469ee20f7b66f30004d9e1b036b33e8cc73b8641ce0
5
5
  SHA512:
6
- metadata.gz: 530ed043fe22df67d38ce2a5ce63f65af5617f2ead4e0de329fe47fe6f0072c25f837861f90f222af24e084d43516785a182125becd0b06e81409d930215a0c0
7
- data.tar.gz: ea5cacee78d55faaaa1aed554c34317a43d156f71f5bc017de4a9031df8c3432b0b785da335efdc85b67ee1dcc68ce064fc1bdc707d8214912a8fd69b0281052
6
+ metadata.gz: 2fa8934e9212705d81769c05fcb6271dd42f6baa2dc7525c11a8a78166c65bfb46482fc50caa96d525c182aabf746663fab4431e57c1fb7cae2fcfa35c580fa0
7
+ data.tar.gz: f7f9b27dbe7a1b47c77592cae929f6f2b6cfa2c83cbcbd298eb84d521521eba5f0196cbdb475097fd875558747c7e05ffd77390a57efff3077fabc918cb7d8f7
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 2.6.7
1
+ ruby 2.7.5
data/Appraisals CHANGED
@@ -1,17 +1,3 @@
1
- appraise 'rails4_2' do
2
- gem 'rails', '~> 4.2.0'
3
- gem "pg", "< 0.21"
4
- end
5
-
6
- appraise 'rails5_0' do
7
- gem 'rails', '~> 5.0.0'
8
- gem "pg", "< 1.0"
9
- end
10
-
11
- appraise 'rails5_1' do
12
- gem 'rails', '~> 5.1.0'
13
- end
14
-
15
1
  appraise 'rails5_2' do
16
2
  gem 'rails', '~> 5.2.0'
17
3
  end
@@ -23,3 +9,7 @@ end
23
9
  appraise 'rails6_1' do
24
10
  gem 'rails', '~> 6.1.0'
25
11
  end
12
+
13
+ appraise 'rails7_0' do
14
+ gem 'rails', '~> 7.0.0.rc1'
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', ['>= 4.2', '< 6.2']
20
+ gem.add_dependency 'activerecord', ['>= 5.2', '< 7.1']
21
21
 
22
22
  gem.add_development_dependency 'appraisal'
23
23
  gem.add_development_dependency 'rspec-rails', '>= 2.14'
@@ -2,6 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 5.1.0"
5
+ gem "rails", "~> 7.0.0.rc1"
6
6
 
7
7
  gemspec path: "../"
@@ -6,11 +6,7 @@ module ActiveRecordViews
6
6
  end
7
7
 
8
8
  def init_state_table!
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
9
+ table_exists = @connection.data_source_exists?('active_record_views')
14
10
 
15
11
  if table_exists && !@connection.column_exists?('active_record_views', 'class_name')
16
12
  @connection.begin_transaction
@@ -70,10 +70,6 @@ module ActiveRecordViews
70
70
  raise ArgumentError, 'not a materialized view'
71
71
  end
72
72
 
73
- if Rails::VERSION::MAJOR < 5
74
- value = ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(value)
75
- end
76
-
77
73
  value
78
74
  end
79
75
 
@@ -8,19 +8,11 @@ module ActiveRecordViews
8
8
  end
9
9
 
10
10
  unless app.config.cache_classes
11
- if app.respond_to?(:reloader)
12
- app.reloader.before_class_unload do
13
- ActiveRecordViews.reload_stale_views!
14
- end
15
- app.executor.to_run do
16
- ActiveRecordViews.reload_stale_views!
17
- end
18
- else
19
- ActiveSupport.on_load :action_controller do
20
- ActionDispatch::Callbacks.before do
21
- ActiveRecordViews.reload_stale_views!
22
- end
23
- end
11
+ app.reloader.before_class_unload do
12
+ ActiveRecordViews.reload_stale_views!
13
+ end
14
+ app.executor.to_run do
15
+ ActiveRecordViews.reload_stale_views!
24
16
  end
25
17
  end
26
18
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordViews
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.4'
3
3
  end
@@ -37,24 +37,18 @@ module ActiveRecordViews
37
37
  end
38
38
 
39
39
  def self.without_transaction(connection)
40
- in_transaction = if connection.respond_to? :transaction_open?
41
- connection.transaction_open?
42
- else
43
- !connection.outside_transaction?
44
- end
45
-
46
40
  states = Thread.current[:active_record_views_without_transaction] ||= {}
47
41
 
48
42
  begin
49
43
  if states[connection]
50
44
  yield states[connection]
51
- elsif in_transaction
45
+ elsif connection.transaction_open?
52
46
  begin
53
47
  temp_connection = connection.pool.checkout
54
48
  states[temp_connection] = states[connection] = temp_connection
55
49
  yield temp_connection
56
50
  ensure
57
- connection.pool.checkin temp_connection
51
+ connection.pool.checkin temp_connection if temp_connection
58
52
  states[temp_connection] = states[connection] = nil
59
53
  end
60
54
  else
@@ -9,25 +9,20 @@ end
9
9
  schema_rake_task = Gem::Version.new(Rails.version) >= Gem::Version.new("6.1") ? 'db:schema:dump' : 'db:structure:dump'
10
10
 
11
11
  Rake::Task[schema_rake_task].enhance do
12
- table_exists = if Rails::VERSION::MAJOR >= 5
13
- ActiveRecord::Base.connection.data_source_exists?('active_record_views')
14
- else
15
- ActiveRecord::Base.connection.table_exists?('active_record_views')
16
- end
12
+ table_exists = ActiveRecord::Base.connection.data_source_exists?('active_record_views')
17
13
 
18
14
  if schema_rake_task == 'db:structure:dump'
19
15
  ActiveRecord::Base.schema_format = :sql
20
16
  end
21
17
 
22
- if table_exists && ActiveRecord::Base.schema_format == :sql
23
- tasks = ActiveRecord::Tasks::DatabaseTasks
18
+ schema_format = if ActiveRecord.respond_to?(:schema_format)
19
+ ActiveRecord.schema_format
20
+ else
21
+ ActiveRecord::Base.schema_format
22
+ end
24
23
 
25
- filename = case
26
- when tasks.respond_to?(:dump_filename)
27
- tasks.dump_filename('primary')
28
- else
29
- tasks.schema_file
30
- end
24
+ if table_exists && schema_format == :sql
25
+ tasks = ActiveRecord::Tasks::DatabaseTasks
31
26
 
32
27
  config = if ActiveRecord::Base.configurations.respond_to?(:configs_for)
33
28
  if Rails.version.start_with?('6.0.')
@@ -49,15 +44,56 @@ Rake::Task[schema_rake_task].enhance do
49
44
  config.fetch('database')
50
45
  end
51
46
 
47
+ filename = case
48
+ when tasks.respond_to?(:schema_dump_path)
49
+ tasks.schema_dump_path(config)
50
+ when tasks.respond_to?(:dump_filename)
51
+ tasks.dump_filename('primary')
52
+ else
53
+ tasks.schema_file
54
+ end
55
+
52
56
  pg_tasks = tasks.send(:class_for_adapter, adapter).new(config)
53
- pg_tasks.send(:set_psql_env)
57
+ psql_env = if pg_tasks.respond_to?(:psql_env, true)
58
+ pg_tasks.send(:psql_env)
59
+ else
60
+ pg_tasks.send(:set_psql_env)
61
+ {}
62
+ end
63
+
64
+ begin
65
+ active_record_views_dump = Tempfile.open("active_record_views_dump.sql")
66
+ require 'shellwords'
67
+ system(psql_env, "pg_dump --data-only --no-owner --table=active_record_views #{Shellwords.escape database} >> #{Shellwords.escape active_record_views_dump.path}")
68
+ raise 'active_record_views metadata dump failed' unless $?.success?
54
69
 
55
- require 'shellwords'
56
- system("pg_dump --data-only --table=active_record_views #{Shellwords.escape database} >> #{Shellwords.escape filename}")
57
- raise 'active_record_views metadata dump failed' unless $?.success?
70
+ pg_tasks.send(:remove_sql_header_comments, active_record_views_dump.path)
58
71
 
59
- File.open filename, 'a' do |io|
60
- io.puts 'UPDATE public.active_record_views SET refreshed_at = NULL WHERE refreshed_at IS NOT NULL;'
72
+ # Substitute out any timestamps that were dumped from the active_record_views table
73
+ #
74
+ # Before:
75
+ #
76
+ # COPY public.active_record_views (name, class_name, checksum, options, refreshed_at) FROM stdin;
77
+ # test_view TestView 42364a017b73ef516a0eca9827e6fa00623257ee {"dependencies":[]} 2021-10-26 02:49:12.247494
78
+ # \.
79
+ #
80
+ # After:
81
+ #
82
+ # COPY public.active_record_views (name, class_name, checksum, options, refreshed_at) FROM stdin;
83
+ # test_view TestView 42364a017b73ef516a0eca9827e6fa00623257ee {"dependencies":[]} \N
84
+ # \.
85
+ active_record_views_dump_content = active_record_views_dump.read
86
+ if active_record_views_dump_content !~ /^COPY public.active_record_views \(.+, refreshed_at\) FROM stdin;$/
87
+ raise 'refreshed_at is not final column'
88
+ end
89
+ active_record_views_dump_content.gsub!(/\t\d\d\d\d-\d\d-\d\d.*$/, "\t\\N")
90
+
91
+ File.open filename, 'a' do |io|
92
+ io.puts active_record_views_dump_content
93
+ end
94
+ ensure
95
+ active_record_views_dump.close
96
+ active_record_views_dump.unlink
61
97
  end
62
98
  end
63
99
  end
@@ -5,11 +5,7 @@ describe ActiveRecordViews::ChecksumCache do
5
5
 
6
6
  describe 'initialisation' do
7
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
8
+ connection.data_source_exists?('active_record_views')
13
9
  end
14
10
 
15
11
  context 'no existing table' do
@@ -8,11 +8,7 @@ describe ActiveRecordViews::Extension do
8
8
 
9
9
  def view_exists?(name)
10
10
  connection = ActiveRecord::Base.connection
11
- if connection.respond_to?(:view_exists?)
12
- connection.view_exists?(name)
13
- else
14
- connection.table_exists?(name)
15
- end
11
+ connection.view_exists?(name)
16
12
  end
17
13
 
18
14
  it 'creates database views from heredocs' do
@@ -119,7 +115,7 @@ describe ActiveRecordViews::Extension do
119
115
  end
120
116
  RB
121
117
 
122
- with_reloader do
118
+ Rails.application.reloader.wrap do
123
119
  expect(DeletedFileTestModel.first.name).to eq 'delete test'
124
120
  end
125
121
 
@@ -133,11 +129,9 @@ describe ActiveRecordViews::Extension do
133
129
  .and change { view_exists?('deleted_file_test_models') }.from(true).to(false)
134
130
  test_request # second request does not `drop_view` again
135
131
 
136
- if Rails::VERSION::MAJOR >= 5
137
- expect {
138
- DeletedFileTestModel.first.name
139
- }.to raise_error NameError, 'uninitialized constant DeletedFileTestModel'
140
- end
132
+ expect {
133
+ DeletedFileTestModel.first.name
134
+ }.to raise_error NameError, 'uninitialized constant DeletedFileTestModel'
141
135
  end
142
136
 
143
137
  it 'does not create if database view is initially up to date' do
@@ -27,10 +27,6 @@ describe ActiveRecordViews do
27
27
  WHERE schemaname = 'public' AND matviewname = 'test'
28
28
  SQL
29
29
 
30
- if Rails::VERSION::MAJOR < 5
31
- value = ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(value)
32
- end
33
-
34
30
  value
35
31
  end
36
32
 
@@ -333,5 +329,16 @@ describe ActiveRecordViews do
333
329
  original_connection.pool.checkin original_connection_2
334
330
  end
335
331
  end
332
+
333
+ it 'does not attempt to checkin when checkout fails' do
334
+ expect(original_connection.pool).to receive(:checkout).and_raise PG::ConnectionBad
335
+ expect(original_connection.pool).to_not receive(:checkin)
336
+
337
+ expect {
338
+ original_connection.transaction do
339
+ ActiveRecordViews.without_transaction(original_connection) { }
340
+ end
341
+ }.to raise_error PG::ConnectionBad
342
+ end
336
343
  end
337
344
  end
@@ -12,6 +12,9 @@ Combustion.initialize! :active_record, :action_controller do
12
12
  config.cache_classes = false
13
13
  config.log_level = :debug
14
14
  config.active_record.schema_format = ENV.fetch('SCHEMA_FORMAT', 'sql').to_sym
15
+ if Gem::Version.new(Rails.version) >= Gem::Version.new("6.1")
16
+ config.active_record.legacy_connection_handling = false
17
+ end
15
18
  if ENV['SKIP_MODEL_EAGER_LOAD']
16
19
  config.eager_load_paths -= Rails.application.config.paths['app/models'].to_a
17
20
  end
data/spec/spec_helper.rb CHANGED
@@ -18,6 +18,9 @@ Rails.application.config.paths['app/models'] << 'app/models_temp'
18
18
 
19
19
  Combustion.initialize! :active_record, :action_controller do
20
20
  config.cache_classes = false
21
+ if Gem::Version.new(Rails.version) >= Gem::Version.new("6.1")
22
+ config.active_record.legacy_connection_handling = false
23
+ end
21
24
  end
22
25
  require 'rspec/rails'
23
26
  require 'super_diff/rspec-rails'
@@ -50,12 +53,7 @@ RSpec.configure do |config|
50
53
  config.before do
51
54
  FileUtils.rm_rf Dir["spec/internal/app/models_temp/*"]
52
55
 
53
- if Rails::VERSION::MAJOR >= 5
54
- Rails.application.reloader.reload!
55
- else
56
- ActionDispatch::Reloader.cleanup!
57
- ActionDispatch::Reloader.prepare!
58
- end
56
+ Rails.application.reloader.reload!
59
57
 
60
58
  connection = ActiveRecord::Base.connection
61
59
 
@@ -83,16 +81,8 @@ RSpec.configure do |config|
83
81
  config.include_context 'sql_statements'
84
82
  end
85
83
 
86
- def with_reloader(&block)
87
- if Rails.application.respond_to?(:reloader)
88
- Rails.application.reloader.wrap(&block)
89
- else
90
- block.call
91
- end
92
- end
93
-
94
84
  def test_request
95
- with_reloader do
85
+ Rails.application.reloader.wrap do
96
86
  status, headers, body = Rails.application.call(
97
87
  'REQUEST_METHOD' => 'GET',
98
88
  'PATH_INFO' => '/',
@@ -1,23 +1,6 @@
1
1
  require 'warning'
2
2
  require 'rails/version'
3
3
 
4
- case Rails::VERSION::STRING
5
- when /^4\.2\./
6
- Warning.ignore(%r{lib/(active_support/core_ext|action_dispatch/middleware)/.+: warning: (method redefined|previous definition)})
7
- Warning.ignore(%r{lib/active_support/core_ext/.+: warning: BigDecimal.new is deprecated})
8
- Warning.ignore(%r{lib/arel/visitors/informix.rb:\d+: warning: assigned but unused variable})
9
- Warning.ignore(%r{lib/active_record/connection_adapters/.+: warning: deprecated Object#=~ is called on Integer})
10
- Warning.ignore(%r{Inheriting from Rack::Session::Abstract::ID is deprecated})
11
- when /^5\.0\./
12
- Warning.ignore(%r{lib/(active_support/core_ext|action_view)/.+: warning: (method redefined|previous definition)})
13
- Warning.ignore(%r{lib/arel/visitors/informix.rb:\d+: warning: assigned but unused variable})
14
- Warning.ignore(%r{lib/action_view/.+: warning: `\*' interpreted as argument prefix})
15
- when /^5\.1\./
16
- Warning.ignore(%r{lib/(active_support/core_ext)/.+: warning: (method redefined|previous definition)})
17
- Warning.ignore(%r{lib/arel/visitors/informix.rb:\d+: warning: assigned but unused variable})
18
- Warning.ignore(%r{lib/active_record/.+/schema_statements.rb:\d+: (warning: in `drop_table': the last argument was passed as a single Hash|warning: although a splat keyword arguments here)})
19
- end
20
-
21
4
  Warning.process do |_warning|
22
5
  :raise
23
6
  end
data/spec/tasks_spec.rb CHANGED
@@ -77,8 +77,27 @@ describe 'rake tasks' do
77
77
 
78
78
  expect(File.exist?('spec/internal/db/schema.rb')).to eq false
79
79
  sql = File.read('spec/internal/db/structure.sql')
80
- expect(sql).to match(/COPY public\.active_record_views.+test_view\tTestView/m)
81
- expect(sql).to match(/UPDATE public\.active_record_views SET refreshed_at = NULL/)
80
+ expect(sql).to match(/CREATE TABLE public\.schema_migrations/)
81
+ expect(sql).to match(/CREATE VIEW public\.test_view/)
82
+ expect(sql).to match(/COPY public\.active_record_views.+test_view\tTestView\t.*\t.*\t\\N$/m)
83
+ end
84
+
85
+ it 'clears refreshed_at values' do
86
+ ActiveRecord::Base.connection.execute "UPDATE active_record_views SET refreshed_at = current_timestamp AT TIME ZONE 'UTC' WHERE name = 'test_view';"
87
+
88
+ rake schema_rake_task
89
+
90
+ ActiveRecord::Base.clear_all_connections!
91
+
92
+ system 'dropdb activerecord_views_test'
93
+ raise unless $?.success?
94
+ system 'createdb activerecord_views_test'
95
+ raise unless $?.success?
96
+ system 'psql -X -q -o /dev/null -f spec/internal/db/structure.sql activerecord_views_test'
97
+ raise unless $?.success?
98
+
99
+ refreshed_ats = ActiveRecord::Base.connection.select_values("SELECT refreshed_at FROM active_record_views WHERE name = 'test_view'")
100
+ expect(refreshed_ats).to eq [nil]
82
101
  end
83
102
 
84
103
  it 'does not write structure.sql when `schema_format = :ruby`', if: schema_rake_task != 'db:structure:dump' do
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.1.0
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Weathered
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-29 00:00:00.000000000 Z
11
+ date: 2021-12-07 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: '4.2'
19
+ version: '5.2'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6.2'
22
+ version: '7.1'
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: '4.2'
29
+ version: '5.2'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6.2'
32
+ version: '7.1'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: appraisal
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -130,12 +130,10 @@ files:
130
130
  - README.markdown
131
131
  - Rakefile
132
132
  - activerecord_views.gemspec
133
- - gemfiles/rails4_2.gemfile
134
- - gemfiles/rails5_0.gemfile
135
- - gemfiles/rails5_1.gemfile
136
133
  - gemfiles/rails5_2.gemfile
137
134
  - gemfiles/rails6_0.gemfile
138
135
  - gemfiles/rails6_1.gemfile
136
+ - gemfiles/rails7_0.gemfile
139
137
  - lib/active_record_views.rb
140
138
  - lib/active_record_views/checksum_cache.rb
141
139
  - lib/active_record_views/database_cleaner/truncation_extension.rb
@@ -185,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
183
  - !ruby/object:Gem::Version
186
184
  version: '0'
187
185
  requirements: []
188
- rubygems_version: 3.0.3.1
186
+ rubygems_version: 3.2.32
189
187
  signing_key:
190
188
  specification_version: 4
191
189
  summary: Automatic database view creation for ActiveRecord
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "rails", "~> 4.2.0"
6
- gem "pg", "< 0.21"
7
-
8
- gemspec path: "../"
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "rails", "~> 5.0.0"
6
- gem "pg", "< 1.0"
7
-
8
- gemspec path: "../"