db-copier 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +75 -0
- data/lib/db-copier.rb +9 -0
- data/lib/db-copier/db-copier.rb +113 -0
- data/lib/db-copier/worker.rb +51 -0
- data/spec/basic_spec.rb +254 -0
- data/spec/spec_helper.rb +4 -0
- metadata +79 -0
data/README.textile
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
h2. DbCopier
|
2
|
+
|
3
|
+
DbCopier is a DSL around Sequel for quickly making back-ups/copies across various database systems with minimal fuss:
|
4
|
+
|
5
|
+
#my_copy_script.rb
|
6
|
+
require 'rubygems'
|
7
|
+
require 'db-copier'
|
8
|
+
source_db => {:adapter => 'mysql', :host => 'localhost', :user => 'root', :password => '', :database => 'db_copier_test_src'}
|
9
|
+
target_db => {:adapter => 'mysql', :host => 'localhost', :user => 'root', :password => '', :database => 'db_copier_test_target'}
|
10
|
+
DbCopier.app do
|
11
|
+
copy :from => source_db, :to => target_db
|
12
|
+
end
|
13
|
+
|
14
|
+
This would create tables and indexes in the target_db for you (if they do not exist) and copy over contents from the source and best of all it <notextile>*works with any database that works with Sequel*</notextile> (which is a pretty damn big set) -- so you can copy your stuff over from mysql over to postgres, no worries.
|
15
|
+
|
16
|
+
h3. Installation
|
17
|
+
|
18
|
+
sudo gem install db-copier
|
19
|
+
|
20
|
+
h3. Options
|
21
|
+
|
22
|
+
You can specify how many rows you would like to copy at a time via the <notextile>*rows_per_copy*</notextile> (default is 50) attribute.
|
23
|
+
copy :from => source_db, :to => target_db, :rows_per_copy => 100 #Copies 100 rows at a time
|
24
|
+
You can also specify the maximum number of open db connections you would like via the <notextile>*max_connections*</notextile> attribute (default is 5).
|
25
|
+
|
26
|
+
copy :from => source_db, :to => target_db, :max_connections => 5 #Maintains a maximum of 5 connections
|
27
|
+
|
28
|
+
h3. More Granular Control
|
29
|
+
|
30
|
+
If you would like to copy only certain tables, you can do that as well using the 'only' and 'except' methods.
|
31
|
+
Example: Copy only the users table
|
32
|
+
|
33
|
+
copy :from => source_db, :to => target_db do
|
34
|
+
only => 'users'
|
35
|
+
end
|
36
|
+
|
37
|
+
Example: Copy only the users and projects tables
|
38
|
+
|
39
|
+
copy :from => source_db, :to => target_db do
|
40
|
+
only => 'users', 'projects'
|
41
|
+
end
|
42
|
+
|
43
|
+
Example: Copy everything but the users and projects tables
|
44
|
+
|
45
|
+
copy :from => source_db, :to => target_db do
|
46
|
+
except => 'users', 'projects'
|
47
|
+
end
|
48
|
+
|
49
|
+
You can also choose to copy only over certain columns of a table using the for_table method.
|
50
|
+
|
51
|
+
Example: Copy only the name and id fields of the users table
|
52
|
+
|
53
|
+
copy :from => source_db, :to => target_db do
|
54
|
+
for_table 'users', :copy_columns => ['name','id']
|
55
|
+
end
|
56
|
+
|
57
|
+
You can mix-and-match to your heart's content.
|
58
|
+
|
59
|
+
copy :from => source_db, :to => target_db, :rows_per_copy => 1000, :max_connections => 10 do
|
60
|
+
except => 'departments', 'projects'
|
61
|
+
for_table 'users', :copy_columns => ['name','id']
|
62
|
+
for_table 'employees', :copy_columns => ['id','age','name']
|
63
|
+
end
|
64
|
+
|
65
|
+
Finally, if you have already created the schema of the target_db db-copier only tries to copy columns that are present in the target_db's schema.
|
66
|
+
|
67
|
+
h4. LICENSE
|
68
|
+
|
69
|
+
(The MIT License)
|
70
|
+
Copyright (c) 2009:
|
71
|
+
"Santosh Kumar"
|
72
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
73
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
74
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
75
|
+
0:0
|
data/lib/db-copier.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module DbCopier
|
4
|
+
class Application
|
5
|
+
attr_reader :tables_to_copy
|
6
|
+
|
7
|
+
def initialize &block
|
8
|
+
@tables_to_copy = []
|
9
|
+
@index_to_copy = []
|
10
|
+
@only_tables_to_copy = []
|
11
|
+
@except_tables_to_copy = []
|
12
|
+
instance_eval &block
|
13
|
+
end
|
14
|
+
|
15
|
+
def copy options = {}
|
16
|
+
begin
|
17
|
+
from, to, @rows_per_copy, max_connections = options[:from], options[:to], (options[:rows_per_copy] || 50), (options[:max_connections] || 5)
|
18
|
+
raise ArgumentError unless from && to && from.is_a?(Hash) && to.is_a?(Hash) && from.size > 0 && to.size > 0
|
19
|
+
@source_db, @target_db = Sequel.connect(from.merge(:max_connections => max_connections, :single_threaded => false)),
|
20
|
+
Sequel.connect(to.merge(:max_connections => max_connections, :single_threaded => false))
|
21
|
+
@source_db.test_connection && @target_db.test_connection #test connections
|
22
|
+
@tables_to_copy = @source_db.tables
|
23
|
+
@target_db.tables
|
24
|
+
instance_eval { yield } if block_given?
|
25
|
+
copy_tables
|
26
|
+
ensure
|
27
|
+
self.close_connections
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def copy_columns
|
32
|
+
#Hash of the form {:table => [:col1, :col2]} -- maintaing record of columns to keep for a table
|
33
|
+
@copy_columns ||= {}
|
34
|
+
end
|
35
|
+
|
36
|
+
protected :copy_columns
|
37
|
+
|
38
|
+
def for_table(table, options = {})
|
39
|
+
raise ArgumentError, "missing required copy_cols attribute" unless (copy_columns = options[:copy_columns])
|
40
|
+
table, copy_columns = table.to_sym, copy_columns.map {|col| col.to_sym}
|
41
|
+
raise ArgumentError, "columns do not exist" unless (@source_db.schema(table).map {|cols| cols.first} & copy_columns) == copy_columns
|
42
|
+
self.copy_columns[table] = copy_columns
|
43
|
+
end
|
44
|
+
|
45
|
+
def index(ind)
|
46
|
+
@index_to_copy << ind
|
47
|
+
end
|
48
|
+
|
49
|
+
def only(*tabs)
|
50
|
+
@tables_to_copy = Array(tabs)
|
51
|
+
end
|
52
|
+
|
53
|
+
def except(*tabs)
|
54
|
+
@tables_to_copy -= Array(tabs).map { |tb| tb.to_sym }
|
55
|
+
end
|
56
|
+
|
57
|
+
def copy_tables
|
58
|
+
threads = []
|
59
|
+
multi_threaded = !(@source_db.single_threaded? || @target_db.single_threaded?)
|
60
|
+
@tables_to_copy.each do |tab|
|
61
|
+
db_src_conn, db_target_con, table_to_copy, copy_columns_for_table =
|
62
|
+
@source_db, @target_db, tab.to_sym, self.copy_columns[tab.to_sym]
|
63
|
+
if multi_threaded
|
64
|
+
t = Thread.new(table_to_copy, db_src_conn, db_target_con, copy_columns_for_table) do
|
65
|
+
$stdout.print green, bold, "starting Thread: #{Thread.current.object_id}", reset, "\n"
|
66
|
+
w = Worker.new :src_db_conn => db_src_conn, :target_db_conn => db_target_con,
|
67
|
+
:table_name => table_to_copy, :copy_columns => copy_columns_for_table
|
68
|
+
w.copy_table
|
69
|
+
end
|
70
|
+
threads << t
|
71
|
+
else
|
72
|
+
$stdout.print green, bold, "running in single threaded mode", reset, "\n"
|
73
|
+
w = Worker.new :src_db_conn => db_src_conn, :target_db_conn => db_target_con,
|
74
|
+
:table_name => table_to_copy, :copy_columns => copy_columns_for_table
|
75
|
+
w.copy_table
|
76
|
+
end
|
77
|
+
end
|
78
|
+
threads.each {|t| t.join} if multi_threaded
|
79
|
+
end
|
80
|
+
|
81
|
+
protected :copy_tables
|
82
|
+
|
83
|
+
def close_connections
|
84
|
+
@source_db.disconnect if defined?(@source_db) && @source_db
|
85
|
+
@target_db.disconnect if defined?(@target_db) && @target_db
|
86
|
+
end
|
87
|
+
|
88
|
+
protected :close_connections
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.app &block
|
93
|
+
Application.new &block
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.generate_create_table_ddl(db_conn, table_to_create_schema_from, new_table_name, only_copy_columns = [])
|
97
|
+
ret = String.new
|
98
|
+
db_conn.schema(table_to_create_schema_from.to_sym).each do |col|
|
99
|
+
col_name, col_type = col[0].to_sym, col[1][:type]
|
100
|
+
#Skip creating this column if it was not specified in the columns to copy for this table
|
101
|
+
next if only_copy_columns.count > 0 && !only_copy_columns.include?(col_name)
|
102
|
+
if col[1][:primary_key]
|
103
|
+
ret << "primary_key #{col_name.inspect}, #{col_type.to_sym.inspect}, :default => #{col[1][:default].inspect}, :null => #{col[1][:allow_null].inspect};\n"
|
104
|
+
else
|
105
|
+
ret << "#{col_type.to_s.capitalize} #{col_name.inspect}, :default => #{col[1][:default].inspect}, :null => #{col[1][:allow_null].inspect};\n"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
ret = (".create_table #{new_table_name.to_sym.inspect} do \n" + ret)
|
109
|
+
ret << "end\n"
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module DbCopier
|
2
|
+
class Worker
|
3
|
+
def initialize(options = {})
|
4
|
+
@src_db_conn, @target_db_conn, @table_name, @rows_per_copy, @copy_columns = options[:src_db_conn], options[:target_db_conn],
|
5
|
+
options[:table_name], (options[:rows_per_copy] || 1000), (options[:copy_columns] || [])
|
6
|
+
raise ArgumentError unless @src_db_conn && @target_db_conn && @table_name
|
7
|
+
@copy_columns ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def copy_table
|
11
|
+
start = Time.now
|
12
|
+
$stdout.print green, bold, "Thread: #{Thread.current.object_id} is copying table: #{@table_name}", reset, "\n"
|
13
|
+
tab_to_copy = @table_name.to_sym
|
14
|
+
num_rows = @src_db_conn[tab_to_copy].count
|
15
|
+
i = 0
|
16
|
+
#Create the table if it does not already exist
|
17
|
+
unless @target_db_conn.table_exists?(tab_to_copy)
|
18
|
+
table_creation_ddl = DbCopier.generate_create_table_ddl(@src_db_conn, tab_to_copy, tab_to_copy, @copy_columns)
|
19
|
+
table_creation_ddl = ("@target_db_conn" + table_creation_ddl)
|
20
|
+
eval table_creation_ddl
|
21
|
+
end
|
22
|
+
|
23
|
+
#This is the intersection of columns specified via the +copy_columns+ argumnent in the +for_table+ method
|
24
|
+
#and those that actually exist in the target table.
|
25
|
+
columns_in_target_db = @target_db_conn.schema(tab_to_copy).map {|cols| cols.first}
|
26
|
+
columns_to_copy =
|
27
|
+
if @copy_columns.count > 0
|
28
|
+
@copy_columns & columns_in_target_db
|
29
|
+
else
|
30
|
+
columns_in_target_db
|
31
|
+
end
|
32
|
+
|
33
|
+
while i < num_rows
|
34
|
+
rows_to_copy = @src_db_conn[tab_to_copy].select(*columns_to_copy).limit(@rows_per_copy, i).all
|
35
|
+
#Special handling of datetime columns
|
36
|
+
rows_to_copy.each { |col_name, col_val| rows_to_copy[col_name] = DateTime.parse(col_val) if col_val.class == Time }
|
37
|
+
i += rows_to_copy.count
|
38
|
+
@target_db_conn[tab_to_copy].multi_insert(rows_to_copy)
|
39
|
+
end
|
40
|
+
|
41
|
+
#copy indexes now
|
42
|
+
@src_db_conn.indexes(tab_to_copy).each do |index_name, index_info|
|
43
|
+
#Make sure we are adding an index to a column that is going to be there
|
44
|
+
next unless (columns_to_copy & index_info[:columns] == index_info[:columns])
|
45
|
+
@target_db_conn.add_index(tab_to_copy, index_info[:columns])
|
46
|
+
end
|
47
|
+
$stdout.print green,bold, "Thread: #{Thread.current.object_id} has COMPLETED copying table: #{@table_name} in #{Time.now - start} seconds", reset, "\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
data/spec/basic_spec.rb
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper.rb"
|
2
|
+
|
3
|
+
describe DbCopier do
|
4
|
+
source_db = {:adapter => 'mysql', :host => 'localhost', :user => 'root', :password => '', :database => 'db_copier_test_src'}
|
5
|
+
target_db = source_db.merge(:database => 'db_copier_test_target')
|
6
|
+
fake_cred_db = target_db.merge(:user => 'rootsss')
|
7
|
+
|
8
|
+
def create_and_populate_table(conn, tbl_name, num_rows = 1000)
|
9
|
+
conn.create_table tbl_name do
|
10
|
+
primary_key :id, :integer, :null => false
|
11
|
+
String :nombre, :null => true
|
12
|
+
DateTime :created_at, :null => false, :default => DateTime.now
|
13
|
+
end
|
14
|
+
rows = []
|
15
|
+
num_rows.times {|i| rows << {:id => (i+1), :nombre => Faker::Name.name, :created_at => DateTime.now}}
|
16
|
+
conn[tbl_name].multi_insert rows
|
17
|
+
end
|
18
|
+
|
19
|
+
before(:all) do
|
20
|
+
#create some connections
|
21
|
+
@source_db_conn, @fake_cred_db_conn, @target_db_conn = Sequel.connect(source_db), Sequel.connect(fake_cred_db),
|
22
|
+
Sequel.connect(target_db)
|
23
|
+
|
24
|
+
create_and_populate_table @source_db_conn, :uno
|
25
|
+
create_and_populate_table @source_db_conn, :dos
|
26
|
+
create_and_populate_table @source_db_conn, :tres
|
27
|
+
create_and_populate_table @source_db_conn, :quatro
|
28
|
+
create_and_populate_table @source_db_conn, :quinto
|
29
|
+
end
|
30
|
+
|
31
|
+
after(:each) do
|
32
|
+
@target_db_conn.tables.each { |tbl| @target_db_conn.drop_table(tbl) } #clear the target tables
|
33
|
+
end
|
34
|
+
|
35
|
+
after(:all) do
|
36
|
+
@source_db_conn.tables.each { |tab| @source_db_conn.drop_table tab } #clear the source tables
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_target_tables
|
40
|
+
@target_db_conn.create_table :uno do
|
41
|
+
primary_key :id, :integer, :null => false
|
42
|
+
String :nombre, :null => true
|
43
|
+
DateTime :created_at, :null => false
|
44
|
+
end
|
45
|
+
@target_db_conn.create_table :dos do
|
46
|
+
primary_key :id, :integer, :null => false
|
47
|
+
String :nombre, :null => true
|
48
|
+
DateTime :created_at, :null => false
|
49
|
+
end
|
50
|
+
@target_db_conn.create_table :tres do
|
51
|
+
primary_key :id, :integer, :null => false
|
52
|
+
String :nombre, :null => true
|
53
|
+
DateTime :created_at, :null => false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_target_with_one_less_column
|
58
|
+
@target_db_conn.create_table :uno do
|
59
|
+
primary_key :id, :integer, :null => false
|
60
|
+
String :nombre, :null => true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should throw an argument error if the +:from+ and +:to+ arguments are not provided for the +copy+ method" do
|
65
|
+
create_target_tables
|
66
|
+
begin
|
67
|
+
DbCopier.app do
|
68
|
+
copy
|
69
|
+
end
|
70
|
+
raise RuntimeError, "shouldn't be here"
|
71
|
+
rescue ArgumentError
|
72
|
+
end
|
73
|
+
|
74
|
+
begin
|
75
|
+
DbCopier.app do
|
76
|
+
copy :from => {:adapter => 'mysql'}
|
77
|
+
end
|
78
|
+
raise RuntimeError, "shouldn't be here"
|
79
|
+
rescue ArgumentError
|
80
|
+
end
|
81
|
+
|
82
|
+
begin
|
83
|
+
DbCopier.app do
|
84
|
+
copy :to => {:adapter => 'mysql'}
|
85
|
+
end
|
86
|
+
raise RuntimeError, "shouldn't be here"
|
87
|
+
rescue ArgumentError
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should throw an argument error if the +:from+ and +:to+ arguments are NOT hashes" do
|
92
|
+
create_target_tables
|
93
|
+
begin
|
94
|
+
DbCopier.app do
|
95
|
+
copy :from => 'foo', :to => 'bar'
|
96
|
+
end
|
97
|
+
raise RuntimeError, "shouldn't be here"
|
98
|
+
rescue ArgumentError
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should throw an Sequel::DatabaseConnectionError for invalid credentials" do
|
103
|
+
create_target_tables
|
104
|
+
begin
|
105
|
+
DbCopier.app do
|
106
|
+
copy :from => source_db, :to => fake_cred_db
|
107
|
+
end
|
108
|
+
raise RuntimeError, "shouldn't be here"
|
109
|
+
rescue Sequel::DatabaseConnectionError
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should copy all tables if no #table methods are called in the dsl" do
|
114
|
+
create_target_tables
|
115
|
+
app = DbCopier.app do
|
116
|
+
copy :from => source_db, :to => target_db
|
117
|
+
end
|
118
|
+
@source_db_conn.tables.map{|tbl| tbl.inspect}.sort.should == @target_db_conn.tables.map{|tbl| tbl.inspect}.sort
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should copy only select tables if they are provided as an #only method in the dsl" do
|
122
|
+
create_target_tables
|
123
|
+
only_tables_to_copy = ['uno', 'dos'].sort
|
124
|
+
app = DbCopier.app do
|
125
|
+
copy :from => source_db, :to => target_db do
|
126
|
+
only *only_tables_to_copy
|
127
|
+
end
|
128
|
+
end
|
129
|
+
only_tables_to_copy.each { |tbl| @source_db_conn[tbl.to_sym].count.should == @target_db_conn[tbl.to_sym].count }
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should not copy tables specified in the #except dsl method" do
|
133
|
+
create_target_tables
|
134
|
+
original_tres_count = @target_db_conn[:tres].count
|
135
|
+
app = DbCopier.app do
|
136
|
+
copy :from => source_db, :to => target_db do
|
137
|
+
except 'tres'
|
138
|
+
end
|
139
|
+
end
|
140
|
+
@target_db_conn[:tres].count.should == original_tres_count
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should throw an ArgumentError if the for_table method is called without appropriate args" do
|
144
|
+
create_target_tables
|
145
|
+
begin
|
146
|
+
app = DbCopier.app do
|
147
|
+
copy :from => source_db, :to => target_db do
|
148
|
+
except 'uno', 'dos'
|
149
|
+
for_table :custom_src_query_ratings #Missing :copy_columns argument
|
150
|
+
end
|
151
|
+
end
|
152
|
+
raise RuntimeError, "Shouldn't be here"
|
153
|
+
rescue ArgumentError
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should only copy the columns specified in the +copy_columns+ argument in the for_table method" do
|
158
|
+
create_target_tables
|
159
|
+
app = DbCopier.app do
|
160
|
+
copy :from => source_db, :to => target_db do
|
161
|
+
except 'tres'
|
162
|
+
for_table :uno, :copy_columns => ['id', 'created_at']
|
163
|
+
end
|
164
|
+
end
|
165
|
+
@target_db_conn[:uno].all.each do |row|
|
166
|
+
row[:nombre].should == nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should throw an ArgumentError if the columns specified in the for_table method does not exist do not exist in the source table" do
|
171
|
+
create_target_tables
|
172
|
+
begin
|
173
|
+
app = DbCopier.app do
|
174
|
+
copy :from => source_db, :to => target_db do
|
175
|
+
except 'tres'
|
176
|
+
for_table :uno, :copy_columns => ['id', 'foo']
|
177
|
+
end
|
178
|
+
end
|
179
|
+
raise RuntimeError, "Shouldn't be here"
|
180
|
+
rescue ArgumentError
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should copy only columns that are there in the target db" do
|
185
|
+
create_target_with_one_less_column
|
186
|
+
app = DbCopier.app do
|
187
|
+
copy :from => source_db, :to => target_db do
|
188
|
+
only 'uno'
|
189
|
+
end
|
190
|
+
end
|
191
|
+
@source_db_conn[:uno].count.should == @target_db_conn[:uno].count
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should create tables in the target db if they do not exist" do
|
195
|
+
app = DbCopier.app do
|
196
|
+
copy :from => source_db, :to => target_db do
|
197
|
+
end
|
198
|
+
end
|
199
|
+
@target_db_conn.tables.map{|tbl| tbl.to_s}.sort.should == @source_db_conn.tables.map{|tbl| tbl.to_s}.sort
|
200
|
+
@source_db_conn.tables.each do |tbl|
|
201
|
+
@source_db_conn[tbl].count.should == @target_db_conn[tbl].count
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should create tables in the target db if they do not exist and it should support a +for_table+ argument" do
|
206
|
+
app = DbCopier.app do
|
207
|
+
copy :from => source_db, :to => target_db do
|
208
|
+
for_table :uno, :copy_columns => ['id', 'created_at']
|
209
|
+
end
|
210
|
+
end
|
211
|
+
@target_db_conn.tables.map{|tbl| tbl.to_s}.sort.should == @source_db_conn.tables.map{|tbl| tbl.to_s}.sort
|
212
|
+
@source_db_conn.tables.each do |tbl|
|
213
|
+
@source_db_conn[tbl].count.should == @target_db_conn[tbl].count
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should copy indexes" do
|
218
|
+
#Create an index
|
219
|
+
@source_db_conn.add_index :uno, :nombre
|
220
|
+
app = DbCopier.app do
|
221
|
+
copy :from => source_db, :to => target_db do
|
222
|
+
only 'uno'
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
@target_db_conn.indexes(:uno).count.should > 0
|
227
|
+
@target_db_conn.indexes(:uno).each { |key, val| val[:columns].should include(:nombre) }
|
228
|
+
@source_db_conn.drop_index :uno, :nombre #clean-up
|
229
|
+
|
230
|
+
@source_db_conn.add_index :dos, [:nombre, :created_at]
|
231
|
+
app = DbCopier.app do
|
232
|
+
copy :from => source_db, :to => target_db do
|
233
|
+
only 'dos'
|
234
|
+
end
|
235
|
+
end
|
236
|
+
@target_db_conn.indexes(:dos).count.should > 0
|
237
|
+
@target_db_conn.indexes(:dos).each { |key, val| val[:columns].should == [:nombre,:created_at] }
|
238
|
+
end
|
239
|
+
|
240
|
+
it "should not copy indexes of columns that are not to be copied" do
|
241
|
+
#Create an index
|
242
|
+
@source_db_conn.add_index :uno, :nombre
|
243
|
+
app = DbCopier.app do
|
244
|
+
copy :from => source_db, :to => target_db do
|
245
|
+
only 'uno'
|
246
|
+
for_table :uno, :copy_columns => [:id,:created_at]
|
247
|
+
end
|
248
|
+
end
|
249
|
+
@target_db_conn.indexes(:uno).count.should == 0
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should contain useful log msgs"
|
253
|
+
|
254
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: db-copier
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Santosh Kumar
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-18 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sequel
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 3.8.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: term-ansicolor
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.4
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email: santosh79@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- lib/db-copier.rb
|
45
|
+
- lib/db-copier/db-copier.rb
|
46
|
+
- lib/db-copier/worker.rb
|
47
|
+
- README.textile
|
48
|
+
- spec/spec_helper.rb
|
49
|
+
- spec/basic_spec.rb
|
50
|
+
has_rdoc: true
|
51
|
+
homepage: http://github.com/santosh79/db-copier
|
52
|
+
licenses: []
|
53
|
+
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.3.5
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: A DSL around Sequel to aid in copying or replicating databases.
|
78
|
+
test_files: []
|
79
|
+
|