remove duplication by loading adapter files from adapter gems.

This commit is contained in:
Micah Geisel 2018-12-21 22:29:38 -07:00
parent 3e3e9055c0
commit b83ed7d1e3
32 changed files with 3 additions and 1487 deletions

View file

@ -26,6 +26,7 @@ Gem::Specification.new do |s|
"cucumber.yml"]
s.files += Dir['lib/**/*.rb']
s.files += Dir['adapters/**/lib/**/*.rb']
s.homepage = "http://github.com/DatabaseCleaner/database_cleaner"
s.license = 'MIT'

View file

@ -1,92 +0,0 @@
require 'database_cleaner/generic/base'
require 'active_record'
require 'erb'
module DatabaseCleaner
module ActiveRecord
def self.available_strategies
%w[truncation transaction deletion]
end
def self.config_file_location=(path)
@config_file_location = path
end
def self.config_file_location
@config_file_location ||= "#{DatabaseCleaner.app_root}/config/database.yml"
end
module Base
include ::DatabaseCleaner::Generic::Base
attr_accessor :connection_hash
def db=(desired_db)
@db = desired_db
load_config
end
def db
@db ||= super
end
def load_config
if self.db != :default && self.db.is_a?(Symbol) && File.file?(ActiveRecord.config_file_location)
connection_details = YAML::load(ERB.new(IO.read(ActiveRecord.config_file_location)).result)
@connection_hash = valid_config(connection_details)[self.db.to_s]
end
end
def valid_config(connection_file)
if !::ActiveRecord::Base.configurations.nil? && !::ActiveRecord::Base.configurations.empty?
if connection_file != ::ActiveRecord::Base.configurations
return ::ActiveRecord::Base.configurations
end
end
connection_file
end
def connection_class
@connection_class ||= if db && !db.is_a?(Symbol)
db
elsif connection_hash
lookup_from_connection_pool || establish_connection
else
::ActiveRecord::Base
end
end
def self.migration_table_name
if ::ActiveRecord::VERSION::MAJOR < 5
::ActiveRecord::Migrator.schema_migrations_table_name
else
::ActiveRecord::SchemaMigration.table_name
end
end
def self.exclusion_condition(column_name)
result = " #{column_name} <> '#{::DatabaseCleaner::ActiveRecord::Base.migration_table_name}' "
if ::ActiveRecord::VERSION::MAJOR >= 5
result += " AND #{column_name} <> '#{::ActiveRecord::Base.internal_metadata_table_name}' "
end
result
end
private
def lookup_from_connection_pool
if ::ActiveRecord::Base.respond_to?(:descendants)
database_name = connection_hash["database"] || connection_hash[:database]
models = ::ActiveRecord::Base.descendants
models.select(&:connection_pool).detect { |m| m.connection_pool.spec.config[:database] == database_name }
end
end
def establish_connection
::ActiveRecord::Base.establish_connection(connection_hash)
::ActiveRecord::Base
end
end
end
end

View file

@ -1,109 +0,0 @@
require 'active_record/base'
require 'active_record/connection_adapters/abstract_adapter'
require "database_cleaner/generic/truncation"
require 'database_cleaner/active_record/base'
require 'database_cleaner/active_record/truncation'
module DatabaseCleaner
module ConnectionAdapters
module AbstractDeleteAdapter
def delete_table(table_name)
raise NotImplementedError
end
end
module GenericDeleteAdapter
def delete_table(table_name)
execute("DELETE FROM #{quote_table_name(table_name)};")
end
end
module OracleDeleteAdapter
def delete_table(table_name)
execute("DELETE FROM #{quote_table_name(table_name)}")
end
end
end
end
module ActiveRecord
module ConnectionAdapters
AbstractAdapter.class_eval { include DatabaseCleaner::ConnectionAdapters::AbstractDeleteAdapter }
JdbcAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(JdbcAdapter)
AbstractMysqlAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(AbstractMysqlAdapter)
Mysql2Adapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(Mysql2Adapter)
SQLiteAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(SQLiteAdapter)
SQLite3Adapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(SQLite3Adapter)
PostgreSQLAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(PostgreSQLAdapter)
IBM_DBAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(IBM_DBAdapter)
SQLServerAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(SQLServerAdapter)
OracleEnhancedAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::OracleDeleteAdapter } if defined?(OracleEnhancedAdapter)
end
end
module DatabaseCleaner::ActiveRecord
module SelectiveTruncation
def tables_to_truncate(connection)
if information_schema_exists?(connection)
(@only || tables_with_new_rows(connection)) - @tables_to_exclude
else
super
end
end
def tables_with_new_rows(connection)
stats = table_stats_query(connection)
if stats != ''
connection.select_values(stats)
else
[]
end
end
def table_stats_query(connection)
@table_stats_query ||= build_table_stats_query(connection)
ensure
@table_stats_query = nil unless @cache_tables
end
def build_table_stats_query(connection)
tables = connection.select_values(<<-SQL)
SELECT table_name
FROM information_schema.tables
WHERE table_schema = database()
AND #{::DatabaseCleaner::ActiveRecord::Base.exclusion_condition('table_name')};
SQL
queries = tables.map do |table|
"(SELECT #{connection.quote(table)} FROM #{connection.quote_table_name(table)} LIMIT 1)"
end
queries.join(' UNION ALL ')
end
def information_schema_exists? connection
return false unless connection.is_a? ActiveRecord::ConnectionAdapters::Mysql2Adapter
@information_schema_exists ||=
begin
connection.execute("SELECT 1 FROM information_schema.tables")
true
rescue
false
end
end
end
class Deletion < Truncation
if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
include SelectiveTruncation
end
def clean
connection = connection_class.connection
connection.disable_referential_integrity do
tables_to_truncate(connection).each do |table_name|
connection.delete_table table_name
end
end
end
end
end

