declare_schema 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/declare_schema_build.yml +21 -5
  3. data/Appraisals +21 -4
  4. data/CHANGELOG.md +40 -0
  5. data/Gemfile +1 -2
  6. data/Gemfile.lock +7 -9
  7. data/README.md +3 -3
  8. data/Rakefile +17 -4
  9. data/bin/declare_schema +1 -1
  10. data/declare_schema.gemspec +1 -1
  11. data/gemfiles/rails_4_mysql.gemfile +22 -0
  12. data/gemfiles/{rails_4.gemfile → rails_4_sqlite.gemfile} +1 -2
  13. data/gemfiles/rails_5_mysql.gemfile +22 -0
  14. data/gemfiles/{rails_5.gemfile → rails_5_sqlite.gemfile} +1 -2
  15. data/gemfiles/rails_6_mysql.gemfile +22 -0
  16. data/gemfiles/{rails_6.gemfile → rails_6_sqlite.gemfile} +2 -3
  17. data/lib/declare_schema/command.rb +10 -3
  18. data/lib/declare_schema/model/column.rb +168 -0
  19. data/lib/declare_schema/model/field_spec.rb +59 -143
  20. data/lib/declare_schema/model/foreign_key_definition.rb +36 -25
  21. data/lib/declare_schema/model/table_options_definition.rb +8 -6
  22. data/lib/declare_schema/version.rb +1 -1
  23. data/lib/generators/declare_schema/migration/migration_generator.rb +1 -1
  24. data/lib/generators/declare_schema/migration/migrator.rb +142 -116
  25. data/spec/lib/declare_schema/field_declaration_dsl_spec.rb +1 -1
  26. data/spec/lib/declare_schema/field_spec_spec.rb +135 -38
  27. data/spec/lib/declare_schema/generator_spec.rb +4 -2
  28. data/spec/lib/declare_schema/interactive_primary_key_spec.rb +8 -2
  29. data/spec/lib/declare_schema/migration_generator_spec.rb +277 -171
  30. data/spec/lib/declare_schema/model/column_spec.rb +141 -0
  31. data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +93 -0
  32. data/spec/lib/declare_schema/model/index_definition_spec.rb +4 -5
  33. data/spec/lib/declare_schema/model/table_options_definition_spec.rb +19 -29
  34. data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +12 -26
  35. data/spec/support/acceptance_spec_helpers.rb +3 -3
  36. metadata +15 -9
@@ -25,7 +25,7 @@ RSpec.describe DeclareSchema::FieldDeclarationDsl do
25
25
  end
26
26
 
27
27
  it 'stores limits' do
28
- expect(TestModel.field_specs['name'].limit).to eq(127)
28
+ expect(TestModel.field_specs['name'].limit).to eq(127), TestModel.field_specs['name'].inspect
29
29
  end
30
30
 
31
31
  # TODO: fill out remaining tests
@@ -1,69 +1,166 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- RSpec.describe 'DeclareSchema Model FieldSpec' do
3
+ begin
4
+ require 'mysql2'
5
+ rescue LoadError
6
+ end
7
+
8
+ RSpec.describe DeclareSchema::Model::FieldSpec do
9
+ let(:model) { double('model', table_options: {}) }
10
+ let(:col_spec) { double('col_spec', sql_type: 'varchar') }
11
+
4
12
  before do
5
13
  load File.expand_path('prepare_testapp.rb', __dir__)
14
+
15
+ if Rails::VERSION::MAJOR < 5
16
+ allow(col_spec).to receive(:type_cast_from_database, &:itself)
17
+ end
6
18
  end
7
19
 
8
- context 'There are no model columns to change' do
9
- it '#different_to should return false for int8 == int8' do
10
- subject = DeclareSchema::Model::FieldSpec.new(Object, :price, :integer, limit: 8, null: false, position: 0)
20
+ describe '#initialize' do
21
+ it 'normalizes option order' do
22
+ subject = described_class.new(model, :price, :integer, anonymize_using: 'x', null: false, position: 0, limit: 4)
23
+ expect(subject.options.keys).to eq([:limit, :null, :anonymize_using])
24
+ end
25
+ end
11
26
 
12
- case Rails::VERSION::MAJOR
13
- when 4
14
- cast_type = ActiveRecord::Type::Integer.new(limit: 8)
15
- col = ActiveRecord::ConnectionAdapters::Column.new("price", nil, cast_type, "integer(8)", false)
16
- else
17
- sql_type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: "integer(8)", type: :integer, limit: 8)
18
- col = ActiveRecord::ConnectionAdapters::Column.new("price", nil, sql_type_metadata, false, "adverts")
27
+ describe '#schema_attributes' do
28
+ describe 'integer 4' do
29
+ it 'returns schema attributes' do
30
+ subject = described_class.new(model, :price, :integer, limit: 4, null: false, position: 0)
31
+ expect(subject.schema_attributes(col_spec)).to eq(type: :integer, limit: 4, null: false)
19
32
  end
20
-
21
- expect(subject.different_to?(subject.name, col)).to eq(false)
22
33
  end
23
34
 
24
- it '#different_to should return false for bigint == bigint' do
25
- subject = DeclareSchema::Model::FieldSpec.new(Object, :price, :bigint, null: false, position: 0)
35
+ describe 'integer 8' do
36
+ it 'returns schema attributes' do
37
+ subject = described_class.new(model, :price, :integer, limit: 8, null: true, position: 2)
38
+ expect(subject.schema_attributes(col_spec)).to eq(type: :integer, limit: 8, null: true)
39
+ end
40
+ end
26
41
 
27
- case Rails::VERSION::MAJOR
28
- when 4
29
- cast_type = ActiveRecord::Type::BigInteger.new(limit: 8)
30
- col = ActiveRecord::ConnectionAdapters::Column.new("price", nil, cast_type, "bigint(20)", false)
31
- else
32
- sql_type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: "bigint(20)", type: :integer, limit: 8)
33
- col = ActiveRecord::ConnectionAdapters::Column.new("price", nil, sql_type_metadata, false, "adverts")
42
+ describe 'bigint' do
43
+ it 'returns schema attributes' do
44
+ subject = described_class.new(model, :price, :bigint, null: false, position: 2)
45
+ expect(subject.schema_attributes(col_spec)).to eq(type: :integer, limit: 8, null: false)
34
46
  end
47
+ end
35
48
 
36
- expect(subject.different_to?(subject.name, col)).to eq(false)
49
+ describe 'string' do
50
+ it 'returns schema attributes (including charset/collation iff mysql)' do
51
+ subject = described_class.new(model, :title, :string, limit: 100, null: true, charset: 'utf8mb4', position: 0)
52
+ if defined?(Mysql2)
53
+ expect(subject.schema_attributes(col_spec)).to eq(type: :string, limit: 100, null: true, charset: 'utf8mb4', collation: 'utf8mb4_bin')
54
+ else
55
+ expect(subject.schema_attributes(col_spec)).to eq(type: :string, limit: 100, null: true)
56
+ end
57
+ end
37
58
  end
38
59
 
