declare_schema 0.3.0 → 0.5.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,14 +10,14 @@ RSpec.describe 'DeclareSchema API' do
10
10
 
11
11
  describe 'example models' do
12
12
  it 'generates a model' do
13
- expect(system("bundle exec rails generate declare_schema:model advert title:string body:text")).to be_truthy
13
+ generate_model 'advert', 'title:string', 'body:text'
14
14
 
15
15
  # The above will generate the test, fixture and a model file like this:
16
16
  # model_declaration = Rails::Generators.invoke('declare_schema:model', ['advert2', 'title:string', 'body:text'])
17
17
  # expect(model_declaration.first).to eq([["Advert"], nil, "app/models/advert.rb", nil,
18
18
  # [["AdvertTest"], "test/models/advert_test.rb", nil, "test/fixtures/adverts.yml"]])
19
19
 
20
- expect(File.read("#{TESTAPP_PATH}/app/models/advert.rb")).to eq(<<~EOS)
20
+ expect_model_definition_to_eq('advert', <<~EOS)
21
21
  class Advert < #{active_record_base_class}
22
22
 
23
23
  fields do
@@ -27,7 +27,8 @@ RSpec.describe 'DeclareSchema API' do
27
27
 
28
28
  end
29
29
  EOS
30
- system("rm -rf #{TESTAPP_PATH}/app/models/advert2.rb #{TESTAPP_PATH}/test/models/advert2.rb #{TESTAPP_PATH}/test/fixtures/advert2.rb")
30
+
31
+ clean_up_model('advert2')
31
32
 
32
33
  # The migration generator uses this information to create a migration.
33
34
  # The following creates and runs the migration:
@@ -36,13 +37,11 @@ RSpec.describe 'DeclareSchema API' do
36
37
 
37
38
  # We're now ready to start demonstrating the API
38
39
 
39
- Rails.application.config.autoload_paths += ["#{TESTAPP_PATH}/app/models"]
40
-
41
- $LOAD_PATH << "#{TESTAPP_PATH}/app/models"
40
+ load_models
42
41
 
43
- unless Rails::VERSION::MAJOR >= 6
42
+ if Rails::VERSION::MAJOR == 5
44
43
  # TODO: get this to work on Travis for Rails 6
45
- Rails::Generators.invoke('declare_schema:migration', %w[-n -m])
44
+ generate_migrations '-n', '-m'
46
45
  end
47
46
 
48
47
  require 'advert'
@@ -6,22 +6,20 @@ RSpec.describe 'DeclareSchema Migration Generator' do
6
6
  end
7
7
 
8
8
  it "generates nested models" do
9
- Rails::Generators.invoke('declare_schema:model', %w[alpha/beta one:string two:integer])
9
+ generate_model 'alpha/beta', 'one:string', 'two:integer'
10
10
 
11
- expect(File.exist?('app/models/alpha/beta.rb')).to be_truthy
12
-
13
- expect(File.read('app/models/alpha/beta.rb')).to eq(<<~EOS)
11
+ expect_model_definition_to_eq('alpha/beta', <<~EOS)
14
12
  class Alpha::Beta < #{active_record_base_class}
15
-
13
+
16
14
  fields do
17
15
  one :string, limit: 255
18
16
  two :integer
19
17
  end
20
-
18
+
21
19
  end
22
20
  EOS
23
21
 
24
- expect(File.read('app/models/alpha.rb')).to eq(<<~EOS)
22
+ expect_model_definition_to_eq('alpha', <<~EOS)
25
23
  module Alpha
26
24
  def self.table_name_prefix
27
25
  'alpha_'
@@ -29,9 +27,9 @@ RSpec.describe 'DeclareSchema Migration Generator' do
29
27
  end
30
28
  EOS
31
29
 
32
- expect(File.read('test/models/alpha/beta_test.rb')).to eq(<<~EOS)
30
+ expect_test_definition_to_eq('alpha/beta', <<~EOS)
33
31
  require 'test_helper'
34
-
32
+
35
33
  class Alpha::BetaTest < ActiveSupport::TestCase
36
34
  # test "the truth" do
37
35
  # assert true
@@ -39,7 +37,50 @@ RSpec.describe 'DeclareSchema Migration Generator' do
39
37
  end
40
38
  EOS
41
39
 
42
- expect(File.exist?('test/fixtures/alpha/beta.yml')).to be_truthy
40
+ case Rails::VERSION::MAJOR
41
+ when 4
42
+ expect_test_fixture_to_eq('alpha/beta', <<~EOS)
43
+ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
44
+
45
+ # This model initially had no columns defined. If you add columns to the
46
+ # model remove the '{}' from the fixture names and add the columns immediately
47
+ # below each fixture, per the syntax in the comments below
48
+ #
49
+ one: {}
50
+ # column: value
51
+ #
52
+ two: {}
53
+ # column: value
54
+ EOS
55
+ when 5
56
+ expect_test_fixture_to_eq('alpha/beta', <<~EOS)
57
+ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
58
+
59
+ # This model initially had no columns defined. If you add columns to the
60
+ # model remove the '{}' from the fixture names and add the columns immediately
61
+ # below each fixture, per the syntax in the comments below
62
+ #
63
+ one: {}
64
+ # column: value
65
+ #
66
+ two: {}
67
+ # column: value
68
+ EOS
69
+ when 6
70
+ expect_test_fixture_to_eq('alpha/beta', <<~EOS)
71
+ # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
72
+
73
+ # This model initially had no columns defined. If you add columns to the
74
+ # model remove the '{}' from the fixture names and add the columns immediately
75
+ # below each fixture, per the syntax in the comments below
76
+ #
77
+ one: {}
78
+ # column: value
79
+ #
80
+ two: {}
81
+ # column: value
82
+ EOS
83
+ end
43
84
 
44
85
  $LOAD_PATH << "#{TESTAPP_PATH}/app/models"
45
86
 
@@ -12,7 +12,7 @@ RSpec.describe 'DeclareSchema Migration Generator interactive primary key' do
12
12
  self.primary_key = "foo_id"
13
13
  end
14
14
 
15
- Rails::Generators.invoke('declare_schema:migration', %w[-n -m])
15
+ generate_migrations '-n', '-m'
16
16
  expect(Foo.primary_key).to eq('foo_id')