View file

@ -1,59 +0,0 @@
require 'database_cleaner/active_record/base'
require 'database_cleaner/generic/transaction'
module DatabaseCleaner::ActiveRecord
class Transaction
include ::DatabaseCleaner::ActiveRecord::Base
include ::DatabaseCleaner::Generic::Transaction
def start
# Hack to make sure that the connection is properly setup for
# the clean code.
connection_class.connection.transaction{ }
if connection_maintains_transaction_count?
if connection_class.connection.respond_to?(:increment_open_transactions)
connection_class.connection.increment_open_transactions
else
connection_class.__send__(:increment_open_transactions)
end
end
if connection_class.connection.respond_to?(:begin_transaction)
connection_class.connection.begin_transaction :joinable => false
else
connection_class.connection.begin_db_transaction
end
end
def clean
connection_class.connection_pool.connections.each do |connection|
next unless connection.open_transactions > 0
if connection.respond_to?(:rollback_transaction)
connection.rollback_transaction
else
connection.rollback_db_transaction
end
# The below is for handling after_commit hooks.. see https://github.com/bmabey/database_cleaner/issues/99
if connection.respond_to?(:rollback_transaction_records, true)
connection.send(:rollback_transaction_records, true)
end
if connection_maintains_transaction_count?
if connection.respond_to?(:decrement_open_transactions)
connection.decrement_open_transactions
else
connection_class.__send__(:decrement_open_transactions)
end
end
end
end
def connection_maintains_transaction_count?
ActiveRecord::VERSION::MAJOR < 4
end
end
end

View file