39
- it '#different_to should return false for int8 == bigint' do
40
- subject = DeclareSchema::Model::FieldSpec.new(Object, :price, :integer, limit: 8, null: false, position: 0)
60
+ describe 'text' do
61
+ it 'returns schema attributes (including charset/collation iff mysql)' do
62
+ subject = described_class.new(model, :title, :text, limit: 200, null: true, charset: 'utf8mb4', position: 2)
63
+ if defined?(Mysql2)
64
+ expect(subject.schema_attributes(col_spec)).to eq(type: :text, limit: 255, null: true, charset: 'utf8mb4', collation: 'utf8mb4_bin')
65
+ else
66
+ expect(subject.schema_attributes(col_spec)).to eq(type: :text, null: true)
67
+ end
68
+ end
41
69
 
42
- case Rails::VERSION::MAJOR
43
- when 4
44
- cast_type = ActiveRecord::Type::BigInteger.new(limit: 8)
45
- col = ActiveRecord::ConnectionAdapters::Column.new("price", nil, cast_type, "bigint(20)", false)
46
- else
47
- sql_type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: "bigint(20)", type: :integer, limit: 8)
48
- col = ActiveRecord::ConnectionAdapters::Column.new("price", nil, sql_type_metadata, false, "adverts")
70
+ it 'allows a default to be set unless mysql' do
71
+ if defined?(Mysql2)
72
+ expect do
73
+ described_class.new(model, :title, :text, limit: 200, null: true, default: 'none', charset: 'utf8mb4', position: 2)
74
+ end.to raise_exception(DeclareSchema::MysqlTextMayNotHaveDefault)
75
+ else
76
+ subject = described_class.new(model, :title, :text, limit: 200, null: true, default: 'none', charset: 'utf8mb4', position: 2)
77
+ expect(subject.schema_attributes(col_spec)).to eq(type: :text, null: true, default: 'none')
78
+ end
79
+ end
80
+
81
+ describe 'decimal' do
82
+ it 'allows precision: and scale:' do
83
+ subject = described_class.new(model, :quantity, :decimal, precision: 8, scale: 10, null: true, position: 3)
84
+ expect(subject.schema_attributes(col_spec)).to eq(type: :decimal, precision: 8, scale: 10, null: true)
85
+ end
86
+
87
+ it 'requires precision:' do
88
+ expect_any_instance_of(described_class).to receive(:warn).with(/precision: required for :decimal type/)
89
+ described_class.new(model, :quantity, :decimal, scale: 10, null: true, position: 3)
90
+ end
91
+
92
+ it 'requires scale:' do
93
+ expect_any_instance_of(described_class).to receive(:warn).with(/scale: required for :decimal type/)
94
+ described_class.new(model, :quantity, :decimal, precision: 8, null: true, position: 3)
95
+ end
96
+ end
97
+
98
+ [:integer, :bigint, :string, :text, :binary, :datetime, :date, :time].each do |t|
99
+ describe t.to_s do
100
+ let(:extra) { t == :string ? { limit: 100 } : {} }
101
+
102
+ it 'does not allow precision:' do
103
+ expect_any_instance_of(described_class).to receive(:warn).with(/precision: only allowed for :decimal type/)
104
+ described_class.new(model, :quantity, t, { precision: 8, null: true, position: 3 }.merge(extra))
105
+ end unless t == :datetime
106
+
107
+ it 'does not allow scale:' do
108
+ expect_any_instance_of(described_class).to receive(:warn).with(/scale: only allowed for :decimal type/)
109
+ described_class.new(model, :quantity, t, { scale: 10, null: true, position: 3 }.merge(extra))
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ describe 'datetime' do
116
+ it 'keeps type as "datetime"' do
117
+ subject = described_class.new(model, :created_at, :datetime, null: false, position: 1)
118
+ expect(subject.schema_attributes(col_spec)).to eq(type: :datetime, null: false)
49
119
  end
120
+ end
50
121
 
51
- expect(subject.different_to?(subject.name, col)).to eq(false)
122
+ describe 'timestamp' do
123
+ it 'normalizes type to "datetime"' do
124
+ subject = described_class.new(model, :created_at, :timestamp, null: true, position: 2)
125
+ expect(subject.schema_attributes(col_spec)).to eq(type: :datetime, null: true)
126
+ end
52
127
  end
53
128
 
54
- it '#different_to should return false for bigint == int8' do
55
- subject = DeclareSchema::Model::FieldSpec.new(Object, :price, :bigint, null: false, position: 0)
129
+ describe 'default:' do
130
+ let(:col_spec) { double('col_spec', sql_type: :integer) }
56
131
 
132
+ it 'typecasts default value' do
133
+ allow(col_spec).to receive(:type_cast_from_database) { |default| Integer(default) }
134
+ subject = described_class.new(model, :price, :integer, limit: 4, default: '42', null: true, position: 2)
135
+ expect(subject.schema_attributes(col_spec)).to eq(type: :integer, limit: 4, default: 42, null: true)
136
+ end
137
+ end
138
+ end
139
+
140
+ describe '#schema_attributes' do
141
+ let(:col_spec) do
57
142
  case Rails::VERSION::MAJOR
58
143
  when 4
59
144
  cast_type = ActiveRecord::Type::Integer.new(limit: 8)
60
- col = ActiveRecord::ConnectionAdapters::Column.new("price", nil, cast_type, "integer(8)", false)
145
+ ActiveRecord::ConnectionAdapters::Column.new("price", nil, cast_type, "integer(8)", false)
61
146
  else
62
147
  sql_type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: "integer(8)", type: :integer, limit: 8)
63
- col = ActiveRecord::ConnectionAdapters::Column.new("price", nil, sql_type_metadata, false, "adverts")
148
+ ActiveRecord::ConnectionAdapters::Column.new("price", nil, sql_type_metadata, false, "adverts")
64
149
  end
150
+ end
151
+
152
+ it 'returns the attributes except name, position' do
153
+ subject = described_class.new(model, :price, :bigint, null: true, default: 0, position: 2)
154
+ expect(subject.schema_attributes(col_spec)).to eq(type: :integer, limit: 8, null: true, default: 0)
155
+ end
156
+
157
+ it 'aliases :bigint and :integer limit: 8' do
158
+ int8 = described_class.new(model, :price, :integer, limit: 8, null: false, position: 0)
159
+ bigint = described_class.new(model, :price, :bigint, null: false, position: 0)
65
160
 
66
- expect(subject.different_to?(subject.name, col)).to eq(false)
161
+ expected_attributes = { type: :integer, limit: 8, null: false }
162
+ expect(int8.schema_attributes(col_spec)).to eq(expected_attributes)
163
+ expect(bigint.schema_attributes(col_spec)).to eq(expected_attributes)
67
164
  end
68
165
  end
69
166
  end
@@ -30,7 +30,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
30
30
  case Rails::VERSION::MAJOR
31
31
  when 4, 5
32
32
  expect_test_definition_to_eq('alpha/beta', <<~EOS)
33
- require 'test_helper'
33
+ require "test_helper"
34
34
 
35
35
  class Alpha::BetaTest < ActiveSupport::TestCase
36
36
  # test "the truth" do
@@ -101,7 +101,9 @@ RSpec.describe 'DeclareSchema Migration Generator' do
101
101
 
102
102
  expect(File.exist?('db/schema.rb')).to be_truthy
103
103
 
104
- expect(File.exist?("db/development.sqlite3") || File.exist?("db/test.sqlite3")).to be_truthy
104
+ if defined?(SQLite3)
105
+ expect(File.exist?("db/development.sqlite3") || File.exist?("db/test.sqlite3")).to be_truthy
106
+ end
105
107
 