17
17
 
18
18
  ### migrate from
@@ -24,28 +24,30 @@ RSpec.describe 'DeclareSchema Migration Generator interactive primary key' do
24
24
  end
25
25
 
26
26
  puts "\n\e[45m Please enter 'id' (no quotes) at the next prompt \e[0m"
27
- Rails::Generators.invoke('declare_schema:migration', %w[-n -m])
27
+ generate_migrations '-n', '-m'
28
28
  expect(Foo.primary_key).to eq('id')
29
29
 
30
30
  nuke_model_class(Foo)
31
31
 
32
32
  ### migrate to
33
33
 
34
- # rename to custom primary_key
35
- class Foo < ActiveRecord::Base
36
- fields do
34
+ if Rails::VERSION::MAJOR >= 5
35
+ # rename to custom primary_key
36
+ class Foo < ActiveRecord::Base
37
+ fields do
38
+ end
39
+ self.primary_key = "foo_id"
37
40
  end
38
- self.primary_key = "foo_id"
39
- end
40
41
 
41
- puts "\n\e[45m Please enter 'drop id' (no quotes) at the next prompt \e[0m"
42
- Rails::Generators.invoke('declare_schema:migration', %w[-n -m])
43
- expect(Foo.primary_key).to eq('foo_id')
42
+ puts "\n\e[45m Please enter 'drop id' (no quotes) at the next prompt \e[0m"
43
+ generate_migrations '-n', '-m'
44
+ expect(Foo.primary_key).to eq('foo_id')
44
45
 
45
- ### ensure it doesn't cause further migrations
46
+ ### ensure it doesn't cause further migrations
46
47
 
47
- # check no further migrations
48
- up, down = Generators::DeclareSchema::Migration::Migrator.run
49
- expect(up).to eq("")
48
+ # check no further migrations
49
+ up = Generators::DeclareSchema::Migration::Migrator.run.first
50
+ expect(up).to eq("")
51
+ end
50
52
  end
51
53
  end
@@ -11,14 +11,12 @@ RSpec.describe 'DeclareSchema Migration Generator' do
11
11
  it 'generates migrations' do
12
12
  ## The migration generator -- introduction
13
13
 
14
- up_down = Generators::DeclareSchema::Migration::Migrator.run
15
- expect(up_down).to eq(["", ""])
14
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to migrate_up("").and migrate_down("")
16
15
 
17
16
  class Advert < ActiveRecord::Base
18
17
  end
19
18
 
20
- up_down = Generators::DeclareSchema::Migration::Migrator.run
21
- expect(up_down).to eq(["", ""])
19
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to migrate_up("").and migrate_down("")
22
20
 
23
21
  Generators::DeclareSchema::Migration::Migrator.ignore_tables = ["green_fishes"]
24
22
 
@@ -30,17 +28,27 @@ RSpec.describe 'DeclareSchema Migration Generator' do
30
28
  name :string, limit: 255, null: true
31
29
  end
32
30
  end
33
- up, down = Generators::DeclareSchema::Migration::Migrator.run
34
- expect(up).to eq(<<~EOS.strip)
35
- create_table :adverts, id: :bigint do |t|
36
- t.string :name, limit: 255
37
- end
38
- EOS
39
- expect(down).to eq("drop_table :adverts")
31
+
32
+ up, _ = Generators::DeclareSchema::Migration::Migrator.run.tap do |migrations|
33
+ expect(migrations).to(
34
+ migrate_up(<<~EOS.strip)
35
+ create_table :adverts, id: :bigint do |t|
36
+ t.string :name, limit: 255
37
+ end
38
+ EOS
39
+ .and migrate_down("drop_table :adverts")
40
+ )
41
+ end
40
42
 
41
43
  ActiveRecord::Migration.class_eval(up)
42
44
  expect(Advert.columns.map(&:name)).to eq(["id", "name"])
43
45
 
46
+ if Rails::VERSION::MAJOR < 5
47
+ # Rails 4 sqlite driver doesn't create PK properly. Fix that by dropping and recreating.
48
+ 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))')
50
+ end
51
+
44
52
  class Advert < ActiveRecord::Base
45
53
  fields do
46
54
  name :string, limit: 255, null: true
@@ -48,19 +56,20 @@ RSpec.describe 'DeclareSchema Migration Generator' do
48
56
  published_at :datetime, null: true
49
57
  end
50
58
  end
51
- up, down = migrate
52
- expect(up).to eq(<<~EOS.strip)
53
- add_column :adverts, :body, :text
54
- add_column :adverts, :published_at, :datetime
55
59
 
56
- add_index :adverts, [:id], unique: true, name: 'PRIMARY_KEY'
57
- EOS
58
- # TODO: ^ TECH-4975 add_index should not be there
60
+ Advert.connection.schema_cache.clear!
61
+ Advert.reset_column_information
59
62
 
60
- expect(down).to eq(<<~EOS.strip)
61
- remove_column :adverts, :body
62
- remove_column :adverts, :published_at
63
- EOS
63
+ expect(migrate).to(
64
+ migrate_up(<<~EOS.strip)
65
+ add_column :adverts, :body, :text
66
+ add_column :adverts, :published_at, :datetime
67
+ EOS
68
+ .and migrate_down(<<~EOS.strip)
69
+ remove_column :adverts, :body
70
+ remove_column :adverts, :published_at
71
+ EOS
72
+ )
64
73
 
65
74
  Advert.field_specs.clear # not normally needed
66
75
  class Advert < ActiveRecord::Base
@@ -70,9 +79,11 @@ RSpec.describe 'DeclareSchema Migration Generator' do
70
79
  end
71
80
  end
72
81
 
73
- up, down = migrate
74
- expect(up).to eq("remove_column :adverts, :published_at")
75
- expect(down).to eq("add_column :adverts, :published_at, :datetime")
82
+ expect(migrate).to(
83
+ migrate_up("remove_column :adverts, :published_at").and(
84
+ migrate_down("add_column :adverts, :published_at, :datetime")
85
+ )
86
+ )
76
87
 
77
88
  nuke_model_class(Advert)
