declare_schema 2.0.0 → 2.1.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.devcontainer/Dockerfile +19 -0
- data/.devcontainer/boot.sh +1 -0
- data/.devcontainer/devcontainer.json +55 -0
- data/.devcontainer/docker-compose.yml +40 -0
- data/.github/workflows/declare_schema_build.yml +35 -11
- data/Appraisals +2 -10
- data/CHANGELOG.md +5 -0
- data/CODE-OF-CONDUCT.md +16 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +6 -1
- data/Gemfile.lock +87 -77
- data/README.md +38 -14
- data/Rakefile +5 -15
- data/catalog-info.yaml +35 -0
- data/config/brakeman.ignore +2 -2
- data/gemfiles/{rails_6_1_sqlite3.gemfile → rails_6_1.gemfile} +3 -0
- data/gemfiles/{rails_7_0_sqlite3.gemfile → rails_7_0.gemfile} +3 -0
- data/gemfiles/{rails_7_1_sqlite3.gemfile → rails_7_1.gemfile} +3 -0
- data/gemfiles/{rails_7_0_mysql2.gemfile → rails_7_2.gemfile} +4 -1
- data/lib/declare_schema/command.rb +2 -8
- data/lib/declare_schema/model/column.rb +1 -1
- data/lib/declare_schema/model/foreign_key_definition.rb +9 -12
- data/lib/declare_schema/model/index_definition.rb +16 -8
- data/lib/declare_schema/model.rb +10 -14
- data/lib/declare_schema/schema_change/base.rb +4 -0
- data/lib/declare_schema/schema_change/primary_key_change.rb +19 -6
- data/lib/declare_schema/version.rb +1 -1
- data/lib/declare_schema.rb +20 -8
- data/lib/generators/declare_schema/migration/migration_generator.rb +15 -2
- data/lib/generators/declare_schema/migration/migrator.rb +16 -9
- data/spec/fixtures/migrations/mysql2/will_generate_unique_constraint_names_rails_6.txt +15 -0
- data/spec/fixtures/migrations/mysql2/will_generate_unique_constraint_names_rails_7.txt +15 -0
- data/spec/fixtures/migrations/postgresql/will_generate_unique_constraint_names_rails_6.txt +15 -0
- data/spec/fixtures/migrations/postgresql/will_generate_unique_constraint_names_rails_7.txt +15 -0
- data/spec/fixtures/migrations/sqlite3/will_generate_unique_constraint_names_rails_6.txt +15 -0
- data/spec/fixtures/migrations/sqlite3/will_generate_unique_constraint_names_rails_7.txt +15 -0
- data/spec/lib/declare_schema/api_spec.rb +1 -3
- data/spec/lib/declare_schema/field_declaration_dsl_spec.rb +3 -3
- data/spec/lib/declare_schema/field_spec_spec.rb +68 -45
- data/spec/lib/declare_schema/generator_spec.rb +2 -4
- data/spec/lib/declare_schema/interactive_primary_key_spec.rb +3 -10
- data/spec/lib/declare_schema/migration_generator_spec.rb +248 -249
- data/spec/lib/declare_schema/model/column_spec.rb +89 -41
- data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +14 -8
- data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +4 -9
- data/spec/lib/declare_schema/model/index_definition_spec.rb +18 -10
- data/spec/lib/declare_schema/model/table_options_definition_spec.rb +11 -11
- data/spec/lib/declare_schema/schema_change/base_spec.rb +5 -7
- data/spec/lib/declare_schema/schema_change/column_add_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/column_change_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/column_remove_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/column_rename_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/foreign_key_add_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/foreign_key_remove_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/index_add_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/index_remove_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/primary_key_change_spec.rb +39 -15
- data/spec/lib/declare_schema/schema_change/table_add_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/table_change_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/table_remove_spec.rb +1 -3
- data/spec/lib/declare_schema/schema_change/table_rename_spec.rb +1 -3
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +0 -4
- data/spec/spec_helper.rb +3 -0
- data/spec/support/adapter_specific_test_helpers.rb +25 -0
- data/spec/{lib/declare_schema → support}/prepare_testapp.rb +3 -1
- data/spec/support/test_app_spec_helpers.rb +7 -0
- metadata +22 -9
- data/gemfiles/rails_6_1_mysql2.gemfile +0 -23
- data/gemfiles/rails_7_1_mysql2.gemfile +0 -23
@@ -0,0 +1,15 @@
|
|
1
|
+
create_table :affiliates, id: :bigint, options: "CHARACTER SET utf8mb4 COLLATE utf8mb4_bin" do |t|
|
2
|
+
t.string :name, limit: 250, null: true, charset: "utf8mb4", collation: "utf8mb4_bin"
|
3
|
+
t.integer :category_id, limit: 8, null: false
|
4
|
+
end
|
5
|
+
create_table :advertisers, id: :bigint, options: "CHARACTER SET utf8mb4 COLLATE utf8mb4_bin" do |t|
|
6
|
+
t.string :name, limit: 250, null: true, charset: "utf8mb4", collation: "utf8mb4_bin"
|
7
|
+
t.integer :category_id, limit: 8, null: false
|
8
|
+
end
|
9
|
+
create_table :categories, id: :bigint, options: "CHARACTER SET utf8mb4 COLLATE utf8mb4_bin" do |t|
|
10
|
+
t.string :name, limit: 250, null: true, charset: "utf8mb4", collation: "utf8mb4_bin"
|
11
|
+
end
|
12
|
+
add_index :affiliates, [:category_id], name: :index_affiliates_on_category_id
|
13
|
+
add_index :advertisers, [:category_id], name: :index_advertisers_on_category_id
|
14
|
+
add_foreign_key :affiliates, :categories, column: :category_id, name: :index_affiliates_on_category_id
|
15
|
+
add_foreign_key :advertisers, :categories, column: :category_id, name: :index_advertisers_on_category_id
|
@@ -3,14 +3,14 @@
|
|
3
3
|
require_relative '../../../lib/declare_schema/field_declaration_dsl'
|
4
4
|
|
5
5
|
RSpec.describe DeclareSchema::FieldDeclarationDsl do
|
6
|
+
include_context 'prepare test app'
|
7
|
+
|
6
8
|
let(:model) { TestModel.new }
|
7
9
|
subject { declared_class.new(model) }
|
8
10
|
|
9
11
|
context 'Using declare_schema' do
|
10
12
|
before do
|
11
|
-
|
12
|
-
|
13
|
-
class TestModel < ActiveRecord::Base
|
13
|
+
class TestModel < ActiveRecord::Base # rubocop:disable Lint/ConstantDefinitionInBlock
|
14
14
|
declare_schema do
|
15
15
|
string :name, limit: 127
|
16
16
|
|
@@ -1,26 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'mysql2'
|
5
|
-
rescue LoadError
|
6
|
-
end
|
7
|
-
|
8
|
-
begin
|
9
|
-
require 'sqlite3'
|
10
|
-
rescue LoadError
|
11
|
-
end
|
12
|
-
|
13
3
|
RSpec.describe DeclareSchema::Model::FieldSpec do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
4
|
+
include_context 'prepare test app'
|
5
|
+
|
6
|
+
let(:model) { double('model', _table_options: {}, _declared_primary_key: 'id') }
|
7
|
+
let(:col_spec) do
|
8
|
+
if current_adapter == 'postgresql'
|
9
|
+
instance_double(ActiveRecord::ConnectionAdapters::PostgreSQL::Column, type: :string, sql_type: 'character varying(100)', oid: 1043, fmod: 2052)
|
10
|
+
else
|
11
|
+
instance_double(ActiveRecord::ConnectionAdapters::Column, type: :string, sql_type: :string)
|
12
|
+
end
|
19
13
|
end
|
20
14
|
|
21
15
|
describe '#initialize' do
|
16
|
+
subject { described_class.new(model, :price, :integer, anonymize_using: 'x', null: false, position: 0, limit: 4) }
|
22
17
|
it 'normalizes option order' do
|
23
|
-
subject = described_class.new(model, :price, :integer, anonymize_using: 'x', null: false, position: 0, limit: 4)
|
24
18
|
expect(subject.options.keys).to eq([:limit, :null, :anonymize_using])
|
25
19
|
end
|
26
20
|
|
@@ -33,48 +27,54 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
33
27
|
|
34
28
|
describe '#schema_attributes' do
|
35
29
|
describe 'integer 4' do
|
30
|
+
subject { described_class.new(model, :price, :integer, limit: 4, null: false, position: 0) }
|
36
31
|
it 'returns schema attributes' do
|
37
|
-
subject = described_class.new(model, :price, :integer, limit: 4, null: false, position: 0)
|
38
32
|
expect(subject.schema_attributes(col_spec)).to eq(type: :integer, limit: 4, null: false)
|
39
33
|
end
|
40
34
|
end
|
41
35
|
|
42
36
|
describe 'integer 8' do
|
37
|
+
subject { described_class.new(model, :price, :integer, limit: 8, null: true, position: 2) }
|
43
38
|
it 'returns schema attributes' do
|
44
|
-
subject = described_class.new(model, :price, :integer, limit: 8, null: true, position: 2)
|
45
39
|
expect(subject.schema_attributes(col_spec)).to eq(type: :integer, limit: 8, null: true)
|
46
40
|
end
|
47
41
|
end
|
48
42
|
|
49
43
|
describe 'bigint' do
|
44
|
+
subject { described_class.new(model, :price, :bigint, null: false, position: 2) }
|
50
45
|
it 'returns schema attributes' do
|
51
|
-
subject = described_class.new(model, :price, :bigint, null: false, position: 2)
|
52
46
|
expect(subject.schema_attributes(col_spec)).to eq(type: :integer, limit: 8, null: false)
|
53
47
|
end
|
54
48
|
end
|
55
49
|
|
56
50
|
describe 'string' do
|
51
|
+
subject { described_class.new(model, :title, :string, limit: 100, null: true, charset: 'utf8mb4', position: 0) }
|
52
|
+
|
57
53
|
it 'returns schema attributes (including charset/collation iff mysql)' do
|
58
|
-
|
59
|
-
|
54
|
+
case current_adapter
|
55
|
+
when 'mysql2'
|
60
56
|
expect(subject.schema_attributes(col_spec)).to eq(type: :string, limit: 100, null: true, charset: 'utf8mb4', collation: 'utf8mb4_bin')
|
61
57
|
else
|
62
58
|
expect(subject.schema_attributes(col_spec)).to eq(type: :string, limit: 100, null: true)
|
63
59
|
end
|
64
60
|
end
|
65
61
|
|
66
|
-
|
62
|
+
context 'MySQL only' do
|
63
|
+
include_context 'skip unless' do
|
64
|
+
let(:adapter) { 'mysql2' }
|
65
|
+
end
|
66
|
+
|
67
67
|
context 'when running on MySQL 8.0' do
|
68
68
|
around do |spec|
|
69
69
|
DeclareSchema.mysql_version = Gem::Version.new('8.0.21')
|
70
70
|
spec.run
|
71
71
|
ensure
|
72
|
-
DeclareSchema.remove_instance_variable('@mysql_version') rescue nil
|
72
|
+
DeclareSchema.remove_instance_variable('@mysql_version') rescue nil # rubocop:disable Style/RescueModifier
|
73
73
|
end
|
74
74
|
|
75
|
-
|
76
|
-
subject = described_class.new(model, :title, :string, limit: 100, null: true, charset: 'utf8', collation: 'utf8_general', position: 0)
|
75
|
+
subject { described_class.new(model, :title, :string, limit: 100, null: true, charset: 'utf8', collation: 'utf8_general', position: 0) }
|
77
76
|
|
77
|
+
it 'normalizes charset and collation' do
|
78
78
|
expect(subject.schema_attributes(col_spec)).to eq(type: :string, limit: 100, null: true, charset: 'utf8mb3', collation: 'utf8mb3_general')
|
79
79
|
end
|
80
80
|
end
|
@@ -89,9 +89,9 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
89
89
|
end
|
90
90
|
|
91
91
|
describe 'text' do
|
92
|
+
subject { described_class.new(model, :title, :text, limit: 200, null: true, charset: 'utf8mb4', position: 2) }
|
92
93
|
it 'returns schema attributes (including charset/collation iff mysql)' do
|
93
|
-
|
94
|
-
if defined?(Mysql2)
|
94
|
+
if current_adapter == 'mysql2'
|
95
95
|
expect(subject.schema_attributes(col_spec)).to eq(type: :text, limit: 255, null: true, charset: 'utf8mb4', collation: 'utf8mb4_bin')
|
96
96
|
else
|
97
97
|
expect(subject.schema_attributes(col_spec)).to eq(type: :text, null: true)
|
@@ -99,7 +99,7 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
it 'allows a default to be set unless mysql' do
|
102
|
-
if
|
102
|
+
if current_adapter == 'mysql2'
|
103
103
|
expect do
|
104
104
|
described_class.new(model, :title, :text, limit: 200, null: true, default: 'none', charset: 'utf8mb4', position: 2)
|
105
105
|
end.to raise_exception(DeclareSchema::MysqlTextMayNotHaveDefault)
|
@@ -110,10 +110,10 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
110
110
|
end
|
111
111
|
|
112
112
|
describe 'limit' do
|
113
|
+
subject { described_class.new(model, :title, :text, null: true, charset: 'utf8mb4', position: 2) }
|
113
114
|
it 'uses default_text_limit option when not explicitly set in field spec' do
|
114
115
|
allow(::DeclareSchema).to receive(:default_text_limit) { 100 }
|
115
|
-
|
116
|
-
if defined?(Mysql2)
|
116
|
+
if current_adapter == 'mysql2'
|
117
117
|
expect(subject.schema_attributes(col_spec)).to eq(type: :text, limit: 255, null: true, charset: 'utf8mb4', collation: 'utf8mb4_bin')
|
118
118
|
else
|
119
119
|
expect(subject.schema_attributes(col_spec)).to eq(type: :text, null: true)
|
@@ -121,11 +121,9 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
121
121
|
end
|
122
122
|
|
123
123
|
it 'raises error when default_text_limit option is nil when not explicitly set in field spec' do
|
124
|
-
if
|
124
|
+
if current_adapter == 'mysql2'
|
125
125
|
expect(::DeclareSchema).to receive(:default_text_limit) { nil }
|
126
|
-
expect
|
127
|
-
described_class.new(model, :title, :text, null: true, charset: 'utf8mb4', position: 2)
|
128
|
-
end.to raise_error(/limit: must be provided for :text field/)
|
126
|
+
expect { subject }.to raise_error(/limit: must be provided for :text field/)
|
129
127
|
end
|
130
128
|
end
|
131
129
|
end
|
@@ -173,18 +171,22 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
173
171
|
end
|
174
172
|
end
|
175
173
|
|
176
|
-
|
174
|
+
context 'MySQL only' do
|
175
|
+
include_context 'skip unless' do
|
176
|
+
let(:adapter) { 'mysql2' }
|
177
|
+
end
|
178
|
+
|
177
179
|
describe 'varbinary' do # TODO: :varbinary is an Invoca addition to Rails; make it a configurable option
|
180
|
+
subject { described_class.new(model, :binary_dump, :varbinary, limit: 200, null: false, position: 2) }
|
178
181
|
it 'is supported' do
|
179
|
-
subject = described_class.new(model, :binary_dump, :varbinary, limit: 200, null: false, position: 2)
|
180
182
|
expect(subject.schema_attributes(col_spec)).to eq(type: :varbinary, limit: 200, null: false)
|
181
183
|
end
|
182
184
|
end
|
183
185
|
end
|
184
186
|
|
185
187
|
describe 'decimal' do
|
188
|
+
subject { described_class.new(model, :quantity, :decimal, precision: 8, scale: 10, null: true, position: 3) }
|
186
189
|
it 'allows precision: and scale:' do
|
187
|
-
subject = described_class.new(model, :quantity, :decimal, precision: 8, scale: 10, null: true, position: 3)
|
188
190
|
expect(subject.schema_attributes(col_spec)).to eq(type: :decimal, precision: 8, scale: 10, null: true)
|
189
191
|
end
|
190
192
|
|
@@ -199,10 +201,18 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
199
201
|
end
|
200
202
|
end
|
201
203
|
|
202
|
-
[:integer, :bigint, :string, :text, :binary, :datetime, :date, :time,
|
204
|
+
[:integer, :bigint, :string, :text, :binary, :datetime, :date, :time, :varbinary].compact.each do |t|
|
203
205
|
describe t.to_s do
|
204
206
|
let(:extra) { t == :string ? { limit: 100 } : {} }
|
205
207
|
|
208
|
+
around do |spec|
|
209
|
+
if t == :varbinary && current_adapter != 'mysql2'
|
210
|
+
spec.skip
|
211
|
+
else
|
212
|
+
spec.run
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
206
216
|
it 'does not allow precision:' do
|
207
217
|
expect_any_instance_of(described_class).to receive(:warn).with(/precision: only allowed for :decimal type/)
|
208
218
|
described_class.new(model, :quantity, t, **{ precision: 8, null: true, position: 3 }.merge(extra))
|
@@ -216,25 +226,31 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
216
226
|
end
|
217
227
|
|
218
228
|
describe 'datetime' do
|
229
|
+
subject { described_class.new(model, :created_at, :datetime, null: false, position: 1) }
|
219
230
|
it 'keeps type as "datetime"' do
|
220
|
-
subject = described_class.new(model, :created_at, :datetime, null: false, position: 1)
|
221
231
|
expect(subject.schema_attributes(col_spec)).to eq(type: :datetime, null: false)
|
222
232
|
end
|
223
233
|
end
|
224
234
|
|
225
235
|
describe 'timestamp' do
|
236
|
+
subject { described_class.new(model, :created_at, :timestamp, null: true, position: 2) }
|
226
237
|
it 'normalizes type to "datetime"' do
|
227
|
-
subject = described_class.new(model, :created_at, :timestamp, null: true, position: 2)
|
228
238
|
expect(subject.schema_attributes(col_spec)).to eq(type: :datetime, null: true)
|
229
239
|
end
|
230
240
|
end
|
231
241
|
|
232
242
|
describe 'default:' do
|
233
|
-
|
243
|
+
subject { described_class.new(model, :price, :integer, limit: 4, default: '42', null: true, position: 2) }
|
244
|
+
|
245
|
+
let(:col_spec) do
|
246
|
+
if current_adapter == 'postgresql'
|
247
|
+
instance_double(ActiveRecord::ConnectionAdapters::PostgreSQL::Column, type: :integer, sql_type: "integer", limit: 4, oid: 23, fmod: -1)
|
248
|
+
else
|
249
|
+
instance_double(ActiveRecord::ConnectionAdapters::Column, type: :integer, sql_type: "integer", limit: 4)
|
250
|
+
end
|
251
|
+
end
|
234
252
|
|
235
253
|
it 'typecasts default value' do
|
236
|
-
allow(col_spec).to receive(:type_cast_from_database) { |default| Integer(default) }
|
237
|
-
subject = described_class.new(model, :price, :integer, limit: 4, default: '42', null: true, position: 2)
|
238
254
|
expect(subject.schema_attributes(col_spec)).to eq(type: :integer, limit: 4, default: 42, null: true)
|
239
255
|
end
|
240
256
|
end
|
@@ -242,8 +258,15 @@ RSpec.describe DeclareSchema::Model::FieldSpec do
|
|
242
258
|
|
243
259
|
describe '#schema_attributes' do
|
244
260
|
let(:col_spec) do
|
245
|
-
|
246
|
-
|
261
|
+
if current_adapter == 'postgresql'
|
262
|
+
instance_double(ActiveRecord::ConnectionAdapters::PostgreSQL::Column,
|
263
|
+
name: "price", type: :integer, sql_type: "integer", limit: 4,
|
264
|
+
null: false, default: nil, default_function: "adverts", oid: 23, fmod: -1)
|
265
|
+
else
|
266
|
+
instance_double(ActiveRecord::ConnectionAdapters::Column,
|
267
|
+
name: "price", type: :integer, sql_type: "integer(8)", limit: 8,
|
268
|
+
null: false, default: nil, default_function: "adverts")
|
269
|
+
end
|
247
270
|
end
|
248
271
|
|
249
272
|
it 'returns the attributes except name, position, and non-SQL options' do
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe 'DeclareSchema Migration Generator' do
|
4
|
-
|
5
|
-
load File.expand_path('prepare_testapp.rb', __dir__)
|
6
|
-
end
|
4
|
+
include_context 'prepare test app'
|
7
5
|
|
8
6
|
it "generates nested models" do
|
9
7
|
generate_model 'alpha/beta', 'one:string', 'two:integer'
|
@@ -57,7 +55,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
|
|
57
55
|
|
58
56
|
expect(File.exist?('db/schema.rb')).to be_truthy
|
59
57
|
|
60
|
-
if
|
58
|
+
if current_adapter == 'sqlite3'
|
61
59
|
if ActiveSupport.version >= Gem::Version.new('7.1.0')
|
62
60
|
expect(File.exist?("storage/development.sqlite3") || File.exist?("storage/test.sqlite3")).to be_truthy
|
63
61
|
else
|
@@ -1,14 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'mysql2'
|
5
|
-
rescue LoadError
|
6
|
-
end
|
7
|
-
|
8
3
|
RSpec.describe 'DeclareSchema Migration Generator interactive primary key' do
|
9
|
-
|
10
|
-
load File.expand_path('prepare_testapp.rb', __dir__)
|
11
|
-
end
|
4
|
+
include_context 'prepare test app'
|
12
5
|
|
13
6
|
context 'Using declare_schema' do
|
14
7
|
it "allows alternate primary keys" do
|
@@ -56,12 +49,12 @@ RSpec.describe 'DeclareSchema Migration Generator interactive primary key' do
|
|
56
49
|
# (0.1ms) DROP TABLE "afoos"
|
57
50
|
# (pry):17
|
58
51
|
# (0.9ms) commit transaction
|
59
|
-
if
|
52
|
+
if current_adapter == 'sqlite3'
|
60
53
|
ActiveRecord::Base.connection.execute("drop table foos")
|
61
54
|
ActiveRecord::Base.connection.execute("CREATE TABLE foos (id integer PRIMARY KEY AUTOINCREMENT NOT NULL)")
|
62
55
|
end
|
63
56
|
|
64
|
-
|
57
|
+
unless current_adapter == 'mysql2' # TODO TECH-4814 Put this test back for Mysql2
|
65
58
|
# replace custom primary_key
|
66
59
|
class Foo < ActiveRecord::Base
|
67
60
|
declare_schema do
|