106
108
  module Alpha; end
107
109
  require 'alpha/beta'
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rails'
4
+ begin
5
+ require 'mysql2'
6
+ rescue LoadError
7
+ end
8
+
3
9
  RSpec.describe 'DeclareSchema Migration Generator interactive primary key' do
4
10
  before do
5
11
  load File.expand_path('prepare_testapp.rb', __dir__)
@@ -31,8 +37,8 @@ RSpec.describe 'DeclareSchema Migration Generator interactive primary key' do
31
37
 
32
38
  ### migrate to
33
39
 
34
- if Rails::VERSION::MAJOR >= 5
35
- # rename to custom primary_key
40
+ if Rails::VERSION::MAJOR >= 5 && !defined?(Mysql2) # TODO TECH-4814 Put this test back for Mysql2
41
+ # replace custom primary_key
36
42
  class Foo < ActiveRecord::Base
37
43
  fields do
38
44
  end
@@ -1,12 +1,60 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rails'
4
+ begin
5
+ require 'mysql2'
6
+ rescue LoadError
7
+ end
4
8
 
5
9
  RSpec.describe 'DeclareSchema Migration Generator' do
6
10
  before do
7
11
  load File.expand_path('prepare_testapp.rb', __dir__)
8
12
  end
9
13
 
14
+ let(:charset_alter_table) do
15
+ if defined?(Mysql2)
16
+ <<~EOS
17
+
18
+
19
+ execute "ALTER TABLE `adverts` CHARACTER SET utf8mb4 COLLATE utf8mb4_bin"
20
+ EOS
21
+ end
22
+ end
23
+ let(:text_limit) do
24
+ if defined?(Mysql2)
25
+ ", limit: 4294967295"
26
+ end
27
+ end
28
+ let(:charset_and_collation) do
29
+ if defined?(Mysql2)
30
+ ', charset: "utf8mb4", collation: "utf8mb4_bin"'
31
+ end
32
+ end
33
+ let(:datetime_precision) do
34
+ if defined?(Mysql2) && Rails::VERSION::MAJOR >= 5
35
+ ', precision: 0'
36
+ end
37
+ end
38
+ let(:table_options) do
39
+ if defined?(Mysql2)
40
+ ", options: \"#{'ENGINE=InnoDB ' if Rails::VERSION::MAJOR == 5}DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\"" +
41
+ if Rails::VERSION::MAJOR >= 6
42
+ ', charset: "utf8mb4", collation: "utf8mb4_bin"'
43
+ else
44
+ ''
45
+ end
46
+ else
47
+ ", id: :integer" unless Rails::VERSION::MAJOR < 5
48
+ end
49
+ end
50
+ let(:lock_version_limit) do
51
+ if defined?(Mysql2)
52
+ ", limit: 4"
53
+ else
54
+ ''
55
+ end
56
+ end
57
+
10
58
  # DeclareSchema - Migration Generator
11
59
  it 'generates migrations' do
12
60
  ## The migration generator -- introduction
@@ -25,7 +73,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
25
73
 
26
74
  class Advert < ActiveRecord::Base
27
75
  fields do
28
- name :string, limit: 255, null: true
76
+ name :string, limit: 250, null: true
29
77
  end
30
78
  end
31
79
 
@@ -33,8 +81,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
33
81
  expect(migrations).to(
34
82
  migrate_up(<<~EOS.strip)
35
83
  create_table :adverts, id: :bigint do |t|
36
- t.string :name, limit: 255
37
- end
84
+ t.string :name, limit: 250, null: true#{charset_and_collation}
85
+ end#{charset_alter_table}
38
86
  EOS
39
87
  .and migrate_down("drop_table :adverts")
40
88
  )
@@ -44,14 +92,18 @@ RSpec.describe 'DeclareSchema Migration Generator' do
44
92
  expect(Advert.columns.map(&:name)).to eq(["id", "name"])
45
93
 
46
94
  if Rails::VERSION::MAJOR < 5
47
- # Rails 4 sqlite driver doesn't create PK properly. Fix that by dropping and recreating.
95
+ # Rails 4 drivers don't always create PK properly. Fix that by dropping and recreating.
48
96
  ActiveRecord::Base.connection.execute("drop table adverts")
49
- ActiveRecord::Base.connection.execute('CREATE TABLE "adverts" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255))')
97
+ if defined?(Mysql2)
98
+ ActiveRecord::Base.connection.execute("CREATE TABLE adverts (id integer PRIMARY KEY AUTO_INCREMENT NOT NULL, name varchar(250)) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin")
99
+ else
100
+ ActiveRecord::Base.connection.execute("CREATE TABLE adverts (id integer PRIMARY KEY AUTOINCREMENT NOT NULL, name varchar(250))")
101
+ end
50
102
  end
51
103
 
52
104
  class Advert < ActiveRecord::Base
53
105
  fields do
54
- name :string, limit: 255, null: true
106
+ name :string, limit: 250, null: true
55
107
  body :text, null: true
56
108
  published_at :datetime, null: true
57
109
  end
@@ -62,8 +114,8 @@ RSpec.describe 'DeclareSchema Migration Generator' do
62
114
 
63
115
  expect(migrate).to(
64
116
  migrate_up(<<~EOS.strip)
65
- add_column :adverts, :body, :text
66
- add_column :adverts, :published_at, :datetime
117
+ add_column :adverts, :body, :text#{text_limit}, null: true#{charset_and_collation}
118
+ add_column :adverts, :published_at, :datetime, null: true
67
119
  EOS
68
120
  .and migrate_down(<<~EOS.strip)
69
121
  remove_column :adverts, :body
@@ -74,33 +126,33 @@ RSpec.describe 'DeclareSchema Migration Generator' do
74
126
  Advert.field_specs.clear # not normally needed
75
127
  class Advert < ActiveRecord::Base
76
128
  fields do
77
- name :string, limit: 255, null: true
129
+ name :string, limit: 250, null: true
78
130
  body :text, null: true
79
131
  end
80
132
  end
81
133
 
82
134
  expect(migrate).to(
83
135
  migrate_up("remove_column :adverts, :published_at").and(
84
- migrate_down("add_column :adverts, :published_at, :datetime")
136
+ migrate_down("add_column :adverts, :published_at, :datetime#{datetime_precision}, null: true")
85
137
  )
86
138
  )
87
139
 
88
140
  nuke_model_class(Advert)
89
141
  class Advert < ActiveRecord::Base
90
142
  fields do
91
- title :string, limit: 255, null: true
143
+ title :string, limit: 250, null: true
92
144
  body :text, null: true
93
145
  end
94
146
  end
95
147
 
96
148
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
97
149
  migrate_up(<<~EOS.strip)
98
- add_column :adverts, :title, :string, limit: 255
150
+ add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
99
151
  remove_column :adverts, :name
100
152
  EOS
101
153
  .and migrate_down(<<~EOS.strip)
102
154
  remove_column :adverts, :title
103
- add_column :adverts, :name, :string, limit: 255
155
+ add_column :adverts, :name, :string, limit: 250, null: true#{charset_and_collation}
104
156
  EOS
105
157
  )
106
158
 
@@ -120,24 +172,24 @@ RSpec.describe 'DeclareSchema Migration Generator' do
120
172
  end
121
173
 
