declare_schema 1.4.0.colin.7 → 1.4.0.colin.9
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/CHANGELOG.md +10 -0
- data/Gemfile.lock +1 -1
- data/README.md +4 -1
- data/lib/declare_schema/model/field_spec.rb +2 -0
- data/lib/declare_schema/model/foreign_key_definition.rb +39 -43
- data/lib/declare_schema/model/habtm_model_shim.rb +30 -30
- data/lib/declare_schema/model/index_definition.rb +51 -30
- data/lib/declare_schema/model/table_options_definition.rb +11 -1
- data/lib/declare_schema/model.rb +55 -42
- data/lib/declare_schema/version.rb +1 -1
- data/lib/declare_schema.rb +34 -2
- data/lib/generators/declare_schema/migration/migrator.rb +32 -21
- data/spec/lib/declare_schema/field_spec_spec.rb +22 -2
- data/spec/lib/declare_schema/migration_generator_spec.rb +63 -41
- data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +28 -27
- data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +84 -62
- data/spec/lib/declare_schema/model/index_definition_spec.rb +126 -55
- data/spec/lib/declare_schema/model/table_options_definition_spec.rb +26 -6
- data/spec/lib/declare_schema_spec.rb +62 -8
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +3 -1
- data/spec/spec_helper.rb +4 -3
- metadata +2 -2
@@ -8,19 +8,20 @@ end
|
|
8
8
|
require_relative '../../../../lib/declare_schema/model/habtm_model_shim'
|
9
9
|
|
10
10
|
RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
11
|
-
let(:join_table) { "
|
12
|
-
let(:foreign_keys) { ["
|
13
|
-
let(:
|
11
|
+
let(:join_table) { "customers_users" }
|
12
|
+
let(:foreign_keys) { ["user_id", "customer_id"] }
|
13
|
+
let(:parent_table_names) { ["users", "customers"] }
|
14
|
+
let(:connection) { instance_double(ActiveRecord::Base.connection.class, "connection") }
|
14
15
|
|
15
16
|
before do
|
16
17
|
load File.expand_path('../prepare_testapp.rb', __dir__)
|
17
18
|
|
18
|
-
class
|
19
|
-
self.table_name = "
|
19
|
+
class User < ActiveRecord::Base
|
20
|
+
self.table_name = "users"
|
20
21
|
end
|
21
22
|
|
22
|
-
class
|
23
|
-
self.table_name = "
|
23
|
+
class Customer < ActiveRecord::Base
|
24
|
+
self.table_name = "customers"
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
@@ -29,26 +30,33 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
29
30
|
let(:reflection) { double("reflection", join_table: join_table,
|
30
31
|
foreign_key: foreign_keys.first,
|
31
32
|
association_foreign_key: foreign_keys.last,
|
32
|
-
active_record:
|
33
|
-
class_name: '
|
33
|
+
active_record: User,
|
34
|
+
class_name: 'Customer',
|
35
|
+
klass: Customer) }
|
34
36
|
it 'returns a new object' do
|
37
|
+
expect(User).to receive(:connection).and_return(connection)
|
38
|
+
|
35
39
|
result = described_class.from_reflection(reflection)
|
36
40
|
|
37
41
|
expect(result).to be_a(described_class)
|
42
|
+
expect(result.foreign_keys).to eq(foreign_keys.reverse)
|
43
|
+
expect(result.parent_table_names).to eq(parent_table_names.reverse)
|
38
44
|
end
|
39
45
|
end
|
40
46
|
end
|
41
47
|
|
42
48
|
describe 'instance methods' do
|
43
|
-
|
44
|
-
|
45
|
-
subject { described_class.new(join_table, foreign_keys, foreign_key_classes, connection) }
|
49
|
+
subject { described_class.new(join_table, foreign_keys, parent_table_names, connection: connection) }
|
46
50
|
|
47
51
|
describe '#initialize' do
|
48
52
|
it 'stores initialization attributes' do
|
49
53
|
expect(subject.join_table).to eq(join_table)
|
50
|
-
expect(subject.foreign_keys).to eq(foreign_keys)
|
51
|
-
|
54
|
+
expect(subject.foreign_keys).to eq(foreign_keys.reverse)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#connection' do
|
59
|
+
it 'returns the connection' do
|
52
60
|
expect(subject.connection).to be(connection)
|
53
61
|
end
|
54
62
|
end
|
@@ -67,51 +75,52 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
67
75
|
|
68
76
|
describe '#field_specs' do
|
69
77
|
it 'returns 2 field specs' do
|
70
|
-
|
71
|
-
expect(
|
72
|
-
|
73
|
-
expect(
|
74
|
-
expect(
|
75
|
-
expect(
|
76
|
-
expect(
|
77
|
-
expect(
|
78
|
-
|
79
|
-
expect(
|
80
|
-
expect(
|
81
|
-
expect(
|
82
|
-
expect(
|
83
|
-
expect(
|
78
|
+
field_specs = subject.field_specs
|
79
|
+
expect(field_specs.size).to eq(2), field_specs.inspect
|
80
|
+
|
81
|
+
expect(field_specs[foreign_keys.first]).to be_a(::DeclareSchema::Model::FieldSpec)
|
82
|
+
expect(field_specs[foreign_keys.first].model).to eq(subject)
|
83
|
+
expect(field_specs[foreign_keys.first].name.to_s).to eq(foreign_keys.first)
|
84
|
+
expect(field_specs[foreign_keys.first].type).to eq(:integer)
|
85
|
+
expect(field_specs[foreign_keys.first].position).to eq(1)
|
86
|
+
|
87
|
+
expect(field_specs[foreign_keys.last]).to be_a(::DeclareSchema::Model::FieldSpec)
|
88
|
+
expect(field_specs[foreign_keys.last].model).to eq(subject)
|
89
|
+
expect(field_specs[foreign_keys.last].name.to_s).to eq(foreign_keys.last)
|
90
|
+
expect(field_specs[foreign_keys.last].type).to eq(:integer)
|
91
|
+
expect(field_specs[foreign_keys.last].position).to eq(0)
|
84
92
|
end
|
85
93
|
end
|
86
94
|
|
87
95
|
describe '#primary_key' do
|
88
|
-
it 'returns false' do
|
89
|
-
expect(subject.
|
96
|
+
it 'returns false because there is no single-column PK for ActiveRecord to use' do
|
97
|
+
expect(subject.primary_key).to eq(false)
|
90
98
|
end
|
91
99
|
end
|
92
100
|
|
93
101
|
describe '#_declared_primary_key' do
|
94
|
-
it 'returns
|
95
|
-
expect(subject._declared_primary_key).to eq(
|
102
|
+
it 'returns the foreign key pair that are used as the primary key in the database' do
|
103
|
+
expect(subject._declared_primary_key).to eq(["customer_id", "user_id"])
|
96
104
|
end
|
97
105
|
end
|
98
106
|
|
99
107
|
describe '#index_definitions_with_primary_key' do
|
100
108
|
it 'returns 2 index definitions' do
|
101
|
-
|
102
|
-
expect(
|
109
|
+
index_definitions = subject.index_definitions_with_primary_key
|
110
|
+
expect(index_definitions.size).to eq(2), index_definitions.inspect
|
103
111
|
|
104
|
-
expect(
|
105
|
-
expect(
|
106
|
-
expect(
|
107
|
-
expect(
|
112
|
+
expect(index_definitions.last).to be_a(::DeclareSchema::Model::IndexDefinition)
|
113
|
+
expect(index_definitions.last.name).to eq('PRIMARY')
|
114
|
+
expect(index_definitions.last.fields).to eq(foreign_keys.reverse)
|
115
|
+
expect(index_definitions.last.unique).to be_truthy
|
108
116
|
end
|
109
117
|
end
|
110
118
|
|
111
119
|
context 'when table and foreign key names are long' do
|
112
120
|
let(:join_table) { "advertiser_campaigns_tracking_pixels" }
|
113
|
-
let(:
|
114
|
-
let(:
|
121
|
+
let(:foreign_keys_and_table_names) { [["advertiser_id", "advertisers"], ["campaign_id", "campaigns"]] }
|
122
|
+
let(:foreign_keys) { foreign_keys_and_table_names.map(&:first) }
|
123
|
+
let(:parent_table_names) { foreign_keys_and_table_names.map(&:last) }
|
115
124
|
|
116
125
|
before do
|
117
126
|
class Table1 < ActiveRecord::Base
|
@@ -124,19 +133,40 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
124
133
|
end
|
125
134
|
|
126
135
|
it 'returns two index definitions and does not raise a IndexNameTooLongError' do
|
127
|
-
|
128
|
-
expect(
|
129
|
-
expect(
|
130
|
-
expect(
|
131
|
-
expect(
|
132
|
-
expect(
|
136
|
+
indexes = subject.index_definitions_with_primary_key.to_a
|
137
|
+
expect(indexes.size).to eq(2), indexes.inspect
|
138
|
+
expect(indexes.last).to be_a(::DeclareSchema::Model::IndexDefinition)
|
139
|
+
expect(indexes.last.name).to eq('PRIMARY')
|
140
|
+
expect(indexes.last.fields).to eq(foreign_keys)
|
141
|
+
expect(indexes.last.unique).to be_truthy
|
142
|
+
expect(indexes.first).to be_a(::DeclareSchema::Model::IndexDefinition)
|
143
|
+
expect(indexes.first.name).to eq('index_advertiser_campaigns_tracking_pixels_on_campaign_id')
|
144
|
+
expect(indexes.first.fields).to eq([foreign_keys.last])
|
145
|
+
expect(indexes.first.unique).to be_falsey
|
133
146
|
end
|
134
147
|
end
|
135
148
|
|
136
149
|
describe '#index_definitions' do
|
150
|
+
it 'returns index_definitions' do
|
151
|
+
indexes = subject.index_definitions
|
152
|
+
expect(indexes.size).to eq(1), indexes.inspect
|
153
|
+
expect(indexes.first.columns).to eq(["user_id"])
|
154
|
+
options = [:name, :unique, :where].map { |k| [k, indexes.first.send(k)] }.to_h
|
155
|
+
expect(options).to eq(name: "index_customers_users_on_user_id",
|
156
|
+
unique: false,
|
157
|
+
where: nil)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe '#index_definitions_with_primary_key' do
|
137
162
|
it 'returns index_definitions_with_primary_key' do
|
138
|
-
|
139
|
-
expect(
|
163
|
+
indexes = subject.index_definitions_with_primary_key
|
164
|
+
expect(indexes.size).to eq(2), indexes.inspect
|
165
|
+
expect(indexes.last.columns).to eq(["customer_id", "user_id"])
|
166
|
+
options = [:name, :unique, :where].map { |k| [k, indexes.last.send(k)] }.to_h
|
167
|
+
expect(options).to eq(name: "PRIMARY",
|
168
|
+
unique: true,
|
169
|
+
where: nil)
|
140
170
|
end
|
141
171
|
end
|
142
172
|
|
@@ -146,21 +176,13 @@ RSpec.describe DeclareSchema::Model::HabtmModelShim do
|
|
146
176
|
end
|
147
177
|
end
|
148
178
|
|
149
|
-
describe '#
|
179
|
+
describe '#constraint_definitions' do
|
150
180
|
it 'returns 2 foreign keys' do
|
151
|
-
|
152
|
-
expect(
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
expect(result.first.parent_table_name).to be(Parent1.table_name)
|
157
|
-
expect(result.first.on_delete_cascade).to be_truthy
|
158
|
-
|
159
|
-
sample = result.to_a.last
|
160
|
-
expect(sample).to be_a(::DeclareSchema::Model::ForeignKeyDefinition)
|
161
|
-
expect(sample.foreign_key).to eq(foreign_keys.last)
|
162
|
-
expect(sample.parent_table_name).to be(Parent2.table_name)
|
163
|
-
expect(sample.on_delete_cascade).to be_truthy
|
181
|
+
constraints = subject.constraint_definitions
|
182
|
+
expect(constraints.map(&:key)).to eq([
|
183
|
+
["customers_users", "customer_id", :delete],
|
184
|
+
["customers_users", "user_id", :delete]
|
185
|
+
])
|
164
186
|
end
|
165
187
|
end
|
166
188
|
end
|
@@ -11,6 +11,7 @@ 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 }
|
14
15
|
|
15
16
|
context 'Using declare_schema' do
|
16
17
|
before do
|
@@ -34,23 +35,19 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
38
|
+
# TODO: create model_spec.rb and move the Model specs below into it. -Colin
|
37
39
|
describe 'instance methods' do
|
38
40
|
let(:model) { model_class.new }
|
41
|
+
let(:table_name) { "index_definition_test_models" }
|
39
42
|
let(:fields) { ['last_name', 'first_name'] }
|
40
|
-
let(:options) { {} }
|
41
|
-
subject(:instance) { described_class.new(
|
43
|
+
let(:options) { { table_name: table_name } }
|
44
|
+
subject(:instance) { described_class.new(fields, **options) }
|
42
45
|
|
43
46
|
describe 'attr_readers' do
|
44
|
-
describe '#
|
45
|
-
subject { instance.
|
47
|
+
describe '#table_name' do
|
48
|
+
subject { instance.table_name }
|
46
49
|
|
47
|
-
it { is_expected.to eq(
|
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
|
50
|
+
it { is_expected.to eq(table_name) }
|
54
51
|
end
|
55
52
|
|
56
53
|
describe '#fields' do
|
@@ -62,27 +59,32 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
62
59
|
describe '#explicit_name' do
|
63
60
|
subject { instance.explicit_name }
|
64
61
|
|
65
|
-
|
62
|
+
context 'with allow_equivalent' do
|
63
|
+
let(:options) { { table_name: table_name, allow_equivalent: true } }
|
64
|
+
|
65
|
+
it { is_expected.to eq(nil) }
|
66
|
+
end
|
66
67
|
|
67
68
|
context 'with name option' do
|
68
|
-
let(:options) { { name: '
|
69
|
+
let(:options) { { table_name: table_name, name: 'index_auth_users_on_names' } }
|
69
70
|
|
70
|
-
it { is_expected.to eq('
|
71
|
+
it { is_expected.to eq('index_auth_users_on_names') }
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
74
75
|
describe '#length' do
|
75
76
|
subject { instance.length }
|
76
|
-
let(:options) { { length: length } }
|
77
|
+
let(:options) { { table_name: table_name, length: length } }
|
77
78
|
|
78
79
|
context 'with integer length' do
|
80
|
+
let(:fields) { ['last_name'] }
|
79
81
|
let(:length) { 2 }
|
80
82
|
|
81
|
-
it { is_expected.to eq(
|
83
|
+
it { is_expected.to eq(last_name: 2) }
|
82
84
|
end
|
83
85
|
|
84
86
|
context 'with Hash length' do
|
85
|
-
let(:length) { {
|
87
|
+
let(:length) { { first_name: 2 } }
|
86
88
|
|
87
89
|
it { is_expected.to eq(length) }
|
88
90
|
end
|
@@ -90,9 +92,9 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
90
92
|
|
91
93
|
describe '#options' do
|
92
94
|
subject { instance.options }
|
93
|
-
let(:options) { { name: 'my_index', unique: false, where: "(
|
95
|
+
let(:options) { { name: 'my_index', table_name: table_name, unique: false, where: "(last_name like 'a%')", length: { last_name: 10, first_name: 5 } } }
|
94
96
|
|
95
|
-
it { is_expected.to eq(options) }
|
97
|
+
it { is_expected.to eq(options.except(:table_name)) }
|
96
98
|
end
|
97
99
|
|
98
100
|
describe '#with_name' do
|
@@ -105,33 +107,25 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
105
107
|
end
|
106
108
|
end
|
107
109
|
|
108
|
-
describe 'class methods' do
|
109
|
-
|
110
|
-
|
111
|
-
describe 'index_definitions' do
|
112
|
-
it do
|
113
|
-
expect(model_class.index_definitions.size).to eq(1)
|
110
|
+
describe 'Model class methods' do
|
111
|
+
describe '.has index_definitions' do
|
112
|
+
subject { model_class.index_definitions }
|
114
113
|
|
115
|
-
|
116
|
-
expect(
|
117
|
-
|
118
|
-
|
114
|
+
it 'returns indexes without primary key' do
|
115
|
+
expect(subject.map(&:to_key)).to eq([
|
116
|
+
['index_index_definition_test_models_on_name', ['name'], { length: nil, unique: false, where: nil }],
|
117
|
+
])
|
119
118
|
end
|
120
119
|
end
|
121
120
|
|
122
|
-
describe 'has index_definitions_with_primary_key' do
|
123
|
-
|
124
|
-
expect(model_class.index_definitions_with_primary_key).to be_kind_of(Set)
|
125
|
-
result = model_class.index_definitions_with_primary_key.sort_by(&:name)
|
126
|
-
expect(result.size).to eq(2)
|
127
|
-
|
128
|
-
expect(result[0].name).to eq('PRIMARY')
|
129
|
-
expect(result[0].fields).to eq(['id'])
|
130
|
-
expect(result[0].unique).to eq(true)
|
121
|
+
describe '.has index_definitions_with_primary_key' do
|
122
|
+
subject { model_class.index_definitions_with_primary_key }
|
131
123
|
|
132
|
-
|
133
|
-
expect(
|
134
|
-
|
124
|
+
it 'returns indexes with primary key' do
|
125
|
+
expect(subject.map(&:to_key)).to eq([
|
126
|
+
['index_index_definition_test_models_on_name', ['name'], { length: nil, unique: false, where: nil }],
|
127
|
+
['PRIMARY', ['id'], { length: nil, unique: true, where: nil }],
|
128
|
+
])
|
135
129
|
end
|
136
130
|
end
|
137
131
|
end
|
@@ -147,6 +141,11 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
147
141
|
ActiveRecord::Base.connection.execute <<~EOS
|
148
142
|
CREATE UNIQUE INDEX index_definition_test_models_on_name ON index_definition_test_models(name)
|
149
143
|
EOS
|
144
|
+
if defined?(Mysql2)
|
145
|
+
ActiveRecord::Base.connection.execute <<~EOS
|
146
|
+
CREATE INDEX index_definition_test_models_on_name_partial ON index_definition_test_models(name(10))
|
147
|
+
EOS
|
148
|
+
end
|
150
149
|
ActiveRecord::Base.connection.execute <<~EOS
|
151
150
|
CREATE TABLE index_definition_compound_index_models (
|
152
151
|
fk1_id INTEGER NOT NULL,
|
@@ -157,29 +156,38 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
157
156
|
ActiveRecord::Base.connection.schema_cache.clear!
|
158
157
|
end
|
159
158
|
|
160
|
-
describe '
|
161
|
-
|
159
|
+
describe 'for_table' do
|
160
|
+
let(:ignore_indexes) { model_class.ignore_indexes }
|
161
|
+
subject { described_class.for_table(model_class.table_name, ignore_indexes, model_class.connection) }
|
162
162
|
|
163
163
|
context 'with single-column PK' do
|
164
164
|
it 'returns the indexes for the model' do
|
165
|
-
expect(subject.
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
expect(subject[1].columns).to eq(['id'])
|
171
|
-
expect(subject[1].unique).to eq(true)
|
165
|
+
expect(subject.map(&:to_key)).to eq([
|
166
|
+
["index_definition_test_models_on_name", ["name"], { unique: true, where: nil, length: nil }],
|
167
|
+
(["index_definition_test_models_on_name_partial", ["name"], { unique: false, where: nil, length: { name: 10 } }] if defined?(Mysql2)),
|
168
|
+
["PRIMARY", ["id"], { unique: true, where: nil, length: nil }]
|
169
|
+
].compact)
|
172
170
|
end
|
173
171
|
end
|
174
172
|
|
175
|
-
context 'with
|
173
|
+
context 'with composite (multi-column) PK' do
|
176
174
|
let(:model_class) { IndexDefinitionCompoundIndexModel }
|
177
175
|
|
178
176
|
it 'returns the indexes for the model' do
|
179
|
-
expect(subject.
|
180
|
-
|
181
|
-
|
182
|
-
|
177
|
+
expect(subject.map(&:to_key)).to eq([
|
178
|
+
["PRIMARY", ["fk1_id", "fk2_id"], { length: nil, unique: true, where: nil }]
|
179
|
+
])
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'with ignored_indexes' do
|
184
|
+
let(:ignore_indexes) { ['index_definition_test_models_on_name'] }
|
185
|
+
|
186
|
+
it 'skips the ignored index' do
|
187
|
+
expect(subject.map(&:to_key)).to eq([
|
188
|
+
(["index_definition_test_models_on_name_partial", ["name"], { unique: false, where: nil, length: { name: 10 } }] if defined?(Mysql2)),
|
189
|
+
["PRIMARY", ["id"], { length: nil, unique: true, where: nil }]
|
190
|
+
].compact)
|
183
191
|
end
|
184
192
|
end
|
185
193
|
end
|
@@ -252,6 +260,69 @@ RSpec.describe DeclareSchema::Model::IndexDefinition do
|
|
252
260
|
end
|
253
261
|
end
|
254
262
|
end
|
263
|
+
|
264
|
+
describe '.normalize_index_length' do
|
265
|
+
let(:columns) { [:last_name] }
|
266
|
+
subject { described_class.normalize_index_length(length, columns: columns) }
|
267
|
+
|
268
|
+
context 'with nil length' do
|
269
|
+
let(:length) { nil }
|
270
|
+
|
271
|
+
it { is_expected.to eq(nil) }
|
272
|
+
end
|
273
|
+
|
274
|
+
context 'when Integer' do
|
275
|
+
let(:length) { 10 }
|
276
|
+
|
277
|
+
it { is_expected.to eq(last_name: length) }
|
278
|
+
|
279
|
+
context 'with multiple columns' do
|
280
|
+
let(:columns) { ["last_name", "first_name"] }
|
281
|
+
|
282
|
+
it { expect { subject }.to raise_exception(ArgumentError, /Index length of Integer only allowed when exactly one column; got 10 for \["last_name", "first_name"]/i) }
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
context 'when empty Hash' do
|
287
|
+
let(:length) { {} }
|
288
|
+
|
289
|
+
it { is_expected.to eq(nil) }
|
290
|
+
end
|
291
|
+
|
292
|
+
context 'when Hash' do
|
293
|
+
let(:length) { { last_name: 10 } }
|
294
|
+
|
295
|
+
it { is_expected.to eq(length) }
|
296
|
+
end
|
297
|
+
|
298
|
+
context 'when Hash with String key' do
|
299
|
+
let(:length) { { "last_name" => 10 } }
|
300
|
+
|
301
|
+
it { is_expected.to eq(last_name: 10) }
|
302
|
+
end
|
303
|
+
|
304
|
+
context 'with multiple columns' do
|
305
|
+
let(:columns) { [:last_name, :first_name] }
|
306
|
+
|
307
|
+
context 'when Hash with String keys' do
|
308
|
+
let(:length) { { "last_name" => 10, "first_name" => 5 } }
|
309
|
+
|
310
|
+
it { is_expected.to eq(last_name: 10, first_name: 5) }
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
context 'with nil length' do
|
315
|
+
let(:length) { nil }
|
316
|
+
|
317
|
+
it { is_expected.to eq(nil) }
|
318
|
+
end
|
319
|
+
|
320
|
+
context 'with an invalid length' do
|
321
|
+
let(:length) { 10.5 }
|
322
|
+
|
323
|
+
it { expect { subject }.to raise_exception(ArgumentError, /length must be nil or Integer or a Hash of column names to lengths; got 10\.5 for \[:last_name]/i) }
|
324
|
+
end
|
325
|
+
end
|
255
326
|
end
|
256
327
|
# TODO: fill out remaining tests
|
257
328
|
end
|
@@ -9,6 +9,8 @@ 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+
|
12
14
|
|
13
15
|
context 'Using declare_schema' do
|
14
16
|
before do
|
@@ -27,27 +29,45 @@ RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
|
|
27
29
|
|
28
30
|
describe '#to_key' do
|
29
31
|
subject { model.to_key }
|
30
|
-
it {
|
32
|
+
it { is_expected.to eq(['table_options_definition_test_models', "{:charset=>#{charset.inspect}, :collation=>#{collation.inspect}}"]) }
|
31
33
|
end
|
32
34
|
|
33
35
|
describe '#settings' do
|
34
36
|
subject { model.settings }
|
35
|
-
it {
|
37
|
+
it { is_expected.to eq("CHARACTER SET #{charset} COLLATE #{collation}") }
|
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
|
36
56
|
end
|
37
57
|
|
38
58
|
describe '#hash' do
|
39
59
|
subject { model.hash }
|
40
|
-
it {
|
60
|
+
it { is_expected.to eq(['table_options_definition_test_models', "{:charset=>#{charset.inspect}, :collation=>#{collation.inspect}}"].hash) }
|
41
61
|
end
|
42
62
|
|
43
63
|
describe '#to_s' do
|
44
64
|
subject { model.to_s }
|
45
|
-
it {
|
65
|
+
it { is_expected.to eq("CHARACTER SET #{charset} COLLATE #{collation}") }
|
46
66
|
end
|
47
67
|
|
48
68
|
describe '#alter_table_statement' do
|
49
69
|
subject { model.alter_table_statement }
|
50
|
-
it {
|
70
|
+
it { is_expected.to match(/execute "ALTER TABLE .*table_options_definition_test_models.* CHARACTER SET #{charset} COLLATE #{collation}"/) }
|
51
71
|
end
|
52
72
|
end
|
53
73
|
|
@@ -67,7 +87,7 @@ RSpec.describe DeclareSchema::Model::TableOptionsDefinition do
|
|
67
87
|
generate_migrations '-n', '-m'
|
68
88
|
end
|
69
89
|
|
70
|
-
it {
|
90
|
+
it { is_expected.to eq(described_class.new(model_class.table_name, **options)) }
|
71
91
|
end
|
72
92
|
end
|
73
93
|
end
|
@@ -8,10 +8,34 @@ RSpec.describe DeclareSchema do
|
|
8
8
|
it { is_expected.to eq("utf8mb4") }
|
9
9
|
end
|
10
10
|
|
11
|
-
context 'when
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
context 'when running on MySQL 5.7' do
|
12
|
+
around do |spec|
|
13
|
+
described_class.mysql_version = Gem::Version.new('5.7.48')
|
14
|
+
spec.run
|
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
|
15
39
|
end
|
16
40
|
end
|
17
41
|
|
@@ -22,10 +46,40 @@ RSpec.describe DeclareSchema do
|
|
22
46
|
it { is_expected.to eq("utf8mb4_bin") }
|
23
47
|
end
|
24
48
|
|
25
|
-
context 'when
|
26
|
-
|
27
|
-
|
28
|
-
|
49
|
+
context 'when running on MySQL 5.7' do
|
50
|
+
around do |spec|
|
51
|
+
described_class.mysql_version = Gem::Version.new('5.7.48')
|
52
|
+
spec.run
|
53
|
+
ensure
|
54
|
+
described_class.remove_instance_variable('@mysql_version')
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when explicitly set' do
|
58
|
+
before { described_class.default_collation = "utf8_general_ci" }
|
59
|
+
after { described_class.default_collation = "utf8mb4_bin" }
|
60
|
+
it { is_expected.to eq("utf8_general_ci") }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when running on MySQL 8.0' do
|
65
|
+
around do |spec|
|
66
|
+
described_class.mysql_version = Gem::Version.new('8.0.21')
|
67
|
+
spec.run
|
68
|
+
ensure
|
69
|
+
described_class.remove_instance_variable('@mysql_version')
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when explicitly set without _ci' do
|
73
|
+
before { described_class.default_collation = "utf8_general" }
|
74
|
+
after { described_class.default_collation = "utf8mb4_bin" }
|
75
|
+
it { is_expected.to eq("utf8mb3_general") }
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'when explicitly set with _ci' do
|
79
|
+
before { described_class.default_collation = "utf8_general_ci" }
|
80
|
+
after { described_class.default_collation = "utf8mb4_bin" }
|
81
|
+
it { is_expected.to eq("utf8mb3_general_ci") }
|
82
|
+
end
|
29
83
|
end
|
30
84
|
end
|
31
85
|
|
@@ -12,6 +12,8 @@ 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+
|
15
17
|
|
16
18
|
describe '#before_generating_migration' do
|
17
19
|
it 'requires a block be passed' do
|
@@ -29,7 +31,7 @@ module Generators
|
|
29
31
|
context 'when explicitly set' do
|
30
32
|
before { described_class.default_charset = "utf8" }
|
31
33
|
after { described_class.default_charset = "utf8mb4" }
|
32
|
-
it { should eq(
|
34
|
+
it { should eq(charset) }
|
33
35
|
end
|
34
36
|
|
35
37
|
it 'should output deprecation warning' do
|