module Scenic module Adapters class Postgres # Updatine a materialized view causes the view to be dropped and # recreated. This causes any associated indexes to be dropped as well. # This object can be used to capture the existing indexes before the drop # and then reapply appropriate indexes following the create. # # @api private class IndexReapplication # Creates the index reapplication object. # # @param connection [Connection] The connection to execute SQL against. # @param speaker [#say] (ActiveRecord::Migration) The object used for # logging the results of reapplying indexes. def initialize(connection:, speaker: ActiveRecord::Migration) @connection = connection @speaker = speaker end # Caches indexes on the provided object before executing the block and # then reapplying the indexes. Each recreated or skipped index is # announced to STDOUT by default. This can be overridden in the # constructor. # # @param name The name of the object we are reapplying indexes on. # @yield Operations to perform before reapplying indexes. # # @return [void] def on(name) indexes = Indexes.new(connection: connection).on(name) yield indexes.each(&method(:try_index_create)) end private attr_reader :connection, :speaker def try_index_create(index) success = with_savepoint(index.index_name) do connection.execute(index.definition) end if success say "index '#{index.index_name}' on '#{index.object_name}' has been recreated" else say "index '#{index.index_name}' on '#{index.object_name}' is no longer valid and has been dropped." end end def with_savepoint(name) connection.execute("SAVEPOINT #{name}") yield connection.execute("RELEASE SAVEPOINT #{name}") true rescue connection.execute("ROLLBACK TO SAVEPOINT #{name}") false end def say(message) subitem = true speaker.say(message, subitem) end end end end end