122
174
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
123
- migrate_up("change_column :adverts, :title, :text").and(
124
- migrate_down("change_column :adverts, :title, :string, limit: 255")
175
+ migrate_up("change_column :adverts, :title, :text#{text_limit}, null: true#{charset_and_collation}").and(
176
+ migrate_down("change_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}")
125
177
  )
126
178
  )
127
179
 
128
180
  class Advert < ActiveRecord::Base
129
181
  fields do
130
- title :string, default: "Untitled", limit: 255, null: true
182
+ title :string, default: "Untitled", limit: 250, null: true
131
183
  body :text, null: true
132
184
  end
133
185
  end
134
186
 
135
187
  expect(migrate).to(
136
188
  migrate_up(<<~EOS.strip)
137
- change_column :adverts, :title, :string, limit: 255, default: "Untitled"
189
+ change_column :adverts, :title, :string, limit: 250, null: true, default: "Untitled"#{charset_and_collation}
138
190
  EOS
139
191
  .and migrate_down(<<~EOS.strip)
140
- change_column :adverts, :title, :string, limit: 255
192
+ change_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
141
193
  EOS
142
194
  )
143
195
 
@@ -150,7 +202,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
150
202
  end
151
203
 
152
204
  up, _ = Generators::DeclareSchema::Migration::Migrator.run.tap do |migrations|
153
- expect(migrations).to migrate_up("add_column :adverts, :price, :integer, limit: 2")
205
+ expect(migrations).to migrate_up("add_column :adverts, :price, :integer, limit: 2, null: true")
154
206
  end
155
207
 
156
208
  # Now run the migration, then change the limit:
@@ -164,30 +216,29 @@ RSpec.describe 'DeclareSchema Migration Generator' do
164
216
 
165
217
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
166
218
  migrate_up(<<~EOS.strip)
167
- change_column :adverts, :price, :integer, limit: 3
219
+ change_column :adverts, :price, :integer, limit: 3, null: true
168
220
  EOS
169
221
  .and migrate_down(<<~EOS.strip)
170
- change_column :adverts, :price, :integer, limit: 2
222
+ change_column :adverts, :price, :integer, limit: 2, null: true
171
223
  EOS
172
224
  )
173
225
 
174
- # Note that limit on a decimal column is ignored (use :scale and :precision)
175
-
176
226
  ActiveRecord::Migration.class_eval("remove_column :adverts, :price")
177
227
  class Advert < ActiveRecord::Base
178
228
  fields do
179
- price :decimal, null: true, limit: 4
229
+ price :decimal, precision: 4, scale: 1, null: true
180
230
  end
181
231
  end
182
232
 
183
- expect(Generators::DeclareSchema::Migration::Migrator.run).to migrate_up("add_column :adverts, :price, :decimal")
184
-
185
233
  # Limits are generally not needed for `text` fields, because by default, `text` fields will use the maximum size
186
234
  # allowed for that database type (0xffffffff for LONGTEXT in MySQL unlimited in Postgres, 1 billion in Sqlite).
187
235
  # If a `limit` is given, it will only be used in MySQL, to choose the smallest TEXT field that will accommodate
188
236
  # that limit (0xff for TINYTEXT, 0xffff for TEXT, 0xffffff for MEDIUMTEXT, 0xffffffff for LONGTEXT).
189
237
 
190
- expect(::DeclareSchema::Model::FieldSpec.mysql_text_limits?).to be_falsey
238
+ if defined?(SQLite3)
239
+ expect(::DeclareSchema::Model::FieldSpec.mysql_text_limits?).to be_falsey
240
+ end
241
+
191
242
  class Advert < ActiveRecord::Base
192
243
  fields do
193
244
  notes :text
@@ -197,114 +248,108 @@ RSpec.describe 'DeclareSchema Migration Generator' do
197
248
 
198
249
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
199
250
  migrate_up(<<~EOS.strip)
200
- add_column :adverts, :price, :decimal
201
- add_column :adverts, :notes, :text, null: false
202
- add_column :adverts, :description, :text, null: false
251
+ add_column :adverts, :price, :decimal, precision: 4, scale: 1, null: true
252
+ add_column :adverts, :notes, :text#{text_limit}, null: false#{charset_and_collation}
253
+ add_column :adverts, :description, :text#{', limit: 65535' if defined?(Mysql2)}, null: false#{charset_and_collation}
203
254
  EOS
204
255
  )
205
256
 
206
- # (There is no limit on `add_column ... :description` above since these tests are run against SQLite.)
207
-
208
257
  Advert.field_specs.delete :price
209
258
  Advert.field_specs.delete :notes
210
259
  Advert.field_specs.delete :description
211
260
 
212
261
  # In MySQL, limits are applied, rounded up:
213
262
 
214
- ::DeclareSchema::Model::FieldSpec::instance_variable_set(:@mysql_text_limits, true)
215
- expect(::DeclareSchema::Model::FieldSpec.mysql_text_limits?).to be_truthy
216
- class Advert < ActiveRecord::Base
217
- fields do
218
- notes :text
219
- description :text, limit: 200
220
- end
221
- end
222
-
223
- expect(Generators::DeclareSchema::Migration::Migrator.run).to(
224
- migrate_up(<<~EOS.strip)
225
- add_column :adverts, :notes, :text, null: false, limit: 4294967295
226
- add_column :adverts, :description, :text, null: false, limit: 255
227
- EOS
228
- )
263
+ if defined?(Mysql2)
264
+ expect(::DeclareSchema::Model::FieldSpec.mysql_text_limits?).to be_truthy
229
265
 
230
- Advert.field_specs.delete :notes
231
-
232
- # Limits that are too high for MySQL will raise an exception.
233
-
234
- ::DeclareSchema::Model::FieldSpec::instance_variable_set(:@mysql_text_limits, true)
235
- expect(::DeclareSchema::Model::FieldSpec.mysql_text_limits?).to be_truthy
236
- expect do
237
266
  class Advert < ActiveRecord::Base
238
267
  fields do
239
268
  notes :text
240
- description :text, limit: 0x1_0000_0000
269
+ description :text, limit: 250
241
270
  end
242
271
  end
243
- end.to raise_exception(ArgumentError, "limit of 4294967296 is too large for MySQL")
244
272
 
245
- Advert.field_specs.delete :notes
273
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
274
+ migrate_up(<<~EOS.strip)
275
+ add_column :adverts, :notes, :text, limit: 4294967295, null: false#{charset_and_collation}
276
+ add_column :adverts, :description, :text, limit: 255, null: false#{charset_and_collation}
277
+ EOS
278
+ )
246
279
 
247
- # And in MySQL, unstated text limits are treated as the maximum (LONGTEXT) limit.
280
+ Advert.field_specs.delete :notes
248
281
 
249
- # To start, we'll set the database schema for `description` to match the above limit of 255.
282
+ # Limits that are too high for MySQL will raise an exception.
250
283
 
251
- expect(::DeclareSchema::Model::FieldSpec.mysql_text_limits?).to be_truthy
252
- Advert.connection.execute "ALTER TABLE adverts ADD COLUMN description TINYTEXT"
253
- Advert.connection.schema_cache.clear!
254
- Advert.reset_column_information
255
- expect(Advert.connection.tables - Generators::DeclareSchema::Migration::Migrator.always_ignore_tables).
256
- to eq(["adverts"])
257
- expect(Advert.columns.map(&:name)).to eq(["id", "body", "title", "description"])
284
+ expect do
285
+ class Advert < ActiveRecord::Base
286
+ fields do
287
+ notes :text
288
+ description :text, limit: 0x1_0000_0000
289
+ end
290
+ end
291
+ end.to raise_exception(ArgumentError, "limit of 4294967296 is too large for MySQL")
258
292
 
