fast_change_table 0.0.6 → 1.0.0
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 +30 -5
- data/README.md +54 -0
- data/Rakefile +6 -0
- data/fast_change_table.gemspec +4 -0
- data/lib/fast_change_table.rb +4 -156
- data/lib/fast_change_table/connection_adapters.rb +31 -0
- data/lib/fast_change_table/fast_change_table.rb +132 -0
- data/lib/fast_change_table/version.rb +1 -1
- data/spec/fast_change_table_spec.rb +83 -0
- data/spec/spec_helper.rb +15 -0
- metadata +39 -7
- data/README +0 -39
- data/test/fast_change_table_test.rb +0 -1
data/Gemfile.lock
CHANGED
@@ -1,18 +1,43 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fast_change_table (0.0
|
5
|
-
activerecord (
|
4
|
+
fast_change_table (1.0.0)
|
5
|
+
activerecord (>= 2.3)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
11
|
-
activesupport (= 2.
|
12
|
-
|
10
|
+
activemodel (3.2.0)
|
11
|
+
activesupport (= 3.2.0)
|
12
|
+
builder (~> 3.0.0)
|
13
|
+
activerecord (3.2.0)
|
14
|
+
activemodel (= 3.2.0)
|
15
|
+
activesupport (= 3.2.0)
|
16
|
+
arel (~> 3.0.0)
|
17
|
+
tzinfo (~> 0.3.29)
|
18
|
+
activesupport (3.2.0)
|
19
|
+
i18n (~> 0.6)
|
20
|
+
multi_json (~> 1.0)
|
21
|
+
arel (3.0.0)
|
22
|
+
builder (3.0.0)
|
23
|
+
diff-lcs (1.1.3)
|
24
|
+
i18n (0.6.0)
|
25
|
+
multi_json (1.0.4)
|
26
|
+
mysql2 (0.3.11)
|
27
|
+
rspec (2.8.0)
|
28
|
+
rspec-core (~> 2.8.0)
|
29
|
+
rspec-expectations (~> 2.8.0)
|
30
|
+
rspec-mocks (~> 2.8.0)
|
31
|
+
rspec-core (2.8.0)
|
32
|
+
rspec-expectations (2.8.0)
|
33
|
+
diff-lcs (~> 1.1.2)
|
34
|
+
rspec-mocks (2.8.0)
|
35
|
+
tzinfo (0.3.31)
|
13
36
|
|
14
37
|
PLATFORMS
|
15
38
|
ruby
|
16
39
|
|
17
40
|
DEPENDENCIES
|
18
41
|
fast_change_table!
|
42
|
+
mysql2
|
43
|
+
rspec
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#Fast Change Table
|
2
|
+
|
3
|
+
Use fast\_change\_table instead of change_table in your migrations on large tables of data. Uses a duplication pattern to speed things up.
|
4
|
+
|
5
|
+
|
6
|
+
uses ordinary change_table syntax but adds two options
|
7
|
+
|
8
|
+
* "replace\_keys" to remove all indexes; new indexes will be specified
|
9
|
+
- "disable\_keys" to remove indexes and apply them after data load; this is a tremendous performance enhancement for a dbms with fast index creation
|
10
|
+
|
11
|
+
__Example:__
|
12
|
+
|
13
|
+
fast_change_table :table_name, :disable_keys => true do |t|
|
14
|
+
t.change :old_string, :string, :limit => 64
|
15
|
+
t.rename :old_string, :new_string
|
16
|
+
t.integer :an_integer
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
__other methods:__
|
21
|
+
|
22
|
+
create\_table\_like(orignal\_table, table\_to\_copy\_to)
|
23
|
+
creates a table with the same structure
|
24
|
+
|
25
|
+
disable\_indexes(table)
|
26
|
+
removes all indexes from a table, returns a list of index objects removed
|
27
|
+
|
28
|
+
enable\_indexes(table, list\_of\_indexes)
|
29
|
+
restores a list of indexes to a table
|
30
|
+
|
31
|
+
fast\_add\_indexes(table, &block)
|
32
|
+
allows you to pass a block to add indexes. For mysql creates specified indexes in one statement; allows the data to be scanned once.
|
33
|
+
|
34
|
+
__Example:__
|
35
|
+
|
36
|
+
|
37
|
+
fast_add_indexes :sometable do |t|
|
38
|
+
t.index :some_column
|
39
|
+
t.index [:some_other_column, :column_three], :name => "a_multicolumn_index"
|
40
|
+
end
|
41
|
+
|
42
|
+
copy\_table(from\_table, to\_table, remaps = [])
|
43
|
+
|
44
|
+
* copies rows from one table into another. this probably only works with Mysql.
|
45
|
+
by default copies data from column of from_table to to_table of same name.
|
46
|
+
will not copy data where there is no corresponding column.
|
47
|
+
the remaps argument can be supplied to tell copy table how to handle unmatched columns or override this behavior
|
48
|
+
|
49
|
+
__Examples:__
|
50
|
+
|
51
|
+
|
52
|
+
copy_table(old_users_without_email_hash, new_table, ['MD5(email)', 'email_hash'])
|
53
|
+
|
54
|
+
copy_table(old_users_without_total, new_table, ['sum(payments)', 'total_payments'])
|
data/Rakefile
CHANGED
data/fast_change_table.gemspec
CHANGED
@@ -21,7 +21,11 @@ Gem::Specification.new do |s|
|
|
21
21
|
# specify any dependencies here; for example:
|
22
22
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
23
23
|
s.add_runtime_dependency('activerecord', '>= 2.3')
|
24
|
+
s.add_development_dependency("rspec")
|
25
|
+
s.add_development_dependency("mysql2")
|
24
26
|
else
|
25
27
|
s.add_dependency('activerecord', '>= 2.3')
|
28
|
+
s.add_development_dependency("rspec")
|
29
|
+
s.add_development_dependency("mysql2")
|
26
30
|
end
|
27
31
|
end
|
data/lib/fast_change_table.rb
CHANGED
@@ -1,164 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
def change_table_with_remaps(table_name)
|
6
|
-
t = Table.new(table_name, self)
|
7
|
-
yield t
|
8
|
-
return t.renamed_columns
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class Table
|
13
|
-
|
14
|
-
def initialize(table_name, base)
|
15
|
-
@table_name = table_name
|
16
|
-
@base = base
|
17
|
-
@renamed_columns = []
|
18
|
-
end
|
19
|
-
|
20
|
-
def renamed_columns
|
21
|
-
@renamed_columns
|
22
|
-
end
|
23
|
-
|
24
|
-
def rename(column_name, new_column_name)
|
25
|
-
@renamed_columns << [column_name, new_column_name]
|
26
|
-
@base.rename_column(@table_name, column_name, new_column_name)
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
1
|
+
require 'active_record'
|
2
|
+
require 'fast_change_table/connection_adapters'
|
3
|
+
require 'fast_change_table/fast_change_table'
|
4
|
+
require 'fast_change_table/version'
|
32
5
|
|
33
6
|
module FastChangeTable
|
34
7
|
def self.included(base)
|
35
8
|
base.extend ClassMethods
|
36
9
|
end
|
37
|
-
|
38
|
-
module ClassMethods
|
39
|
-
def fast_change_table(table_name, options = {}, &block)
|
40
|
-
options.symbolize_keys!
|
41
|
-
old_table_name = "old_#{table_name}"
|
42
|
-
rename_table(table_name, old_table_name)
|
43
|
-
begin
|
44
|
-
create_table_like(old_table_name, table_name, options)
|
45
|
-
renamed_columns = change_table_with_remaps(table_name, &block)
|
46
|
-
index_list = options[:disable_keys] ? disable_indexes(table_name) : []
|
47
|
-
#prepare the columns names for the insert statements
|
48
|
-
copy_table(old_table_name, table_name, renamed_columns)
|
49
|
-
enable_indexes(table_name, index_list) if options[:disable_keys]
|
50
|
-
drop_table(old_table_name)
|
51
|
-
rescue Exception => e
|
52
|
-
puts "#{e}\n#{e.backtrace}"
|
53
|
-
drop_table(table_name) if table_exists?(table_name)
|
54
|
-
rename_table(old_table_name, table_name)
|
55
|
-
raise e
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def fast_add_indexes(table, &blk)
|
60
|
-
phoney = PhoneyTable.new(table.to_s)
|
61
|
-
yield phoney
|
62
|
-
enable_indexes(table, phoney.indexes)
|
63
|
-
end
|
64
|
-
|
65
|
-
#create_table_like( :sometable, :newtable, :remove_keys => true)
|
66
|
-
def create_table_like(like_table, table, options = {})
|
67
|
-
options.symbolize_keys!
|
68
|
-
code = table_schema_code(like_table)
|
69
|
-
code.gsub!(/create_table\s+"#{like_table}"/, "create_table :#{table}")
|
70
|
-
if options[:replace_keys] or options[:remove_keys]
|
71
|
-
code.gsub!(/add_index\s+"#{like_table}"/, "#add_index :#{table}")
|
72
|
-
else
|
73
|
-
code.gsub!(/add_index\s+"#{like_table}"/, "add_index :#{table}")
|
74
|
-
end
|
75
|
-
class_eval(code)
|
76
|
-
true
|
77
|
-
end
|
78
|
-
|
79
|
-
#copy_table( :sometable, :newtable, [[:old_column, :new_column]])
|
80
|
-
def copy_table(from, to, remaps = [])
|
81
|
-
old = connection.columns(from).collect(&:name)
|
82
|
-
current = connection.columns(to).collect(&:name)
|
83
|
-
remapped_columns = remaps.collect {|c| c.first.to_s}.compact
|
84
|
-
common = (current & old).sort - remapped_columns
|
85
|
-
from_columns = common.collect {|c| "`#{c}`"}
|
86
|
-
to_columns = common.collect {|c| "`#{c}`"}
|
87
|
-
remaps.each do |remap|
|
88
|
-
remap = [remap].flatten
|
89
|
-
next if remap.length != 2
|
90
|
-
from_columns << remap.first
|
91
|
-
to_columns << remap.last
|
92
|
-
end
|
93
|
-
from_columns_to_s = from_columns.join(', ')
|
94
|
-
to_columns_to_s = to_columns.join(', ')
|
95
|
-
execute "INSERT INTO #{to}(#{to_columns_to_s}) SELECT #{from_columns_to_s} FROM #{from}"
|
96
|
-
end
|
97
|
-
|
98
|
-
def table_schema_code(table)
|
99
|
-
dumper = ActiveRecord::SchemaDumper.send(:new, connection)
|
100
|
-
stream = StringIO.new
|
101
|
-
dumper.send(:table, table.to_s, stream)
|
102
|
-
stream.rewind
|
103
|
-
code = stream.read
|
104
|
-
end
|
105
|
-
|
106
|
-
#removes all the indexes
|
107
|
-
def disable_indexes(table)
|
108
|
-
list = connection.indexes(table)
|
109
|
-
list.each do |i|
|
110
|
-
remove_index table, :name => i.name
|
111
|
-
end
|
112
|
-
list
|
113
|
-
end
|
114
|
-
|
115
|
-
#
|
116
|
-
def enable_indexes(table, list)
|
117
|
-
list.each do |i|
|
118
|
-
options = {}
|
119
|
-
options[:name] = i.name if i.name
|
120
|
-
options[:length] = i.lengths if i.lengths
|
121
|
-
options[:unique] = i.unique if i.unique
|
122
|
-
add_index table, i.columns, options
|
123
|
-
end
|
124
|
-
true
|
125
|
-
end
|
126
|
-
|
127
|
-
class PhoneyTable
|
128
|
-
|
129
|
-
attr_accessor :indexes
|
130
|
-
|
131
|
-
def initialize(tablename)
|
132
|
-
@table = tablename
|
133
|
-
@indexes = []
|
134
|
-
end
|
135
|
-
|
136
|
-
def index(columns, options = {})
|
137
|
-
new_index = PhoneyIndex.new(@table, columns, options)
|
138
|
-
@indexes << new_index unless @indexes.to_a.any? {|i| i == new_index}
|
139
|
-
end
|
140
|
-
|
141
|
-
def indexes; @indexes.to_a.uniq end
|
142
|
-
end
|
143
|
-
|
144
|
-
class PhoneyIndex
|
145
|
-
|
146
|
-
attr_accessor :columns, :lengths, :name, :unique
|
147
|
-
|
148
|
-
def initialize(table, cols, options)
|
149
|
-
cols = [cols].flatten
|
150
|
-
self.columns = cols.collect(&:to_s)
|
151
|
-
self.lengths = options[:length]
|
152
|
-
self.unique = !!options[:unique]
|
153
|
-
self.name = options[:name] || "index_#{table}_on_#{columns.join('_and_')}"
|
154
|
-
self.name = "#{columns.join('_')}_idx" if name.length > 64
|
155
|
-
end
|
156
|
-
|
157
|
-
def ==(val)
|
158
|
-
columns == val.columns rescue false
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
10
|
end
|
163
11
|
|
164
12
|
::ActiveRecord::Migration.send :include, FastChangeTable
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters #:nodoc:
|
3
|
+
|
4
|
+
module SchemaStatements
|
5
|
+
def change_table_with_remaps(table_name)
|
6
|
+
t = Table.new(table_name, self)
|
7
|
+
yield t
|
8
|
+
return t.renamed_columns
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Table
|
13
|
+
|
14
|
+
def initialize(table_name, base)
|
15
|
+
@table_name = table_name
|
16
|
+
@base = base
|
17
|
+
@renamed_columns = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def renamed_columns
|
21
|
+
@renamed_columns
|
22
|
+
end
|
23
|
+
|
24
|
+
def rename(column_name, new_column_name)
|
25
|
+
@renamed_columns << [column_name, new_column_name]
|
26
|
+
@base.rename_column(@table_name, column_name, new_column_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module FastChangeTable
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def fast_change_table(table_name, options = {}, &block)
|
10
|
+
options.symbolize_keys!
|
11
|
+
old_table_name = "old_#{table_name}"
|
12
|
+
rename_table(table_name, old_table_name)
|
13
|
+
begin
|
14
|
+
create_table_like(old_table_name, table_name, options)
|
15
|
+
renamed_columns = change_table_with_remaps(table_name, &block)
|
16
|
+
index_list = options[:disable_keys] ? disable_indexes(table_name) : []
|
17
|
+
#prepare the columns names for the insert statements
|
18
|
+
copy_table(old_table_name, table_name, renamed_columns)
|
19
|
+
enable_indexes(table_name, index_list) if options[:disable_keys]
|
20
|
+
drop_table(old_table_name)
|
21
|
+
rescue Exception => e
|
22
|
+
puts "#{e}\n#{e.backtrace}"
|
23
|
+
drop_table(table_name) if table_exists?(table_name)
|
24
|
+
rename_table(old_table_name, table_name)
|
25
|
+
raise e
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def fast_add_indexes(table, &blk)
|
30
|
+
phoney = PhoneyTable.new(table.to_s)
|
31
|
+
yield phoney
|
32
|
+
enable_indexes(table, phoney.indexes)
|
33
|
+
end
|
34
|
+
|
35
|
+
#create_table_like( :sometable, :newtable, :remove_keys => true)
|
36
|
+
def create_table_like(like_table, table, options = {})
|
37
|
+
options.symbolize_keys!
|
38
|
+
code = table_schema_code(like_table)
|
39
|
+
code.gsub!(/create_table\s+"#{like_table}"/, "create_table :#{table}")
|
40
|
+
if options[:replace_keys] or options[:remove_keys]
|
41
|
+
code.gsub!(/add_index\s+"#{like_table}"/, "#add_index :#{table}")
|
42
|
+
else
|
43
|
+
code.gsub!(/add_index\s+"#{like_table}"/, "add_index :#{table}")
|
44
|
+
end
|
45
|
+
class_eval(code)
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
#copy_table( :sometable, :newtable, [[:old_column, :new_column]])
|
50
|
+
def copy_table(from, to, remaps = [])
|
51
|
+
old = connection.columns(from).collect(&:name)
|
52
|
+
current = connection.columns(to).collect(&:name)
|
53
|
+
remapped_columns = remaps.collect {|c| c.first.to_s}.compact
|
54
|
+
common = (current & old).sort - remapped_columns
|
55
|
+
from_columns = common.collect {|c| "`#{c}`"}
|
56
|
+
to_columns = common.collect {|c| "`#{c}`"}
|
57
|
+
remaps.each do |remap|
|
58
|
+
remap = [remap].flatten
|
59
|
+
next if remap.length != 2
|
60
|
+
from_columns << remap.first
|
61
|
+
to_columns << remap.last
|
62
|
+
end
|
63
|
+
from_columns_to_s = from_columns.join(', ')
|
64
|
+
to_columns_to_s = to_columns.join(', ')
|
65
|
+
execute "INSERT INTO #{to}(#{to_columns_to_s}) SELECT #{from_columns_to_s} FROM #{from}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def table_schema_code(table)
|
69
|
+
dumper = ActiveRecord::SchemaDumper.send(:new, connection)
|
70
|
+
stream = StringIO.new
|
71
|
+
dumper.send(:table, table.to_s, stream)
|
72
|
+
stream.rewind
|
73
|
+
code = stream.read
|
74
|
+
end
|
75
|
+
|
76
|
+
#removes all the indexes
|
77
|
+
def disable_indexes(table)
|
78
|
+
list = connection.indexes(table)
|
79
|
+
list.each do |i|
|
80
|
+
remove_index table, :name => i.name
|
81
|
+
end
|
82
|
+
list
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
def enable_indexes(table, list)
|
87
|
+
list.each do |i|
|
88
|
+
options = {}
|
89
|
+
options[:name] = i.name if i.name
|
90
|
+
options[:length] = i.lengths if i.lengths
|
91
|
+
options[:unique] = i.unique if i.unique
|
92
|
+
add_index table, i.columns, options
|
93
|
+
end
|
94
|
+
true
|
95
|
+
end
|
96
|
+
|
97
|
+
class PhoneyTable
|
98
|
+
|
99
|
+
attr_accessor :indexes
|
100
|
+
|
101
|
+
def initialize(tablename)
|
102
|
+
@table = tablename
|
103
|
+
@indexes = []
|
104
|
+
end
|
105
|
+
|
106
|
+
def index(columns, options = {})
|
107
|
+
new_index = PhoneyIndex.new(@table, columns, options)
|
108
|
+
@indexes << new_index unless @indexes.to_a.any? {|i| i == new_index}
|
109
|
+
end
|
110
|
+
|
111
|
+
def indexes; @indexes.to_a.uniq end
|
112
|
+
end
|
113
|
+
|
114
|
+
class PhoneyIndex
|
115
|
+
|
116
|
+
attr_accessor :columns, :lengths, :name, :unique
|
117
|
+
|
118
|
+
def initialize(table, cols, options)
|
119
|
+
cols = [cols].flatten
|
120
|
+
self.columns = cols.collect(&:to_s)
|
121
|
+
self.lengths = options[:length]
|
122
|
+
self.unique = !!options[:unique]
|
123
|
+
self.name = options[:name] || "index_#{table}_on_#{columns.join('_and_')}"
|
124
|
+
self.name = "#{columns.join('_')}_idx" if name.length > 64
|
125
|
+
end
|
126
|
+
|
127
|
+
def ==(val)
|
128
|
+
columns == val.columns rescue false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRecord::Migration do
|
4
|
+
before(:each) do
|
5
|
+
ActiveRecord::Migration.create_table :my_table, :force => true do |t|
|
6
|
+
t.integer :an_integer
|
7
|
+
t.string :a_string
|
8
|
+
t.string :a_name
|
9
|
+
end
|
10
|
+
@connection = ActiveRecord::Migration.connection
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:each) do
|
14
|
+
ActiveRecord::Migration.drop_table(:my_copied_table) rescue nil
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "initialize table" do
|
18
|
+
it "should have expected starting table" do
|
19
|
+
@connection.columns("my_table").all? do |c|
|
20
|
+
["id", "an_integer", "a_string", "a_name"].include?(c.name)
|
21
|
+
end.should eq(true)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#create_table_like" do
|
26
|
+
it "should create an identical table" do
|
27
|
+
ActiveRecord::Migration.create_table_like(:my_table, :my_copied_table)
|
28
|
+
|
29
|
+
@connection.columns("my_copied_table").all? do |c|
|
30
|
+
["id", "an_integer", "a_string", "a_name"].include?(c.name.to_s)
|
31
|
+
end.should eq(true)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#fast_add_indexes, #disable_indexes, #enable_indexes" do
|
36
|
+
it "should add index, remove it then put it back" do
|
37
|
+
ActiveRecord::Migration.fast_add_indexes :my_table do |t|
|
38
|
+
t.index :an_integer, :name => "an_index"
|
39
|
+
end
|
40
|
+
@connection.indexes("my_table").collect(&:name).include?("an_index").should eq(true)
|
41
|
+
|
42
|
+
indexes = ActiveRecord::Migration.disable_indexes("my_table")
|
43
|
+
@connection.indexes("my_table").collect(&:name).include?("an_index").should eq(false)
|
44
|
+
|
45
|
+
ActiveRecord::Migration.enable_indexes("my_table", indexes)
|
46
|
+
@connection.indexes("my_table").collect(&:name).include?("an_index").should eq(true)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#copy_table" do
|
51
|
+
it "should copy the records from one table to another" do
|
52
|
+
@connection.execute "INSERT my_table (an_integer, a_string, a_name) VALUES (1,'String','Name')"
|
53
|
+
ActiveRecord::Migration.create_table_like(:my_table, :my_copied_table)
|
54
|
+
ActiveRecord::Migration.add_column(:my_copied_table, :new_column, :string)
|
55
|
+
ActiveRecord::Migration.copy_table(:my_table, :my_copied_table, [["'Nothing'", "new_column"]])
|
56
|
+
record = @connection.select_all("select * from my_copied_table").first
|
57
|
+
record['an_integer'].should eq(1)
|
58
|
+
record['a_string'].should eq('String')
|
59
|
+
record['a_name'].should eq('Name')
|
60
|
+
record['new_column'].should eq('Nothing')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#fast_change_table" do
|
65
|
+
it "should bring it all together" do
|
66
|
+
@connection.execute "INSERT my_table (an_integer, a_string, a_name) VALUES (1,'String','Name')"
|
67
|
+
ActiveRecord::Migration.add_index :my_table, :an_integer, :name => "an_index"
|
68
|
+
ActiveRecord::Migration.fast_change_table :my_table, :remove_keys => true do |t|
|
69
|
+
t.change :an_integer, :integer
|
70
|
+
t.change :a_string, :string
|
71
|
+
t.change :a_name, :string
|
72
|
+
t.string :new_column
|
73
|
+
end
|
74
|
+
record = @connection.select_all("select * from my_table").first
|
75
|
+
record['an_integer'].should eq(1)
|
76
|
+
record['a_string'].should eq('String')
|
77
|
+
record['a_name'].should eq('Name')
|
78
|
+
record['new_column'].should eq(nil)
|
79
|
+
@connection.indexes("my_table").empty?.should eq(true)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'fast_change_table'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
# some (optional) config here
|
8
|
+
end
|
9
|
+
|
10
|
+
ActiveRecord::Base.establish_connection(
|
11
|
+
:adapter => "mysql2",
|
12
|
+
:database => "fast_change_table_test"
|
13
|
+
)
|
14
|
+
|
15
|
+
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast_change_table
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
+
- 1
|
7
8
|
- 0
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.6
|
10
|
+
version: 1.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Grady Griffin
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-02-02 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: activerecord
|
@@ -32,6 +32,34 @@ dependencies:
|
|
32
32
|
version: "2.3"
|
33
33
|
type: :runtime
|
34
34
|
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rspec
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: mysql2
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
35
63
|
description: Uses table duplication to speed up migrations on large tables
|
36
64
|
email:
|
37
65
|
- gradyg@izea.com
|
@@ -45,12 +73,15 @@ files:
|
|
45
73
|
- .gitignore
|
46
74
|
- Gemfile
|
47
75
|
- Gemfile.lock
|
48
|
-
- README
|
76
|
+
- README.md
|
49
77
|
- Rakefile
|
50
78
|
- fast_change_table.gemspec
|
51
79
|
- lib/fast_change_table.rb
|
80
|
+
- lib/fast_change_table/connection_adapters.rb
|
81
|
+
- lib/fast_change_table/fast_change_table.rb
|
52
82
|
- lib/fast_change_table/version.rb
|
53
|
-
-
|
83
|
+
- spec/fast_change_table_spec.rb
|
84
|
+
- spec/spec_helper.rb
|
54
85
|
homepage: https://github.com/moxie/fast_change_table
|
55
86
|
licenses: []
|
56
87
|
|
@@ -85,4 +116,5 @@ signing_key:
|
|
85
116
|
specification_version: 3
|
86
117
|
summary: Faster table changes
|
87
118
|
test_files:
|
88
|
-
-
|
119
|
+
- spec/fast_change_table_spec.rb
|
120
|
+
- spec/spec_helper.rb
|
data/README
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
Use fast_change_table instead of change_table in your migrations on large tables of data. Uses a duplication pattern to speed things up.
|
2
|
-
|
3
|
-
# Known issues
|
4
|
-
- Not tested
|
5
|
-
|
6
|
-
uses ordinary change_table syntax but adds two options
|
7
|
-
- "replace_keys" to remove all indexes; new indexes will be specified
|
8
|
-
- "disable_keys" to remove indexes and apply them after data load; this is a tremendous performance enhancement for a dbms with fast index creation
|
9
|
-
|
10
|
-
other methods:
|
11
|
-
|
12
|
-
create_table_like(orignal_table, table_to_copy_to)
|
13
|
-
creates a table with the same structure
|
14
|
-
|
15
|
-
disable_indexes(table)
|
16
|
-
removes all indexes from a table, returns a list of index objects removed
|
17
|
-
|
18
|
-
enable_indexes(table, list_of_indexes)
|
19
|
-
restores a list of indexes to a table
|
20
|
-
|
21
|
-
fast_add_indexes(table, &block)
|
22
|
-
allows you to pass a block to add indexes. For mysql creates specified indexes in one statement; allows the data to be scanned once.
|
23
|
-
example
|
24
|
-
|
25
|
-
fast_add_indexes :sometable do |t|
|
26
|
-
t.index :some_column
|
27
|
-
t.index [:some_other_column, :column_three], :name => "a_multicolumn_index"
|
28
|
-
end
|
29
|
-
|
30
|
-
copy_table(from_table, to_table, remaps = [])
|
31
|
-
copies rows from one table into another. this probably only works with Mysql.
|
32
|
-
by default copies data from column of from_table to to_table of same name.
|
33
|
-
will not copy data where there is no corresponding column.
|
34
|
-
the remaps argument can be supplied to tell copy table how to handle unmatched columns or override this behavior
|
35
|
-
examples
|
36
|
-
|
37
|
-
copy_table(old_users_without_email_hash, new_table, ['MD5(email)', 'email_hash'])
|
38
|
-
|
39
|
-
copy_table(old_users_without_total, new_table, ['sum(payments)', 'total_payments'])
|
@@ -1 +0,0 @@
|
|
1
|
-
require 'test/unit'
|