78
89
  class Advert < ActiveRecord::Base
@@ -82,20 +93,22 @@ RSpec.describe 'DeclareSchema Migration Generator' do
82
93
  end
83
94
  end
84
95
 
85
- up, down = Generators::DeclareSchema::Migration::Migrator.run
86
- expect(up).to eq(<<~EOS.strip)
87
- add_column :adverts, :title, :string, limit: 255
88
- remove_column :adverts, :name
89
- EOS
90
-
91
- expect(down).to eq(<<~EOS.strip)
92
- remove_column :adverts, :title
93
- add_column :adverts, :name, :string, limit: 255
94
- EOS
95
-
96
- up, down = Generators::DeclareSchema::Migration::Migrator.run(adverts: { name: :title })
97
- expect(up).to eq("rename_column :adverts, :name, :title")
98
- expect(down).to eq("rename_column :adverts, :title, :name")
96
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
97
+ migrate_up(<<~EOS.strip)
98
+ add_column :adverts, :title, :string, limit: 255
99
+ remove_column :adverts, :name
100
+ EOS
101
+ .and migrate_down(<<~EOS.strip)
102
+ remove_column :adverts, :title
103
+ add_column :adverts, :name, :string, limit: 255
104
+ EOS
105
+ )
106
+
107
+ expect(Generators::DeclareSchema::Migration::Migrator.run(adverts: { name: :title })).to(
108
+ migrate_up("rename_column :adverts, :name, :title").and(
109
+ migrate_down("rename_column :adverts, :title, :name")
110
+ )
111
+ )
99
112
 
100
113
  migrate
101
114
 
@@ -106,9 +119,11 @@ RSpec.describe 'DeclareSchema Migration Generator' do
106
119
  end
107
120
  end
108
121
 
109
- up_down = Generators::DeclareSchema::Migration::Migrator.run
110
- expect(up_down).to eq(["change_column :adverts, :title, :text",
111
- "change_column :adverts, :title, :string, limit: 255"])
122
+ 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")
125
+ )
126
+ )
112
127
 
113
128
  class Advert < ActiveRecord::Base
114
129
  fields do
@@ -117,11 +132,14 @@ RSpec.describe 'DeclareSchema Migration Generator' do
117
132
  end
118
133
  end
119
134
 
120
- up, down = migrate
121
- expect(up.split(',').slice(0,3).join(',')).to eq('change_column :adverts, :title, :string')
122
- expect(up.split(',').slice(3,2).sort.join(',')).to eq(" default: \"Untitled\", limit: 255")
123
- expect(down).to eq("change_column :adverts, :title, :string, limit: 255")
124
-
135
+ expect(migrate).to(
136
+ migrate_up(<<~EOS.strip)
137
+ change_column :adverts, :title, :string, limit: 255, default: "Untitled"
138
+ EOS
139
+ .and migrate_down(<<~EOS.strip)
140
+ change_column :adverts, :title, :string, limit: 255
141
+ EOS
142
+ )
125
143
 
126
144
  ### Limits
127
145
 
@@ -131,8 +149,9 @@ RSpec.describe 'DeclareSchema Migration Generator' do
131
149
  end
132
150
  end
133
151
 
134
- up = Generators::DeclareSchema::Migration::Migrator.run.first
135
- expect(up).to eq("add_column :adverts, :price, :integer, limit: 2")
152
+ up, _ = Generators::DeclareSchema::Migration::Migrator.run.tap do |migrations|
153
+ expect(migrations).to migrate_up("add_column :adverts, :price, :integer, limit: 2")
154
+ end
136
155
 
137
156
  # Now run the migration, then change the limit:
138
157
 
@@ -143,9 +162,14 @@ RSpec.describe 'DeclareSchema Migration Generator' do
143
162
  end
144
163
  end
145
164
 
146
- up, down = Generators::DeclareSchema::Migration::Migrator.run
147
- expect(up).to eq("change_column :adverts, :price, :integer, limit: 3")
148
- expect(down).to eq("change_column :adverts, :price, :integer, limit: 2")
165
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
166
+ migrate_up(<<~EOS.strip)
167
+ change_column :adverts, :price, :integer, limit: 3
168
+ EOS
169
+ .and migrate_down(<<~EOS.strip)
170
+ change_column :adverts, :price, :integer, limit: 2
171
+ EOS
172
+ )
149
173
 
150
174
  # Note that limit on a decimal column is ignored (use :scale and :precision)
151
175
 
@@ -156,8 +180,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
156
180
  end
157
181
  end
158
182
 
159
- up = Generators::DeclareSchema::Migration::Migrator.run.first
160
- expect(up).to eq("add_column :adverts, :price, :decimal")
183
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to migrate_up("add_column :adverts, :price, :decimal")
161
184
 
162
185
  # Limits are generally not needed for `text` fields, because by default, `text` fields will use the maximum size
163
186
  # allowed for that database type (0xffffffff for LONGTEXT in MySQL unlimited in Postgres, 1 billion in Sqlite).
@@ -172,12 +195,13 @@ RSpec.describe 'DeclareSchema Migration Generator' do
172
195
  end
173
196
  end
174
197
 
175
- up = Generators::DeclareSchema::Migration::Migrator.run.first
176
- expect(up).to eq(<<~EOS.strip)
177
- add_column :adverts, :price, :decimal
178
- add_column :adverts, :notes, :text, null: false
179
- add_column :adverts, :description, :text, null: false
180
- EOS
198
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
199
+ 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
203
+ EOS
204
+ )
181
205
 
182
206
  # (There is no limit on `add_column ... :description` above since these tests are run against SQLite.)
183
207
 
@@ -196,11 +220,12 @@ RSpec.describe 'DeclareSchema Migration Generator' do
196
220
  end
197
221
  end
198
222
 
199
- up = Generators::DeclareSchema::Migration::Migrator.run.first
200
- expect(up).to eq(<<~EOS.strip)
201
- add_column :adverts, :notes, :text, null: false, limit: 4294967295
202
- add_column :adverts, :description, :text, null: false, limit: 255
203
- EOS
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
+ )
204
229
 
205
230
  Advert.field_specs.delete :notes
206
231
 