259
- # Now migrate to an unstated text limit:
293
+ Advert.field_specs.delete :notes
260
294
 
261
- class Advert < ActiveRecord::Base
262
- fields do
263
- description :text
264
- end
265
- end
295
+ # And in MySQL, unstated text limits are treated as the maximum (LONGTEXT) limit.
266
296
 
267
- expect(Generators::DeclareSchema::Migration::Migrator.run).to(
268
- migrate_up(<<~EOS.strip)
269
- change_column :adverts, :description, :text, limit: 4294967295, null: false
270
- EOS
271
- .and migrate_down(<<~EOS.strip)
272
- change_column :adverts, :description, :text
273
- EOS
274
- )
297
+ # To start, we'll set the database schema for `description` to match the above limit of 250.
275
298
 
276
- # TODO TECH-4814: The above test should have this output:
277
- # TODO => "change_column :adverts, :description, :text, limit: 255
299
+ Advert.connection.execute "ALTER TABLE adverts ADD COLUMN description TINYTEXT"
300
+ Advert.connection.schema_cache.clear!
301
+ Advert.reset_column_information
302
+ expect(Advert.connection.tables - Generators::DeclareSchema::Migration::Migrator.always_ignore_tables).
303
+ to eq(["adverts"])
304
+ expect(Advert.columns.map(&:name)).to eq(["id", "body", "title", "description"])
278
305
 
279
- # And migrate to a stated text limit that is the same as the unstated one:
306
+ # Now migrate to an unstated text limit:
280
307
 
281
- class Advert < ActiveRecord::Base
282
- fields do
283
- description :text, limit: 0xffffffff
308
+ class Advert < ActiveRecord::Base
309
+ fields do
310
+ description :text
311
+ end
284
312
  end
285
- end
286
313
 
287
- expect(Generators::DeclareSchema::Migration::Migrator.run).to(
288
- migrate_up(<<~EOS.strip)
289
- change_column :adverts, :description, :text, limit: 4294967295, null: false
290
- EOS
291
- .and migrate_down(<<~EOS.strip)
292
- change_column :adverts, :description, :text
293
- EOS
294
- )
295
- ::DeclareSchema::Model::FieldSpec::instance_variable_set(:@mysql_text_limits, false)
314
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
315
+ migrate_up(<<~EOS.strip)
316
+ change_column :adverts, :description, :text, limit: 4294967295, null: false#{charset_and_collation}
317
+ EOS
318
+ .and migrate_down(<<~EOS.strip)
319
+ change_column :adverts, :description, :text#{', limit: 255' if defined?(Mysql2)}, null: true#{charset_and_collation}
320
+ EOS
321
+ )
322
+
323
+ # And migrate to a stated text limit that is the same as the unstated one:
324
+
325
+ class Advert < ActiveRecord::Base
326
+ fields do
327
+ description :text, limit: 0xffffffff
328
+ end
329
+ end
330
+
331
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
332
+ migrate_up(<<~EOS.strip)
333
+ change_column :adverts, :description, :text, limit: 4294967295, null: false#{charset_and_collation}
334
+ EOS
335
+ .and migrate_down(<<~EOS.strip)
336
+ change_column :adverts, :description, :text#{', limit: 255' if defined?(Mysql2)}, null: true#{charset_and_collation}
337
+ EOS
338
+ )
339
+ end
296
340
 
297
341
  Advert.field_specs.clear
298
342
  Advert.connection.schema_cache.clear!
299
343
  Advert.reset_column_information
300
344
  class Advert < ActiveRecord::Base
301
345
  fields do
302
- name :string, limit: 255, null: true
346
+ name :string, limit: 250, null: true
303
347
  end
304
348
  end
305
349
 
306
350
  up = Generators::DeclareSchema::Migration::Migrator.run.first
307
351
  ActiveRecord::Migration.class_eval up
352
+
308
353
  Advert.connection.schema_cache.clear!
309
354
  Advert.reset_column_information
310
355
 
@@ -316,7 +361,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
316
361
  class Category < ActiveRecord::Base; end
317
362
  class Advert < ActiveRecord::Base
318
363
  fields do
319
- name :string, limit: 255, null: true
364
+ name :string, limit: 250, null: true
320
365
  end
321
366
  belongs_to :category
322
367
  end
@@ -326,11 +371,15 @@ RSpec.describe 'DeclareSchema Migration Generator' do
326
371
  add_column :adverts, :category_id, :integer, limit: 8, null: false
327
372
 
328
373
  add_index :adverts, [:category_id], name: 'on_category_id'
374
+
375
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" if defined?(Mysql2)}
329
376
  EOS
330
377
  .and migrate_down(<<~EOS.strip)
331
378
  remove_column :adverts, :category_id
332
379
 
333
380
  remove_index :adverts, name: :on_category_id rescue ActiveRecord::StatementInvalid
381
+
382
+ #{"remove_foreign_key(\"adverts\", name: \"index_adverts_on_category_id\")\n" if defined?(Mysql2)}
334
383
  EOS
335
384
  )
336
385
 
@@ -350,6 +399,9 @@ RSpec.describe 'DeclareSchema Migration Generator' do
350
399
  add_column :adverts, :c_id, :integer, limit: 8, null: false
351
400
 
352
401
  add_index :adverts, [:c_id], name: 'on_c_id'
402
+
403
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
404
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
353
405
  EOS
354
406
  )
355
407
 
@@ -367,6 +419,9 @@ RSpec.describe 'DeclareSchema Migration Generator' do
367
419
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
368
420
  migrate_up(<<~EOS.strip)
369
421
  add_column :adverts, :category_id, :integer, limit: 8, null: false
422
+
423
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
424
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
370
425
  EOS
371
426
  )
372
427
 
@@ -386,6 +441,9 @@ RSpec.describe 'DeclareSchema Migration Generator' do
386
441
  add_column :adverts, :category_id, :integer, limit: 8, null: false
387
442
 
388
443
  add_index :adverts, [:category_id], name: 'my_index'
444
+
445
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
446
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
389
447
  EOS
390
448
  )
391
449
 
@@ -406,14 +464,20 @@ RSpec.describe 'DeclareSchema Migration Generator' do
406
464
 
407
465
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
408
466
  migrate_up(<<~EOS.strip)
409
- add_column :adverts, :created_at, :datetime
410
- add_column :adverts, :updated_at, :datetime
411
- add_column :adverts, :lock_version, :integer, null: false, default: 1
467
+ add_column :adverts, :created_at, :datetime, null: true
468
+ add_column :adverts, :updated_at, :datetime, null: true
469
+ add_column :adverts, :lock_version, :integer#{lock_version_limit}, null: false, default: 1
470
+
471
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
472
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
412
473
  EOS
413
474
  .and migrate_down(<<~EOS.strip)
414
475
  remove_column :adverts, :created_at
415
476
  remove_column :adverts, :updated_at
416
477
  remove_column :adverts, :lock_version
478
+
479
+ #{"remove_foreign_key(\"adverts\", name: \"index_adverts_on_category_id\")\n" +
480
+ "remove_foreign_key(\"adverts\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
417
481
  EOS