@ -1,274 +0,0 @@
require 'active_record/base'
require 'active_record/connection_adapters/abstract_adapter'
#Load available connection adapters
%w(
abstract_mysql_adapter postgresql_adapter sqlite3_adapter mysql_adapter mysql2_adapter oracle_enhanced_adapter
).each do |known_adapter|
begin
require "active_record/connection_adapters/#{known_adapter}"
rescue LoadError
end
end
require "database_cleaner/generic/truncation"
require 'database_cleaner/active_record/base'
module DatabaseCleaner
module ConnectionAdapters
module AbstractAdapter
# used to be called views but that can clash with gems like schema_plus
# this gem is not meant to be exposing such an extra interface any way
def database_cleaner_view_cache
@views ||= select_values("select table_name from information_schema.views where table_schema = '#{current_database}'") rescue []
end
def database_cleaner_table_cache
# the adapters don't do caching (#130) but we make the assumption that the list stays the same in tests
@database_cleaner_tables ||= ::ActiveRecord::VERSION::MAJOR >= 5 ? data_sources : tables
end
def truncate_table(table_name)
raise NotImplementedError
end
def truncate_tables(tables)
tables.each do |table_name|
self.truncate_table(table_name)
end
end
end
module AbstractMysqlAdapter
def truncate_table(table_name)
execute("TRUNCATE TABLE #{quote_table_name(table_name)};")
end
def truncate_tables(tables)
tables.each { |t| truncate_table(t) }
end
def pre_count_truncate_tables(tables, options = {:reset_ids => true})
filter = options[:reset_ids] ? method(:has_been_used?) : method(:has_rows?)
truncate_tables(tables.select(&filter))
end
private
def row_count(table)
# Patch for MysqlAdapter with ActiveRecord 3.2.7 later
# select_value("SELECT 1") #=> "1"
select_value("SELECT EXISTS (SELECT 1 FROM #{quote_table_name(table)} LIMIT 1)").to_i
end
def auto_increment_value(table)
select_value(<<-SQL).to_i
SELECT auto_increment
FROM information_schema.tables
WHERE table_name = '#{table}'
AND table_schema = database()
SQL
end
# This method tells us if the given table has been inserted into since its
# last truncation. Note that the table might have been populated, which
# increased the auto-increment counter, but then cleaned again such that
# it appears empty now.
def has_been_used?(table)
has_rows?(table) || auto_increment_value(table) > 1
end
def has_rows?(table)
row_count(table) > 0
end
end
module IBM_DBAdapter
def truncate_table(table_name)
execute("TRUNCATE #{quote_table_name(table_name)} IMMEDIATE")
end
end
module SQLiteAdapter
def delete_table(table_name)
execute("DELETE FROM #{quote_table_name(table_name)};")
if uses_sequence
execute("DELETE FROM sqlite_sequence where name = '#{table_name}';")
end
end
alias truncate_table delete_table
def truncate_tables(tables)
tables.each { |t| truncate_table(t) }
end
private
# Returns a boolean indicating if the SQLite database is using the sqlite_sequence table.
def uses_sequence
select_value("SELECT name FROM sqlite_master WHERE type='table' AND name='sqlite_sequence';")
end
end
module TruncateOrDelete
def truncate_table(table_name)
begin
execute("TRUNCATE TABLE #{quote_table_name(table_name)};")
rescue ::ActiveRecord::StatementInvalid
execute("DELETE FROM #{quote_table_name(table_name)};")
end
end
end
module OracleAdapter
def truncate_table(table_name)
execute("TRUNCATE TABLE #{quote_table_name(table_name)}")
end
end
module PostgreSQLAdapter
def db_version
@db_version ||= postgresql_version
end
def cascade
@cascade ||= db_version >= 80200 ? 'CASCADE' : ''
end
def restart_identity
@restart_identity ||= db_version >= 80400 ? 'RESTART IDENTITY' : ''
end
def truncate_table(table_name)
truncate_tables([table_name])
end
def truncate_tables(table_names)
return if table_names.nil? || table_names.empty?
execute("TRUNCATE TABLE #{table_names.map{|name| quote_table_name(name)}.join(', ')} #{restart_identity} #{cascade};")
end
def pre_count_truncate_tables(tables, options = {:reset_ids => true})
filter = options[:reset_ids] ? method(:has_been_used?) : method(:has_rows?)
truncate_tables(tables.select(&filter))
end
def database_cleaner_table_cache
# AR returns a list of tables without schema but then returns a
# migrations table with the schema. There are other problems, too,
# with using the base list. If a table exists in multiple schemas
# within the search path, truncation without the schema name could
# result in confusing, if not unexpected results.
@database_cleaner_tables ||= tables_with_schema
end
private
# Returns a boolean indicating if the given table has an auto-inc number higher than 0.
# Note, this is different than an empty table since an table may populated, the index increased,
# but then the table is cleaned. In other words, this function tells us if the given table
# was ever inserted into.
def has_been_used?(table)
return has_rows?(table) unless has_sequence?(table)
cur_val = select_value("SELECT currval('#{table}_id_seq');").to_i rescue 0
cur_val > 0
end
def has_sequence?(table)
select_value("SELECT true FROM pg_class WHERE relname = '#{table}_id_seq';")
end
def has_rows?(table)
select_value("SELECT true FROM #{table} LIMIT 1;")
end
def tables_with_schema
rows = select_rows <<-_SQL
SELECT schemaname || '.' || tablename
FROM pg_tables
WHERE
tablename !~ '_prt_' AND
#{::DatabaseCleaner::ActiveRecord::Base.exclusion_condition('tablename')} AND
schemaname = ANY (current_schemas(false))
_SQL
rows.collect { |result| result.first }
end
end
end
end
module ActiveRecord
module ConnectionAdapters
#Apply adapter decoraters where applicable (adapter should be loaded)
AbstractAdapter.class_eval { include DatabaseCleaner::ConnectionAdapters::AbstractAdapter }
if defined?(JdbcAdapter)
if defined?(OracleJdbcConnection)
JdbcAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::OracleAdapter }
else
JdbcAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::TruncateOrDelete }
end
end
AbstractMysqlAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::AbstractMysqlAdapter } if defined?(AbstractMysqlAdapter)
Mysql2Adapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::AbstractMysqlAdapter } if defined?(Mysql2Adapter)
MysqlAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::AbstractMysqlAdapter } if defined?(MysqlAdapter)
SQLiteAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::SQLiteAdapter } if defined?(SQLiteAdapter)
SQLite3Adapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::SQLiteAdapter } if defined?(SQLite3Adapter)
PostgreSQLAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::PostgreSQLAdapter } if defined?(PostgreSQLAdapter)
IBM_DBAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::IBM_DBAdapter } if defined?(IBM_DBAdapter)
SQLServerAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::TruncateOrDelete } if defined?(SQLServerAdapter)
OracleEnhancedAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::OracleAdapter } if defined?(OracleEnhancedAdapter)
end
end
module DatabaseCleaner::ActiveRecord
class Truncation
include ::DatabaseCleaner::ActiveRecord::Base
include ::DatabaseCleaner::Generic::Truncation
def clean
connection = connection_class.connection
connection.disable_referential_integrity do
if pre_count? && connection.respond_to?(:pre_count_truncate_tables)
connection.pre_count_truncate_tables(tables_to_truncate(connection), {:reset_ids => reset_ids?})
else
connection.truncate_tables(tables_to_truncate(connection))
end
end
end
private
def tables_to_truncate(connection)
tables_in_db = cache_tables? ? connection.database_cleaner_table_cache : connection.tables
to_reject = (@tables_to_exclude + connection.database_cleaner_view_cache)
(@only || tables_in_db).reject do |table|
if ( m = table.match(/([^.]+)$/) )
to_reject.include?(m[1])
else
false
end
end
end
# overwritten
def migration_storage_names
[::DatabaseCleaner::ActiveRecord::Base.migration_table_name]
end
def cache_tables?
!!@cache_tables
end
def pre_count?
@pre_count == true
end
def reset_ids?
@reset_ids != false
end
end
end