@@ -239,9 +264,14 @@ RSpec.describe 'DeclareSchema Migration Generator' do
239
264
  end
240
265
  end
241
266
 
242
- up, down = Generators::DeclareSchema::Migration::Migrator.run
243
- expect(up).to eq("change_column :adverts, :description, :text, limit: 4294967295, null: false")
244
- expect(down).to eq("change_column :adverts, :description, :text")
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
+ )
245
275
 
246
276
  # TODO TECH-4814: The above test should have this output:
247
277
  # TODO => "change_column :adverts, :description, :text, limit: 255
@@ -254,9 +284,14 @@ RSpec.describe 'DeclareSchema Migration Generator' do
254
284
  end
255
285
  end
256
286
 
257
- up, down = Generators::DeclareSchema::Migration::Migrator.run
258
- expect(up).to eq("change_column :adverts, :description, :text, limit: 4294967295, null: false")
259
- expect(down).to eq("change_column :adverts, :description, :text")
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
+ )
260
295
  ::DeclareSchema::Model::FieldSpec::instance_variable_set(:@mysql_text_limits, false)
261
296
 
262
297
  Advert.field_specs.clear
@@ -286,18 +321,21 @@ RSpec.describe 'DeclareSchema Migration Generator' do
286
321
  belongs_to :category
287
322
  end
288
323
 
289
- up, down = Generators::DeclareSchema::Migration::Migrator.run
290
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
291
- add_column :adverts, :category_id, :integer, limit: 8, null: false
292
- add_index :adverts, [:category_id], name: 'on_category_id'
293
- EOS
294
- expect(down.sub(/\n+/, "\n")).to eq(<<~EOS.strip)
295
- remove_column :adverts, :category_id
296
- remove_index :adverts, name: :on_category_id rescue ActiveRecord::StatementInvalid
297
- EOS
324
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
325
+ migrate_up(<<~EOS.strip)
326
+ add_column :adverts, :category_id, :integer, limit: 8, null: false
327
+
328
+ add_index :adverts, [:category_id], name: 'on_category_id'
329
+ EOS
330
+ .and migrate_down(<<~EOS.strip)
331
+ remove_column :adverts, :category_id
332
+
333
+ remove_index :adverts, name: :on_category_id rescue ActiveRecord::StatementInvalid
334
+ EOS
335
+ )
298
336
 
299
337
  Advert.field_specs.delete(:category_id)
300
- Advert.index_specs.delete_if {|spec| spec.fields==["category_id"]}
338
+ Advert.index_definitions.delete_if { |spec| spec.fields==["category_id"] }
301
339
 
302
340
  # If you specify a custom foreign key, the migration generator observes that:
303
341
 
@@ -306,14 +344,17 @@ RSpec.describe 'DeclareSchema Migration Generator' do
306
344
  fields { }
307
345
  belongs_to :category, foreign_key: "c_id", class_name: 'Category'
308
346
  end
309
- up = Generators::DeclareSchema::Migration::Migrator.run.first
310
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
311
- add_column :adverts, :c_id, :integer, limit: 8, null: false
312
- add_index :adverts, [:c_id], name: 'on_c_id'
313
- EOS
347
+
348
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
349
+ migrate_up(<<~EOS.strip)
350
+ add_column :adverts, :c_id, :integer, limit: 8, null: false
351
+
352
+ add_index :adverts, [:c_id], name: 'on_c_id'
353
+ EOS
354
+ )
314
355
 
315
356
  Advert.field_specs.delete(:c_id)
316
- Advert.index_specs.delete_if { |spec| spec.fields == ["c_id"] }
357
+ Advert.index_definitions.delete_if { |spec| spec.fields == ["c_id"] }
317
358
 
318
359
  # You can avoid generating the index by specifying `index: false`
319
360
 
@@ -322,11 +363,15 @@ RSpec.describe 'DeclareSchema Migration Generator' do
322
363
  fields { }
323
364
  belongs_to :category, index: false
324
365
  end
325
- up = Generators::DeclareSchema::Migration::Migrator.run.first
326
- expect(up.gsub(/\n+/, "\n")).to eq("add_column :adverts, :category_id, :integer, limit: 8, null: false")
366
+
367
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
368
+ migrate_up(<<~EOS.strip)
369
+ add_column :adverts, :category_id, :integer, limit: 8, null: false
370
+ EOS
371
+ )
327
372
 
328
373
  Advert.field_specs.delete(:category_id)
329
- Advert.index_specs.delete_if { |spec| spec.fields == ["category_id"] }
374
+ Advert.index_definitions.delete_if { |spec| spec.fields == ["category_id"] }
330
375
 
331
376
  # You can specify the index name with :index
332
377
 
@@ -335,14 +380,17 @@ RSpec.describe 'DeclareSchema Migration Generator' do
335
380
  fields { }
336
381
  belongs_to :category, index: 'my_index'
337
382
  end
338
- up = Generators::DeclareSchema::Migration::Migrator.run.first
339
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
340
- add_column :adverts, :category_id, :integer, limit: 8, null: false
341
- add_index :adverts, [:category_id], name: 'my_index'
342
- EOS
383
+
384
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
385
+ migrate_up(<<~EOS.strip)
386
+ add_column :adverts, :category_id, :integer, limit: 8, null: false
387
+
388
+ add_index :adverts, [:category_id], name: 'my_index'
389
+ EOS
390
+ )
343
391
 
344
392
  Advert.field_specs.delete(:category_id)
345
- Advert.index_specs.delete_if { |spec| spec.fields == ["category_id"] }
393
+ Advert.index_definitions.delete_if { |spec| spec.fields == ["category_id"] }
346
394
 
347
395
  ### Timestamps and Optimimistic Locking
348
396
 
@@ -355,17 +403,19 @@ RSpec.describe 'DeclareSchema Migration Generator' do
355
403
  optimistic_lock
356
404
  end
357
405
  end