418
482
  )
419
483
 
@@ -427,15 +491,18 @@ RSpec.describe 'DeclareSchema Migration Generator' do
427
491
 
428
492
  class Advert < ActiveRecord::Base
429
493
  fields do
430
- title :string, index: true, limit: 255, null: true
494
+ title :string, index: true, limit: 250, null: true
431
495
  end
432
496
  end
433
497
 
434
498
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
435
499
  migrate_up(<<~EOS.strip)
436
- add_column :adverts, :title, :string, limit: 255
500
+ add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
437
501
 
438
502
  add_index :adverts, [:title], name: 'on_title'
503
+
504
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
505
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
439
506
  EOS
440
507
  )
441
508
 
@@ -445,15 +512,18 @@ RSpec.describe 'DeclareSchema Migration Generator' do
445
512
 
446
513
  class Advert < ActiveRecord::Base
447
514
  fields do
448
- title :string, index: true, unique: true, null: true, limit: 255
515
+ title :string, index: true, unique: true, null: true, limit: 250
449
516
  end
450
517
  end
451
518
 
452
519
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
453
520
  migrate_up(<<~EOS.strip)
454
- add_column :adverts, :title, :string, limit: 255
521
+ add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
455
522
 
456
523
  add_index :adverts, [:title], unique: true, name: 'on_title'
524
+
525
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
526
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
457
527
  EOS
458
528
  )
459
529
 
@@ -463,15 +533,18 @@ RSpec.describe 'DeclareSchema Migration Generator' do
463
533
 
464
534
  class Advert < ActiveRecord::Base
465
535
  fields do
466
- title :string, index: 'my_index', limit: 255, null: true
536
+ title :string, index: 'my_index', limit: 250, null: true
467
537
  end
468
538
  end
469
539
 
470
540
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
471
541
  migrate_up(<<~EOS.strip)
472
- add_column :adverts, :title, :string, limit: 255
542
+ add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
473
543
 
474
544
  add_index :adverts, [:title], name: 'my_index'
545
+
546
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
547
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
475
548
  EOS
476
549
  )
477
550
 
@@ -485,9 +558,12 @@ RSpec.describe 'DeclareSchema Migration Generator' do
485
558
 
486
559
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
487
560
  migrate_up(<<~EOS.strip)
488
- add_column :adverts, :title, :string, limit: 255
561
+ add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
489
562
 
490
563
  add_index :adverts, [:title], name: 'on_title'
564
+
565
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
566
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
491
567
  EOS
492
568
  )
493
569
 
@@ -501,9 +577,12 @@ RSpec.describe 'DeclareSchema Migration Generator' do
501
577
 
502
578
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
503
579
  migrate_up(<<~EOS.strip)
504
- add_column :adverts, :title, :string, limit: 255
580
+ add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
505
581
 
506
582
  add_index :adverts, [:title], unique: true, name: 'my_index'
583
+
584
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
585
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
507
586
  EOS
508
587
  )
509
588
 
@@ -517,9 +596,12 @@ RSpec.describe 'DeclareSchema Migration Generator' do
517
596
 
518
597
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
519
598
  migrate_up(<<~EOS.strip)
520
- add_column :adverts, :title, :string, limit: 255
599
+ add_column :adverts, :title, :string, limit: 250, null: true#{charset_and_collation}
521
600
 
522
601
  add_index :adverts, [:title, :category_id], name: 'on_title_and_category_id'
602
+
603
+ #{"add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
604
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")" if defined?(Mysql2)}
523
605
  EOS
524
606
  )
525
607
 
@@ -536,7 +618,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
536
618
  class Advert < ActiveRecord::Base
537
619
  self.table_name = "ads"
538
620
  fields do
539
- title :string, limit: 255, null: true
621
+ title :string, limit: 250, null: true
540
622
  body :text, null: true
541
623
  end
542
624
  end
@@ -548,10 +630,16 @@ RSpec.describe 'DeclareSchema Migration Generator' do
548
630
  migrate_up(<<~EOS.strip)
549
631
  rename_table :adverts, :ads
550
632
 
551
- add_column :ads, :title, :string, limit: 255
552
- add_column :ads, :body, :text
633
+ add_column :ads, :title, :string, limit: 250, null: true#{charset_and_collation}
634
+ add_column :ads, :body, :text#{', limit: 4294967295' if defined?(Mysql2)}, null: true#{charset_and_collation}
553
635
 
554
- add_index :ads, [:id], unique: true, name: 'PRIMARY'
636
+ #{if defined?(SQLite3)
637
+ "add_index :ads, [:id], unique: true, name: 'PRIMARY'\n"
638
+ elsif defined?(Mysql2)
639
+ "execute \"ALTER TABLE ads DROP PRIMARY KEY, ADD PRIMARY KEY (id)\"\n\n" +
640
+ "add_foreign_key(\"adverts\", \"categories\", column: \"category_id\", name: \"index_adverts_on_category_id\")\n" +
641
+ "add_foreign_key(\"adverts\", \"categories\", column: \"c_id\", name: \"index_adverts_on_c_id\")"
642
+ end}
555
643
  EOS
556
644
  .and migrate_down(<<~EOS.strip)
557
645
  remove_column :ads, :title
@@ -559,14 +647,20 @@ RSpec.describe 'DeclareSchema Migration Generator' do
559
647
 
560
648
  rename_table :ads, :adverts
561
649
 
562
- add_index :adverts, [:id], unique: true, name: 'PRIMARY'
650
+ #{if defined?(SQLite3)
651
+ "add_index :adverts, [:id], unique: true, name: 'PRIMARY'\n"
652
+ elsif defined?(Mysql2)
653
+ "execute \"ALTER TABLE adverts DROP PRIMARY KEY, ADD PRIMARY KEY (id)\"\n\n" +
654
+ "remove_foreign_key(\"adverts\", name: \"index_adverts_on_category_id\")\n" +
655
+ "remove_foreign_key(\"adverts\", name: \"index_adverts_on_c_id\")"
656
+ end}
563
657
  EOS
564
658
  )
565
659
 
566
660
  # Set the table name back to what it should be and confirm we're in sync:
567
661
 
568
- Advert.field_specs.delete(:title)
569
- Advert.field_specs.delete(:body)
662
+ nuke_model_class(Advert)
663
+
570
664
  class Advert < ActiveRecord::Base
571
665
  self.table_name = "adverts"
572
666
  end
@@ -581,7 +675,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
581
675
 
582
676
  class Advertisement < ActiveRecord::Base
583
677
  fields do
584
- title :string, limit: 255, null: true
678
+ title :string, limit: 250, null: true
585
679
  body :text, null: true
586
680
  end
587
681
  end
@@ -590,20 +684,28 @@ RSpec.describe 'DeclareSchema Migration Generator' do
590
684
  migrate_up(<<~EOS.strip)
591
685
  rename_table :adverts, :advertisements
592
686
 
593
- add_column :advertisements, :title, :string, limit: 255
594
- add_column :advertisements, :body, :text
687
+ add_column :advertisements, :title, :string, limit: 250, null: true#{charset_and_collation}
688
+ add_column :advertisements, :body, :text#{', limit: 4294967295' if defined?(Mysql2)}, null: true#{charset_and_collation}
595
689
  remove_column :advertisements, :name
596
690
 
