declare_schema 1.3.6 → 1.4.0.colin.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -18
- data/Gemfile.lock +1 -1
- data/README.md +82 -41
- data/lib/declare_schema/model/field_spec.rb +0 -2
- data/lib/declare_schema/model/foreign_key_definition.rb +43 -40
- data/lib/declare_schema/model/habtm_model_shim.rb +26 -26
- data/lib/declare_schema/model/index_definition.rb +41 -30
- data/lib/declare_schema/model/table_options_definition.rb +1 -11
- data/lib/declare_schema/model.rb +66 -60
- data/lib/declare_schema/schema_change/column_add.rb +2 -4
- data/lib/declare_schema/schema_change/index_add.rb +3 -1
- data/lib/declare_schema/version.rb +1 -1
- data/lib/declare_schema.rb +3 -45
- data/lib/generators/declare_schema/migration/migrator.rb +19 -29
- data/spec/lib/declare_schema/field_spec_spec.rb +2 -22
- data/spec/lib/declare_schema/migration_generator_spec.rb +81 -92
- data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +23 -22
- data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +61 -76
- data/spec/lib/declare_schema/model/index_definition_spec.rb +106 -37
- data/spec/lib/declare_schema/model/table_options_definition_spec.rb +6 -26
- data/spec/lib/declare_schema/schema_change/index_add_spec.rb +28 -1
- data/spec/lib/declare_schema_spec.rb +8 -102
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +1 -3
- data/spec/spec_helper.rb +3 -4
- metadata +2 -2
@@ -11,7 +11,6 @@ require_relative '../../../../lib/declare_schema/model/index_definition'
|
|
11
11
|
|
12
12
|
RSpec.describe DeclareSchema::Model::IndexDefinition do
|
13
13
|
let(:model_class) { IndexDefinitionTestModel }
|
14
|
-
let(:table_name) { model_class.table_name }
|
15
14
|
|
16
15
|
context 'Using declare_schema' do
|
17
16
|
before do
|
@@ -35,26 +34,103 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
describe 'instance methods' do
|
38
|
+
let(:model) { model_class.new }
|
39
|
+
let(:fields) { ['last_name', 'first_name'] }
|
40
|
+
let(:options) { {} }
|
41
|
+
subject(:instance) { described_class.new(model_class, fields, **options) }
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
describe 'attr_readers' do
|
44
|
+
describe '#table' do
|
45
|
+
subject { instance.table }
|
46
|
+
|
47
|
+
it { is_expected.to eq(model_class.table_name) }
|
48
|
+
|
49
|
+
context 'with table_name option' do
|
50
|
+
let(:options) { { table_name: 'auth_users' } }
|
51
|
+
|
52
|
+
it { is_expected.to eq('auth_users') }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#fields' do
|
57
|
+
subject { instance.fields }
|
58
|
+
|
59
|
+
it { is_expected.to eq(fields) }
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#explicit_name' do
|
63
|
+
subject { instance.explicit_name }
|
64
|
+
|
65
|
+
it { is_expected.to eq(nil) }
|
66
|
+
|
67
|
+
context 'with name option' do
|
68
|
+
let(:options) { { name: 'index_auth_users_on_last_name_and_first_name' } }
|
69
|
+
|
70
|
+
it { is_expected.to eq('index_auth_users_on_last_name_and_first_name') }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#length' do
|
75
|
+
subject { instance.length }
|
76
|
+
let(:options) { { length: length } }
|
77
|
+
|
78
|
+
context 'with integer length' do
|
79
|
+
let(:length) { 2 }
|
80
|
+
|
81
|
+
it { is_expected.to eq(length) }
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'with Hash length' do
|
85
|
+
let(:length) { { name: 2 } }
|
86
|
+
|
87
|
+
it { is_expected.to eq(length) }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#options' do
|
92
|
+
subject { instance.options }
|
93
|
+
let(:options) { { name: 'my_index', unique: false, where: "(name like 'a%')", length: 10 } }
|
94
|
+
|
95
|
+
it { is_expected.to eq(options) }
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#with_name' do
|
99
|
+
subject { instance.with_name('new_name') }
|
100
|
+
|
101
|
+
it { is_expected.to be_kind_of(described_class) }
|
102
|
+
it { expect(instance.name).to eq('index_index_definition_test_models_on_last_name_and_first_name') }
|
103
|
+
it { expect(subject.name).to eq('new_name') }
|
47
104
|
end
|
48
105
|
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe 'class methods' do
|
109
|
+
let(:model) { model_class.new }
|
49
110
|
|
50
|
-
describe '
|
51
|
-
|
111
|
+
describe 'index_definitions' do
|
112
|
+
it do
|
113
|
+
expect(model_class.index_definitions.size).to eq(1)
|
52
114
|
|
53
|
-
|
54
|
-
expect(
|
55
|
-
|
56
|
-
|
57
|
-
|
115
|
+
expect(model_class.index_definitions[0].name).to eq('index_index_definition_test_models_on_name')
|
116
|
+
expect(model_class.index_definitions[0].fields).to eq(['name'])
|
117
|
+
expect(model_class.index_definitions[0].unique).to eq(false)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe 'has index_definitions_with_primary_key' do
|
122
|
+
it do
|
123
|
+
expect(model_class.index_definitions_with_primary_key).to be_kind_of(Array)
|
124
|
+
result = model_class.index_definitions_with_primary_key.sort_by(&:name)
|
125
|
+
expect(result.size).to eq(2)
|
126
|
+
|
127
|
+
expect(result[0].name).to eq('PRIMARY')
|
128
|
+
expect(result[0].fields).to eq(['id'])
|
129
|
+
expect(result[0].unique).to eq(true)
|
130
|
+
|
131
|
+
expect(result[1].name).to eq('index_index_definition_test_models_on_name')
|
132
|
+
expect(result[1].fields).to eq(['name'])
|
133
|
+
expect(result[1].unique).to eq(false)
|
58
134
|
end
|
59
135
|
end
|
60
136
|
end
|
@@ -80,36 +156,29 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
80
156
|
ActiveRecord::Base.connection.schema_cache.clear!
|
81
157
|
end
|
82
158
|
|
83
|
-
describe '
|
84
|
-
|
85
|
-
subject { described_class.for_table(model_class.table_name, ignore_indexes, model_class.connection) }
|
159
|
+
describe 'for_model' do
|
160
|
+
subject { described_class.for_model(model_class) }
|
86
161
|
|
87
162
|
context 'with single-column PK' do
|
88
163
|
it 'returns the indexes for the model' do
|
89
|
-
expect(subject.
|
90
|
-
|
91
|
-
|
92
|
-
])
|
164
|
+
expect(subject.size).to eq(2), subject.inspect
|
165
|
+
expect(subject[0].name).to eq('index_definition_test_models_on_name')
|
166
|
+
expect(subject[0].columns).to eq(['name'])
|
167
|
+
expect(subject[0].unique).to eq(true)
|
168
|
+
expect(subject[1].name).to eq('PRIMARY')
|
169
|
+
expect(subject[1].columns).to eq(['id'])
|
170
|
+
expect(subject[1].unique).to eq(true)
|
93
171
|
end
|
94
172
|
end
|
95
173
|
|
96
|
-
context 'with
|
174
|
+
context 'with compound-column PK' do
|
97
175
|
let(:model_class) { IndexDefinitionCompoundIndexModel }
|
98
176
|
|
99
177
|
it 'returns the indexes for the model' do
|
100
|
-
expect(subject.
|
101
|
-
|
102
|
-
])
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
context 'with ignored_indexes' do
|
107
|
-
let(:ignore_indexes) { ['index_definition_test_models_on_name'] }
|
108
|
-
|
109
|
-
it 'skips the ignored index' do
|
110
|
-
expect(subject.map(&:to_key)).to eq([
|
111
|
-
["PRIMARY", ["id"], true, nil]
|
112
|
-
])
|
178
|
+
expect(subject.size).to eq(1), subject.inspect
|
179
|
+
expect(subject[0].name).to eq('PRIMARY')
|
180
|
+
expect(subject[0].columns).to eq(['fk1_id', 'fk2_id'])
|
181
|
+
expect(subject[0].unique).to eq(true)
|
113
182
|
end
|
114
183
|
end
|
115
184
|
end
|
@@ -9,8 +9,6 @@ require_relative '../../../../lib/declare_schema/model/table_options_definition'
|
|
9
9
|
|
10
10
|
RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
|
11
11
|
let(:model_class) { TableOptionsDefinitionTestModel }
|
12
|
-
let(:charset) { DeclareSchema.normalize_charset('utf8') }
|
13
|
-
let(:collation) { DeclareSchema.normalize_collation('utf8_general') } # adapt so that tests will pass on MySQL 5.7 or 8+
|
14
12
|
|
15
13
|
context 'Using declare_schema' do
|
16
14
|
before do
|
@@ -29,45 +27,27 @@ RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
|
|
29
27
|
|
30
28
|
describe '#to_key' do
|
31
29
|
subject { model.to_key }
|
32
|
-
it {
|
30
|
+
it { should eq(['table_options_definition_test_models', '{:charset=>"utf8", :collation=>"utf8_general"}']) }
|
33
31
|
end
|
34
32
|
|
35
33
|
describe '#settings' do
|
36
34
|
subject { model.settings }
|
37
|
-
it {
|
38
|
-
|
39
|
-
if defined?(Mysql2)
|
40
|
-
context 'when running in MySQL 8' do
|
41
|
-
around do |spec|
|
42
|
-
DeclareSchema.mysql_version = Gem::Version.new('8.0.21')
|
43
|
-
spec.run
|
44
|
-
ensure
|
45
|
-
DeclareSchema.remove_instance_variable('@mysql_version') rescue nil
|
46
|
-
end
|
47
|
-
|
48
|
-
it { is_expected.to eq("CHARACTER SET utf8mb3 COLLATE utf8mb3_general") }
|
49
|
-
|
50
|
-
context 'when _ci collation' do
|
51
|
-
let(:table_options) { { charset: "utf8", collation: "utf8_general_ci"} }
|
52
|
-
it { is_expected.to eq("CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci") }
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
35
|
+
it { should eq("CHARACTER SET utf8 COLLATE utf8_general") }
|
56
36
|
end
|
57
37
|
|
58
38
|
describe '#hash' do
|
59
39
|
subject { model.hash }
|
60
|
-
it {
|
40
|
+
it { should eq(['table_options_definition_test_models', '{:charset=>"utf8", :collation=>"utf8_general"}'].hash) }
|
61
41
|
end
|
62
42
|
|
63
43
|
describe '#to_s' do
|
64
44
|
subject { model.to_s }
|
65
|
-
it {
|
45
|
+
it { should eq("CHARACTER SET utf8 COLLATE utf8_general") }
|
66
46
|
end
|
67
47
|
|
68
48
|
describe '#alter_table_statement' do
|
69
49
|
subject { model.alter_table_statement }
|
70
|
-
it {
|
50
|
+
it { should match(/execute "ALTER TABLE .*table_options_definition_test_models.* CHARACTER SET utf8 COLLATE utf8_general"/) }
|
71
51
|
end
|
72
52
|
end
|
73
53
|
|
@@ -87,7 +67,7 @@ RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
|
|
87
67
|
generate_migrations '-n', '-m'
|
88
68
|
end
|
89
69
|
|
90
|
-
it {
|
70
|
+
it { should eq(described_class.new(model_class.table_name, **options)) }
|
91
71
|
end
|
92
72
|
end
|
93
73
|
end
|
@@ -30,7 +30,7 @@ RSpec.describe DeclareSchema::SchemaChange::IndexAdd do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
context 'with where:' do
|
33
|
-
let(:where) { "'last_name like 'A%'"}
|
33
|
+
let(:where) { "'last_name like 'A%'" }
|
34
34
|
subject { described_class.new(table_name, column_names, name: name, unique: unique, where: where) }
|
35
35
|
|
36
36
|
it 'responds with command' do
|
@@ -45,6 +45,33 @@ RSpec.describe DeclareSchema::SchemaChange::IndexAdd do
|
|
45
45
|
expect(subject.up).to eq("add_index :#{table_name}, #{column_names.map(&:to_sym).inspect}, name: #{name.to_sym.inspect}, unique: true\n")
|
46
46
|
end
|
47
47
|
end
|
48
|
+
|
49
|
+
context 'with limit: nil' do
|
50
|
+
let(:limit) { nil }
|
51
|
+
subject { described_class.new(table_name, column_names, name: name, unique: unique, limit: limit) }
|
52
|
+
|
53
|
+
it 'responds with command' do
|
54
|
+
expect(subject.up).to eq("add_index :#{table_name}, #{column_names.map(&:to_sym).inspect}, name: #{name.to_sym.inspect}\n")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with limit: 2' do
|
59
|
+
let(:limit) { 2 }
|
60
|
+
subject { described_class.new(table_name, column_names, name: name, unique: unique, limit: limit) }
|
61
|
+
|
62
|
+
it 'responds with command' do
|
63
|
+
expect(subject.up).to eq("add_index :#{table_name}, #{column_names.map(&:to_sym).inspect}, name: #{name.to_sym.inspect}, limit: #{limit}\n")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with limit: hash' do
|
68
|
+
let(:limit) { { last_name: 10, first_name: 1 } }
|
69
|
+
subject { described_class.new(table_name, column_names, name: name, unique: unique, limit: limit) }
|
70
|
+
|
71
|
+
it 'responds with command' do
|
72
|
+
expect(subject.up).to eq("add_index :#{table_name}, #{column_names.map(&:to_sym).inspect}, name: #{name.to_sym.inspect}, limit: { last_name: 10, first_name: 1 }\n")
|
73
|
+
end
|
74
|
+
end
|
48
75
|
end
|
49
76
|
|
50
77
|
describe '#down' do
|
@@ -8,54 +8,10 @@ RSpec.describe DeclareSchema do
|
|
8
8
|
it { is_expected.to eq("utf8mb4") }
|
9
9
|
end
|
10
10
|
|
11
|
-
context 'when
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
ensure
|
16
|
-
described_class.remove_instance_variable('@mysql_version') rescue nil
|
17
|
-
end
|
18
|
-
|
19
|
-
context 'when explicitly set' do
|
20
|
-
before { described_class.default_charset = "utf8" }
|
21
|
-
after { described_class.default_charset = "utf8mb4" }
|
22
|
-
it { is_expected.to eq("utf8") }
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context 'when running on MySQL 8.0' do
|
27
|
-
around do |spec|
|
28
|
-
described_class.mysql_version = Gem::Version.new('8.0.21')
|
29
|
-
spec.run
|
30
|
-
ensure
|
31
|
-
described_class.remove_instance_variable('@mysql_version') rescue nil
|
32
|
-
end
|
33
|
-
|
34
|
-
context 'when explicitly set' do
|
35
|
-
before { described_class.default_charset = "utf8" }
|
36
|
-
after { described_class.default_charset = "utf8mb4" }
|
37
|
-
it { is_expected.to eq("utf8mb3") }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
context 'when MySQL version not known yet' do
|
42
|
-
before { described_class.remove_instance_variable('@mysql_version') rescue nil }
|
43
|
-
after { described_class.remove_instance_variable('@mysql_version') rescue nil }
|
44
|
-
|
45
|
-
context 'when set' do
|
46
|
-
let(:connection) { double("connection", select_value: "8.0.21") }
|
47
|
-
|
48
|
-
it "is lazy, so it doesn't use the database connection until read" do
|
49
|
-
expect(ActiveRecord::Base).to receive(:connection) do
|
50
|
-
@connection_called = true
|
51
|
-
connection
|
52
|
-
end
|
53
|
-
described_class.default_charset = "utf8"
|
54
|
-
expect(@connection_called).to be_falsey
|
55
|
-
described_class.default_charset
|
56
|
-
expect(@connection_called).to be_truthy
|
57
|
-
end
|
58
|
-
end
|
11
|
+
context 'when explicitly set' do
|
12
|
+
before { described_class.default_charset = "utf8" }
|
13
|
+
after { described_class.default_charset = "utf8mb4" }
|
14
|
+
it { is_expected.to eq("utf8") }
|
59
15
|
end
|
60
16
|
end
|
61
17
|
|
@@ -66,60 +22,10 @@ RSpec.describe DeclareSchema do
|
|
66
22
|
it { is_expected.to eq("utf8mb4_bin") }
|
67
23
|
end
|
68
24
|
|
69
|
-
context 'when
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
ensure
|
74
|
-
described_class.remove_instance_variable('@mysql_version')
|
75
|
-
end
|
76
|
-
|
77
|
-
context 'when explicitly set' do
|
78
|
-
before { described_class.default_collation = "utf8_general_ci" }
|
79
|
-
after { described_class.default_collation = "utf8mb4_bin" }
|
80
|
-
it { is_expected.to eq("utf8_general_ci") }
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
context 'when running on MySQL 8.0' do
|
85
|
-
around do |spec|
|
86
|
-
described_class.mysql_version = Gem::Version.new('8.0.21')
|
87
|
-
spec.run
|
88
|
-
ensure
|
89
|
-
described_class.remove_instance_variable('@mysql_version')
|
90
|
-
end
|
91
|
-
|
92
|
-
context 'when explicitly set without _ci' do
|
93
|
-
before { described_class.default_collation = "utf8_general" }
|
94
|
-
after { described_class.default_collation = "utf8mb4_bin" }
|
95
|
-
it { is_expected.to eq("utf8mb3_general") }
|
96
|
-
end
|
97
|
-
|
98
|
-
context 'when explicitly set with _ci' do
|
99
|
-
before { described_class.default_collation = "utf8_general_ci" }
|
100
|
-
after { described_class.default_collation = "utf8mb4_bin" }
|
101
|
-
it { is_expected.to eq("utf8mb3_general_ci") }
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
context 'when MySQL version not known yet' do
|
106
|
-
before { described_class.remove_instance_variable('@mysql_version') rescue nil }
|
107
|
-
after { described_class.remove_instance_variable('@mysql_version') rescue nil }
|
108
|
-
|
109
|
-
context 'when set' do
|
110
|
-
let(:connection) { double("connection", select_value: "8.0.21") }
|
111
|
-
|
112
|
-
it "is lazy, so it doesn't use the database connection until read" do
|
113
|
-
expect(ActiveRecord::Base).to receive(:connection) do
|
114
|
-
@connection_called = true
|
115
|
-
connection
|
116
|
-
end
|
117
|
-
described_class.default_collation = "utf8_general_ci"
|
118
|
-
expect(@connection_called).to be_falsey
|
119
|
-
described_class.default_collation
|
120
|
-
expect(@connection_called).to be_truthy
|
121
|
-
end
|
122
|
-
end
|
25
|
+
context 'when explicitly set' do
|
26
|
+
before { described_class.default_collation = "utf8mb4_general_ci" }
|
27
|
+
after { described_class.default_collation = "utf8mb4_bin" }
|
28
|
+
it { is_expected.to eq("utf8mb4_general_ci") }
|
123
29
|
end
|
124
30
|
end
|
125
31
|
|
@@ -12,8 +12,6 @@ module Generators
|
|
12
12
|
module Migration
|
13
13
|
RSpec.describe Migrator do
|
14
14
|
subject { described_class.new }
|
15
|
-
let(:charset) { ::DeclareSchema.normalize_charset('utf8') }
|
16
|
-
let(:collation) { ::DeclareSchema.normalize_collation('utf8_general') } # adapt so that tests will pass on MySQL 5.7 or 8+
|
17
15
|
|
18
16
|
describe '#before_generating_migration' do
|
19
17
|
it 'requires a block be passed' do
|
@@ -31,7 +29,7 @@ module Generators
|
|
31
29
|
context 'when explicitly set' do
|
32
30
|
before { described_class.default_charset = "utf8" }
|
33
31
|
after { described_class.default_charset = "utf8mb4" }
|
34
|
-
it { should eq(
|
32
|
+
it { should eq("utf8") }
|
35
33
|
end
|
36
34
|
|
37
35
|
it 'should output deprecation warning' do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require 'pry'
|
3
|
+
require "bundler/setup"
|
4
|
+
require "declare_schema"
|
5
|
+
require "climate_control"
|
7
6
|
|
8
7
|
require_relative "./support/acceptance_spec_helpers"
|
9
8
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: declare_schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0.colin.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Invoca Development adapted from hobo_fields by Tom Locke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|