View file

@ -170,7 +170,8 @@ module DatabaseCleaner
end
def require_orm_strategy(orm, strategy)
require "database_cleaner/#{orm.to_s}/#{strategy.to_s}"
$LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/../../adapters/database_cleaner-#{orm}/lib/database_cleaner/#{orm}")
require "database_cleaner/#{orm}/#{strategy}"
rescue LoadError
raise UnknownStrategySpecified, "The '#{strategy}' strategy does not exist for the #{orm} ORM! Available strategies: #{orm_module.available_strategies.join(', ')}"
end

View file

@ -1,7 +0,0 @@
module DatabaseCleaner
module CouchPotato
def self.available_strategies
%w[truncation]
end
end
end

View file

@ -1,28 +0,0 @@
require 'database_cleaner/generic/truncation'
module DatabaseCleaner
module CouchPotato
class Truncation
include ::DatabaseCleaner::Generic::Truncation
def initialize(options = {})
if options.has_key?(:only) || options.has_key?(:except)
raise ArgumentError, "The :only and :except options are not available for use with CouchPotato/CouchDB."
elsif !options.empty?
raise ArgumentError, "Unsupported option. You specified #{options.keys.join(',')}."
end
super
end
def clean
database.recreate!
end
private
def database
::CouchPotato.couchrest_database
end
end
end
end

View file

@ -1,21 +0,0 @@
require 'database_cleaner/generic/base'
module DatabaseCleaner
module DataMapper
def self.available_strategies
%w[truncation transaction]
end
module Base
include ::DatabaseCleaner::Generic::Base
def db=(desired_db)
@db = desired_db
end
def db
@db ||= :default
end
end
end
end

View file

@ -1,28 +0,0 @@
require 'database_cleaner/data_mapper/base'
require 'database_cleaner/generic/transaction'
module DatabaseCleaner::DataMapper
class Transaction
include ::DatabaseCleaner::DataMapper::Base
include ::DatabaseCleaner::Generic::Transaction
def start(repository = self.db)
::DataMapper.repository(repository) do |r|
transaction = DataMapper::Transaction.new(r)
transaction.begin
r.adapter.push_transaction(transaction)
end
end
def clean(repository = self.db)
::DataMapper.repository(repository) do |r|
adapter = r.adapter
while adapter.current_transaction
adapter.current_transaction.rollback
adapter.pop_transaction
end
end
end
end
end

View file

