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

connection[R]

Public Class Methods

new(connection) click to toggle source

@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

refresh_all_materialized_views() click to toggle source

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
refresh_materialized_view(view_name, with_dependencies: false, concurrently: false) click to toggle source

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

attempt_non_concurrent_refresh?(ex, concurrently) click to toggle source

@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
concurrent_refersh_sql(name) click to toggle source
# File lib/viewy/dependency_management/view_refresher.rb, line 85
              def concurrent_refersh_sql(name)
        <<-SQL.strip
          REFRESH MATERIALIZED VIEW CONCURRENTLY #{name}
        SQL
      end
refresh_dependent_views(view_name, concurrently:) click to toggle source
# 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
refresh_single_view(view_name, concurrently:) click to toggle source
# 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
refresh_sql(name, concurrently) click to toggle source

@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