lhm 1.2.0 → 2.2.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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.rubocop.yml +256 -0
- data/.travis.yml +5 -1
- data/CHANGELOG.md +26 -0
- data/README.md +87 -8
- data/Rakefile +6 -4
- data/bin/lhm-config.sh +7 -0
- data/bin/lhm-kill-queue +13 -15
- data/bin/lhm-spec-clobber.sh +5 -4
- data/bin/lhm-spec-grants.sh +2 -2
- data/bin/lhm-spec-setup-cluster.sh +2 -3
- data/gemfiles/ar-2.3_mysql.gemfile +2 -1
- data/gemfiles/ar-3.2_mysql.gemfile +1 -1
- data/gemfiles/ar-3.2_mysql2.gemfile +1 -1
- data/gemfiles/dm_mysql.gemfile +1 -1
- data/lhm.gemspec +7 -8
- data/lib/lhm/atomic_switcher.rb +2 -1
- data/lib/lhm/chunker.rb +51 -39
- data/lib/lhm/command.rb +4 -2
- data/lib/lhm/connection.rb +14 -2
- data/lib/lhm/entangler.rb +5 -5
- data/lib/lhm/intersection.rb +29 -16
- data/lib/lhm/invoker.rb +31 -10
- data/lib/lhm/locked_switcher.rb +6 -6
- data/lib/lhm/migration.rb +7 -5
- data/lib/lhm/migrator.rb +57 -9
- data/lib/lhm/printer.rb +54 -0
- data/lib/lhm/sql_helper.rb +4 -4
- data/lib/lhm/table.rb +12 -12
- data/lib/lhm/throttler/time.rb +29 -0
- data/lib/lhm/throttler.rb +32 -0
- data/lib/lhm/version.rb +1 -1
- data/lib/lhm.rb +71 -6
- data/spec/.lhm.example +1 -1
- data/spec/README.md +20 -13
- data/spec/fixtures/lines.ddl +7 -0
- data/spec/fixtures/permissions.ddl +5 -0
- data/spec/fixtures/tracks.ddl +5 -0
- data/spec/fixtures/users.ddl +4 -2
- data/spec/integration/atomic_switcher_spec.rb +7 -7
- data/spec/integration/chunker_spec.rb +11 -5
- data/spec/integration/cleanup_spec.rb +72 -0
- data/spec/integration/entangler_spec.rb +11 -11
- data/spec/integration/integration_helper.rb +49 -17
- data/spec/integration/lhm_spec.rb +157 -37
- data/spec/integration/locked_switcher_spec.rb +7 -7
- data/spec/integration/table_spec.rb +15 -17
- data/spec/test_helper.rb +28 -0
- data/spec/unit/atomic_switcher_spec.rb +6 -6
- data/spec/unit/chunker_spec.rb +95 -73
- data/spec/unit/datamapper_connection_spec.rb +1 -0
- data/spec/unit/entangler_spec.rb +19 -19
- data/spec/unit/intersection_spec.rb +27 -15
- data/spec/unit/lhm_spec.rb +29 -0
- data/spec/unit/locked_switcher_spec.rb +14 -14
- data/spec/unit/migration_spec.rb +10 -5
- data/spec/unit/migrator_spec.rb +53 -41
- data/spec/unit/printer_spec.rb +79 -0
- data/spec/unit/sql_helper_spec.rb +10 -10
- data/spec/unit/table_spec.rb +11 -11
- data/spec/unit/throttler_spec.rb +73 -0
- data/spec/unit/unit_helper.rb +1 -13
- metadata +63 -24
- data/spec/bootstrap.rb +0 -13
data/spec/unit/chunker_spec.rb
CHANGED
@@ -6,106 +6,128 @@ require File.expand_path(File.dirname(__FILE__)) + '/unit_helper'
|
|
6
6
|
require 'lhm/table'
|
7
7
|
require 'lhm/migration'
|
8
8
|
require 'lhm/chunker'
|
9
|
+
require 'lhm/throttler'
|
9
10
|
|
10
11
|
describe Lhm::Chunker do
|
11
12
|
include UnitHelper
|
12
13
|
|
13
14
|
before(:each) do
|
14
|
-
@origin
|
15
|
-
@destination = Lhm::Table.new(
|
16
|
-
@migration
|
17
|
-
@
|
15
|
+
@origin = Lhm::Table.new('foo')
|
16
|
+
@destination = Lhm::Table.new('bar')
|
17
|
+
@migration = Lhm::Migration.new(@origin, @destination)
|
18
|
+
@connection = MiniTest::Mock.new
|
19
|
+
# This is a poor man's stub
|
20
|
+
@throttler = Object.new
|
21
|
+
def @throttler.run
|
22
|
+
# noop
|
23
|
+
end
|
24
|
+
def @throttler.stride
|
25
|
+
1
|
26
|
+
end
|
27
|
+
@chunker = Lhm::Chunker.new(@migration, @connection, :throttler => @throttler,
|
28
|
+
:start => 1,
|
29
|
+
:limit => 10)
|
18
30
|
end
|
19
31
|
|
20
|
-
describe
|
21
|
-
|
22
|
-
@
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
it "should copy the correct range and column" do
|
27
|
-
@chunker.copy(from = 1, to = 100).must_equal(
|
28
|
-
"insert ignore into `destination` (`secret`) " +
|
29
|
-
"select `secret` from `origin` " +
|
30
|
-
"where `id` between 1 and 100"
|
31
|
-
)
|
32
|
-
end
|
33
|
-
end
|
32
|
+
describe '#run' do
|
33
|
+
it 'chunks the result set according to the stride size' do
|
34
|
+
def @throttler.stride
|
35
|
+
2
|
36
|
+
end
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
@connection.expect(:update, 2) do |stmt|
|
39
|
+
stmt.first =~ /between 1 and 2/
|
40
|
+
end
|
41
|
+
@connection.expect(:update, 2) do |stmt|
|
42
|
+
stmt.first =~ /between 3 and 4/
|
43
|
+
end
|
44
|
+
@connection.expect(:update, 2) do |stmt|
|
45
|
+
stmt.first =~ /between 5 and 6/
|
46
|
+
end
|
47
|
+
@connection.expect(:update, 2) do |stmt|
|
48
|
+
stmt.first =~ /between 7 and 8/
|
49
|
+
end
|
50
|
+
@connection.expect(:update, 2) do |stmt|
|
51
|
+
stmt.first =~ /between 9 and 10/
|
52
|
+
end
|
39
53
|
|
40
|
-
|
41
|
-
@
|
54
|
+
@chunker.run
|
55
|
+
@connection.verify
|
42
56
|
end
|
43
57
|
|
44
|
-
it
|
45
|
-
|
46
|
-
|
58
|
+
it 'handles stride changes during execution' do
|
59
|
+
# roll our own stubbing
|
60
|
+
def @throttler.stride
|
61
|
+
@run_count ||= 0
|
62
|
+
@run_count = @run_count + 1
|
63
|
+
if @run_count > 1
|
64
|
+
3
|
65
|
+
else
|
66
|
+
2
|
67
|
+
end
|
47
68
|
end
|
48
|
-
end
|
49
|
-
end
|
50
69
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
70
|
+
@connection.expect(:update, 2) do |stmt|
|
71
|
+
stmt.first =~ /between 1 and 2/
|
72
|
+
end
|
73
|
+
@connection.expect(:update, 2) do |stmt|
|
74
|
+
stmt.first =~ /between 3 and 5/
|
75
|
+
end
|
76
|
+
@connection.expect(:update, 2) do |stmt|
|
77
|
+
stmt.first =~ /between 6 and 8/
|
78
|
+
end
|
79
|
+
@connection.expect(:update, 2) do |stmt|
|
80
|
+
stmt.first =~ /between 9 and 10/
|
81
|
+
end
|
57
82
|
|
58
|
-
|
59
|
-
@
|
83
|
+
@chunker.run
|
84
|
+
@connection.verify
|
60
85
|
end
|
61
86
|
|
62
|
-
it
|
63
|
-
@chunker
|
64
|
-
|
87
|
+
it 'correctly copies single record tables' do
|
88
|
+
@chunker = Lhm::Chunker.new(@migration, @connection, :throttler => @throttler,
|
89
|
+
:start => 1,
|
90
|
+
:limit => 1)
|
65
91
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
92
|
+
@connection.expect(:update, 1) do |stmt|
|
93
|
+
stmt.first =~ /between 1 and 1/
|
94
|
+
end
|
70
95
|
|
71
|
-
|
72
|
-
|
73
|
-
@chunker = Lhm::Chunker.new(@migration, nil, {
|
74
|
-
:stride => 100_000, :start => 2, :limit => 150_000
|
75
|
-
})
|
96
|
+
@chunker.run
|
97
|
+
@connection.verify
|
76
98
|
end
|
77
99
|
|
78
|
-
it
|
79
|
-
@chunker.
|
80
|
-
|
100
|
+
it 'separates filter conditions from chunking conditions' do
|
101
|
+
@chunker = Lhm::Chunker.new(@migration, @connection, :throttler => @throttler,
|
102
|
+
:start => 1,
|
103
|
+
:limit => 2)
|
104
|
+
@connection.expect(:update, 1) do |stmt|
|
105
|
+
stmt.first =~ /where \(foo.created_at > '2013-07-10' or foo.baz = 'quux'\) and `foo`/
|
106
|
+
end
|
81
107
|
|
82
|
-
|
83
|
-
|
84
|
-
|
108
|
+
def @migration.conditions
|
109
|
+
"where foo.created_at > '2013-07-10' or foo.baz = 'quux'"
|
110
|
+
end
|
85
111
|
|
86
|
-
|
87
|
-
@
|
112
|
+
@chunker.run
|
113
|
+
@connection.verify
|
88
114
|
end
|
89
|
-
end
|
90
115
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
116
|
+
it "doesn't mess with inner join filters" do
|
117
|
+
@chunker = Lhm::Chunker.new(@migration, @connection, :throttler => @throttler,
|
118
|
+
:start => 1,
|
119
|
+
:limit => 2)
|
120
|
+
@connection.expect(:update, 1) do |stmt|
|
121
|
+
puts stmt
|
122
|
+
stmt.first =~ /inner join bar on foo.id = bar.foo_id and/
|
123
|
+
end
|
97
124
|
|
98
|
-
|
99
|
-
|
100
|
-
bottom.must_equal 53
|
101
|
-
top.must_equal 121
|
125
|
+
def @migration.conditions
|
126
|
+
'inner join bar on foo.id = bar.foo_id'
|
102
127
|
end
|
103
|
-
end
|
104
|
-
end
|
105
128
|
|
106
|
-
|
107
|
-
|
108
|
-
@chunker.throttle_seconds.must_equal 0.1
|
129
|
+
@chunker.run
|
130
|
+
@connection.verify
|
109
131
|
end
|
110
132
|
end
|
111
133
|
end
|
data/spec/unit/entangler_spec.rb
CHANGED
@@ -11,44 +11,44 @@ describe Lhm::Entangler do
|
|
11
11
|
include UnitHelper
|
12
12
|
|
13
13
|
before(:each) do
|
14
|
-
@origin = Lhm::Table.new(
|
15
|
-
@destination = Lhm::Table.new(
|
14
|
+
@origin = Lhm::Table.new('origin')
|
15
|
+
@destination = Lhm::Table.new('destination')
|
16
16
|
@migration = Lhm::Migration.new(@origin, @destination)
|
17
17
|
@entangler = Lhm::Entangler.new(@migration)
|
18
18
|
end
|
19
19
|
|
20
|
-
describe
|
20
|
+
describe 'activation' do
|
21
21
|
before(:each) do
|
22
|
-
@origin.columns[
|
23
|
-
@origin.columns[
|
22
|
+
@origin.columns['info'] = { :type => 'varchar(255)' }
|
23
|
+
@origin.columns['tags'] = { :type => 'varchar(255)' }
|
24
24
|
|
25
|
-
@destination.columns[
|
26
|
-
@destination.columns[
|
25
|
+
@destination.columns['info'] = { :type => 'varchar(255)' }
|
26
|
+
@destination.columns['tags'] = { :type => 'varchar(255)' }
|
27
27
|
end
|
28
28
|
|
29
|
-
it
|
29
|
+
it 'should create insert trigger to destination table' do
|
30
30
|
ddl = %Q{
|
31
31
|
create trigger `lhmt_ins_origin`
|
32
32
|
after insert on `origin` for each row
|
33
33
|
replace into `destination` (`info`, `tags`) /* large hadron migration */
|
34
|
-
values (NEW
|
34
|
+
values (`NEW`.`info`, `NEW`.`tags`)
|
35
35
|
}
|
36
36
|
|
37
37
|
@entangler.entangle.must_include strip(ddl)
|
38
38
|
end
|
39
39
|
|
40
|
-
it
|
40
|
+
it 'should create an update trigger to the destination table' do
|
41
41
|
ddl = %Q{
|
42
42
|
create trigger `lhmt_upd_origin`
|
43
43
|
after update on `origin` for each row
|
44
44
|
replace into `destination` (`info`, `tags`) /* large hadron migration */
|
45
|
-
values (NEW
|
45
|
+
values (`NEW`.`info`, `NEW`.`tags`)
|
46
46
|
}
|
47
47
|
|
48
48
|
@entangler.entangle.must_include strip(ddl)
|
49
49
|
end
|
50
50
|
|
51
|
-
it
|
51
|
+
it 'should create a delete trigger to the destination table' do
|
52
52
|
ddl = %Q{
|
53
53
|
create trigger `lhmt_del_origin`
|
54
54
|
after delete on `origin` for each row
|
@@ -60,17 +60,17 @@ describe Lhm::Entangler do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
describe
|
64
|
-
it
|
65
|
-
@entangler.untangle.must_include(
|
63
|
+
describe 'removal' do
|
64
|
+
it 'should remove insert trigger' do
|
65
|
+
@entangler.untangle.must_include('drop trigger if exists `lhmt_ins_origin`')
|
66
66
|
end
|
67
67
|
|
68
|
-
it
|
69
|
-
@entangler.untangle.must_include(
|
68
|
+
it 'should remove update trigger' do
|
69
|
+
@entangler.untangle.must_include('drop trigger if exists `lhmt_upd_origin`')
|
70
70
|
end
|
71
71
|
|
72
|
-
it
|
73
|
-
@entangler.untangle.must_include(
|
72
|
+
it 'should remove delete trigger' do
|
73
|
+
@entangler.untangle.must_include('drop trigger if exists `lhmt_del_origin`')
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -9,31 +9,43 @@ require 'lhm/migrator'
|
|
9
9
|
describe Lhm::Intersection do
|
10
10
|
include UnitHelper
|
11
11
|
|
12
|
-
it
|
13
|
-
origin = Lhm::Table.new(
|
14
|
-
origin.columns[
|
15
|
-
origin.columns[
|
12
|
+
it 'should not have dropped changes' do
|
13
|
+
origin = Lhm::Table.new('origin')
|
14
|
+
origin.columns['dropped'] = varchar
|
15
|
+
origin.columns['retained'] = varchar
|
16
16
|
|
17
|
-
destination = Lhm::Table.new(
|
18
|
-
destination.columns[
|
17
|
+
destination = Lhm::Table.new('destination')
|
18
|
+
destination.columns['retained'] = varchar
|
19
19
|
|
20
20
|
intersection = Lhm::Intersection.new(origin, destination)
|
21
|
-
intersection.
|
21
|
+
intersection.destination.include?('dropped').must_equal(false)
|
22
22
|
end
|
23
23
|
|
24
|
-
it
|
25
|
-
origin = Lhm::Table.new(
|
26
|
-
origin.columns[
|
27
|
-
origin.columns[
|
24
|
+
it 'should have unchanged columns' do
|
25
|
+
origin = Lhm::Table.new('origin')
|
26
|
+
origin.columns['dropped'] = varchar
|
27
|
+
origin.columns['retained'] = varchar
|
28
28
|
|
29
|
-
destination = Lhm::Table.new(
|
30
|
-
destination.columns[
|
29
|
+
destination = Lhm::Table.new('destination')
|
30
|
+
destination.columns['retained'] = varchar
|
31
31
|
|
32
32
|
intersection = Lhm::Intersection.new(origin, destination)
|
33
|
-
intersection.
|
33
|
+
intersection.destination.must_equal(['retained'])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should have renamed columns' do
|
37
|
+
origin = Lhm::Table.new('origin')
|
38
|
+
origin.columns['old_name'] = varchar
|
39
|
+
|
40
|
+
destination = Lhm::Table.new('destination')
|
41
|
+
destination.columns['new_name'] = varchar
|
42
|
+
|
43
|
+
intersection = Lhm::Intersection.new(origin, destination, { 'old_name' => 'new_name' })
|
44
|
+
intersection.origin.must_equal(['old_name'])
|
45
|
+
intersection.destination.must_equal(['new_name'])
|
34
46
|
end
|
35
47
|
|
36
48
|
def varchar
|
37
|
-
{ :metadata =>
|
49
|
+
{ :metadata => 'VARCHAR(255)' }
|
38
50
|
end
|
39
51
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright (c) 2011 - 2013, SoundCloud Ltd.
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__)) + '/unit_helper'
|
4
|
+
|
5
|
+
describe Lhm do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Lhm.remove_class_variable :@@logger if Lhm.class_variable_defined? :@@logger
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'logger' do
|
12
|
+
|
13
|
+
it 'should use the default parameters if no logger explicitly set' do
|
14
|
+
Lhm.logger.must_be_kind_of Logger
|
15
|
+
Lhm.logger.level.must_equal Logger::INFO
|
16
|
+
Lhm.logger.instance_eval { @logdev }.dev.must_equal STDOUT
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should use s new logger if set' do
|
20
|
+
l = Logger.new('omg.ponies')
|
21
|
+
l.level = Logger::ERROR
|
22
|
+
Lhm.logger = l
|
23
|
+
|
24
|
+
Lhm.logger.level.must_equal Logger::ERROR
|
25
|
+
Lhm.logger.instance_eval { @logdev }.dev.must_be_kind_of File
|
26
|
+
Lhm.logger.instance_eval { @logdev }.dev.path.must_equal 'omg.ponies'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -12,39 +12,39 @@ describe Lhm::LockedSwitcher do
|
|
12
12
|
|
13
13
|
before(:each) do
|
14
14
|
@start = Time.now
|
15
|
-
@origin = Lhm::Table.new(
|
16
|
-
@destination = Lhm::Table.new(
|
15
|
+
@origin = Lhm::Table.new('origin')
|
16
|
+
@destination = Lhm::Table.new('destination')
|
17
17
|
@migration = Lhm::Migration.new(@origin, @destination, @start)
|
18
18
|
@switcher = Lhm::LockedSwitcher.new(@migration, nil)
|
19
19
|
end
|
20
20
|
|
21
|
-
describe
|
22
|
-
it
|
21
|
+
describe 'uncommitted' do
|
22
|
+
it 'should disable autocommit first' do
|
23
23
|
@switcher.
|
24
24
|
statements[0..1].
|
25
25
|
must_equal([
|
26
|
-
|
27
|
-
|
26
|
+
'set @lhm_auto_commit = @@session.autocommit',
|
27
|
+
'set session autocommit = 0'
|
28
28
|
])
|
29
29
|
end
|
30
30
|
|
31
|
-
it
|
31
|
+
it 'should reapply original autocommit settings at the end' do
|
32
32
|
@switcher.
|
33
33
|
statements[-1].
|
34
|
-
must_equal(
|
34
|
+
must_equal('set session autocommit = @lhm_auto_commit')
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
describe
|
39
|
-
it
|
38
|
+
describe 'switch' do
|
39
|
+
it 'should lock origin and destination table, switch, commit and unlock' do
|
40
40
|
@switcher.
|
41
41
|
switch.
|
42
42
|
must_equal([
|
43
|
-
|
43
|
+
'lock table `origin` write, `destination` write',
|
44
44
|
"alter table `origin` rename `#{ @migration.archive_name }`",
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
'alter table `destination` rename `origin`',
|
46
|
+
'commit',
|
47
|
+
'unlock tables'
|
48
48
|
])
|
49
49
|
end
|
50
50
|
end
|
data/spec/unit/migration_spec.rb
CHANGED
@@ -11,13 +11,18 @@ describe Lhm::Migration do
|
|
11
11
|
|
12
12
|
before(:each) do
|
13
13
|
@start = Time.now
|
14
|
-
@origin = Lhm::Table.new(
|
15
|
-
@destination = Lhm::Table.new(
|
16
|
-
@migration = Lhm::Migration.new(@origin, @destination, @start)
|
14
|
+
@origin = Lhm::Table.new('origin')
|
15
|
+
@destination = Lhm::Table.new('destination')
|
16
|
+
@migration = Lhm::Migration.new(@origin, @destination, nil, @start)
|
17
17
|
end
|
18
18
|
|
19
|
-
it
|
20
|
-
stamp = "%Y_%m_%d_%H_%M_%S_#{
|
19
|
+
it 'should name archive' do
|
20
|
+
stamp = "%Y_%m_%d_%H_%M_%S_#{ '%03d' % (@start.usec / 1000) }"
|
21
21
|
@migration.archive_name.must_equal "lhma_#{ @start.strftime(stamp) }_origin"
|
22
22
|
end
|
23
|
+
|
24
|
+
it 'should limit table name to 64 characters' do
|
25
|
+
migration = Lhm::Migration.new(OpenStruct.new(:name => 'a_very_very_long_table_name_that_should_make_the_LHMA_table_go_over_64_chars'), nil)
|
26
|
+
migration.archive_name.size == 64
|
27
|
+
end
|
23
28
|
end
|
data/spec/unit/migrator_spec.rb
CHANGED
@@ -10,125 +10,137 @@ describe Lhm::Migrator do
|
|
10
10
|
include UnitHelper
|
11
11
|
|
12
12
|
before(:each) do
|
13
|
-
@table = Lhm::Table.new(
|
13
|
+
@table = Lhm::Table.new('alt')
|
14
14
|
@creator = Lhm::Migrator.new(@table)
|
15
15
|
end
|
16
16
|
|
17
|
-
describe
|
18
|
-
it
|
17
|
+
describe 'index changes' do
|
18
|
+
it 'should add an index' do
|
19
19
|
@creator.add_index(:a)
|
20
20
|
|
21
21
|
@creator.statements.must_equal([
|
22
|
-
|
22
|
+
'create index `index_alt_on_a` on `lhmn_alt` (`a`)'
|
23
23
|
])
|
24
24
|
end
|
25
25
|
|
26
|
-
it
|
26
|
+
it 'should add a composite index' do
|
27
27
|
@creator.add_index([:a, :b])
|
28
28
|
|
29
29
|
@creator.statements.must_equal([
|
30
|
-
|
30
|
+
'create index `index_alt_on_a_and_b` on `lhmn_alt` (`a`, `b`)'
|
31
31
|
])
|
32
32
|
end
|
33
33
|
|
34
|
-
it
|
35
|
-
@creator.add_index([
|
34
|
+
it 'should add an index with prefix length' do
|
35
|
+
@creator.add_index(['a(10)', 'b'])
|
36
36
|
|
37
37
|
@creator.statements.must_equal([
|
38
|
-
|
38
|
+
'create index `index_alt_on_a_and_b` on `lhmn_alt` (`a`(10), `b`)'
|
39
39
|
])
|
40
40
|
end
|
41
41
|
|
42
|
-
it
|
42
|
+
it 'should add an index with a custom name' do
|
43
43
|
@creator.add_index([:a, :b], :custom_index_name)
|
44
44
|
|
45
45
|
@creator.statements.must_equal([
|
46
|
-
|
46
|
+
'create index `custom_index_name` on `lhmn_alt` (`a`, `b`)'
|
47
47
|
])
|
48
48
|
end
|
49
49
|
|
50
|
-
it
|
51
|
-
|
50
|
+
it 'should raise an error when the index name is not a string or symbol' do
|
51
|
+
assert_raises ArgumentError do
|
52
|
+
@creator.add_index([:a, :b], :name => :custom_index_name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should add a unique index' do
|
57
|
+
@creator.add_unique_index(['a(5)', :b])
|
52
58
|
|
53
59
|
@creator.statements.must_equal([
|
54
|
-
|
60
|
+
'create unique index `index_alt_on_a_and_b` on `lhmn_alt` (`a`(5), `b`)'
|
55
61
|
])
|
56
62
|
end
|
57
63
|
|
58
|
-
it
|
64
|
+
it 'should add a unique index with a custom name' do
|
59
65
|
@creator.add_unique_index([:a, :b], :custom_index_name)
|
60
66
|
|
61
67
|
@creator.statements.must_equal([
|
62
|
-
|
68
|
+
'create unique index `custom_index_name` on `lhmn_alt` (`a`, `b`)'
|
63
69
|
])
|
64
70
|
end
|
65
71
|
|
66
|
-
it
|
67
|
-
|
72
|
+
it 'should raise an error when the unique index name is not a string or symbol' do
|
73
|
+
assert_raises ArgumentError do
|
74
|
+
@creator.add_unique_index([:a, :b], :name => :custom_index_name)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should remove an index' do
|
79
|
+
@creator.remove_index(['b', 'a'])
|
68
80
|
|
69
81
|
@creator.statements.must_equal([
|
70
|
-
|
82
|
+
'drop index `index_alt_on_b_and_a` on `lhmn_alt`'
|
71
83
|
])
|
72
84
|
end
|
73
85
|
|
74
|
-
it
|
86
|
+
it 'should remove an index with a custom name' do
|
75
87
|
@creator.remove_index([:a, :b], :custom_index_name)
|
76
88
|
|
77
89
|
@creator.statements.must_equal([
|
78
|
-
|
90
|
+
'drop index `custom_index_name` on `lhmn_alt`'
|
79
91
|
])
|
80
92
|
end
|
81
93
|
end
|
82
94
|
|
83
|
-
describe
|
84
|
-
it
|
85
|
-
@creator.add_column(
|
95
|
+
describe 'column changes' do
|
96
|
+
it 'should add a column' do
|
97
|
+
@creator.add_column('logins', 'INT(12)')
|
86
98
|
|
87
99
|
@creator.statements.must_equal([
|
88
|
-
|
100
|
+
'alter table `lhmn_alt` add column `logins` INT(12)'
|
89
101
|
])
|
90
102
|
end
|
91
103
|
|
92
|
-
it
|
93
|
-
@creator.remove_column(
|
104
|
+
it 'should remove a column' do
|
105
|
+
@creator.remove_column('logins')
|
94
106
|
|
95
107
|
@creator.statements.must_equal([
|
96
|
-
|
108
|
+
'alter table `lhmn_alt` drop `logins`'
|
97
109
|
])
|
98
110
|
end
|
99
111
|
|
100
|
-
it
|
101
|
-
@creator.change_column(
|
112
|
+
it 'should change a column' do
|
113
|
+
@creator.change_column('logins', 'INT(11)')
|
102
114
|
|
103
115
|
@creator.statements.must_equal([
|
104
|
-
|
116
|
+
'alter table `lhmn_alt` modify column `logins` INT(11)'
|
105
117
|
])
|
106
118
|
end
|
107
119
|
end
|
108
120
|
|
109
|
-
describe
|
110
|
-
it
|
111
|
-
ddl = @creator.ddl(
|
121
|
+
describe 'direct changes' do
|
122
|
+
it 'should accept a ddl statement' do
|
123
|
+
ddl = @creator.ddl('alter table `%s` add column `f` tinyint(1)' % @creator.name)
|
112
124
|
|
113
125
|
@creator.statements.must_equal([
|
114
|
-
|
126
|
+
'alter table `lhmn_alt` add column `f` tinyint(1)'
|
115
127
|
])
|
116
128
|
end
|
117
129
|
end
|
118
130
|
|
119
|
-
describe
|
120
|
-
it
|
121
|
-
@creator.add_column(
|
122
|
-
@creator.add_column(
|
131
|
+
describe 'multiple changes' do
|
132
|
+
it 'should add two columns' do
|
133
|
+
@creator.add_column('first', 'VARCHAR(64)')
|
134
|
+
@creator.add_column('last', 'VARCHAR(64)')
|
123
135
|
@creator.statements.length.must_equal(2)
|
124
136
|
|
125
137
|
@creator.
|
126
138
|
statements[0].
|
127
|
-
must_equal(
|
139
|
+
must_equal('alter table `lhmn_alt` add column `first` VARCHAR(64)')
|
128
140
|
|
129
141
|
@creator.
|
130
142
|
statements[1].
|
131
|
-
must_equal(
|
143
|
+
must_equal('alter table `lhmn_alt` add column `last` VARCHAR(64)')
|
132
144
|
end
|
133
145
|
end
|
134
146
|
end
|