@ -1,172 +0,0 @@
require "database_cleaner/generic/truncation"
require 'database_cleaner/data_mapper/base'
module DataMapper
module Adapters
class DataObjectsAdapter
def storage_names(repository = :default)
raise NotImplementedError
end
def truncate_tables(table_names)
table_names.each do |table_name|
truncate_table table_name
end
end
end
class MysqlAdapter < DataObjectsAdapter
# taken from http://github.com/godfat/dm-mapping/tree/master
def storage_names(repository = :default)
select 'SHOW TABLES'
end
def truncate_table(table_name)
execute("TRUNCATE TABLE #{quote_name(table_name)};")
end
# copied from activerecord
def disable_referential_integrity
old = select("SELECT @@FOREIGN_KEY_CHECKS;")
begin
execute("SET FOREIGN_KEY_CHECKS = 0;")
yield
ensure
execute("SET FOREIGN_KEY_CHECKS = ?", *old)
end
end
end
module SqliteAdapterMethods
# taken from http://github.com/godfat/dm-mapping/tree/master
def storage_names(repository = :default)
# activerecord-2.1.0/lib/active_record/connection_adapters/sqlite_adapter.rb: 177
sql = <<-SQL
SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
SQL
# activerecord-2.1.0/lib/active_record/connection_adapters/sqlite_adapter.rb: 181
select(sql)
end
def truncate_table(table_name)
execute("DELETE FROM #{quote_name(table_name)};")
if uses_sequence?
execute("DELETE FROM sqlite_sequence where name = '#{table_name}';")
end
end
# this is a no-op copied from activerecord
# i didn't find out if/how this is possible
# activerecord also doesn't do more here
def disable_referential_integrity
yield
end
private
# Returns a boolean indicating if the SQLite database is using the sqlite_sequence table.
def uses_sequence?
sql = <<-SQL
SELECT name FROM sqlite_master
WHERE type='table' AND name='sqlite_sequence'
SQL
select(sql).first
end
end
class SqliteAdapter; include SqliteAdapterMethods; end
class Sqlite3Adapter; include SqliteAdapterMethods; end
# FIXME
# i don't know if this works
# i basically just copied activerecord code to get a rough idea what they do.
# i don't have postgres available, so i won't be the one to write this.
# maybe codes below gets some postgres/datamapper user going, though.
class PostgresAdapter < DataObjectsAdapter
# taken from http://github.com/godfat/dm-mapping/tree/master
def storage_names(repository = :default)
sql = <<-SQL
SELECT table_name FROM "information_schema"."tables"
WHERE table_schema = current_schema() and table_type = 'BASE TABLE'
SQL
select(sql)
end
def truncate_table(table_name)
execute("TRUNCATE TABLE #{quote_name(table_name)} RESTART IDENTITY CASCADE;")
end
# override to use a single statement
def truncate_tables(table_names)
quoted_names = table_names.collect { |n| quote_name(n) }.join(', ')
execute("TRUNCATE TABLE #{quoted_names} RESTART IDENTITY;")
end
# FIXME
# copied from activerecord
def supports_disable_referential_integrity?
version = select("SHOW server_version")[0][0].split('.')
(version[0].to_i >= 8 && version[1].to_i >= 1) ? true : false
rescue
return false
end
# FIXME
# copied unchanged from activerecord
def disable_referential_integrity(repository = :default)
if supports_disable_referential_integrity? then
execute(storage_names(repository).collect do |name|
"ALTER TABLE #{quote_name(name)} DISABLE TRIGGER ALL"
end.join(";"))
end
yield
ensure
if supports_disable_referential_integrity? then
execute(storage_names(repository).collect do |name|
"ALTER TABLE #{quote_name(name)} ENABLE TRIGGER ALL"
end.join(";"))
end
end
end
end
end
module DatabaseCleaner
module DataMapper
class Truncation
include ::DatabaseCleaner::DataMapper::Base
include ::DatabaseCleaner::Generic::Truncation
def clean(repository = self.db)
adapter = ::DataMapper.repository(repository).adapter
adapter.disable_referential_integrity do
adapter.truncate_tables(tables_to_truncate(repository))
end
end
private
def tables_to_truncate(repository = self.db)
(@only || ::DataMapper.repository(repository).adapter.storage_names(repository)) - @tables_to_exclude
end
# overwritten
def migration_storage_names
%w[migration_info]
end
end
end
end

View file

@ -1,16 +0,0 @@
module DatabaseCleaner
module Mongo
def self.available_strategies
%w[truncation]
end
module Base
def db=(desired_db)
@db = desired_db
end
def db
@db || raise("You have not specified a database. (see Mongo::Database)")
end
end
end
end

View file

