From c5709414eb23931070b65b92ed17c25ea9c374a4 Mon Sep 17 00:00:00 2001 From: Nathan Palmer Date: Fri, 17 Oct 2014 11:40:23 -0400 Subject: [PATCH 01/14] Allowed you to pre-process .sql files through erb --- lib/activerecord-database-views/view.rb | 10 ++++++++-- lib/activerecord-database-views/view_collection.rb | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/activerecord-database-views/view.rb b/lib/activerecord-database-views/view.rb index a457f12..bd949a0 100644 --- a/lib/activerecord-database-views/view.rb +++ b/lib/activerecord-database-views/view.rb @@ -1,3 +1,5 @@ +require 'erb' + module ActiveRecord::DatabaseViews class View attr_reader :path @@ -15,7 +17,7 @@ def load! end def name - File.basename(path, '.sql') + File.basename(File.basename(path, '.erb'), '.sql') end private @@ -25,7 +27,11 @@ def full_path end def sql - File.read(full_path) + if File.extname(path) == '.erb' + ERB.new(File.read(full_path)).result + else + File.read(full_path) + end end def call_sql!(sql) diff --git a/lib/activerecord-database-views/view_collection.rb b/lib/activerecord-database-views/view_collection.rb index c9ac744..9101c8b 100644 --- a/lib/activerecord-database-views/view_collection.rb +++ b/lib/activerecord-database-views/view_collection.rb @@ -41,7 +41,7 @@ def retrieve_related_view(exception) end def view_paths - Dir.glob('db/views/**/*.sql') + Dir.glob('db/views/**/*.{sql,sql.erb}') end end end From 9c8cbcce7d18e900c9e909afc230bd2788a0389a Mon Sep 17 00:00:00 2001 From: Nathan Palmer Date: Fri, 17 Oct 2014 11:40:40 -0400 Subject: [PATCH 02/14] Fixed the mis-naming of exc in the catch --- lib/activerecord-database-views/view_collection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/activerecord-database-views/view_collection.rb b/lib/activerecord-database-views/view_collection.rb index 9101c8b..0f2fd25 100644 --- a/lib/activerecord-database-views/view_collection.rb +++ b/lib/activerecord-database-views/view_collection.rb @@ -29,7 +29,7 @@ def load_view(view) if (related_view = retrieve_related_view(exception)) load_view(related_view) and retry else - raise exc + raise exception end end end From ea3bece16079d2432d4f228da824e86ae8aa1a91 Mon Sep 17 00:00:00 2001 From: Nathan Palmer Date: Fri, 17 Oct 2014 11:41:08 -0400 Subject: [PATCH 03/14] Rolling back the db transaction in the case of postgres where you cannot continue where you left off --- lib/activerecord-database-views/view_collection.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/activerecord-database-views/view_collection.rb b/lib/activerecord-database-views/view_collection.rb index 0f2fd25..b947790 100644 --- a/lib/activerecord-database-views/view_collection.rb +++ b/lib/activerecord-database-views/view_collection.rb @@ -27,6 +27,7 @@ def load_view(view) view.load! and views.delete(view) rescue ActiveRecord::StatementInvalid => exception if (related_view = retrieve_related_view(exception)) + ActiveRecord::Base.connection.rollback_db_transaction load_view(related_view) and retry else raise exception From 3e2b1ffddd6c277e5077f44a1a2c7c4dc302a8f9 Mon Sep 17 00:00:00 2001 From: Nathan Palmer Date: Wed, 19 Nov 2014 23:13:22 -0500 Subject: [PATCH 04/14] Added a single test to get the testing infrastructure setup --- Gemfile.lock | 31 +++++++++++++++++++++++++++++ Rakefile | 2 +- activerecord-database-views.gemspec | 3 +++ db/views/sql_view1.sql | 0 db/views/sql_view2.sql | 0 test/test_helper.rb | 4 +++- test/view_collection_test.rb | 8 ++++++++ 7 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 db/views/sql_view1.sql create mode 100644 db/views/sql_view2.sql create mode 100644 test/view_collection_test.rb diff --git a/Gemfile.lock b/Gemfile.lock index 09dd097..636bd8b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,13 +2,44 @@ PATH remote: . specs: activerecord-database-views (0.1.0) + activerecord (~> 4.0, <= 5.0) GEM remote: https://rubygems.org/ specs: + activemodel (4.1.7) + activesupport (= 4.1.7) + builder (~> 3.1) + activerecord (4.1.7) + activemodel (= 4.1.7) + activesupport (= 4.1.7) + arel (~> 5.0.0) + activesupport (4.1.7) + i18n (~> 0.6, >= 0.6.9) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.1) + tzinfo (~> 1.1) + arel (5.0.1.20140414130214) + builder (3.2.2) + byebug (3.5.1) + columnize (~> 0.8) + debugger-linecache (~> 1.2) + slop (~> 3.6) + columnize (0.8.9) + debugger-linecache (1.2.0) + i18n (0.6.11) + json (1.8.1) + minitest (5.4.2) + slop (3.6.0) + thread_safe (0.3.4) + tzinfo (1.2.2) + thread_safe (~> 0.1) PLATFORMS ruby DEPENDENCIES activerecord-database-views! + byebug + minitest diff --git a/Rakefile b/Rakefile index 47e7ef4..b30b22b 100644 --- a/Rakefile +++ b/Rakefile @@ -2,7 +2,7 @@ require 'rake' require 'rake/testtask' Rake::TestTask.new do |t| - t.libs << 'lib' + t.libs = ['lib','test'] t.pattern = 'test/**/*_test.rb' t.verbose = false end diff --git a/activerecord-database-views.gemspec b/activerecord-database-views.gemspec index fff5a57..7c773e4 100644 --- a/activerecord-database-views.gemspec +++ b/activerecord-database-views.gemspec @@ -16,4 +16,7 @@ Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY s.require_paths = ['lib'] s.rubyforge_project = '[none]' + + s.add_development_dependency 'minitest' + s.add_runtime_dependency 'activerecord', '~> 4.0', '<= 5.0' end diff --git a/db/views/sql_view1.sql b/db/views/sql_view1.sql new file mode 100644 index 0000000..e69de29 diff --git a/db/views/sql_view2.sql b/db/views/sql_view2.sql new file mode 100644 index 0000000..e69de29 diff --git a/test/test_helper.rb b/test/test_helper.rb index 1d9c9fb..020a1db 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,2 +1,4 @@ require 'bundler/setup' - +require 'minitest/autorun' +require 'active_record' +require 'activerecord-database-views' diff --git a/test/view_collection_test.rb b/test/view_collection_test.rb new file mode 100644 index 0000000..bd97283 --- /dev/null +++ b/test/view_collection_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/test_helper' + +class ViewCollectionTests < MiniTest::Test + def test_it_can_find_sql_files + collection = ActiveRecord::DatabaseViews::ViewCollection.new + assert_equal 2, collection.views.length + end +end From 5274354fdfa77a3ca95b67687881d2126500393c Mon Sep 17 00:00:00 2001 From: Nathan Palmer Date: Sun, 23 Nov 2014 15:08:24 -0500 Subject: [PATCH 05/14] Added a few tests for relation and column drop handling Added functionality to handle when columns have been dropped to drop and re-run the view --- Gemfile.lock | 14 +++++------ activerecord-database-views.gemspec | 2 ++ ...1.sql => sql_a_queries_from_base_view.sql} | 0 db/views/{sql_view2.sql => sql_base_view.sql} | 0 .../view_collection.rb | 20 +++++++++++++++- test/test_helper.rb | 1 + test/view_collection_test.rb | 24 +++++++++++++++++++ 7 files changed, 52 insertions(+), 9 deletions(-) rename db/views/{sql_view1.sql => sql_a_queries_from_base_view.sql} (100%) rename db/views/{sql_view2.sql => sql_base_view.sql} (100%) diff --git a/Gemfile.lock b/Gemfile.lock index 636bd8b..b4b49f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -22,16 +22,13 @@ GEM tzinfo (~> 1.1) arel (5.0.1.20140414130214) builder (3.2.2) - byebug (3.5.1) - columnize (~> 0.8) - debugger-linecache (~> 1.2) - slop (~> 3.6) - columnize (0.8.9) - debugger-linecache (1.2.0) i18n (0.6.11) json (1.8.1) + metaclass (0.0.4) minitest (5.4.2) - slop (3.6.0) + mocha (1.1.0) + metaclass (~> 0.0.1) + pg (0.17.1) thread_safe (0.3.4) tzinfo (1.2.2) thread_safe (~> 0.1) @@ -41,5 +38,6 @@ PLATFORMS DEPENDENCIES activerecord-database-views! - byebug minitest + mocha + pg diff --git a/activerecord-database-views.gemspec b/activerecord-database-views.gemspec index 7c773e4..b928be9 100644 --- a/activerecord-database-views.gemspec +++ b/activerecord-database-views.gemspec @@ -18,5 +18,7 @@ Gem::Specification.new do |s| s.rubyforge_project = '[none]' s.add_development_dependency 'minitest' + s.add_development_dependency 'mocha' + s.add_development_dependency 'pg' s.add_runtime_dependency 'activerecord', '~> 4.0', '<= 5.0' end diff --git a/db/views/sql_view1.sql b/db/views/sql_a_queries_from_base_view.sql similarity index 100% rename from db/views/sql_view1.sql rename to db/views/sql_a_queries_from_base_view.sql diff --git a/db/views/sql_view2.sql b/db/views/sql_base_view.sql similarity index 100% rename from db/views/sql_view2.sql rename to db/views/sql_base_view.sql diff --git a/lib/activerecord-database-views/view_collection.rb b/lib/activerecord-database-views/view_collection.rb index b947790..518d5f9 100644 --- a/lib/activerecord-database-views/view_collection.rb +++ b/lib/activerecord-database-views/view_collection.rb @@ -1,6 +1,8 @@ module ActiveRecord::DatabaseViews class ViewCollection MISSING_RELATION_REGEX = /relation \"(.*)\" does not exist/ + MISSING_VIEW_REGEX = /view \"(.*)\" does not exist/ + DROP_COLUMNS_REGEX = /cannot drop columns from view/ include Enumerable @@ -26,7 +28,13 @@ def load_view(view) begin view.load! and views.delete(view) rescue ActiveRecord::StatementInvalid => exception - if (related_view = retrieve_related_view(exception)) + if schema_changed?(exception) + view.drop! + load_view(view) + elsif (related_view = retrieve_related_view(exception)) + ActiveRecord::Base.connection.rollback_db_transaction + load_view(related_view) and retry + elsif (related_view = retrieve_missing_view(exception)) ActiveRecord::Base.connection.rollback_db_transaction load_view(related_view) and retry else @@ -41,6 +49,16 @@ def retrieve_related_view(exception) find { |view| view.name == related_view_name } end + def retrieve_missing_view(exception) + related_view_name = exception.message.scan(MISSING_VIEW_REGEX).flatten.first + return false if related_view_name.blank? + find { |view| view.name == related_view_name } + end + + def schema_changed?(exception) + exception.message =~ DROP_COLUMNS_REGEX + end + def view_paths Dir.glob('db/views/**/*.{sql,sql.erb}') end diff --git a/test/test_helper.rb b/test/test_helper.rb index 020a1db..7e848aa 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,4 +1,5 @@ require 'bundler/setup' require 'minitest/autorun' +require 'mocha/test_unit' require 'active_record' require 'activerecord-database-views' diff --git a/test/view_collection_test.rb b/test/view_collection_test.rb index bd97283..2df400f 100644 --- a/test/view_collection_test.rb +++ b/test/view_collection_test.rb @@ -5,4 +5,28 @@ def test_it_can_find_sql_files collection = ActiveRecord::DatabaseViews::ViewCollection.new assert_equal 2, collection.views.length end + + def test_it_can_properly_catch_and_execute_a_relation_dependency + collection = ActiveRecord::DatabaseViews::ViewCollection.new + ActiveRecord::DatabaseViews::View.any_instance.expects(:load!).raises(ActiveRecord::StatementInvalid, 'relation "sql_base_view" does not exist') + assert_raises (ActiveRecord::ConnectionNotEstablished) { + collection.load! + } + end + + def test_it_can_properly_catch_and_execute_a_dependency + collection = ActiveRecord::DatabaseViews::ViewCollection.new + ActiveRecord::DatabaseViews::View.any_instance.expects(:load!).raises(ActiveRecord::StatementInvalid, 'view "sql_base_view" does not exist') + assert_raises (ActiveRecord::ConnectionNotEstablished) { + collection.load! + } + end + + def test_it_can_properly_catch_and_execute_when_columns_are_dropped + collection = ActiveRecord::DatabaseViews::ViewCollection.new + ActiveRecord::DatabaseViews::View.any_instance.expects(:load!).raises(ActiveRecord::StatementInvalid, 'cannot drop columns from view') + assert_raises (ActiveRecord::ConnectionNotEstablished) { + collection.load! + } + end end From ea868247850b8b2863826cbca032daa3645c600a Mon Sep 17 00:00:00 2001 From: Nathan Palmer Date: Sun, 23 Nov 2014 15:17:10 -0500 Subject: [PATCH 06/14] Added logic to detect and drop the view if the columns have changed --- lib/activerecord-database-views/view_collection.rb | 4 +++- test/view_collection_test.rb | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/activerecord-database-views/view_collection.rb b/lib/activerecord-database-views/view_collection.rb index 518d5f9..a751f88 100644 --- a/lib/activerecord-database-views/view_collection.rb +++ b/lib/activerecord-database-views/view_collection.rb @@ -3,6 +3,7 @@ class ViewCollection MISSING_RELATION_REGEX = /relation \"(.*)\" does not exist/ MISSING_VIEW_REGEX = /view \"(.*)\" does not exist/ DROP_COLUMNS_REGEX = /cannot drop columns from view/ + CHANGE_COLUMNS_REGEX = /cannot change name of view column \"(.*)\" to \"(.*)\"/ include Enumerable @@ -56,7 +57,8 @@ def retrieve_missing_view(exception) end def schema_changed?(exception) - exception.message =~ DROP_COLUMNS_REGEX + exception.message =~ DROP_COLUMNS_REGEX || + exception.message =~ CHANGE_COLUMNS_REGEX end def view_paths diff --git a/test/view_collection_test.rb b/test/view_collection_test.rb index 2df400f..ec10e97 100644 --- a/test/view_collection_test.rb +++ b/test/view_collection_test.rb @@ -29,4 +29,12 @@ def test_it_can_properly_catch_and_execute_when_columns_are_dropped collection.load! } end + + def test_it_can_properly_catch_and_execute_when_columns_are_changed + collection = ActiveRecord::DatabaseViews::ViewCollection.new + ActiveRecord::DatabaseViews::View.any_instance.expects(:load!).raises(ActiveRecord::StatementInvalid, 'cannot change name of view column "test1" to "test1_full"') + assert_raises (ActiveRecord::ConnectionNotEstablished) { + collection.load! + } + end end From 709ffd6b760d487580adf9f491b11fb580dbf713 Mon Sep 17 00:00:00 2001 From: Nathan Palmer Date: Sun, 23 Nov 2014 15:33:57 -0500 Subject: [PATCH 07/14] Added a catch for undefined column which will drop all the remaining views and run them again so we're dealing with missing relations/views at that point and have a name --- .../view_collection.rb | 25 +++++++++++++++++-- test/view_collection_test.rb | 8 ++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/activerecord-database-views/view_collection.rb b/lib/activerecord-database-views/view_collection.rb index a751f88..9b8183f 100644 --- a/lib/activerecord-database-views/view_collection.rb +++ b/lib/activerecord-database-views/view_collection.rb @@ -4,6 +4,7 @@ class ViewCollection MISSING_VIEW_REGEX = /view \"(.*)\" does not exist/ DROP_COLUMNS_REGEX = /cannot drop columns from view/ CHANGE_COLUMNS_REGEX = /cannot change name of view column \"(.*)\" to \"(.*)\"/ + UNDEFINED_COLUMN_REGEX = /column (.*) does not exist/ include Enumerable @@ -26,17 +27,33 @@ def load! private def load_view(view) + name = view.name + begin view.load! and views.delete(view) + puts "#{name}: Loaded" rescue ActiveRecord::StatementInvalid => exception + ActiveRecord::Base.connection.rollback_db_transaction + if schema_changed?(exception) + puts "#{name}: Column definitions have changed" + # Drop the view view.drop! + # Load it again + load_view(view) + elsif undefined_column?(exception) + puts "#{name}: Undefined column" + # Drop all the remaining views since we can't detect which one it is + views.each(&:drop!) + # Load the view again (which will trigger a missing relation error and proceed to load that view) load_view(view) elsif (related_view = retrieve_related_view(exception)) - ActiveRecord::Base.connection.rollback_db_transaction + puts "#{name}: Contains missing relation" + # Load the relation that is mentioned load_view(related_view) and retry elsif (related_view = retrieve_missing_view(exception)) - ActiveRecord::Base.connection.rollback_db_transaction + puts "#{name}: Contains missing view" + # Load the view that is mentioned load_view(related_view) and retry else raise exception @@ -61,6 +78,10 @@ def schema_changed?(exception) exception.message =~ CHANGE_COLUMNS_REGEX end + def undefined_column?(exception) + exception.message =~ UNDEFINED_COLUMN_REGEX + end + def view_paths Dir.glob('db/views/**/*.{sql,sql.erb}') end diff --git a/test/view_collection_test.rb b/test/view_collection_test.rb index ec10e97..e50e5f5 100644 --- a/test/view_collection_test.rb +++ b/test/view_collection_test.rb @@ -37,4 +37,12 @@ def test_it_can_properly_catch_and_execute_when_columns_are_changed collection.load! } end + + def test_it_can_property_catch_and_execute_when_a_column_is_undefined + collection = ActiveRecord::DatabaseViews::ViewCollection.new + ActiveRecord::DatabaseViews::View.any_instance.expects(:load!).raises(ActiveRecord::StatementInvalid, 'column test1 does not exist') + assert_raises (ActiveRecord::ConnectionNotEstablished) { + collection.load! + } + end end From c216988e513f9896cc56bf61270fff6b7ab91aac Mon Sep 17 00:00:00 2001 From: Paul Gallagher Date: Fri, 19 Jun 2015 15:19:26 +0800 Subject: [PATCH 08/14] ignore rvm/rbenv configs --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 560d1a6..a288c05 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ tmp .yardoc _yardoc doc/ + +# virtual environment configs +.ruby-* \ No newline at end of file From 4f15ce7e4ed17f6eacf807ce3b68d506d8eab22f Mon Sep 17 00:00:00 2001 From: Paul Gallagher Date: Fri, 19 Jun 2015 15:20:39 +0800 Subject: [PATCH 09/14] remove Gemfile.lock - ideally not sourced for gem development --- Gemfile.lock | 43 ------------------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 Gemfile.lock diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index b4b49f8..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,43 +0,0 @@ -PATH - remote: . - specs: - activerecord-database-views (0.1.0) - activerecord (~> 4.0, <= 5.0) - -GEM - remote: https://rubygems.org/ - specs: - activemodel (4.1.7) - activesupport (= 4.1.7) - builder (~> 3.1) - activerecord (4.1.7) - activemodel (= 4.1.7) - activesupport (= 4.1.7) - arel (~> 5.0.0) - activesupport (4.1.7) - i18n (~> 0.6, >= 0.6.9) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.1) - tzinfo (~> 1.1) - arel (5.0.1.20140414130214) - builder (3.2.2) - i18n (0.6.11) - json (1.8.1) - metaclass (0.0.4) - minitest (5.4.2) - mocha (1.1.0) - metaclass (~> 0.0.1) - pg (0.17.1) - thread_safe (0.3.4) - tzinfo (1.2.2) - thread_safe (~> 0.1) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-database-views! - minitest - mocha - pg From bef4cc6f3b48522ac194655b307d125d4f04ad5d Mon Sep 17 00:00:00 2001 From: Paul Gallagher Date: Fri, 19 Jun 2015 15:21:05 +0800 Subject: [PATCH 10/14] ignore Gemfile.lock --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a288c05..619b240 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.gem *.rbc .bundle +Gemfile.lock .config coverage InstalledFiles From ea68af8969e77faf469f3c8dcd91bda12a92c1e1 Mon Sep 17 00:00:00 2001 From: Paul Gallagher Date: Fri, 19 Jun 2015 15:36:45 +0800 Subject: [PATCH 11/14] loosen activerecord dependency to allow 3.x --- activerecord-database-views.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord-database-views.gemspec b/activerecord-database-views.gemspec index b928be9..ea90683 100644 --- a/activerecord-database-views.gemspec +++ b/activerecord-database-views.gemspec @@ -20,5 +20,5 @@ Gem::Specification.new do |s| s.add_development_dependency 'minitest' s.add_development_dependency 'mocha' s.add_development_dependency 'pg' - s.add_runtime_dependency 'activerecord', '~> 4.0', '<= 5.0' + s.add_runtime_dependency 'activerecord', '>= 3.0', '<= 5.0' end From b737e0c65ecbc849b0e89f7fa8f14bf88dc9b3ec Mon Sep 17 00:00:00 2001 From: Paul Gallagher Date: Fri, 19 Jun 2015 17:15:20 +0800 Subject: [PATCH 12/14] add view_exclusion_filter support --- README.md | 10 ++++++++++ lib/activerecord-database-views.rb | 10 ++++++++++ lib/activerecord-database-views/view_collection.rb | 8 +++++++- test/view_collection_test.rb | 11 +++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 314b828..4572234 100644 --- a/README.md +++ b/README.md @@ -97,3 +97,13 @@ end ``` As a bonus you will be able to reload views using rake task as well, i.e. `rake reload_views:db:migrate` + +### How to conditionally exclude views +Sometimes selected views may need to be excluded from loading, for example if not valid for a certain environment. + +An exclusion filter may be registered (for example in an initialization file): + +```ruby +ActiveRecord::DatabaseViews.register_view_exclusion_filter( lambda { |name| name == 'exclude_this_view' }) +``` + diff --git a/lib/activerecord-database-views.rb b/lib/activerecord-database-views.rb index 13ad494..10a909b 100644 --- a/lib/activerecord-database-views.rb +++ b/lib/activerecord-database-views.rb @@ -2,6 +2,16 @@ require 'activerecord-database-views/view_collection' module ActiveRecord::DatabaseViews + + def self.register_view_exclusion_filter(proc_handle=nil) + if proc_handle && proc_handle.respond_to?(:call) + @view_exclusion_filter = proc_handle + elsif proc_handle == false + @view_exclusion_filter = nil + end + @view_exclusion_filter + end + def self.views ViewCollection.new end diff --git a/lib/activerecord-database-views/view_collection.rb b/lib/activerecord-database-views/view_collection.rb index 795a3fa..e3de51a 100644 --- a/lib/activerecord-database-views/view_collection.rb +++ b/lib/activerecord-database-views/view_collection.rb @@ -1,4 +1,5 @@ module ActiveRecord::DatabaseViews + class ViewCollection MISSING_RELATION_REGEX = /relation \"(.*)\" does not exist/ MISSING_VIEW_REGEX = /view \"(.*)\" does not exist/ @@ -13,7 +14,12 @@ class ViewCollection delegate :each, to: :views def initialize - @views = view_paths.map { |path| View.new(path) } + view_exclusion_filter = ActiveRecord::DatabaseViews.register_view_exclusion_filter + @views = view_paths.map do |path| + view = View.new(path) + next if view_exclusion_filter && view_exclusion_filter.call(view.name) + view + end.compact end def drop! diff --git a/test/view_collection_test.rb b/test/view_collection_test.rb index e50e5f5..e48c012 100644 --- a/test/view_collection_test.rb +++ b/test/view_collection_test.rb @@ -45,4 +45,15 @@ def test_it_can_property_catch_and_execute_when_a_column_is_undefined collection.load! } end + + def test_it_respects_view_exclusion_filter + ActiveRecord::DatabaseViews.register_view_exclusion_filter( lambda { |name| name == 'sql_a_queries_from_base_view' }) + assert ActiveRecord::DatabaseViews.register_view_exclusion_filter.is_a?(Proc) + collection = ActiveRecord::DatabaseViews::ViewCollection.new + assert_equal ['sql_base_view'], collection.collect(&:name) + + ActiveRecord::DatabaseViews.register_view_exclusion_filter(false) + assert ActiveRecord::DatabaseViews.register_view_exclusion_filter.nil? + end + end From c3e395d095f61a123d3b9a403e735edfd32e9986 Mon Sep 17 00:00:00 2001 From: Paul Gallagher Date: Fri, 19 Jun 2015 17:16:03 +0800 Subject: [PATCH 13/14] whitespace confirmity for README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4572234..9503837 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,8 @@ end ```ruby class ReverseUser < ActiveRecord::Base private - - def self.discriminate_class_for_record(record) + + def self.discriminate_class_for_record(record) User end end From 12241641532ea5dbe5272c0009ce1879bd94e428 Mon Sep 17 00:00:00 2001 From: Paul Gallagher Date: Fri, 19 Jun 2015 17:45:28 +0800 Subject: [PATCH 14/14] allow logging to be suppressed * kind of nice when reloading views during CI testing;-) --- lib/activerecord-database-views.rb | 14 ++++++------- .../view_collection.rb | 20 ++++++++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/activerecord-database-views.rb b/lib/activerecord-database-views.rb index 10a909b..9c3771b 100644 --- a/lib/activerecord-database-views.rb +++ b/lib/activerecord-database-views.rb @@ -12,19 +12,19 @@ def self.register_view_exclusion_filter(proc_handle=nil) @view_exclusion_filter end - def self.views - ViewCollection.new + def self.views(verbose=true) + ViewCollection.new verbose end - def self.without - views.drop! + def self.without(verbose=true) + views(verbose).drop! yield if block_given? - views.load! + views(verbose).load! end - def self.reload! + def self.reload!(verbose=true) ActiveRecord::Base.transaction do - without + without verbose end end end diff --git a/lib/activerecord-database-views/view_collection.rb b/lib/activerecord-database-views/view_collection.rb index e3de51a..630bada 100644 --- a/lib/activerecord-database-views/view_collection.rb +++ b/lib/activerecord-database-views/view_collection.rb @@ -9,11 +9,12 @@ class ViewCollection include Enumerable - attr_reader :views + attr_reader :views, :verbose delegate :each, to: :views - def initialize + def initialize(verbose=true) + @verbose = verbose view_exclusion_filter = ActiveRecord::DatabaseViews.register_view_exclusion_filter @views = view_paths.map do |path| view = View.new(path) @@ -32,33 +33,38 @@ def load! private + def log(msg) + return unless verbose + puts msg + end + def load_view(view) name = view.name begin view.load! and views.delete(view) - puts "#{name}: Loaded" + log "#{name}: Loaded" rescue ActiveRecord::StatementInvalid => exception ActiveRecord::Base.connection.rollback_db_transaction if schema_changed?(exception) - puts "#{name}: Column definitions have changed" + log "#{name}: Column definitions have changed" # Drop the view view.drop! # Load it again load_view(view) elsif undefined_column?(exception) - puts "#{name}: Undefined column" + log "#{name}: Undefined column" # Drop all the remaining views since we can't detect which one it is views.each(&:drop!) # Load the view again (which will trigger a missing relation error and proceed to load that view) load_view(view) elsif (related_view = retrieve_related_view(exception)) - puts "#{name}: Contains missing relation" + log "#{name}: Contains missing relation" # Load the relation that is mentioned load_view(related_view) and retry elsif (related_view = retrieve_missing_view(exception)) - puts "#{name}: Contains missing view" + log "#{name}: Contains missing view" # Load the view that is mentioned load_view(related_view) and retry else