358
- up, down = Generators::DeclareSchema::Migration::Migrator.run
359
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
360
- add_column :adverts, :created_at, :datetime
361
- add_column :adverts, :updated_at, :datetime
362
- add_column :adverts, :lock_version, :integer, null: false, default: 1
363
- EOS
364
- expect(down.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
365
- remove_column :adverts, :created_at
366
- remove_column :adverts, :updated_at
367
- remove_column :adverts, :lock_version
368
- EOS
406
+
407
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
408
+ 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
412
+ EOS
413
+ .and migrate_down(<<~EOS.strip)
414
+ remove_column :adverts, :created_at
415
+ remove_column :adverts, :updated_at
416
+ remove_column :adverts, :lock_version
417
+ EOS
418
+ )
369
419
 
370
420
  Advert.field_specs.delete(:updated_at)
371
421
  Advert.field_specs.delete(:created_at)
@@ -380,13 +430,16 @@ RSpec.describe 'DeclareSchema Migration Generator' do
380
430
  title :string, index: true, limit: 255, null: true
381
431
  end
382
432
  end
383
- up = Generators::DeclareSchema::Migration::Migrator.run.first
384
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
385
- add_column :adverts, :title, :string, limit: 255
386
- add_index :adverts, [:title], name: 'on_title'
387
- EOS
388
433
 
389
- Advert.index_specs.delete_if { |spec| spec.fields==["title"] }
434
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
435
+ migrate_up(<<~EOS.strip)
436
+ add_column :adverts, :title, :string, limit: 255
437
+
438
+ add_index :adverts, [:title], name: 'on_title'
439
+ EOS
440
+ )
441
+
442
+ Advert.index_definitions.delete_if { |spec| spec.fields==["title"] }
390
443
 
391
444
  # You can ask for a unique index
392
445
 
@@ -395,13 +448,16 @@ RSpec.describe 'DeclareSchema Migration Generator' do
395
448
  title :string, index: true, unique: true, null: true, limit: 255
396
449
  end
397
450
  end
398
- up = Generators::DeclareSchema::Migration::Migrator.run.first
399
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
400
- add_column :adverts, :title, :string, limit: 255
401
- add_index :adverts, [:title], unique: true, name: 'on_title'
402
- EOS
403
451
 
404
- Advert.index_specs.delete_if { |spec| spec.fields == ["title"] }
452
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
453
+ migrate_up(<<~EOS.strip)
454
+ add_column :adverts, :title, :string, limit: 255
455
+
456
+ add_index :adverts, [:title], unique: true, name: 'on_title'
457
+ EOS
458
+ )
459
+
460
+ Advert.index_definitions.delete_if { |spec| spec.fields == ["title"] }
405
461
 
406
462
  # You can specify the name for the index
407
463
 
@@ -410,52 +466,64 @@ RSpec.describe 'DeclareSchema Migration Generator' do
410
466
  title :string, index: 'my_index', limit: 255, null: true
411
467
  end
412
468
  end
413
- up = Generators::DeclareSchema::Migration::Migrator.run.first
414
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
415
- add_column :adverts, :title, :string, limit: 255
416
- add_index :adverts, [:title], name: 'my_index'
417
- EOS
418
469
 
419
- Advert.index_specs.delete_if { |spec| spec.fields==["title"] }
470
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
471
+ migrate_up(<<~EOS.strip)
472
+ add_column :adverts, :title, :string, limit: 255
473
+
474
+ add_index :adverts, [:title], name: 'my_index'
475
+ EOS
476
+ )
477
+
478
+ Advert.index_definitions.delete_if { |spec| spec.fields==["title"] }
420
479
 
421
480
  # You can ask for an index outside of the fields block
422
481
 
423
482
  class Advert < ActiveRecord::Base
424
483
  index :title
425
484
  end
426
- up = Generators::DeclareSchema::Migration::Migrator.run.first
427
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
428
- add_column :adverts, :title, :string, limit: 255
429
- add_index :adverts, [:title], name: 'on_title'
430
- EOS
431
485
 
432
- Advert.index_specs.delete_if { |spec| spec.fields == ["title"] }
486
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
487
+ migrate_up(<<~EOS.strip)
488
+ add_column :adverts, :title, :string, limit: 255
489
+
490
+ add_index :adverts, [:title], name: 'on_title'
491
+ EOS
492
+ )
493
+
494
+ Advert.index_definitions.delete_if { |spec| spec.fields == ["title"] }
433
495
 
434
496
  # The available options for the index function are `:unique` and `:name`
435
497
 
436
498
  class Advert < ActiveRecord::Base
437
499
  index :title, unique: true, name: 'my_index'
438
500
  end
439
- up = Generators::DeclareSchema::Migration::Migrator.run.first
440
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
441
- add_column :adverts, :title, :string, limit: 255
442
- add_index :adverts, [:title], unique: true, name: 'my_index'
443
- EOS
444
501
 
445
- Advert.index_specs.delete_if { |spec| spec.fields == ["title"] }
502
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
503
+ migrate_up(<<~EOS.strip)
504
+ add_column :adverts, :title, :string, limit: 255
505
+
506
+ add_index :adverts, [:title], unique: true, name: 'my_index'
507
+ EOS
508
+ )
509
+
510
+ Advert.index_definitions.delete_if { |spec| spec.fields == ["title"] }
446
511
 
447
512
  # You can create an index on more than one field
448
513
 
449
514
  class Advert < ActiveRecord::Base
450
515
  index [:title, :category_id]
451
516
  end
452
- up = Generators::DeclareSchema::Migration::Migrator.run.first
453
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
454
- add_column :adverts, :title, :string, limit: 255
455
- add_index :adverts, [:title, :category_id], name: 'on_title_and_category_id'
456
- EOS
457
517
 
458
- Advert.index_specs.delete_if { |spec| spec.fields==["title", "category_id"] }
518
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
519
+ migrate_up(<<~EOS.strip)
520
+ add_column :adverts, :title, :string, limit: 255
521
+
522
+ add_index :adverts, [:title, :category_id], name: 'on_title_and_category_id'
523
+ EOS
524
+ )
525
+
526
+ Advert.index_definitions.delete_if { |spec| spec.fields==["title", "category_id"] }
459
527
 
460
528
  # Finally, you can specify that the migration generator should completely ignore an
461
529
  # index by passing its name to ignore_index in the model.
@@ -476,19 +544,24 @@ RSpec.describe 'DeclareSchema Migration Generator' do
476
544
  Advert.connection.schema_cache.clear!
