lib/database_flusher/active_record/deletion_strategy.rb
# frozen_string_literal: true
require 'database_flusher/active_record/adapters/abstract_adapter'
require 'database_flusher/active_record/adapters/mysql2_adapter'
require 'database_flusher/active_record/adapters/postgresql_adapter'
require 'database_flusher/active_record/adapters/sqlite_adapter'
module DatabaseFlusher
module ActiveRecord
class DeletionStrategy
attr_reader :tables
class Subscriber
# INSERT [IGNORE] [INTO] schema_name.table_name
PATTERN = %r{
\A\s*
INSERT
(?:\s+IGNORE)?
(?:\s+INTO)?
\s+
(?:[`"]?([^.\s`"]+)[`"]?\.)? # schema
(?:[`"]?([^.\s`"]+)[`"]?) # table
}xi
def initialize(strategy)
@strategy = strategy
end
def call(_, _, _, _, payload)
sql = payload[:sql]
match = sql.match(PATTERN)
return unless match
table = match[2]
if table
schema = match[1]
if schema
table = "#{schema}.#{table}"
end
@strategy.tables << table
end
end
end
def initialize
@tables = Set.new
end
def start
@subscriber ||= ActiveSupport::Notifications.subscribe(
'sql.active_record',
Subscriber.new(self)
)
end
def stop
if @subscriber
ActiveSupport::Notifications.unsubscribe(@subscriber)
@subscriber = nil
end
end
def clean
return if tables.empty?
# puts "Cleaning #{tables.inspect}"
adapter.delete(*tables)
tables.clear
end
def clean_all
adapter.delete(*all_tables)
end
private
def connection
@connection ||= ::ActiveRecord::Base.connection
end
def adapter
@adapter ||= DatabaseFlusher::ActiveRecord.
const_get("#{connection.adapter_name}Adapter").
new(connection)
end
def all_tables
# NOTE connection.tables warns on AR 5 with some adapters
tables = ActiveSupport::Deprecation.silence { connection.tables }
tables.reject do |t|
(t == ::ActiveRecord::SchemaMigration.table_name) ||
(::ActiveRecord::Base.respond_to?(:internal_metadata_table_name) &&
(t == ::ActiveRecord::Base.internal_metadata_table_name))
end
end
end
end
end