class Viewy::DependencyManagement::ViewRefresher
Provides a means of refreshing materialized views in the order in which they were created
@!attribute connection [r]
@return [ActiveRecord::ConnectionAdapters::PostgreSQLAdapter] the underlying Postgres connection
Attributes
Public Class Methods
@param connection [ActiveRecord::ConnectionAdapters::PostgreSQLAdapter] An ActiveRecord connection
to a Postgres Database
# File lib/viewy/dependency_management/view_refresher.rb, line 14 def initialize(connection) @connection = connection @sorter = Viewy::DependencyManagement::ViewSorter.new end
Public Instance Methods
This method will refresh all materialized views in order of dependency
# File lib/viewy/dependency_management/view_refresher.rb, line 20 def refresh_all_materialized_views @sorter.sorted_materialized_views.each do |view_name| refresh_single_view(view_name, concurrently: false) end end
Refreshes a single materialized view
@param view_name [String] the name of a materialized view
# File lib/viewy/dependency_management/view_refresher.rb, line 29 def refresh_materialized_view(view_name, with_dependencies: false, concurrently: false) if with_dependencies refresh_dependent_views(view_name, concurrently: concurrently) end refresh_single_view(view_name, concurrently: concurrently) end
Private Instance Methods
@param ex [ActiveRecord::StatementInvalid] an exception raised during the view refresh @param concurrently [Boolean] whether or not the refresh that raised the exception was concurrent
@raise [ActiveRecord::StatementInvalid] re-raised if the original exception does not indicate the refresh
should be retried non-concurrently
@return [Boolean] true if the system should attempt to refresh the view non-concurrently after a concurrent
refresh has failed. Since Postgres raises an error when an unpopulated view is refreshed concurrently, this allows the system to populated such views if needed
# File lib/viewy/dependency_management/view_refresher.rb, line 64 def attempt_non_concurrent_refresh?(ex, concurrently) original_exception = ex.cause should_retry_non_concurrently = original_exception.instance_of?(PG::FeatureNotSupported) || original_exception.instance_of?(PG::ObjectNotInPrerequisiteState) if should_retry_non_concurrently concurrently else raise ex end end
# File lib/viewy/dependency_management/view_refresher.rb, line 85 def concurrent_refersh_sql(name) <<-SQL.strip REFRESH MATERIALIZED VIEW CONCURRENTLY #{name} SQL end
# File lib/viewy/dependency_management/view_refresher.rb, line 36 def refresh_dependent_views(view_name, concurrently:) view_dep = Viewy::Models::MaterializedViewDependency.find(view_name) dependencies = @sorter.sorted_materialized_view_subset(view_names: view_dep.view_dependencies) dependencies.each do |view_dependency| refresh_single_view(view_dependency, concurrently: concurrently) end end
# File lib/viewy/dependency_management/view_refresher.rb, line 44 def refresh_single_view(view_name, concurrently:) view_name = view_name.split('.').last begin connection.execute(refresh_sql(view_name, concurrently)) rescue ActiveRecord::StatementInvalid => ex if attempt_non_concurrent_refresh?(ex, concurrently) connection.execute(refresh_sql(view_name, false)) end end end
@param name [String] the name of a materialized view @return [String] the SQL statement needed to refresh the passed view
# File lib/viewy/dependency_management/view_refresher.rb, line 78 def refresh_sql(name, concurrently) return concurrent_refersh_sql(name) if concurrently <<-SQL.strip REFRESH MATERIALIZED VIEW #{name} SQL end