477
545
  Advert.reset_column_information
478
546
 
479
- up, down = Generators::DeclareSchema::Migration::Migrator.run("adverts" => "ads")
480
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
481
- rename_table :adverts, :ads
482
- add_column :ads, :title, :string, limit: 255
483
- add_column :ads, :body, :text
484
- add_index :ads, [:id], unique: true, name: 'PRIMARY_KEY'
485
- EOS
486
- expect(down.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
487
- remove_column :ads, :title
488
- remove_column :ads, :body
489
- rename_table :ads, :adverts
490
- add_index :adverts, [:id], unique: true, name: 'PRIMARY_KEY'
491
- EOS
547
+ expect(Generators::DeclareSchema::Migration::Migrator.run("adverts" => "ads")).to(
548
+ migrate_up(<<~EOS.strip)
549
+ rename_table :adverts, :ads
550
+
551
+ add_column :ads, :title, :string, limit: 255
552
+ add_column :ads, :body, :text
553
+
554
+ add_index :ads, [:id], unique: true, name: 'PRIMARY'
555
+ EOS
556
+ .and migrate_down(<<~EOS.strip)
557
+ remove_column :ads, :title
558
+ remove_column :ads, :body
559
+
560
+ rename_table :ads, :adverts
561
+
562
+ add_index :adverts, [:id], unique: true, name: 'PRIMARY'
563
+ EOS
564
+ )
492
565
 
493
566
  # Set the table name back to what it should be and confirm we're in sync:
494
567
 
@@ -512,21 +585,27 @@ RSpec.describe 'DeclareSchema Migration Generator' do
512
585
  body :text, null: true
513
586
  end
514
587
  end
515
- up, down = Generators::DeclareSchema::Migration::Migrator.run("adverts" => "advertisements")
516
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
517
- rename_table :adverts, :advertisements
518
- add_column :advertisements, :title, :string, limit: 255
519
- add_column :advertisements, :body, :text
520
- remove_column :advertisements, :name
521
- add_index :advertisements, [:id], unique: true, name: 'PRIMARY_KEY'
522
- EOS
523
- expect(down.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
524
- remove_column :advertisements, :title
525
- remove_column :advertisements, :body
526
- add_column :adverts, :name, :string, limit: 255
527
- rename_table :advertisements, :adverts
528
- add_index :adverts, [:id], unique: true, name: 'PRIMARY_KEY'
529
- EOS
588
+
589
+ expect(Generators::DeclareSchema::Migration::Migrator.run("adverts" => "advertisements")).to(
590
+ migrate_up(<<~EOS.strip)
591
+ rename_table :adverts, :advertisements
592
+
593
+ add_column :advertisements, :title, :string, limit: 255
594
+ add_column :advertisements, :body, :text
595
+ remove_column :advertisements, :name
596
+
597
+ add_index :advertisements, [:id], unique: true, name: 'PRIMARY'
598
+ EOS
599
+ .and migrate_down(<<~EOS.strip)
600
+ remove_column :advertisements, :title
601
+ remove_column :advertisements, :body
602
+ add_column :adverts, :name, :string, limit: 255
603
+
604
+ rename_table :advertisements, :adverts
605
+
606
+ add_index :adverts, [:id], unique: true, name: 'PRIMARY'
607
+ EOS
608
+ )
530
609
 
531
610
  ### Drop a table
532
611
 
@@ -536,9 +615,24 @@ RSpec.describe 'DeclareSchema Migration Generator' do
536
615
 
537
616
  # Dropping tables is where the automatic down-migration really comes in handy:
538
617
 
539
- up, down = Generators::DeclareSchema::Migration::Migrator.run
540
- expect(up).to eq("drop_table :adverts")
541
- expect(down.gsub(/,.*/m, '')).to eq("create_table \"adverts\"")
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
+ expect(Generators::DeclareSchema::Migration::Migrator.run).to(
631
+ migrate_up(<<~EOS.strip)
632
+ drop_table :adverts
633
+ EOS
634
+ .and migrate_down(Rails::VERSION::MAJOR >= 5 ? rails5_table_create : rails4_table_create)
635
+ )
542
636
 
543
637
  ## STI
544
638
 
@@ -559,20 +653,26 @@ RSpec.describe 'DeclareSchema Migration Generator' do
559
653
  end
560
654
  class SuperFancyAdvert < FancyAdvert
561
655
  end
562
- up, down = Generators::DeclareSchema::Migration::Migrator.run
563
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
564
- add_column :adverts, :type, :string, limit: 255
565
- add_index :adverts, [:type], name: 'on_type'
566
- EOS
567
- expect(down.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
568
- remove_column :adverts, :type
569
- remove_index :adverts, name: :on_type rescue ActiveRecord::StatementInvalid
570
- EOS
656
+
657
+ up, _ = Generators::DeclareSchema::Migration::Migrator.run do |migrations|
658
+ expect(migrations).to(
659
+ migrate_up(<<~EOS.strip)
660
+ add_column :adverts, :type, :string, limit: 255
661
+
662
+ add_index :adverts, [:type], name: 'on_type'
663
+ EOS
664
+ .and migrate_down(<<~EOS.strip)
665
+ remove_column :adverts, :type
666
+
667
+ remove_index :adverts, name: :on_type rescue ActiveRecord::StatementInvalid
668
+ EOS
669
+ )
670
+ end
571
671
 
572
672
  Advert.field_specs.delete(:type)
573
673
  nuke_model_class(SuperFancyAdvert)
574
674
  nuke_model_class(FancyAdvert)
575
- Advert.index_specs.delete_if { |spec| spec.fields==["type"] }
675
+ Advert.index_definitions.delete_if { |spec| spec.fields==["type"] }
576
676
 
577
677
  ## Coping with multiple changes
578
678
 
@@ -600,16 +700,17 @@ RSpec.describe 'DeclareSchema Migration Generator' do
600
700
  body :text, null: true
601
701
  end
602
702
  end
603
- up, down = Generators::DeclareSchema::Migration::Migrator.run(adverts: { title: :name })
604
- expect(up).to eq(<<~EOS.strip)
605
- rename_column :adverts, :title, :name
606
- change_column :adverts, :name, :string, limit: 255, default: \"No Name\"
607
- EOS
608
703
 
609
- expect(down).to eq(<<~EOS.strip)
610
- rename_column :adverts, :name, :title
611
- change_column :adverts, :title, :string, limit: 255, default: \"Untitled\"
612
- EOS
704
+ expect(Generators::DeclareSchema::Migration::Migrator.run(adverts: { title: :name })).to(
705
+ migrate_up(<<~EOS.strip)
706
+ rename_column :adverts, :title, :name
707
+ change_column :adverts, :name, :string, limit: 255, default: "No Name"
708
+ EOS
709
+ .and migrate_down(<<~EOS.strip)
710
+ rename_column :adverts, :name, :title
711
+ change_column :adverts, :title, :string, limit: 255, default: "Untitled"
712
+ EOS
713
+ )
613
714
 
614
715
  ### Rename a table and add a column
615
716
 
@@ -621,13 +722,17 @@ RSpec.describe 'DeclareSchema Migration Generator' do
621
722
  created_at :datetime
622
723
  end
623
724
  end
624
- up = Generators::DeclareSchema::Migration::Migrator.run(adverts: :ads).first
625
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
626
- rename_table :adverts, :ads
627
- add_column :ads, :created_at, :datetime, null: false
628
- change_column :ads, :title, :string, limit: 255, null: false, default: \"Untitled\"
629
- add_index :ads, [:id], unique: true, name: 'PRIMARY_KEY'
630
- EOS
725
+
726
+ expect(Generators::DeclareSchema::Migration::Migrator.run(adverts: :ads)).to(
727
+ migrate_up(<<~EOS.strip)
728
+ rename_table :adverts, :ads
729
+
730
+ add_column :ads, :created_at, :datetime, null: false
731
+ change_column :ads, :title, :string, limit: 255, null: false, default: \"Untitled\"
732
+
733
+ add_index :ads, [:id], unique: true, name: 'PRIMARY'
734
+ EOS
735
+ )
631
736
 
632
737
  class Advert < ActiveRecord::Base
633
738
  fields do
@@ -648,11 +753,14 @@ RSpec.describe 'DeclareSchema Migration Generator' do
648
753
  end
649
754
  self.primary_key = "advert_id"
650
755
  end
651
- up, _down = Generators::DeclareSchema::Migration::Migrator.run(adverts: { id: :advert_id })
652
- expect(up.gsub(/\n+/, "\n")).to eq(<<~EOS.strip)
653
- rename_column :adverts, :id, :advert_id
654
- add_index :adverts, [:advert_id], unique: true, name: 'PRIMARY_KEY'
655
- EOS
756
+
757
+ expect(Generators::DeclareSchema::Migration::Migrator.run(adverts: { id: :advert_id })).to(
758
+ migrate_up(<<~EOS.strip)
759
+ rename_column :adverts, :id, :advert_id
760
+
761
+ add_index :adverts, [:advert_id], unique: true, name: 'PRIMARY'
762
+ EOS
763
+ )
656
764
 
657
765
  nuke_model_class(Advert)
658
766
  ActiveRecord::Base.connection.execute("drop table `adverts`;")
@@ -691,7 +799,200 @@ RSpec.describe 'DeclareSchema Migration Generator' do
691
799
  expect(Ad.field_specs['company'].options[:validates].inspect).to eq("{:presence=>true, :uniqueness=>{:case_sensitive=>false}}")
692
800
  end
693
801
 
694
- if Rails::VERSION::MAJOR >= 5
802
+ describe 'serialize' do
803
+ before do
804
+ class Ad < ActiveRecord::Base
805
+ @serialize_args = []
806
+
807
+ class << self
808
+ attr_reader :serialize_args
809
+
810
+ def serialize(*args)
811
+ @serialize_args << args
812
+ end
813
+ end
814
+ end
815
+ end
816
+
817
+ describe 'untyped' do
818
+ it 'allows serialize: true' do
819
+ class Ad < ActiveRecord::Base
820
+ fields do
821
+ allow_list :text, limit: 0xFFFF, serialize: true
822
+ end
823
+ end
824
+
825
+ expect(Ad.serialize_args).to eq([[:allow_list]])
826
+ end
827
+
828
+ it 'converts defaults with .to_yaml' do
829
+ class Ad < ActiveRecord::Base
830
+ 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
835
+ end
836
+ end
837
+
838
+ expect(Ad.field_specs['allow_list'].default).to eq("--- []\n")
839
+ expect(Ad.field_specs['allow_hash'].default).to eq("--- {}\n")
840
+ expect(Ad.field_specs['allow_string'].default).to eq("---\n- abc\n")
841
+ expect(Ad.field_specs['allow_null'].default).to eq(nil)
842
+ end
843
+ end
844
+
845
+ describe 'Array' do
846
+ it 'allows serialize: Array' do
847
+ class Ad < ActiveRecord::Base
848
+ fields do
849
+ allow_list :string, limit: 255, serialize: Array, null: true
850
+ end
851
+ end
852
+
853
+ expect(Ad.serialize_args).to eq([[:allow_list, Array]])
854
+ end
855
+
856
+ it 'allows Array defaults' do
857
+ class Ad < ActiveRecord::Base
858
+ 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
863
+ end
864
+ end
865
+
866
+ expect(Ad.field_specs['allow_list'].default).to eq("---\n- 2\n")
867
+ expect(Ad.field_specs['allow_string'].default).to eq("---\n- abc\n")
868
+ expect(Ad.field_specs['allow_empty'].default).to eq(nil)
869
+ expect(Ad.field_specs['allow_null'].default).to eq(nil)
870
+ end
871
+ end
872
+
873
+ describe 'Hash' do
874
+ it 'allows serialize: Hash' do
875
+ class Ad < ActiveRecord::Base
876
+ fields do
877
+ allow_list :string, limit: 255, serialize: Hash, null: true
878
+ end
879
+ end
880
+
881
+ expect(Ad.serialize_args).to eq([[:allow_list, Hash]])
882
+ end
883
+
884
+ it 'allows Hash defaults' do
885
+ class Ad < ActiveRecord::Base
886
+ 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
890
+ end
891
+ end
892
+
893
+ expect(Ad.field_specs['allow_loc'].default).to eq("---\nstate: CA\n")
894
+ expect(Ad.field_specs['allow_hash'].default).to eq(nil)
895
+ expect(Ad.field_specs['allow_null'].default).to eq(nil)
896
+ end
897
+ end
898
+
899
+ describe 'JSON' do
900
+ it 'allows serialize: JSON' do
901
+ class Ad < ActiveRecord::Base
902
+ fields do
903
+ allow_list :string, limit: 255, serialize: JSON
904
+ end
905
+ end
906
+
907
+ expect(Ad.serialize_args).to eq([[:allow_list, JSON]])
908
+ end
909
+
910
+ it 'allows JSON defaults' do
911
+ class Ad < ActiveRecord::Base
912
+ 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
917
+ end
918
+ end
919
+
920
+ expect(Ad.field_specs['allow_hash'].default).to eq("{\"state\":\"CA\"}")
921
+ expect(Ad.field_specs['allow_empty_array'].default).to eq("[]")
922
+ expect(Ad.field_specs['allow_empty_hash'].default).to eq("{}")
923
+ expect(Ad.field_specs['allow_null'].default).to eq(nil)
924
+ end
925
+ end
926
+
927
+ class ValueClass
928
+ delegate :present?, :inspect, to: :@value
929
+
930
+ def initialize(value)
931
+ @value = value
932
+ end
933
+
934
+ class << self
935
+ def dump(object)
936
+ if object&.present?
937
+ object.inspect
938
+ end
939
+ end
940
+
941
+ def load(serialized)
942
+ if serialized
943
+ raise 'not used ???'
944
+ end
945
+ end
946
+ end
947
+ end
948
+
949
+ describe 'custom coder' do
950
+ it 'allows serialize: ValueClass' do
951
+ class Ad < ActiveRecord::Base
952
+ fields do
953
+ allow_list :string, limit: 255, serialize: ValueClass
954
+ end
955
+ end
956
+
957
+ expect(Ad.serialize_args).to eq([[:allow_list, ValueClass]])
958
+ end
959
+
960
+ it 'allows ValueClass defaults' do
961
+ class Ad < ActiveRecord::Base
962
+ 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
966
+ end
967
+ end
968
+
969
+ expect(Ad.field_specs['allow_hash'].default).to eq("[2]")
970
+ expect(Ad.field_specs['allow_empty_array'].default).to eq(nil)
971
+ expect(Ad.field_specs['allow_null'].default).to eq(nil)
972
+ end
973
+ end
974
+
975
+ it 'disallows serialize: with a non-string column type' do
976
+ expect do
977
+ class Ad < ActiveRecord::Base
978
+ fields do
979
+ allow_list :integer, limit: 8, serialize: true
980
+ end
981
+ end
982
+ end.to raise_exception(ArgumentError, /must be :string or :text/)
983
+ end
984
+ end
985
+
986
+ context "for Rails #{Rails::VERSION::MAJOR}" do
987
+ if Rails::VERSION::MAJOR >= 5
988
+ let(:optional_true) { { optional: true } }
989
+ let(:optional_false) { { optional: false } }
990
+ else
991
+ let(:optional_true) { {} }
992
+ let(:optional_false) { {} }
993
+ end
994
+ let(:optional_flag) { { false => optional_false, true => optional_true } }
995
+
695
996
  describe 'belongs_to' do
696
997
  before do
697
998
  unless defined?(AdCategory)
@@ -718,10 +1019,10 @@ RSpec.describe 'DeclareSchema Migration Generator' do
718
1019
  reset_column_information
719
1020
  belongs_to :ad_category, optional: true
720
1021
  end
721
- expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional: true)
1022
+ expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional_true)
722
1023
  end
723
1024
 
724
- describe 'contradictory settings' do # contradictory settings are ok during migration
1025
+ describe 'contradictory settings' do # contradictory settings are ok--for example, during migration
725
1026
  it 'passes through optional: true, null: false' do
726
1027
  class AdvertBelongsTo < ActiveRecord::Base
727
1028
  self.table_name = 'adverts'
@@ -729,7 +1030,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
729
1030
  reset_column_information
730
1031
  belongs_to :ad_category, optional: true, null: false
731
1032
  end
732
- expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional: true)
1033
+ expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional_true)
733
1034
  expect(AdvertBelongsTo.field_specs['ad_category_id'].options&.[](:null)).to eq(false)