@ -1,62 +0,0 @@
require 'database_cleaner/mongo/base'
require 'database_cleaner/generic/truncation'
require 'database_cleaner/mongo/truncation_mixin'
module DatabaseCleaner
module Mongo
class Truncation
include ::DatabaseCleaner::Generic::Truncation
include TruncationMixin
include Base
private
def database
db
end
def collections_cache
@@collections_cache ||= {}
end
def mongoid_collection_names
@@mongoid_collection_names ||= Hash.new{|h,k| h[k]=[]}.tap do |names|
ObjectSpace.each_object(Class) do |klass|
(names[klass.db.name] << klass.collection_name) if valid_collection_name?(klass)
end
end
end
def not_caching(db_name, list)
@@not_caching ||= {}
unless @@not_caching.has_key?(db_name)
@@not_caching[db_name] = true
puts "Not caching collection names for db #{db_name}. Missing these from models: #{list}"
end
end
def collections
return collections_cache[database.name] if collections_cache.has_key?(database.name)
db_collections = database.collections.select { |c| c.name !~ /^system\./ }
missing_collections = mongoid_collection_names[database.name] - db_collections.map(&:name)
if missing_collections.empty?
collections_cache[database.name] = db_collections
else
not_caching(database.name, missing_collections)
end
db_collections
end
private
def valid_collection_name?(klass)
klass.ancestors.map(&:to_s).include?('Mongoid::Document') &&
!klass.embedded &&
!klass.collection_name.empty?
end
end
end
end

View file

@ -1,26 +0,0 @@
module DatabaseCleaner
module Mongo
module TruncationMixin
def clean
if @only
collections.each { |c| c.send(truncate_method_name) if @only.include?(c.name) }
else
collections.each { |c| c.send(truncate_method_name) unless @tables_to_exclude.include?(c.name) }
end
true
end
private
def collections
database.collections.select { |c| c.name !~ /^system\./ }
end
def truncate_method_name
# This constant only exists in the 2.x series.
defined?(::Mongo::VERSION) ? :delete_many : :remove
end
end
end
end

View file

@ -1,20 +0,0 @@
require 'database_cleaner/generic/base'
module DatabaseCleaner
module MongoMapper
def self.available_strategies
%w[truncation]
end
module Base
include ::DatabaseCleaner::Generic::Base
def db=(desired_db)
@db = desired_db
end
def db
@db ||= :default
end
end
end
end

View file

@ -1,19 +0,0 @@
require 'database_cleaner/mongo_mapper/base'
require 'database_cleaner/generic/truncation'
require 'database_cleaner/mongo/truncation_mixin'
module DatabaseCleaner
module MongoMapper
class Truncation
include ::DatabaseCleaner::MongoMapper::Base
include ::DatabaseCleaner::Generic::Truncation
include ::DatabaseCleaner::Mongo::TruncationMixin
private
def database
::MongoMapper.database
end
end
end
end

View file

@ -1,20 +0,0 @@
require 'database_cleaner/generic/base'
module DatabaseCleaner
module Mongoid
def self.available_strategies
%w[truncation]
end
module Base
include ::DatabaseCleaner::Generic::Base
def db=(desired_db)
@db = desired_db
end
def db
@db || :default
end
end
end
end

View file

@ -1,49 +0,0 @@
require 'database_cleaner/mongoid/base'
require 'database_cleaner/generic/truncation'
require 'database_cleaner/mongo/truncation_mixin'
require 'database_cleaner/mongo2/truncation_mixin'
require 'database_cleaner/moped/truncation_base'
require 'mongoid/version'
module DatabaseCleaner
module Mongoid
class Truncation
include ::DatabaseCleaner::Mongoid::Base
include ::DatabaseCleaner::Generic::Truncation
if ::Mongoid::VERSION < '3'
include ::DatabaseCleaner::Mongo::TruncationMixin
private
def database
::Mongoid.database
end
elsif ::Mongoid::VERSION < '5'
include ::DatabaseCleaner::Moped::TruncationBase
private
def session
::Mongoid::VERSION > "5.0.0" ? ::Mongoid.default_client : ::Mongoid.default_session
end
def database
if not(@db.nil? or @db == :default)
::Mongoid.databases[@db]
else
::Mongoid.database
end
end
else
include ::DatabaseCleaner::Mongo2::TruncationMixin
end
end
end
end

View file

@ -1,39 +0,0 @@
require 'database_cleaner/generic/base'
module DatabaseCleaner
module Moped
def self.available_strategies
%w[truncation]
end
module Base
include ::DatabaseCleaner::Generic::Base
def db=(desired_db)
@db = desired_db
end
def db
@db ||= :default
end
def host_port=(desired_host)
@host = desired_host
end
def host
@host ||= '127.0.0.1:27017'
end
def db_version
@db_version ||= session.command('buildinfo' => 1)['version']
end
private
def session
@session ||= ::Moped::Session.new([host], database: db)
end
end
end
end

View file

@ -1,9 +0,0 @@
require 'database_cleaner/moped/truncation_base'
module DatabaseCleaner
module Moped
class Truncation
include ::DatabaseCleaner::Moped::TruncationBase
end
end
end

View file

