database_cleaner 0.5.0 → 0.6.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile.lock +145 -0
- data/History.txt +43 -1
- data/README.textile +49 -1
- data/Rakefile +4 -0
- data/TODO +3 -0
- data/VERSION.yml +3 -2
- data/examples/Gemfile +46 -0
- data/examples/Gemfile.lock +145 -0
- data/examples/config/database.yml +7 -0
- data/examples/config/database.yml.example +8 -0
- data/examples/db/activerecord_one.db +0 -0
- data/examples/db/activerecord_two.db +0 -0
- data/examples/db/datamapper_default.db +0 -0
- data/examples/db/datamapper_one.db +0 -0
- data/examples/db/datamapper_two.db +0 -0
- data/examples/db/sqlite_databases_go_here +0 -0
- data/examples/features/example_multiple_db.feature +23 -0
- data/examples/features/example_multiple_orm.feature +22 -0
- data/examples/features/step_definitions/activerecord_steps.rb +31 -0
- data/examples/features/step_definitions/couchpotato_steps.rb +31 -0
- data/examples/features/step_definitions/datamapper_steps.rb +37 -0
- data/examples/features/step_definitions/mongoid_steps.rb +23 -0
- data/examples/features/step_definitions/mongomapper_steps.rb +31 -0
- data/examples/features/step_definitions/translation_steps.rb +55 -0
- data/examples/features/support/env.rb +49 -10
- data/examples/lib/activerecord_models.rb +34 -5
- data/examples/lib/couchpotato_models.rb +46 -6
- data/examples/lib/datamapper_models.rb +37 -3
- data/examples/lib/mongoid_models.rb +49 -0
- data/examples/lib/mongomapper_models.rb +36 -2
- data/features/cleaning.feature +1 -0
- data/features/cleaning_multiple_dbs.feature +20 -0
- data/features/cleaning_multiple_orms.feature +29 -0
- data/features/step_definitions/database_cleaner_steps.rb +21 -14
- data/features/support/feature_runner.rb +39 -0
- data/lib/database_cleaner/active_record/base.rb +46 -0
- data/lib/database_cleaner/active_record/transaction.rb +10 -10
- data/lib/database_cleaner/active_record/truncation.rb +42 -11
- data/lib/database_cleaner/base.rb +129 -0
- data/lib/database_cleaner/configuration.rb +45 -82
- data/lib/database_cleaner/couch_potato/base.rb +7 -0
- data/lib/database_cleaner/couch_potato/truncation.rb +4 -2
- data/lib/database_cleaner/cucumber.rb +0 -1
- data/lib/database_cleaner/data_mapper/base.rb +21 -0
- data/lib/database_cleaner/data_mapper/transaction.rb +10 -5
- data/lib/database_cleaner/data_mapper/truncation.rb +52 -19
- data/lib/database_cleaner/generic/base.rb +23 -0
- data/lib/database_cleaner/generic/truncation.rb +43 -0
- data/lib/database_cleaner/mongo_mapper/base.rb +20 -0
- data/lib/database_cleaner/mongo_mapper/truncation.rb +9 -3
- data/lib/database_cleaner/mongoid/base.rb +20 -0
- data/lib/database_cleaner/mongoid/truncation.rb +27 -0
- data/spec/database_cleaner/active_record/base_spec.rb +130 -0
- data/spec/database_cleaner/active_record/transaction_spec.rb +65 -0
- data/spec/database_cleaner/active_record/truncation_spec.rb +19 -18
- data/spec/database_cleaner/base_spec.rb +441 -0
- data/spec/database_cleaner/configuration_spec.rb +255 -65
- data/spec/database_cleaner/couch_potato/truncation_spec.rb +4 -3
- data/spec/database_cleaner/data_mapper/base_spec.rb +30 -0
- data/spec/database_cleaner/data_mapper/transaction_spec.rb +23 -0
- data/spec/database_cleaner/data_mapper/truncation_spec.rb +11 -0
- data/spec/database_cleaner/generic/base_spec.rb +22 -0
- data/spec/database_cleaner/generic/truncation_spec.rb +68 -0
- data/spec/database_cleaner/mongo_mapper/base_spec.rb +33 -0
- data/spec/database_cleaner/mongo_mapper/mongo_examples.rb +8 -0
- data/spec/database_cleaner/mongo_mapper/truncation_spec.rb +12 -19
- data/spec/database_cleaner/mongoid/truncation_spec.rb +84 -0
- data/spec/database_cleaner/shared_strategy_spec.rb +13 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -3
- metadata +83 -8
- data/examples/features/step_definitions/example_steps.rb +0 -8
- data/lib/database_cleaner/truncation_base.rb +0 -41
|
@@ -1,21 +1,36 @@
|
|
|
1
|
-
require
|
|
1
|
+
require 'active_record/base'
|
|
2
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
|
3
|
+
require "database_cleaner/generic/truncation"
|
|
4
|
+
require 'database_cleaner/active_record/base'
|
|
2
5
|
|
|
3
6
|
module ActiveRecord
|
|
4
7
|
module ConnectionAdapters
|
|
5
8
|
|
|
6
|
-
class
|
|
9
|
+
class AbstractAdapter
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class SQLiteAdapter < AbstractAdapter
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class MysqlAdapter < AbstractAdapter
|
|
7
16
|
def truncate_table(table_name)
|
|
8
17
|
execute("TRUNCATE TABLE #{quote_table_name(table_name)};")
|
|
9
18
|
end
|
|
10
19
|
end
|
|
11
20
|
|
|
12
|
-
class
|
|
21
|
+
class Mysql2Adapter < AbstractAdapter
|
|
22
|
+
def truncate_table(table_name)
|
|
23
|
+
execute("TRUNCATE TABLE #{quote_table_name(table_name)};")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class SQLite3Adapter < SQLiteAdapter
|
|
13
28
|
def truncate_table(table_name)
|
|
14
29
|
execute("DELETE FROM #{quote_table_name(table_name)};")
|
|
15
30
|
end
|
|
16
31
|
end
|
|
17
32
|
|
|
18
|
-
class JdbcAdapter
|
|
33
|
+
class JdbcAdapter < AbstractAdapter
|
|
19
34
|
def truncate_table(table_name)
|
|
20
35
|
begin
|
|
21
36
|
execute("TRUNCATE TABLE #{quote_table_name(table_name)};")
|
|
@@ -25,19 +40,32 @@ module ActiveRecord
|
|
|
25
40
|
end
|
|
26
41
|
end
|
|
27
42
|
|
|
28
|
-
class PostgreSQLAdapter
|
|
43
|
+
class PostgreSQLAdapter < AbstractAdapter
|
|
44
|
+
|
|
45
|
+
def self.db_version
|
|
46
|
+
@db_version ||= connection.select_values(
|
|
47
|
+
"SELECT CHARACTER_VALUE
|
|
48
|
+
FROM INFORMATION_SCHEMA.SQL_IMPLEMENTATION_INFO
|
|
49
|
+
WHERE IMPLEMENTATION_INFO_NAME = 'DBMS VERSION' ").to_s
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.cascade
|
|
53
|
+
@cascade ||= db_version >= "08.02" ? "CASCADE" : ""
|
|
54
|
+
end
|
|
55
|
+
|
|
29
56
|
def truncate_table(table_name)
|
|
30
|
-
execute("TRUNCATE TABLE #{quote_table_name(table_name)}
|
|
57
|
+
execute("TRUNCATE TABLE #{quote_table_name(table_name)} #{self.class.cascade};")
|
|
31
58
|
end
|
|
59
|
+
|
|
32
60
|
end
|
|
33
61
|
|
|
34
|
-
class SQLServerAdapter
|
|
62
|
+
class SQLServerAdapter < AbstractAdapter
|
|
35
63
|
def truncate_table(table_name)
|
|
36
64
|
execute("TRUNCATE TABLE #{quote_table_name(table_name)};")
|
|
37
65
|
end
|
|
38
66
|
end
|
|
39
67
|
|
|
40
|
-
class OracleEnhancedAdapter
|
|
68
|
+
class OracleEnhancedAdapter < AbstractAdapter
|
|
41
69
|
def truncate_table(table_name)
|
|
42
70
|
execute("TRUNCATE TABLE #{quote_table_name(table_name)}")
|
|
43
71
|
end
|
|
@@ -48,7 +76,9 @@ end
|
|
|
48
76
|
|
|
49
77
|
|
|
50
78
|
module DatabaseCleaner::ActiveRecord
|
|
51
|
-
class Truncation
|
|
79
|
+
class Truncation
|
|
80
|
+
include ::DatabaseCleaner::ActiveRecord::Base
|
|
81
|
+
include ::DatabaseCleaner::Generic::Truncation
|
|
52
82
|
|
|
53
83
|
def clean
|
|
54
84
|
connection.disable_referential_integrity do
|
|
@@ -61,11 +91,12 @@ module DatabaseCleaner::ActiveRecord
|
|
|
61
91
|
private
|
|
62
92
|
|
|
63
93
|
def tables_to_truncate
|
|
64
|
-
|
|
94
|
+
(@only || connection.tables) - @tables_to_exclude
|
|
65
95
|
end
|
|
66
96
|
|
|
67
97
|
def connection
|
|
68
|
-
|
|
98
|
+
#::ActiveRecord::Base.connection
|
|
99
|
+
connection_klass.connection
|
|
69
100
|
end
|
|
70
101
|
|
|
71
102
|
# overwritten
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
module DatabaseCleaner
|
|
2
|
+
class Base
|
|
3
|
+
|
|
4
|
+
def initialize(desired_orm = nil,opts = {})
|
|
5
|
+
if desired_orm == :autodetect || desired_orm.nil?
|
|
6
|
+
autodetect
|
|
7
|
+
else
|
|
8
|
+
self.orm = desired_orm
|
|
9
|
+
end
|
|
10
|
+
self.db = opts[:connection] if opts.has_key? :connection
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def db=(desired_db)
|
|
14
|
+
self.strategy_db = desired_db
|
|
15
|
+
@db = desired_db
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def strategy_db=(desired_db)
|
|
19
|
+
if strategy.respond_to? :db=
|
|
20
|
+
strategy.db = desired_db
|
|
21
|
+
elsif desired_db!= :default
|
|
22
|
+
raise ArgumentError, "You must provide a strategy object that supports non default databases when you specify a database"
|
|
23
|
+
end
|
|
24
|
+
rescue NoStrategySetError
|
|
25
|
+
#handle NoStrategySetError by doing nothing at all
|
|
26
|
+
desired_db
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def db
|
|
30
|
+
@db || :default
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def create_strategy(*args)
|
|
34
|
+
strategy, *strategy_args = args
|
|
35
|
+
orm_strategy(strategy).new(*strategy_args)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def clean_with(*args)
|
|
39
|
+
strategy = create_strategy(*args)
|
|
40
|
+
strategy.clean
|
|
41
|
+
strategy
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
alias clean_with! clean_with
|
|
45
|
+
|
|
46
|
+
def strategy=(args)
|
|
47
|
+
strategy, *strategy_args = args
|
|
48
|
+
if strategy.is_a?(Symbol)
|
|
49
|
+
@strategy = create_strategy(*args)
|
|
50
|
+
elsif strategy_args.empty?
|
|
51
|
+
@strategy = strategy
|
|
52
|
+
else
|
|
53
|
+
raise ArgumentError, "You must provide a strategy object, or a symbol for a known strategy along with initialization params."
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
self.strategy_db = self.db
|
|
57
|
+
|
|
58
|
+
@strategy
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def strategy
|
|
62
|
+
return @strategy if @strategy
|
|
63
|
+
raise NoStrategySetError, "Please set a strategy with DatabaseCleaner.strategy=."
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def orm=(desired_orm)
|
|
67
|
+
@orm = desired_orm
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def orm
|
|
71
|
+
@orm || autodetect
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def start
|
|
75
|
+
strategy.start
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def clean
|
|
79
|
+
strategy.clean
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
alias clean! clean
|
|
83
|
+
|
|
84
|
+
def auto_detected?
|
|
85
|
+
return true unless @autodetected.nil?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
#TODO make strategies directly comparable
|
|
89
|
+
def ==(other)
|
|
90
|
+
self.orm == other.orm && self.db == other.db && self.strategy.class == other.strategy.class
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def orm_module
|
|
96
|
+
::DatabaseCleaner.orm_module(orm)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def orm_strategy(strategy)
|
|
100
|
+
require "database_cleaner/#{orm.to_s}/#{strategy.to_s}"
|
|
101
|
+
orm_module.const_get(strategy.to_s.capitalize)
|
|
102
|
+
rescue LoadError => e
|
|
103
|
+
if orm_module.respond_to? :available_strategies
|
|
104
|
+
raise UnknownStrategySpecified, "The '#{strategy}' strategy does not exist for the #{orm} ORM! Available strategies: #{orm_module.available_strategies.join(', ')}"
|
|
105
|
+
else
|
|
106
|
+
raise UnknownStrategySpecified, "The '#{strategy}' strategy does not exist for the #{orm} ORM!"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def autodetect
|
|
111
|
+
@orm ||= begin
|
|
112
|
+
@autodetected = true
|
|
113
|
+
if defined? ::ActiveRecord
|
|
114
|
+
:active_record
|
|
115
|
+
elsif defined? ::DataMapper
|
|
116
|
+
:data_mapper
|
|
117
|
+
elsif defined? ::MongoMapper
|
|
118
|
+
:mongo_mapper
|
|
119
|
+
elsif defined? ::Mongoid
|
|
120
|
+
:mongoid
|
|
121
|
+
elsif defined? ::CouchPotato
|
|
122
|
+
:couch_potato
|
|
123
|
+
else
|
|
124
|
+
raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, MongoMapper, Mongoid, or CouchPotato loaded?"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -1,114 +1,77 @@
|
|
|
1
|
+
require 'database_cleaner/base'
|
|
2
|
+
|
|
1
3
|
module DatabaseCleaner
|
|
2
4
|
|
|
3
5
|
class NoStrategySetError < StandardError; end
|
|
4
6
|
class NoORMDetected < StandardError; end
|
|
5
7
|
class UnknownStrategySpecified < ArgumentError; end
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
def
|
|
9
|
-
|
|
9
|
+
class << self
|
|
10
|
+
def [](orm,opts = {})
|
|
11
|
+
raise NoORMDetected if orm.nil?
|
|
12
|
+
@connections ||= []
|
|
13
|
+
cleaner = DatabaseCleaner::Base.new(orm,opts)
|
|
14
|
+
connections.push cleaner
|
|
15
|
+
cleaner
|
|
10
16
|
end
|
|
11
|
-
end
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
%w[truncation transaction]
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
module MongoMapper
|
|
20
|
-
def self.available_strategies
|
|
21
|
-
%w[truncation]
|
|
18
|
+
def app_root=(desired_root)
|
|
19
|
+
@app_root = desired_root
|
|
22
20
|
end
|
|
23
|
-
end
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
%w[truncation]
|
|
22
|
+
def app_root
|
|
23
|
+
@app_root || Dir.pwd
|
|
28
24
|
end
|
|
29
|
-
end
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def create_strategy(*args)
|
|
34
|
-
strategy, *strategy_args = args
|
|
35
|
-
orm_strategy(strategy).new(*strategy_args)
|
|
26
|
+
def connections
|
|
27
|
+
@connections ||= [::DatabaseCleaner::Base.new]
|
|
36
28
|
end
|
|
37
29
|
|
|
38
|
-
def
|
|
39
|
-
strategy =
|
|
40
|
-
|
|
41
|
-
strategy
|
|
30
|
+
def strategy=(stratagem)
|
|
31
|
+
self.connections.each { |connect| connect.strategy = stratagem }
|
|
32
|
+
remove_duplicates
|
|
42
33
|
end
|
|
43
34
|
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@strategy = create_strategy(*args)
|
|
48
|
-
elsif strategy_args.empty?
|
|
49
|
-
@strategy = strategy
|
|
50
|
-
else
|
|
51
|
-
raise ArgumentError, "You must provide a strategy object, or a symbol for a know strategy along with initialization params."
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def orm=(orm_string)
|
|
56
|
-
@orm = orm_string
|
|
35
|
+
def orm=(orm)
|
|
36
|
+
self.connections.each { |connect| connect.orm = orm }
|
|
37
|
+
remove_duplicates
|
|
57
38
|
end
|
|
58
39
|
|
|
59
40
|
def start
|
|
60
|
-
|
|
41
|
+
self.connections.each { |connection| connection.start }
|
|
61
42
|
end
|
|
62
43
|
|
|
63
44
|
def clean
|
|
64
|
-
|
|
45
|
+
self.connections.each { |connection| connection.clean }
|
|
65
46
|
end
|
|
66
47
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def strategy
|
|
70
|
-
return @strategy if @strategy
|
|
71
|
-
raise NoStrategySetError, "Please set a strategy with DatabaseCleaner.strategy=."
|
|
48
|
+
def clean_with(stratagem)
|
|
49
|
+
self.connections.each { |connection| connection.clean_with stratagem }
|
|
72
50
|
end
|
|
73
51
|
|
|
74
|
-
def
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
raise UnknownStrategySpecified, "The '#{strategy}' strategy does not exist for the #{orm} ORM! Available strategies: #{orm_module.available_strategies.join(', ')}"
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def orm
|
|
83
|
-
@orm ||=begin
|
|
84
|
-
if defined? ::ActiveRecord
|
|
85
|
-
'active_record'
|
|
86
|
-
elsif defined? ::DataMapper
|
|
87
|
-
'data_mapper'
|
|
88
|
-
elsif defined? ::MongoMapper
|
|
89
|
-
'mongo_mapper'
|
|
90
|
-
elsif defined? ::CouchPotato
|
|
91
|
-
'couch_potato'
|
|
92
|
-
else
|
|
93
|
-
raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, MongoMapper or CouchPotato loaded?"
|
|
94
|
-
end
|
|
52
|
+
def remove_duplicates
|
|
53
|
+
temp = []
|
|
54
|
+
self.connections.each do |connect|
|
|
55
|
+
temp.push connect unless temp.include? connect
|
|
95
56
|
end
|
|
57
|
+
@connections = temp
|
|
96
58
|
end
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
59
|
+
|
|
60
|
+
def orm_module(symbol)
|
|
61
|
+
case symbol
|
|
62
|
+
when :active_record
|
|
63
|
+
DatabaseCleaner::ActiveRecord
|
|
64
|
+
when :data_mapper
|
|
65
|
+
DatabaseCleaner::DataMapper
|
|
66
|
+
when :mongo
|
|
67
|
+
DatabaseCleaner::Mongo
|
|
68
|
+
when :mongoid
|
|
69
|
+
DatabaseCleaner::Mongoid
|
|
70
|
+
when :mongo_mapper
|
|
71
|
+
DatabaseCleaner::MongoMapper
|
|
72
|
+
when :couch_potato
|
|
73
|
+
DatabaseCleaner::CouchPotato
|
|
109
74
|
end
|
|
110
75
|
end
|
|
111
|
-
|
|
112
76
|
end
|
|
113
|
-
|
|
114
77
|
end
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
require 'database_cleaner/
|
|
1
|
+
require 'database_cleaner/generic/truncation'
|
|
2
2
|
|
|
3
3
|
module DatabaseCleaner
|
|
4
4
|
module CouchPotato
|
|
5
|
-
class Truncation
|
|
5
|
+
class Truncation
|
|
6
|
+
include ::DatabaseCleaner::Generic::Truncation
|
|
7
|
+
|
|
6
8
|
def initialize(options = {})
|
|
7
9
|
if options.has_key?(:only) || options.has_key?(:except)
|
|
8
10
|
raise ArgumentError, "The :only and :except options are not available for use with CouchPotato/CouchDB."
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'database_cleaner/generic/base'
|
|
2
|
+
module DatabaseCleaner
|
|
3
|
+
module DataMapper
|
|
4
|
+
def self.available_strategies
|
|
5
|
+
%w[truncation transaction]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module Base
|
|
9
|
+
include ::DatabaseCleaner::Generic::Base
|
|
10
|
+
|
|
11
|
+
def db=(desired_db)
|
|
12
|
+
@db = desired_db
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def db
|
|
16
|
+
@db || :default
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
+
require 'database_cleaner/data_mapper/base'
|
|
2
|
+
|
|
1
3
|
module DatabaseCleaner::DataMapper
|
|
2
4
|
class Transaction
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
include ::DatabaseCleaner::DataMapper::Base
|
|
6
|
+
#TODO Figure out repositories, may have to refactor connection_klass to something more sensible
|
|
7
|
+
def start(repository = nil)
|
|
8
|
+
repository = self.db if repository.nil?
|
|
9
|
+
::DataMapper.repository(repository) do |r|
|
|
6
10
|
transaction = DataMapper::Transaction.new(r)
|
|
7
11
|
transaction.begin
|
|
8
12
|
r.adapter.push_transaction(transaction)
|
|
9
13
|
end
|
|
10
14
|
end
|
|
11
15
|
|
|
12
|
-
def clean(
|
|
13
|
-
|
|
16
|
+
def clean(repository = nil)
|
|
17
|
+
repository = self.db if repository.nil?
|
|
18
|
+
::DataMapper.repository(repository) do |r|
|
|
14
19
|
adapter = r.adapter
|
|
15
20
|
while adapter.current_transaction
|
|
16
21
|
adapter.current_transaction.rollback
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
require "database_cleaner/
|
|
1
|
+
require "database_cleaner/generic/truncation"
|
|
2
|
+
require 'database_cleaner/data_mapper/base'
|
|
2
3
|
|
|
3
4
|
module DataMapper
|
|
4
5
|
module Adapters
|
|
@@ -29,12 +30,13 @@ module DataMapper
|
|
|
29
30
|
execute("SET FOREIGN_KEY_CHECKS = 0;")
|
|
30
31
|
yield
|
|
31
32
|
ensure
|
|
32
|
-
execute("SET FOREIGN_KEY_CHECKS = #{old};")
|
|
33
|
+
execute("SET FOREIGN_KEY_CHECKS = #{old.first};")
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
end
|
|
37
38
|
|
|
39
|
+
|
|
38
40
|
class Sqlite3Adapter < DataObjectsAdapter
|
|
39
41
|
|
|
40
42
|
# taken from http://github.com/godfat/dm-mapping/tree/master
|
|
@@ -46,7 +48,7 @@ module DataMapper
|
|
|
46
48
|
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
|
47
49
|
SQL
|
|
48
50
|
# activerecord-2.1.0/lib/active_record/connection_adapters/sqlite_adapter.rb: 181
|
|
49
|
-
select
|
|
51
|
+
select(sql)
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
def truncate_table(table_name)
|
|
@@ -61,7 +63,32 @@ module DataMapper
|
|
|
61
63
|
end
|
|
62
64
|
|
|
63
65
|
end
|
|
66
|
+
|
|
67
|
+
class SqliteAdapter < DataObjectsAdapter
|
|
68
|
+
# taken from http://github.com/godfat/dm-mapping/tree/master
|
|
69
|
+
def storage_names(repository = :default)
|
|
70
|
+
# activerecord-2.1.0/lib/active_record/connection_adapters/sqlite_adapter.rb: 177
|
|
71
|
+
sql = <<-SQL.compress_lines
|
|
72
|
+
SELECT name
|
|
73
|
+
FROM sqlite_master
|
|
74
|
+
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
|
|
75
|
+
SQL
|
|
76
|
+
# activerecord-2.1.0/lib/active_record/connection_adapters/sqlite_adapter.rb: 181
|
|
77
|
+
select(sql)
|
|
78
|
+
end
|
|
64
79
|
|
|
80
|
+
def truncate_table(table_name)
|
|
81
|
+
execute("DELETE FROM #{quote_name(table_name)};")
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# this is a no-op copied from activerecord
|
|
85
|
+
# i didn't find out if/how this is possible
|
|
86
|
+
# activerecord also doesn't do more here
|
|
87
|
+
def disable_referential_integrity
|
|
88
|
+
yield
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
65
92
|
|
|
66
93
|
# FIXME
|
|
67
94
|
# i don't know if this works
|
|
@@ -115,28 +142,34 @@ module DataMapper
|
|
|
115
142
|
end
|
|
116
143
|
|
|
117
144
|
|
|
118
|
-
module DatabaseCleaner
|
|
119
|
-
|
|
145
|
+
module DatabaseCleaner
|
|
146
|
+
module DataMapper
|
|
147
|
+
class Truncation
|
|
148
|
+
include ::DatabaseCleaner::DataMapper::Base
|
|
149
|
+
include ::DatabaseCleaner::Generic::Truncation
|
|
120
150
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
151
|
+
def clean(repository = nil)
|
|
152
|
+
repository = self.db if repository.nil?
|
|
153
|
+
adapter = ::DataMapper.repository(repository).adapter
|
|
154
|
+
adapter.disable_referential_integrity do
|
|
155
|
+
tables_to_truncate(repository).each do |table_name|
|
|
156
|
+
adapter.truncate_table table_name
|
|
157
|
+
end
|
|
126
158
|
end
|
|
127
159
|
end
|
|
128
|
-
end
|
|
129
160
|
|
|
130
|
-
|
|
161
|
+
private
|
|
131
162
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
163
|
+
def tables_to_truncate(repository = nil)
|
|
164
|
+
repository = self.db if repository.nil?
|
|
165
|
+
(@only || ::DataMapper.repository(repository).adapter.storage_names(repository)) - @tables_to_exclude
|
|
166
|
+
end
|
|
135
167
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
168
|
+
# overwritten
|
|
169
|
+
def migration_storage_name
|
|
170
|
+
'migration_info'
|
|
171
|
+
end
|
|
140
172
|
|
|
173
|
+
end
|
|
141
174
|
end
|
|
142
175
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module ::DatabaseCleaner
|
|
2
|
+
module Generic
|
|
3
|
+
module Base
|
|
4
|
+
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
base.send(:include, InstanceMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module InstanceMethods
|
|
11
|
+
def db
|
|
12
|
+
:default
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module ClassMethods
|
|
17
|
+
def available_strategies
|
|
18
|
+
%W[]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module DatabaseCleaner
|
|
2
|
+
module Generic
|
|
3
|
+
module Truncation
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.send(:include, InstanceMethods)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module InstanceMethods
|
|
9
|
+
def initialize(opts={})
|
|
10
|
+
if !opts.empty? && !(opts.keys - [:only, :except]).empty?
|
|
11
|
+
raise ArgumentError, "The only valid options are :only and :except. You specified #{opts.keys.join(',')}."
|
|
12
|
+
end
|
|
13
|
+
if opts.has_key?(:only) && opts.has_key?(:except)
|
|
14
|
+
raise ArgumentError, "You may only specify either :only or :either. Doing both doesn't really make sense does it?"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
@only = opts[:only]
|
|
18
|
+
@tables_to_exclude = (opts[:except] || [])
|
|
19
|
+
@tables_to_exclude << migration_storage_name unless migration_storage_name.nil?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def start
|
|
23
|
+
#included for compatability reasons, do nothing if you don't need to
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def clean
|
|
27
|
+
raise NotImplementedError
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
def tables_to_truncate
|
|
32
|
+
raise NotImplementedError
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# overwrite in subclasses
|
|
36
|
+
# default implementation given because migration storage need not be present
|
|
37
|
+
def migration_storage_name
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'database_cleaner/generic/base'
|
|
2
|
+
module DatabaseCleaner
|
|
3
|
+
module MongoMapper
|
|
4
|
+
def self.available_strategies
|
|
5
|
+
%w[truncation]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module Base
|
|
9
|
+
include ::DatabaseCleaner::Generic::Base
|
|
10
|
+
|
|
11
|
+
def db=(desired_db)
|
|
12
|
+
@db = desired_db
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def db
|
|
16
|
+
@db || :default
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|