734
1035
  end
735
1036
 
@@ -740,7 +1041,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
740
1041
  reset_column_information
741
1042
  belongs_to :ad_category, optional: false, null: true
742
1043
  end
743
- expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional: false)
1044
+ expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional_false)
744
1045
  expect(AdvertBelongsTo.field_specs['ad_category_id'].options&.[](:null)).to eq(true)
745
1046
  end
746
1047
  end
@@ -754,7 +1055,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
754
1055
  belongs_to :ad_category, null: #{nullable}
755
1056
  end
756
1057
  EOS
757
- expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional: nullable)
1058
+ expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional_flag[nullable])
758
1059
  expect(AdvertBelongsTo.field_specs['ad_category_id'].options&.[](:null)).to eq(nullable)
759
1060
  end
760
1061
 
@@ -765,7 +1066,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
765
1066
  belongs_to :ad_category, optional: #{nullable}
766
1067
  end
767
1068
  EOS
768
- expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional: nullable)
1069
+ expect(AdvertBelongsTo.reflections['ad_category'].options).to eq(optional_flag[nullable])
769
1070
  expect(AdvertBelongsTo.field_specs['ad_category_id'].options&.[](:null)).to eq(nullable)
770
1071
  end
771
1072
  end
@@ -781,7 +1082,7 @@ RSpec.describe 'DeclareSchema Migration Generator' do
781
1082
  end
782
1083
  end
783
1084
 
784
- Rails::Generators.invoke('declare_schema:migration', %w[-n -m])
1085
+ generate_migrations '-n', '-m'
785
1086
 
786
1087
  migrations = Dir.glob('db/migrate/*declare_schema_migration*.rb')
787
1088
  expect(migrations.size).to eq(1), migrations.inspect