@ -1,44 +0,0 @@
require 'database_cleaner/moped/base'
require 'database_cleaner/generic/truncation'
module DatabaseCleaner
module Moped
module TruncationBase
include ::DatabaseCleaner::Moped::Base
include ::DatabaseCleaner::Generic::Truncation
def clean
if @only
collections.each { |c| session[c].find.remove_all if @only.include?(c) }
else
collections.each { |c| session[c].find.remove_all unless @tables_to_exclude.include?(c) }
end
wait_for_removals_to_finish
true
end
private
def collections
if db != :default
session.use(db)
end
if db_version.split('.').first.to_i >= 3
session.command(listCollections: 1, filter: { 'name' => { '$not' => /.?system\.|\$/ } })['cursor']['firstBatch'].map do |collection|
collection['name']
end
else
session['system.namespaces'].find(name: { '$not' => /\.system\.|\$/ }).to_a.map do |collection|
_, name = collection['name'].split('.', 2)
name
end
end
end
def wait_for_removals_to_finish
session.command(getlasterror: 1)
end
end
end
end

View file

@ -1,62 +0,0 @@
require 'database_cleaner/generic/base'
module DatabaseCleaner
module Neo4j
def self.available_strategies
%w[transaction truncation deletion]
end
module Base
include ::DatabaseCleaner::Generic::Base
def db=(desired_db)
@db = desired_db == :default ? nil : desired_db
end
def db
@db ||= nil
end
def start
if db_type == :embedded_db and not session.running?
session.start
else
session
end
end
def database
db && default_db.merge(db) || default_db
end
private
def default_db
{:type => default_db_type, :path => default_db_path}
end
def default_db_type
:server_db
end
def default_db_path(type = default_db_type)
type == :server_db ? 'http://localhost:7475/' : './db/test'
end
def db_type
database[:type]
end
def db_path
database[:path]
end
def db_params
database.reject!{|key, value| [:type, :path].include? key }
end
def session
@session ||= ::Neo4j::Session.open(db_type, db_path, db_params)
end
end
end
end

View file

@ -1,16 +0,0 @@
require 'database_cleaner/neo4j/base'
require 'neo4j-core'
module DatabaseCleaner
module Neo4j
class Deletion
include ::DatabaseCleaner::Neo4j::Base
def clean
::Neo4j::Transaction.run do
session._query('MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r')
end
end
end
end
end

View file

@ -1,35 +0,0 @@
require 'database_cleaner/neo4j/base'
require 'database_cleaner/generic/transaction'
require 'neo4j-core'
module DatabaseCleaner
module Neo4j
class Transaction
include ::DatabaseCleaner::Generic::Transaction
include ::DatabaseCleaner::Neo4j::Base
attr_accessor :tx
def start
super
rollback
self.tx = ::Neo4j::Transaction.new
end
def clean
rollback
end
private
def rollback
if tx
tx.failure
tx.close
end
ensure
self.tx = nil
end
end
end
end

View file

@ -1,9 +0,0 @@
require 'database_cleaner/neo4j/base'
require 'database_cleaner/neo4j/deletion'
module DatabaseCleaner
module Neo4j
class Truncation < DatabaseCleaner::Neo4j::Deletion
end
end
end

View file

@ -1,19 +0,0 @@
require 'database_cleaner/redis/truncation'
module DatabaseCleaner
module Ohm
def self.available_strategies
%w(truncation)
end
class Truncation < ::DatabaseCleaner::Redis::Truncation
private
def default_redis
::Ohm.redis
end
end
end
end

View file

@ -1,37 +0,0 @@
require 'database_cleaner/generic/base'
module DatabaseCleaner
module Redis
def self.available_strategies
%w{truncation}
end
module Base
include ::DatabaseCleaner::Generic::Base
def db=(desired_db)
@db = desired_db
end
def db
@db ||= :default
end
alias url db
private
def connection
@connection ||= begin
if url == :default
::Redis.new
elsif db.is_a?(::Redis) # pass directly the connection
db
else
::Redis.new(:url => url)
end
end
end
end
end
end

View file

@ -1,26 +0,0 @@
require 'database_cleaner/redis/base'
require 'database_cleaner/generic/truncation'
module DatabaseCleaner
module Redis
class Truncation
include ::DatabaseCleaner::Redis::Base
include ::DatabaseCleaner::Generic::Truncation
def clean
if @only
@only.each do |term|
connection.keys(term).each { |k| connection.del k }
end
elsif @tables_to_exclude
keys_except = []
@tables_to_exclude.each { |term| keys_except += connection.keys(term) }
connection.keys.each { |k| connection.del(k) unless keys_except.include?(k) }
else
connection.flushdb
end
connection.quit unless url == :default
end
end
end
end

View file

