convergence 1.0.6 → 1.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 +4 -4
- data/.github/workflows/ruby.yml +35 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +57 -0
- data/CONTRIBUTING.md +80 -0
- data/Gemfile.lock +25 -9
- data/README.md +160 -1
- data/Rakefile +45 -2
- data/convergence.gemspec +5 -1
- data/lib/convergence/cli.rb +10 -2
- data/lib/convergence/column.rb +3 -2
- data/lib/convergence/command/apply.rb +38 -9
- data/lib/convergence/command/dryrun.rb +5 -5
- data/lib/convergence/command/export.rb +19 -1
- data/lib/convergence/command.rb +6 -0
- data/lib/convergence/database_connector/postgres_connector.rb +25 -0
- data/lib/convergence/database_connector/sqlite_connector.rb +22 -0
- data/lib/convergence/database_connector.rb +6 -0
- data/lib/convergence/default_parameter/mysql_default_parameter.rb +1 -1
- data/lib/convergence/default_parameter/postgres_default_parameter.rb +57 -0
- data/lib/convergence/default_parameter/sqlite_default_parameter.rb +57 -0
- data/lib/convergence/default_parameter.rb +6 -0
- data/lib/convergence/diff.rb +46 -3
- data/lib/convergence/dsl.rb +18 -3
- data/lib/convergence/dumper/mysql_schema_dumper.rb +37 -9
- data/lib/convergence/dumper/postgres_schema_dumper.rb +193 -0
- data/lib/convergence/dumper/sqlite_schema_dumper.rb +132 -0
- data/lib/convergence/dumper.rb +113 -0
- data/lib/convergence/sql_generator/mysql_generator.rb +32 -3
- data/lib/convergence/sql_generator/postgres_generator.rb +270 -0
- data/lib/convergence/sql_generator/sqlite_generator.rb +192 -0
- data/lib/convergence/table.rb +3 -2
- data/lib/convergence/version.rb +1 -1
- data/spec/config/spec_database.yml +12 -0
- data/spec/convergence/config_spec.rb +75 -0
- data/spec/convergence/diff_spec.rb +291 -44
- data/spec/convergence/dsl_spec.rb +26 -0
- data/spec/convergence/dumper/mysql_schema_dumper_spec.rb +25 -2
- data/spec/convergence/dumper/postgres_schema_dumper_spec.rb +103 -0
- data/spec/convergence/dumper/sqlite_schema_dumper_spec.rb +85 -0
- data/spec/convergence/dumper_spec.rb +110 -16
- data/spec/convergence/foreign_key_spec.rb +33 -0
- data/spec/convergence/index_spec.rb +52 -0
- data/spec/convergence/pretty_diff_spec.rb +85 -0
- data/spec/convergence/table_spec.rb +46 -0
- data/spec/fixtures/add_table_with_enum_set.schema +5 -0
- data/spec/fixtures/change_table_comment_to_paper.schema +2 -0
- data/spec/fixtures/execute_raw_sql.schema +28 -0
- data/spec/fixtures/postgres/add_columns_to_paper.schema +29 -0
- data/spec/fixtures/postgres/add_table.schema +32 -0
- data/spec/fixtures/postgres/change_comment_columns_to_paper.schema +28 -0
- data/spec/fixtures/postgres/change_table_comment_to_paper.schema +28 -0
- data/spec/fixtures/postgres/drop_foreign_key.schema +25 -0
- data/spec/fixtures/postgres/drop_table.schema +19 -0
- data/spec/fixtures/postgres/remove_columns_to_paper.schema +27 -0
- data/spec/fixtures/postgres/rename_column_on_paper.schema +28 -0
- data/spec/fixtures/postgres/rename_table.schema +28 -0
- data/spec/fixtures/postgres_test_db.sql +41 -0
- data/spec/fixtures/rename_column_to_author.schema +26 -0
- data/spec/fixtures/rename_table.schema +26 -0
- data/spec/fixtures/sqlite/add_columns_to_paper.schema +29 -0
- data/spec/fixtures/sqlite/add_table.schema +32 -0
- data/spec/fixtures/sqlite/change_columns_to_paper.schema +28 -0
- data/spec/fixtures/sqlite/drop_foreign_key.schema +25 -0
- data/spec/fixtures/sqlite/drop_table.schema +19 -0
- data/spec/fixtures/sqlite/remove_columns_to_paper.schema +27 -0
- data/spec/fixtures/sqlite/rename_column_on_paper.schema +28 -0
- data/spec/fixtures/sqlite/rename_table.schema +27 -0
- data/spec/fixtures/sqlite_test_db.sql +31 -0
- data/spec/fixtures/test_db.sql +10 -0
- data/spec/integrations/command_diff.rb +35 -0
- data/spec/integrations/command_dryrun.rb +59 -2
- data/spec/integrations/command_export.rb +28 -0
- data/spec/postgres_integrations/command_dryrun.rb +101 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/sqlite_integrations/command_dryrun.rb +92 -0
- metadata +135 -7
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'convergence/dumper/sqlite_schema_dumper'
|
|
3
|
+
require 'convergence/database_connector'
|
|
4
|
+
|
|
5
|
+
describe Convergence::Dumper::SqliteSchemaDumper do
|
|
6
|
+
let(:connector) do
|
|
7
|
+
Convergence::DatabaseConnector.new(sqlite_settings)
|
|
8
|
+
end
|
|
9
|
+
let(:dumper) do
|
|
10
|
+
Convergence::Dumper::SqliteSchemaDumper.new(connector)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#dump' do
|
|
14
|
+
subject { dumper.dump }
|
|
15
|
+
|
|
16
|
+
it 'should be dump tables' do
|
|
17
|
+
expect(subject['papers']).not_to be_nil
|
|
18
|
+
expect(subject['authors']).not_to be_nil
|
|
19
|
+
expect(subject['paper_authors']).not_to be_nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe 'table columns' do
|
|
23
|
+
it 'should be dump table columns' do
|
|
24
|
+
papers = subject['papers']
|
|
25
|
+
expect(papers.columns['id']).not_to be_nil
|
|
26
|
+
expect(papers.columns['slug']).not_to be_nil
|
|
27
|
+
expect(papers.columns['title1']).not_to be_nil
|
|
28
|
+
expect(papers.columns['title2']).not_to be_nil
|
|
29
|
+
expect(papers.columns['description']).not_to be_nil
|
|
30
|
+
expect(papers.columns['edition_number']).not_to be_nil
|
|
31
|
+
expect(papers.columns['published_at']).not_to be_nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe 'table column options' do
|
|
35
|
+
it 'should be dump primary key as auto_increment' do
|
|
36
|
+
expect(subject['papers'].columns['id'].options[:primary_key]).to be_truthy
|
|
37
|
+
expect(subject['papers'].columns['id'].options[:extra]).to eq('auto_increment')
|
|
38
|
+
expect(subject['papers'].columns['id'].options[:null]).to be_falsy
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'should be dump limit' do
|
|
42
|
+
expect(subject['papers'].columns['title1'].options[:limit]).to eq('300')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'should be dump not null definition' do
|
|
46
|
+
expect(subject['papers'].columns['title1'].options[:null]).to be_falsy
|
|
47
|
+
expect(subject['authors'].columns['created_at'].options[:null]).to be_truthy
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'should be dump default' do
|
|
51
|
+
expect(subject['papers'].columns['edition_number'].options[:default]).to eq('0')
|
|
52
|
+
expect(subject['papers'].columns['published_at'].options[:default])
|
|
53
|
+
.to be_a(Proc)
|
|
54
|
+
.and have_attributes(call: 'CURRENT_TIMESTAMP')
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe 'indexes' do
|
|
60
|
+
it 'should be dump index of authors' do
|
|
61
|
+
index = subject['authors'].indexes['index_authors_on_created_at']
|
|
62
|
+
expect(index).not_to be_nil
|
|
63
|
+
expect(index.index_columns).to eq(['created_at'])
|
|
64
|
+
expect(index.options[:unique]).to eq(false)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'should be dump unique index of papers' do
|
|
68
|
+
index = subject['papers'].indexes['index_papers_on_slug']
|
|
69
|
+
expect(index).not_to be_nil
|
|
70
|
+
expect(index.index_columns).to eq(['slug'])
|
|
71
|
+
expect(index.options[:unique]).to eq(true)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe 'foreign keys' do
|
|
76
|
+
it 'should be dump the foreign key with its original constraint name' do
|
|
77
|
+
foreign_key = subject['paper_authors'].foreign_keys['paper_authors_author_id_fk']
|
|
78
|
+
expect(foreign_key).not_to be_nil
|
|
79
|
+
expect(foreign_key.from_columns).to eq(['author_id'])
|
|
80
|
+
expect(foreign_key.to_table).to eq('authors')
|
|
81
|
+
expect(foreign_key.to_columns).to eq(['id'])
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -13,15 +13,15 @@ describe Convergence::Dumper do
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
let(:table1_dsl) do
|
|
16
|
-
dsl =
|
|
17
|
-
create_table :dummy_table, engine: "MyISAM" do |t|
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
dsl = <<~DSL
|
|
17
|
+
create_table :dummy_table, engine: "MyISAM" do |t|
|
|
18
|
+
t.int :id, limit: 11
|
|
19
|
+
t.varchar :name, limit: 100, null: true, comment: "name"
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
end
|
|
24
|
-
|
|
21
|
+
t.index :name, name: "idx_name"
|
|
22
|
+
t.foreign_key :id, reference: :dummy_ref, reference_column: :id, name: "dummy_table_id_fk"
|
|
23
|
+
end
|
|
24
|
+
DSL
|
|
25
25
|
dsl.strip
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -51,15 +51,15 @@ end
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
let(:table1_dsl) do
|
|
54
|
-
dsl =
|
|
55
|
-
create_table :"dummy-table", engine: "MyISAM" do |t|
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
dsl = <<~DSL
|
|
55
|
+
create_table :"dummy-table", engine: "MyISAM" do |t|
|
|
56
|
+
t.int :id, limit: 11
|
|
57
|
+
t.varchar :"column-1", limit: 100, null: true, comment: "column 1"
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
end
|
|
62
|
-
|
|
59
|
+
t.index :"column-1", name: "idx_column-1"
|
|
60
|
+
t.foreign_key :"column-1", reference: :"dummy-ref", reference_column: :"dummy-column", name: "dummy-table_column-1_fk"
|
|
61
|
+
end
|
|
62
|
+
DSL
|
|
63
63
|
dsl.strip
|
|
64
64
|
end
|
|
65
65
|
|
|
@@ -68,5 +68,99 @@ end
|
|
|
68
68
|
expect(dsl).to eq(table1_dsl)
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
|
+
|
|
72
|
+
context "when the table column has default option with proc" do
|
|
73
|
+
let(:table1) do
|
|
74
|
+
Convergence::Table.new('dummy_table').tap do |t|
|
|
75
|
+
t.int :edition_number, default: 0
|
|
76
|
+
t.datetime :created_at, default: -> { "CURRENT_TIMESTAMP" }
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
let(:table1_dsl) do
|
|
81
|
+
dsl = <<~DSL
|
|
82
|
+
create_table :dummy_table do |t|
|
|
83
|
+
t.int :edition_number, default: 0
|
|
84
|
+
t.datetime :created_at, default: -> { "CURRENT_TIMESTAMP" }
|
|
85
|
+
end
|
|
86
|
+
DSL
|
|
87
|
+
dsl.strip
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it 'should be able to dump dsl' do
|
|
91
|
+
dsl = Convergence::Dumper.new.dump_table_dsl(table1)
|
|
92
|
+
expect(dsl).to eq(table1_dsl)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe '#dump_rails_migration' do
|
|
98
|
+
let(:table1) do
|
|
99
|
+
Convergence::Table.new('dummy_table', engine: 'MyISAM').tap do |t|
|
|
100
|
+
t.int :id, primary_key: true, extra: 'auto_increment'
|
|
101
|
+
t.varchar :name, limit: 100, null: true, comment: 'name'
|
|
102
|
+
t.datetime :created_at, null: false
|
|
103
|
+
t.datetime :updated_at, null: false
|
|
104
|
+
|
|
105
|
+
t.index :name, name: 'idx_name'
|
|
106
|
+
t.foreign_key :id, reference: 'dummy_ref', reference_column: :id
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
let(:migration_dsl) do
|
|
111
|
+
dsl = <<~DSL
|
|
112
|
+
class DummyMigration < ActiveRecord::Migration[7.0]
|
|
113
|
+
def change
|
|
114
|
+
create_table :dummy_table do |t|
|
|
115
|
+
t.string :name, limit: 100, null: true, comment: "name"
|
|
116
|
+
t.timestamps null: false
|
|
117
|
+
t.index :name, name: "idx_name"
|
|
118
|
+
t.foreign_key :dummy_ref, column: :id, name: "dummy_table_id_fk"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
DSL
|
|
123
|
+
dsl.strip
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'omits the implicit auto-increment id column' do
|
|
127
|
+
migration = Convergence::Dumper.new.dump_rails_migration({ 'dummy_table' => table1 }, 'DummyMigration')
|
|
128
|
+
expect(migration).to eq(migration_dsl)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'collapses created_at/updated_at into t.timestamps' do
|
|
132
|
+
migration = Convergence::Dumper.new.dump_rails_migration({ 'dummy_table' => table1 }, 'DummyMigration')
|
|
133
|
+
expect(migration).to be_include('t.timestamps null: false')
|
|
134
|
+
expect(migration).not_to be_include('t.datetime :created_at')
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
context 'when the column is a MySQL tinyint(1) boolean' do
|
|
138
|
+
let(:table1) do
|
|
139
|
+
Convergence::Table.new('dummy_table').tap do |t|
|
|
140
|
+
t.boolean :active, default: true
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it 'maps it to a native boolean column' do
|
|
145
|
+
migration = Convergence::Dumper.new.dump_rails_migration({ 'dummy_table' => table1 }, 'DummyMigration')
|
|
146
|
+
expect(migration).to be_include('t.boolean :active, default: true')
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
context 'when created_at/updated_at have mismatched null options' do
|
|
151
|
+
let(:table1) do
|
|
152
|
+
Convergence::Table.new('dummy_table').tap do |t|
|
|
153
|
+
t.datetime :created_at, null: false
|
|
154
|
+
t.datetime :updated_at, null: true
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it 'keeps them as separate columns instead of collapsing into t.timestamps' do
|
|
159
|
+
migration = Convergence::Dumper.new.dump_rails_migration({ 'dummy_table' => table1 }, 'DummyMigration')
|
|
160
|
+
expect(migration).not_to be_include('t.timestamps')
|
|
161
|
+
expect(migration).to be_include('t.datetime :created_at, null: false')
|
|
162
|
+
expect(migration).to be_include('t.datetime :updated_at, null: true')
|
|
163
|
+
end
|
|
164
|
+
end
|
|
71
165
|
end
|
|
72
166
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'convergence/foreign_key'
|
|
3
|
+
|
|
4
|
+
describe Convergence::ForeignKey do
|
|
5
|
+
describe '#initialize' do
|
|
6
|
+
it 'wraps a single from_column/to_column into an array of strings' do
|
|
7
|
+
fk = Convergence::ForeignKey.new('fk_name', :author_id, 'authors', :id, {})
|
|
8
|
+
expect(fk.from_columns).to eq(['author_id'])
|
|
9
|
+
expect(fk.to_columns).to eq(['id'])
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'wraps multiple from_columns/to_columns into arrays of strings' do
|
|
13
|
+
fk = Convergence::ForeignKey.new('fk_name', [:a_id, :b_id], 'targets', [:a, :b], {})
|
|
14
|
+
expect(fk.from_columns).to eq(['a_id', 'b_id'])
|
|
15
|
+
expect(fk.to_columns).to eq(['a', 'b'])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'stringifies the target table name' do
|
|
19
|
+
fk = Convergence::ForeignKey.new('fk_name', :author_id, :authors, :id, {})
|
|
20
|
+
expect(fk.to_table).to eq('authors')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'defaults the :name option to the key name' do
|
|
24
|
+
fk = Convergence::ForeignKey.new('fk_name', :author_id, 'authors', :id, {})
|
|
25
|
+
expect(fk.options[:name]).to eq('fk_name')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'preserves any additional options passed in' do
|
|
29
|
+
fk = Convergence::ForeignKey.new('fk_name', :author_id, 'authors', :id, on_delete: :cascade)
|
|
30
|
+
expect(fk.options[:on_delete]).to eq(:cascade)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'convergence/index'
|
|
3
|
+
|
|
4
|
+
describe Convergence::Index do
|
|
5
|
+
describe '#initialize' do
|
|
6
|
+
it 'defaults the :name option to the index name' do
|
|
7
|
+
index = Convergence::Index.new('idx_name', 'name', {})
|
|
8
|
+
expect(index.options[:name]).to eq('idx_name')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'wraps a single column into an array of strings' do
|
|
12
|
+
index = Convergence::Index.new('idx_name', :name, {})
|
|
13
|
+
expect(index.index_columns).to eq(['name'])
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'wraps multiple columns into an array of strings' do
|
|
17
|
+
index = Convergence::Index.new('idx_name', [:first_name, :last_name], {})
|
|
18
|
+
expect(index.index_columns).to eq(['first_name', 'last_name'])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'when length is a single Integer' do
|
|
22
|
+
it 'applies it to every column' do
|
|
23
|
+
index = Convergence::Index.new('idx_name', [:first_name, :last_name], length: 10)
|
|
24
|
+
expect(index.options[:length]).to eq('first_name' => 10, 'last_name' => 10)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context 'when length is a Hash keyed by symbol' do
|
|
29
|
+
it 'normalizes the keys to strings' do
|
|
30
|
+
index = Convergence::Index.new('idx_name', [:first_name, :last_name], length: { first_name: 10, last_name: 20 })
|
|
31
|
+
expect(index.options[:length]).to eq('first_name' => 10, 'last_name' => 20)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '#quoted_columns' do
|
|
37
|
+
it 'quotes each column name with backticks' do
|
|
38
|
+
index = Convergence::Index.new('idx_name', [:first_name, :last_name], {})
|
|
39
|
+
expect(index.quoted_columns).to eq(['`first_name`', '`last_name`'])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'appends the prefix length in parentheses when configured' do
|
|
43
|
+
index = Convergence::Index.new('idx_name', [:first_name, :last_name], length: { first_name: 10 })
|
|
44
|
+
expect(index.quoted_columns).to eq(['`first_name`(10)', '`last_name`'])
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'escapes a backtick embedded in a column name' do
|
|
48
|
+
index = Convergence::Index.new('idx_name', 'weird`name', {})
|
|
49
|
+
expect(index.quoted_columns).to eq(['`weird``name`'])
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'convergence/pretty_diff'
|
|
3
|
+
require 'convergence/table'
|
|
4
|
+
|
|
5
|
+
describe Convergence::PrettyDiff do
|
|
6
|
+
describe '#output' do
|
|
7
|
+
context 'when a table is added' do
|
|
8
|
+
let(:from_tables) { {} }
|
|
9
|
+
let(:to_tables) do
|
|
10
|
+
{ 'users' => Convergence::Table.new('users').tap { |t| t.int('id', primary_key: true) } }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should show the added table with a + prefix on every line' do
|
|
14
|
+
output = Convergence::PrettyDiff.new(from_tables, to_tables).output
|
|
15
|
+
expect(output).to be_include('+ create_table :users do |t|')
|
|
16
|
+
expect(output).to be_include('+ t.int :id, primary_key: true')
|
|
17
|
+
expect(output).to be_include('+ end')
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'when a table is removed' do
|
|
22
|
+
let(:from_tables) do
|
|
23
|
+
{ 'users' => Convergence::Table.new('users').tap { |t| t.int('id', primary_key: true) } }
|
|
24
|
+
end
|
|
25
|
+
let(:to_tables) { {} }
|
|
26
|
+
|
|
27
|
+
it 'should show the removed table with a - prefix on every line' do
|
|
28
|
+
output = Convergence::PrettyDiff.new(from_tables, to_tables).output
|
|
29
|
+
expect(output).to be_include('- create_table :users do |t|')
|
|
30
|
+
expect(output).to be_include('- t.int :id, primary_key: true')
|
|
31
|
+
expect(output).to be_include('- end')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'when a table column is changed' do
|
|
36
|
+
let(:from_tables) do
|
|
37
|
+
{ 'users' => Convergence::Table.new('users').tap { |t| t.varchar('name', limit: 100) } }
|
|
38
|
+
end
|
|
39
|
+
let(:to_tables) do
|
|
40
|
+
{ 'users' => Convergence::Table.new('users').tap { |t| t.varchar('name', limit: 200) } }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'should show a unified diff of only the changed column' do
|
|
44
|
+
output = Convergence::PrettyDiff.new(from_tables, to_tables).output
|
|
45
|
+
expect(output).to be_include('- t.varchar :name, limit: 100')
|
|
46
|
+
expect(output).to be_include('+ t.varchar :name, limit: 200')
|
|
47
|
+
expect(output).to be_include(' create_table :users do |t|')
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'when nothing changed' do
|
|
52
|
+
let(:tables) do
|
|
53
|
+
{ 'users' => Convergence::Table.new('users').tap { |t| t.int('id', primary_key: true) } }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'should return an empty string' do
|
|
57
|
+
output = Convergence::PrettyDiff.new(tables, tables).output
|
|
58
|
+
expect(output).to eq('')
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'when tables are added, removed, and changed at the same time' do
|
|
63
|
+
let(:from_tables) do
|
|
64
|
+
{
|
|
65
|
+
'authors' => Convergence::Table.new('authors').tap { |t| t.int('id', primary_key: true) },
|
|
66
|
+
'papers' => Convergence::Table.new('papers').tap { |t| t.varchar('title', limit: 100) }
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
let(:to_tables) do
|
|
70
|
+
{
|
|
71
|
+
'papers' => Convergence::Table.new('papers').tap { |t| t.varchar('title', limit: 200) },
|
|
72
|
+
'comments' => Convergence::Table.new('comments').tap { |t| t.int('id', primary_key: true) }
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'should show every add/remove/change table diff' do
|
|
77
|
+
output = Convergence::PrettyDiff.new(from_tables, to_tables).output
|
|
78
|
+
expect(output).to be_include('+ create_table :comments do |t|')
|
|
79
|
+
expect(output).to be_include('- create_table :authors do |t|')
|
|
80
|
+
expect(output).to be_include('- t.varchar :title, limit: 100')
|
|
81
|
+
expect(output).to be_include('+ t.varchar :title, limit: 200')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -26,6 +26,52 @@ describe Convergence::Table do
|
|
|
26
26
|
table.decimal(dummy_column, default: 1)
|
|
27
27
|
expect(table.columns[dummy_column].options[:default]).to eq(1.0)
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
it 'should extract renamed_from into its own accessor' do
|
|
31
|
+
table.int(dummy_column, renamed_from: 'old_column')
|
|
32
|
+
expect(table.columns[dummy_column].renamed_from).to eq('old_column')
|
|
33
|
+
expect(table.columns[dummy_column].options).not_to have_key(:renamed_from)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'should have a nil renamed_from when not specified' do
|
|
37
|
+
table.int(dummy_column)
|
|
38
|
+
expect(table.columns[dummy_column].renamed_from).to be_nil
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe 'renamed_from' do
|
|
43
|
+
it 'should extract renamed_from into its own accessor' do
|
|
44
|
+
renamed_table = Convergence::Table.new('new_table', renamed_from: 'old_table')
|
|
45
|
+
expect(renamed_table.renamed_from).to eq('old_table')
|
|
46
|
+
expect(renamed_table.table_options).not_to have_key(:renamed_from)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'should have a nil renamed_from when not specified' do
|
|
50
|
+
expect(table.renamed_from).to be_nil
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe '#boolean' do
|
|
55
|
+
it 'should be stored as a tinyint(1) column' do
|
|
56
|
+
table.boolean(dummy_column)
|
|
57
|
+
expect(table.columns[dummy_column].type).to eq(:tinyint)
|
|
58
|
+
expect(table.columns[dummy_column].options[:limit]).to eq(1)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'should convert a true default to 1' do
|
|
62
|
+
table.boolean(dummy_column, default: true)
|
|
63
|
+
expect(table.columns[dummy_column].options[:default]).to eq(1)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'should convert a false default to 0' do
|
|
67
|
+
table.boolean(dummy_column, default: false)
|
|
68
|
+
expect(table.columns[dummy_column].options[:default]).to eq(0)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'should preserve other options' do
|
|
72
|
+
table.boolean(dummy_column, null: false)
|
|
73
|
+
expect(table.columns[dummy_column].options[:null]).to eq(false)
|
|
74
|
+
end
|
|
29
75
|
end
|
|
30
76
|
|
|
31
77
|
describe '#index' do
|
|
@@ -14,6 +14,8 @@ create_table "papers", collate: "utf8_general_ci", comment: "Paper" do |t|
|
|
|
14
14
|
t.varchar "title1", limit: 300, comment: "Title 1"
|
|
15
15
|
t.varchar "title2", limit: 300, comment: "Title 2"
|
|
16
16
|
t.text "description", null: true, comment: "Description"
|
|
17
|
+
t.int "edition_number", default: 0
|
|
18
|
+
t.datetime "published_at", default: -> { "CURRENT_TIMESTAMP" }
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
create_table "paper_authors", collate: "utf8_general_ci", comment: "Paper Author Relation" do |t|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
create_table "authors", collate: "utf8_general_ci", comment: "" do |t|
|
|
2
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
3
|
+
t.varchar "name", limit: 110
|
|
4
|
+
t.int "age", unsigned: true
|
|
5
|
+
t.datetime "created_at", null: true
|
|
6
|
+
t.datetime "updated_at", null: true
|
|
7
|
+
|
|
8
|
+
t.index "created_at", name: "index_authors_on_created_at"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
create_table "papers", collate: "utf8_general_ci", comment: "Paper" do |t|
|
|
12
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
13
|
+
t.varchar "slug", comment: "Slug"
|
|
14
|
+
t.varchar "title1", limit: 300, comment: "Title 1"
|
|
15
|
+
t.varchar "title2", limit: 300, comment: "Title 2"
|
|
16
|
+
t.text "description", null: true, comment: "Description"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
create_table "paper_authors", collate: "utf8_general_ci", comment: "Paper Author Relation" do |t|
|
|
20
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
21
|
+
t.int "paper_id", comment: "Paper id"
|
|
22
|
+
t.int "author_id", comment: "Paper author id"
|
|
23
|
+
|
|
24
|
+
t.foreign_key "author_id", reference: "authors", reference_column: "id", name: "paper_authors_author_id_fk"
|
|
25
|
+
t.foreign_key "paper_id", reference: "papers", reference_column: "id", name: "paper_authors_paper_id_fk"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
execute "UPDATE authors SET age = 0 WHERE age IS NULL"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
create_table "authors" do |t|
|
|
2
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
3
|
+
t.varchar "name", limit: 110
|
|
4
|
+
t.int "age"
|
|
5
|
+
t.datetime "created_at", null: true
|
|
6
|
+
t.datetime "updated_at", null: true
|
|
7
|
+
|
|
8
|
+
t.index "created_at", name: "index_authors_on_created_at"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
create_table "papers", comment: "Paper" do |t|
|
|
12
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
13
|
+
t.varchar "slug", comment: "Slug"
|
|
14
|
+
t.varchar "title1", limit: 300, comment: "Title 1"
|
|
15
|
+
t.varchar "title2", limit: 300, comment: "Title 2"
|
|
16
|
+
t.text "description", null: true, comment: "Description"
|
|
17
|
+
t.varchar "subtitle", null: true, comment: "Subtitle"
|
|
18
|
+
|
|
19
|
+
t.index "slug", name: "index_papers_on_slug", unique: true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
create_table "paper_authors", comment: "Paper Author Relation" do |t|
|
|
23
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
24
|
+
t.int "paper_id", comment: "Paper id"
|
|
25
|
+
t.int "author_id", comment: "Paper author id"
|
|
26
|
+
|
|
27
|
+
t.foreign_key "author_id", reference: "authors", reference_column: "id", name: "paper_authors_author_id_fk"
|
|
28
|
+
t.foreign_key "paper_id", reference: "papers", reference_column: "id", name: "paper_authors_paper_id_fk"
|
|
29
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
create_table "authors" do |t|
|
|
2
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
3
|
+
t.varchar "name", limit: 110
|
|
4
|
+
t.int "age"
|
|
5
|
+
t.datetime "created_at", null: true
|
|
6
|
+
t.datetime "updated_at", null: true
|
|
7
|
+
|
|
8
|
+
t.index "created_at", name: "index_authors_on_created_at"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
create_table "papers", comment: "Paper" do |t|
|
|
12
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
13
|
+
t.varchar "slug", comment: "Slug"
|
|
14
|
+
t.varchar "title1", limit: 300, comment: "Title 1"
|
|
15
|
+
t.varchar "title2", limit: 300, comment: "Title 2"
|
|
16
|
+
t.text "description", null: true, comment: "Description"
|
|
17
|
+
|
|
18
|
+
t.index "slug", name: "index_papers_on_slug", unique: true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
create_table "paper_authors", comment: "Paper Author Relation" do |t|
|
|
22
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
23
|
+
t.int "paper_id", comment: "Paper id"
|
|
24
|
+
t.int "author_id", comment: "Paper author id"
|
|
25
|
+
|
|
26
|
+
t.foreign_key "author_id", reference: "authors", reference_column: "id", name: "paper_authors_author_id_fk"
|
|
27
|
+
t.foreign_key "paper_id", reference: "papers", reference_column: "id", name: "paper_authors_paper_id_fk"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
create_table "dummies", comment: "Dummy Table" do |t|
|
|
31
|
+
t.int "id", primary_key: true, extra: "auto_increment", comment: "Hello Convergence"
|
|
32
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
create_table "authors" do |t|
|
|
2
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
3
|
+
t.varchar "name", limit: 110
|
|
4
|
+
t.int "age"
|
|
5
|
+
t.datetime "created_at", null: true, comment: "Created At"
|
|
6
|
+
t.datetime "updated_at", null: true
|
|
7
|
+
|
|
8
|
+
t.index "created_at", name: "index_authors_on_created_at"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
create_table "papers", comment: "Paper" do |t|
|
|
12
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
13
|
+
t.varchar "slug", comment: "Slug"
|
|
14
|
+
t.varchar "title1", limit: 300, comment: "Title 1"
|
|
15
|
+
t.varchar "title2", limit: 300, comment: "Title 2"
|
|
16
|
+
t.text "description", null: true, comment: "Description"
|
|
17
|
+
|
|
18
|
+
t.index "slug", name: "index_papers_on_slug", unique: true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
create_table "paper_authors", comment: "Paper Author Relation" do |t|
|
|
22
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
23
|
+
t.int "paper_id", comment: "Paper id"
|
|
24
|
+
t.int "author_id", comment: "Paper author id"
|
|
25
|
+
|
|
26
|
+
t.foreign_key "author_id", reference: "authors", reference_column: "id", name: "paper_authors_author_id_fk"
|
|
27
|
+
t.foreign_key "paper_id", reference: "papers", reference_column: "id", name: "paper_authors_paper_id_fk"
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
create_table "authors", comment: "Author Table" do |t|
|
|
2
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
3
|
+
t.varchar "name", limit: 110
|
|
4
|
+
t.int "age"
|
|
5
|
+
t.datetime "created_at", null: true
|
|
6
|
+
t.datetime "updated_at", null: true
|
|
7
|
+
|
|
8
|
+
t.index "created_at", name: "index_authors_on_created_at"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
create_table "papers", comment: "Paper" do |t|
|
|
12
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
13
|
+
t.varchar "slug", comment: "Slug"
|
|
14
|
+
t.varchar "title1", limit: 300, comment: "Title 1"
|
|
15
|
+
t.varchar "title2", limit: 300, comment: "Title 2"
|
|
16
|
+
t.text "description", null: true, comment: "Description"
|
|
17
|
+
|
|
18
|
+
t.index "slug", name: "index_papers_on_slug", unique: true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
create_table "paper_authors", comment: "Paper Author Relation" do |t|
|
|
22
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
23
|
+
t.int "paper_id", comment: "Paper id"
|
|
24
|
+
t.int "author_id", comment: "Paper author id"
|
|
25
|
+
|
|
26
|
+
t.foreign_key "author_id", reference: "authors", reference_column: "id", name: "paper_authors_author_id_fk"
|
|
27
|
+
t.foreign_key "paper_id", reference: "papers", reference_column: "id", name: "paper_authors_paper_id_fk"
|
|
28
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
create_table "authors" do |t|
|
|
2
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
3
|
+
t.varchar "name", limit: 110
|
|
4
|
+
t.int "age"
|
|
5
|
+
t.datetime "created_at", null: true
|
|
6
|
+
t.datetime "updated_at", null: true
|
|
7
|
+
|
|
8
|
+
t.index "created_at", name: "index_authors_on_created_at"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
create_table "papers", comment: "Paper" do |t|
|
|
12
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
13
|
+
t.varchar "slug", comment: "Slug"
|
|
14
|
+
t.varchar "title1", limit: 300, comment: "Title 1"
|
|
15
|
+
t.varchar "title2", limit: 300, comment: "Title 2"
|
|
16
|
+
t.text "description", null: true, comment: "Description"
|
|
17
|
+
|
|
18
|
+
t.index "slug", name: "index_papers_on_slug", unique: true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
create_table "paper_authors", comment: "Paper Author Relation" do |t|
|
|
22
|
+
t.int "id", primary_key: true, extra: "auto_increment"
|
|
23
|
+
t.int "paper_id", comment: "Paper id"
|
|
24
|
+
t.int "author_id", comment: "Paper author id"
|
|
25
|
+
end
|