597
- add_index :advertisements, [:id], unique: true, name: 'PRIMARY'
691
+ #{if defined?(SQLite3)
692
+ "add_index :advertisements, [:id], unique: true, name: 'PRIMARY'"
693
+ elsif defined?(Mysql2)
694
+ "execute \"ALTER TABLE advertisements DROP PRIMARY KEY, ADD PRIMARY KEY (id)\""
695
+ end}
598
696
  EOS
599
697
  .and migrate_down(<<~EOS.strip)
600
698
  remove_column :advertisements, :title
601
699
  remove_column :advertisements, :body
602
- add_column :adverts, :name, :string, limit: 255
700
+ add_column :adverts, :name, :string, limit: 250, null: true#{charset_and_collation}
603
701
 
604
702
  rename_table :advertisements, :adverts
605
703
 
606
- add_index :adverts, [:id], unique: true, name: 'PRIMARY'
704
+ #{if defined?(SQLite3)
705
+ "add_index :adverts, [:id], unique: true, name: 'PRIMARY'"
706
+ elsif defined?(Mysql2)
707
+ "execute \"ALTER TABLE adverts DROP PRIMARY KEY, ADD PRIMARY KEY (id)\""
708
+ end}
607
709
  EOS
608
710
  )
609
711
 
@@ -615,23 +717,15 @@ RSpec.describe 'DeclareSchema Migration Generator' do
615
717
 
616
718
  # Dropping tables is where the automatic down-migration really comes in handy:
617
719
 
618
- rails4_table_create = <<~EOS.strip
619
- create_table "adverts", force: :cascade do |t|
620
- t.string "name", limit: 255
621
- end
622
- EOS
623
-
624
- rails5_table_create = <<~EOS.strip
625
- create_table "adverts", id: :integer, force: :cascade do |t|
626
- t.string "name", limit: 255
627
- end
628
- EOS
629
-
630
720
  expect(Generators::DeclareSchema::Migration::Migrator.run).to(
631
721
  migrate_up(<<~EOS.strip)
632
722
  drop_table :adverts
633
723
  EOS
634
- .and migrate_down(Rails::VERSION::MAJOR >= 5 ? rails5_table_create : rails4_table_create)
724
+ .and migrate_down(<<~EOS.strip)
725
+ create_table "adverts"#{table_options}, force: :cascade do |t|
726
+ t.string "name", limit: 250#{charset_and_collation}
727
+ end
728
+ EOS
635
729
  )
636
730
 
637
731
  ## STI
@@ -643,7 +737,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
643
737
  class Advert < ActiveRecord::Base
644
738
  fields do
645
739
  body :text, null: true
646
- title :string, default: "Untitled", limit: 255, null: true
740
+ title :string, default: "Untitled", limit: 250, null: true
647
741
  end
648
742
  end
649
743
  up = Generators::DeclareSchema::Migration::Migrator.run.first
@@ -657,7 +751,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
657
751
  up, _ = Generators::DeclareSchema::Migration::Migrator.run do |migrations|
658
752
  expect(migrations).to(
659
753
  migrate_up(<<~EOS.strip)
660
- add_column :adverts, :type, :string, limit: 255
754
+ add_column :adverts, :type, :string, limit: 250, null: true#{charset_and_collation}
661
755
 
662
756
  add_index :adverts, [:type], name: 'on_type'
663
757
  EOS
@@ -696,7 +790,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
696
790
 
697
791
  class Advert < ActiveRecord::Base
698
792
  fields do
699
- name :string, default: "No Name", limit: 255, null: true
793
+ name :string, default: "No Name", limit: 250, null: true
700
794
  body :text, null: true
701
795
  end
702
796
  end
@@ -704,11 +798,11 @@ RSpec.describe 'DeclareSchema Migration Generator' do
704
798
  expect(Generators::DeclareSchema::Migration::Migrator.run(adverts: { title: :name })).to(
705
799
  migrate_up(<<~EOS.strip)
706
800
  rename_column :adverts, :title, :name
707
- change_column :adverts, :name, :string, limit: 255, default: "No Name"
801
+ change_column :adverts, :name, :string, limit: 250, null: true, default: "No Name"#{charset_and_collation}
708
802
  EOS
709
803
  .and migrate_down(<<~EOS.strip)
710
804
  rename_column :adverts, :name, :title
711
- change_column :adverts, :title, :string, limit: 255, default: "Untitled"
805
+ change_column :adverts, :title, :string, limit: 250, null: true, default: "Untitled"#{charset_and_collation}
712
806
  EOS
713
807
  )
714
808
 
@@ -717,7 +811,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
717
811
  nuke_model_class(Advert)
718
812
  class Ad < ActiveRecord::Base
719
813
  fields do
720
- title :string, default: "Untitled", limit: 255
814
+ title :string, default: "Untitled", limit: 250
721
815
  body :text, null: true
722
816
  created_at :datetime
723
817
  end
@@ -728,16 +822,20 @@ RSpec.describe 'DeclareSchema Migration Generator' do
728
822
  rename_table :adverts, :ads
729
823
 
730
824
  add_column :ads, :created_at, :datetime, null: false
731
- change_column :ads, :title, :string, limit: 255, null: false, default: \"Untitled\"
825
+ change_column :ads, :title, :string, limit: 250, null: false, default: \"Untitled\"#{charset_and_collation}
732
826
 
733
- add_index :ads, [:id], unique: true, name: 'PRIMARY'
827
+ #{if defined?(SQLite3)
828
+ "add_index :ads, [:id], unique: true, name: 'PRIMARY'"
829
+ elsif defined?(Mysql2)
830
+ 'execute "ALTER TABLE ads DROP PRIMARY KEY, ADD PRIMARY KEY (id)"'
831
+ end}
734
832
  EOS
735
833
  )
736
834
 
737
835
  class Advert < ActiveRecord::Base
738
836
  fields do
739
837
  body :text, null: true
740
- title :string, default: "Untitled", limit: 255, null: true
838
+ title :string, default: "Untitled", limit: 250, null: true
741
839
  end
742
840
  end
743
841
 
@@ -758,7 +856,11 @@ RSpec.describe 'DeclareSchema Migration Generator' do
758
856
  migrate_up(<<~EOS.strip)
759
857
  rename_column :adverts, :id, :advert_id
760
858
 
761
- add_index :adverts, [:advert_id], unique: true, name: 'PRIMARY'
859
+ #{if defined?(SQLite3)
860
+ "add_index :adverts, [:advert_id], unique: true, name: 'PRIMARY'"
861
+ elsif defined?(Mysql2)
862
+ 'execute "ALTER TABLE adverts DROP PRIMARY KEY, ADD PRIMARY KEY (advert_id)"'
863
+ end}
762
864
  EOS
763
865
  )
764
866
 
@@ -771,7 +873,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
771
873
 
772
874
  class User < ActiveRecord::Base
773
875
  fields do
774
- company :string, limit: 255, ruby_default: -> { "BigCorp" }
876
+ company :string, limit: 250, ruby_default: -> { "BigCorp" }
775
877
  end
776
878
  end
777
879
  expect(User.field_specs.keys).to eq(['company'])
@@ -790,7 +892,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
790
892
  expect(Ad).to receive(:validates).with(:company, presence: true, uniqueness: { case_sensitive: false })
791
893
  class Ad < ActiveRecord::Base
792
894
  fields do
