database_cleaner-active_record 1.99.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +80 -0
- data/.gitignore +5 -0
- data/.travis.yml +23 -2
- data/Appraisals +23 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +8 -4
- data/README.md +37 -44
- data/bin/setup +0 -1
- data/database_cleaner-active_record.gemspec +12 -21
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/rails_5.1.gemfile +13 -0
- data/gemfiles/rails_5.2.gemfile +13 -0
- data/gemfiles/rails_6.0.gemfile +13 -0
- data/gemfiles/rails_6.1.gemfile +20 -0
- data/gemfiles/rails_7.0.gemfile +13 -0
- data/gemfiles/rails_7.1.gemfile +13 -0
- data/lib/database_cleaner/active_record/base.rb +54 -55
- data/lib/database_cleaner/active_record/deletion.rb +49 -86
- data/lib/database_cleaner/active_record/transaction.rb +10 -47
- data/lib/database_cleaner/active_record/truncation.rb +184 -223
- data/lib/database_cleaner/active_record/version.rb +1 -1
- data/lib/database_cleaner/active_record.rb +3 -2
- metadata +38 -42
- data/Gemfile.lock +0 -73
@@ -1,107 +1,70 @@
|
|
1
1
|
require 'active_record'
|
2
|
-
require 'active_record/connection_adapters/abstract_adapter'
|
3
|
-
require "database_cleaner/generic/truncation"
|
4
2
|
require 'database_cleaner/active_record/truncation'
|
5
3
|
|
6
4
|
module DatabaseCleaner
|
7
|
-
module
|
8
|
-
|
9
|
-
def
|
10
|
-
|
5
|
+
module ActiveRecord
|
6
|
+
class Deletion < Truncation
|
7
|
+
def clean
|
8
|
+
connection.disable_referential_integrity do
|
9
|
+
if pre_count? && connection.respond_to?(:pre_count_tables)
|
10
|
+
delete_tables(connection, connection.pre_count_tables(tables_to_truncate(connection)))
|
11
|
+
else
|
12
|
+
delete_tables(connection, tables_to_truncate(connection))
|
13
|
+
end
|
14
|
+
end
|
11
15
|
end
|
12
|
-
end
|
13
16
|
|
14
|
-
|
15
|
-
def delete_table(table_name)
|
16
|
-
execute("DELETE FROM #{quote_table_name(table_name)};")
|
17
|
-
end
|
18
|
-
end
|
17
|
+
private
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
def delete_tables(connection, table_names)
|
20
|
+
table_names.each do |table_name|
|
21
|
+
delete_table(connection, table_name)
|
22
|
+
end
|
23
23
|
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
module ActiveRecord
|
29
|
-
module ConnectionAdapters
|
30
|
-
AbstractAdapter.class_eval { include DatabaseCleaner::ConnectionAdapters::AbstractDeleteAdapter }
|
31
|
-
|
32
|
-
JdbcAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(JdbcAdapter)
|
33
|
-
AbstractMysqlAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(AbstractMysqlAdapter)
|
34
|
-
Mysql2Adapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(Mysql2Adapter)
|
35
|
-
SQLiteAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(SQLiteAdapter)
|
36
|
-
SQLite3Adapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(SQLite3Adapter)
|
37
|
-
PostgreSQLAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(PostgreSQLAdapter)
|
38
|
-
IBM_DBAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(IBM_DBAdapter)
|
39
|
-
SQLServerAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::GenericDeleteAdapter } if defined?(SQLServerAdapter)
|
40
|
-
OracleEnhancedAdapter.class_eval { include ::DatabaseCleaner::ConnectionAdapters::OracleDeleteAdapter } if defined?(OracleEnhancedAdapter)
|
41
|
-
end
|
42
|
-
end
|
43
24
|
|
44
|
-
|
45
|
-
|
46
|
-
def tables_to_truncate(connection)
|
47
|
-
if information_schema_exists?(connection)
|
48
|
-
(@only || tables_with_new_rows(connection)) - @tables_to_exclude
|
49
|
-
else
|
50
|
-
super
|
25
|
+
def delete_table connection, table_name
|
26
|
+
connection.execute("DELETE FROM #{connection.quote_table_name(table_name)} WHERE 1=1")
|
51
27
|
end
|
52
|
-
end
|
53
28
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
29
|
+
def tables_to_truncate(connection)
|
30
|
+
if information_schema_exists?(connection)
|
31
|
+
@except += connection.database_cleaner_view_cache + migration_storage_names
|
32
|
+
(@only.any? ? @only : tables_with_new_rows(connection)) - @except
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
60
36
|
end
|
61
|
-
end
|
62
37
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
38
|
+
def tables_with_new_rows(connection)
|
39
|
+
stats = table_stats_query(connection)
|
40
|
+
if stats != ''
|
41
|
+
connection.select_values(stats)
|
42
|
+
else
|
43
|
+
[]
|
44
|
+
end
|
45
|
+
end
|
68
46
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
WHERE table_schema = database()
|
74
|
-
AND #{::DatabaseCleaner::ActiveRecord::Base.exclusion_condition('table_name')};
|
75
|
-
SQL
|
76
|
-
queries = tables.map do |table|
|
77
|
-
"(SELECT #{connection.quote(table)} FROM #{connection.quote_table_name(table)} LIMIT 1)"
|
47
|
+
def table_stats_query(connection)
|
48
|
+
@table_stats_query ||= build_table_stats_query(connection)
|
49
|
+
ensure
|
50
|
+
@table_stats_query = nil unless @cache_tables
|
78
51
|
end
|
79
|
-
queries.join(' UNION ALL ')
|
80
|
-
end
|
81
52
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
53
|
+
def build_table_stats_query(connection)
|
54
|
+
tables = connection.select_values(<<-SQL)
|
55
|
+
SELECT table_name
|
56
|
+
FROM information_schema.tables
|
57
|
+
WHERE table_schema = database()
|
58
|
+
AND #{self.class.exclusion_condition('table_name')};
|
59
|
+
SQL
|
60
|
+
queries = tables.map do |table|
|
61
|
+
"(SELECT #{connection.quote(table)} FROM #{connection.quote_table_name(table)} LIMIT 1)"
|
90
62
|
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
class Deletion < Truncation
|
95
|
-
if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
|
96
|
-
include SelectiveTruncation
|
97
|
-
end
|
63
|
+
queries.join(' UNION ALL ')
|
64
|
+
end
|
98
65
|
|
99
|
-
|
100
|
-
|
101
|
-
connection.disable_referential_integrity do
|
102
|
-
tables_to_truncate(connection).each do |table_name|
|
103
|
-
connection.delete_table table_name
|
104
|
-
end
|
66
|
+
def information_schema_exists? connection
|
67
|
+
connection.adapter_name == "Mysql2"
|
105
68
|
end
|
106
69
|
end
|
107
70
|
end
|
@@ -1,59 +1,22 @@
|
|
1
1
|
require 'database_cleaner/active_record/base'
|
2
|
-
require 'database_cleaner/generic/transaction'
|
3
2
|
|
4
|
-
module DatabaseCleaner
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module DatabaseCleaner
|
4
|
+
module ActiveRecord
|
5
|
+
class Transaction < Base
|
6
|
+
def start
|
7
|
+
# Hack to make sure that the connection is properly set up before cleaning
|
8
|
+
connection_class.connection.transaction {}
|
8
9
|
|
9
|
-
|
10
|
-
# Hack to make sure that the connection is properly setup for
|
11
|
-
# the clean code.
|
12
|
-
connection_class.connection.transaction{ }
|
13
|
-
|
14
|
-
if connection_maintains_transaction_count?
|
15
|
-
if connection_class.connection.respond_to?(:increment_open_transactions)
|
16
|
-
connection_class.connection.increment_open_transactions
|
17
|
-
else
|
18
|
-
connection_class.__send__(:increment_open_transactions)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
if connection_class.connection.respond_to?(:begin_transaction)
|
22
|
-
connection_class.connection.begin_transaction :joinable => false
|
23
|
-
else
|
24
|
-
connection_class.connection.begin_db_transaction
|
10
|
+
connection_class.connection.begin_transaction joinable: false
|
25
11
|
end
|
26
|
-
end
|
27
|
-
|
28
12
|
|
29
|
-
def clean
|
30
|
-
connection_class.connection_pool.connections.each do |connection|
|
31
|
-
next unless connection.open_transactions > 0
|
32
13
|
|
33
|
-
|
14
|
+
def clean
|
15
|
+
connection_class.connection_pool.connections.each do |connection|
|
16
|
+
next unless connection.open_transactions > 0
|
34
17
|
connection.rollback_transaction
|
35
|
-
else
|
36
|
-
connection.rollback_db_transaction
|
37
|
-
end
|
38
|
-
|
39
|
-
# The below is for handling after_commit hooks.. see https://github.com/bmabey/database_cleaner/issues/99
|
40
|
-
if connection.respond_to?(:rollback_transaction_records, true)
|
41
|
-
connection.send(:rollback_transaction_records, true)
|
42
|
-
end
|
43
|
-
|
44
|
-
if connection_maintains_transaction_count?
|
45
|
-
if connection.respond_to?(:decrement_open_transactions)
|
46
|
-
connection.decrement_open_transactions
|
47
|
-
else
|
48
|
-
connection_class.__send__(:decrement_open_transactions)
|
49
|
-
end
|
50
18
|
end
|
51
19
|
end
|
52
20
|
end
|
53
|
-
|
54
|
-
def connection_maintains_transaction_count?
|
55
|
-
ActiveRecord::VERSION::MAJOR < 4
|
56
|
-
end
|
57
|
-
|
58
21
|
end
|
59
22
|
end
|