@ -1,22 +0,0 @@
require 'database_cleaner/generic/base'
module DatabaseCleaner
module Sequel
def self.available_strategies
%w(truncation transaction deletion)
end
module Base
include ::DatabaseCleaner::Generic::Base
def db=(desired_db)
@db = desired_db
end
def db
return @db if @db && @db != :default
raise "As you have more than one active sequel database you have to specify the one to use manually!" if ::Sequel::DATABASES.count > 1
::Sequel::DATABASES.first || :default
end
end
end
end

View file

@ -1,47 +0,0 @@
require 'database_cleaner/sequel/base'
require 'database_cleaner/generic/truncation'
require 'database_cleaner/sequel/truncation'
module DatabaseCleaner::Sequel
class Deletion < Truncation
def disable_referential_integrity(tables)
case db.database_type
when :postgres
db.run('SET CONSTRAINTS ALL DEFERRED')
tables_to_truncate(db).each do |table|
db.run("ALTER TABLE \"#{table}\" DISABLE TRIGGER ALL")
end
when :mysql
old = db.fetch('SELECT @@FOREIGN_KEY_CHECKS').first[:@@FOREIGN_KEY_CHECKS]
db.run('SET FOREIGN_KEY_CHECKS = 0')
end
yield
ensure
case db.database_type
when :postgres
tables.each do |table|
db.run("ALTER TABLE \"#{table}\" ENABLE TRIGGER ALL")
end
when :mysql
db.run("SET FOREIGN_KEY_CHECKS = #{old}")
end
end
def delete_tables(db, tables)
tables.each do |table|
db[table.to_sym].delete
end
end
def clean
return unless dirty?
tables = tables_to_truncate(db)
db.transaction do
disable_referential_integrity(tables) do
delete_tables(db, tables)
end
end
end
end
end

View file

@ -1,40 +0,0 @@
require 'database_cleaner/sequel/base'
module DatabaseCleaner
module Sequel
class Transaction
include ::DatabaseCleaner::Sequel::Base
def self.check_fiber_brokenness
if !@checked_fiber_brokenness && Fiber.new { Thread.current }.resume != Thread.current
raise RuntimeError, "This ruby engine's Fibers are not compatible with Sequel's connection pool. " +
"To work around this, please use DatabaseCleaner.cleaning with a block instead of " +
"DatabaseCleaner.start and DatabaseCleaner.clean"
end
@checked_fiber_brokenness = true
end
def start
self.class.check_fiber_brokenness
@fibers ||= []
db = self.db
f = Fiber.new do
db.transaction(:rollback => :always, :savepoint => true) do
Fiber.yield
end
end
f.resume
@fibers << f
end
def clean
f = @fibers.pop
f.resume
end
def cleaning
self.db.transaction(:rollback => :always, :savepoint => true) { yield }
end
end
end
end

View file

@ -1,79 +0,0 @@
require 'database_cleaner/generic/truncation'
require 'database_cleaner/sequel/base'
module DatabaseCleaner
module Sequel
class Truncation
include ::DatabaseCleaner::Sequel::Base
include ::DatabaseCleaner::Generic::Truncation
def start
@last_txid = txid
end
def clean
return unless dirty?
tables = tables_to_truncate(db)
# Count rows before truncating
if pre_count?
tables = pre_count_tables(tables)
end
case db.database_type
when :postgres
# PostgreSQL requires all tables with FKs to be truncates in the same command, or have the CASCADE keyword
# appended. Bulk truncation without CASCADE is:
# * Safer. Tables outside of tables_to_truncate won't be affected.
# * Faster. Less roundtrips to the db.
unless tables.empty?
tables_sql = tables.map { |t| %("#{t}") }.join(',')
db.run "TRUNCATE TABLE #{tables_sql} RESTART IDENTITY;"
end
else
truncate_tables(db, tables)
end
end
private
def pre_count_tables tables
tables.reject { |table| db[table.to_sym].count == 0 }
end
def truncate_tables(db, tables)
tables.each do |table|
db[table.to_sym].truncate
if db.database_type == :sqlite && db.table_exists?(:sqlite_sequence)
db[:sqlite_sequence].where(name: table).delete
end
end
end
def dirty?
@last_txid != txid || @last_txid.nil?
end
def txid
case db.database_type
when :postgres
db.fetch('SELECT txid_snapshot_xmax(txid_current_snapshot()) AS txid').first[:txid]
end
end
def tables_to_truncate(db)
(@only || db.tables.map(&:to_s)) - @tables_to_exclude
end
# overwritten
def migration_storage_names
%w(schema_info schema_migrations)
end
def pre_count?
@pre_count == true
end
end
end
end