793
- company :string, limit: 255, index: true, unique: true, validates: { presence: true, uniqueness: { case_sensitive: false } }
895
+ company :string, limit: 250, index: true, unique: true, validates: { presence: true, uniqueness: { case_sensitive: false } }
794
896
  end
795
897
  self.primary_key = "advert_id"
796
898
  end
@@ -828,10 +930,10 @@ RSpec.describe 'DeclareSchema Migration Generator' do
828
930
  it 'converts defaults with .to_yaml' do
829
931
  class Ad < ActiveRecord::Base
830
932
  fields do
831
- allow_list :string, limit: 255, serialize: true, null: true, default: []
832
- allow_hash :string, limit: 255, serialize: true, null: true, default: {}
833
- allow_string :string, limit: 255, serialize: true, null: true, default: ['abc']
834
- allow_null :string, limit: 255, serialize: true, null: true, default: nil
933
+ allow_list :string, limit: 250, serialize: true, null: true, default: []
934
+ allow_hash :string, limit: 250, serialize: true, null: true, default: {}
935
+ allow_string :string, limit: 250, serialize: true, null: true, default: ['abc']
936
+ allow_null :string, limit: 250, serialize: true, null: true, default: nil
835
937
  end
836
938
  end
837
939
 
@@ -846,7 +948,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
846
948
  it 'allows serialize: Array' do
847
949
  class Ad < ActiveRecord::Base
848
950
  fields do
849
- allow_list :string, limit: 255, serialize: Array, null: true
951
+ allow_list :string, limit: 250, serialize: Array, null: true
850
952
  end
851
953
  end
852
954
 
@@ -856,10 +958,10 @@ RSpec.describe 'DeclareSchema Migration Generator' do
856
958
  it 'allows Array defaults' do
857
959
  class Ad < ActiveRecord::Base
858
960
  fields do
859
- allow_list :string, limit: 255, serialize: Array, null: true, default: [2]
860
- allow_string :string, limit: 255, serialize: Array, null: true, default: ['abc']
861
- allow_empty :string, limit: 255, serialize: Array, null: true, default: []
862
- allow_null :string, limit: 255, serialize: Array, null: true, default: nil
961
+ allow_list :string, limit: 250, serialize: Array, null: true, default: [2]
962
+ allow_string :string, limit: 250, serialize: Array, null: true, default: ['abc']
963
+ allow_empty :string, limit: 250, serialize: Array, null: true, default: []
964
+ allow_null :string, limit: 250, serialize: Array, null: true, default: nil
863
965
  end
864
966
  end
865
967
 
@@ -874,7 +976,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
874
976
  it 'allows serialize: Hash' do
875
977
  class Ad < ActiveRecord::Base
876
978
  fields do
877
- allow_list :string, limit: 255, serialize: Hash, null: true
979
+ allow_list :string, limit: 250, serialize: Hash, null: true
878
980
  end
879
981
  end
880
982
 
@@ -884,9 +986,9 @@ RSpec.describe 'DeclareSchema Migration Generator' do
884
986
  it 'allows Hash defaults' do
885
987
  class Ad < ActiveRecord::Base
886
988
  fields do
887
- allow_loc :string, limit: 255, serialize: Hash, null: true, default: { 'state' => 'CA' }
888
- allow_hash :string, limit: 255, serialize: Hash, null: true, default: {}
889
- allow_null :string, limit: 255, serialize: Hash, null: true, default: nil
989
+ allow_loc :string, limit: 250, serialize: Hash, null: true, default: { 'state' => 'CA' }
990
+ allow_hash :string, limit: 250, serialize: Hash, null: true, default: {}
991
+ allow_null :string, limit: 250, serialize: Hash, null: true, default: nil
890
992
  end
891
993
  end
892
994
 
@@ -900,7 +1002,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
900
1002
  it 'allows serialize: JSON' do
901
1003
  class Ad < ActiveRecord::Base
902
1004
  fields do
903
- allow_list :string, limit: 255, serialize: JSON
1005
+ allow_list :string, limit: 250, serialize: JSON
904
1006
  end
905
1007
  end
906
1008
 
@@ -910,10 +1012,10 @@ RSpec.describe 'DeclareSchema Migration Generator' do
910
1012
  it 'allows JSON defaults' do
911
1013
  class Ad < ActiveRecord::Base
912
1014
  fields do
913
- allow_hash :string, limit: 255, serialize: JSON, null: true, default: { 'state' => 'CA' }
914
- allow_empty_array :string, limit: 255, serialize: JSON, null: true, default: []
915
- allow_empty_hash :string, limit: 255, serialize: JSON, null: true, default: {}
916
- allow_null :string, limit: 255, serialize: JSON, null: true, default: nil
1015
+ allow_hash :string, limit: 250, serialize: JSON, null: true, default: { 'state' => 'CA' }
1016
+ allow_empty_array :string, limit: 250, serialize: JSON, null: true, default: []
1017
+ allow_empty_hash :string, limit: 250, serialize: JSON, null: true, default: {}
1018
+ allow_null :string, limit: 250, serialize: JSON, null: true, default: nil
917
1019
  end
918
1020
  end
919
1021
 
@@ -950,7 +1052,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
950
1052
  it 'allows serialize: ValueClass' do
951
1053
  class Ad < ActiveRecord::Base
952
1054
  fields do
953
- allow_list :string, limit: 255, serialize: ValueClass
1055
+ allow_list :string, limit: 250, serialize: ValueClass
954
1056
  end
955
1057
  end
956
1058
 
@@ -960,9 +1062,9 @@ RSpec.describe 'DeclareSchema Migration Generator' do
960
1062
  it 'allows ValueClass defaults' do
961
1063
  class Ad < ActiveRecord::Base
962
1064
  fields do
963
- allow_hash :string, limit: 255, serialize: ValueClass, null: true, default: ValueClass.new([2])
964
- allow_empty_array :string, limit: 255, serialize: ValueClass, null: true, default: ValueClass.new([])
965
- allow_null :string, limit: 255, serialize: ValueClass, null: true, default: nil
1065
+ allow_hash :string, limit: 250, serialize: ValueClass, null: true, default: ValueClass.new([2])
1066
+ allow_empty_array :string, limit: 250, serialize: ValueClass, null: true, default: ValueClass.new([])
1067
+ allow_null :string, limit: 250, serialize: ValueClass, null: true, default: nil
966
1068
  end
967
1069
  end
968
1070
 
@@ -1003,7 +1105,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
1003
1105
 
1004
1106
  class Advert < ActiveRecord::Base
1005
1107
  fields do
1006
- name :string, limit: 255, null: true
1108
+ name :string, limit: 250, null: true
1007
1109
  category_id :integer, limit: 8
1008
1110
  nullable_category_id :integer, limit: 8, null: true
1009
1111
  end
@@ -1108,6 +1210,10 @@ RSpec.describe 'DeclareSchema Migration Generator' do
1108
1210
  migrations = Dir.glob('db/migrate/*declare_schema_migration*.rb')
1109
1211
  expect(migrations.size).to eq(1), migrations.inspect
1110
1212
 
1213
+ if defined?(Mysql2) && Rails::VERSION::MAJOR < 5
1214
+ ActiveRecord::Base.connection.execute("ALTER TABLE adverts ADD PRIMARY KEY (id)")
1215
+ end
1216
+
1111
1217
  class Advert < active_record_base_class.constantize
1112
1218
  fields do
1113
1219
  price :integer, limit: 8