enum_table 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,51 @@
1
+ module EnumTable
2
+ module SchemaDumper
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ alias_method_chain :tables, :enum_table
7
+ alias_method_chain :ignore_tables, :enum_table
8
+ end
9
+
10
+ def tables_with_enum_table(stream)
11
+ tables_without_enum_table(stream)
12
+ table_names = @connection.enum_tables
13
+ table_names.each do |table_name|
14
+ stream.puts " create_enum_table #{table_name.inspect}, force: true do |t|"
15
+ enum_table_column(stream, table_name, 'id', SchemaStatements::DEFAULT_ID_ATTRIBUTES)
16
+ enum_table_column(stream, table_name, 'value', SchemaStatements::DEFAULT_VALUE_ATTRIBUTES)
17
+ @connection.execute("SELECT id, value FROM #{table_name} ORDER BY id").each do |row|
18
+ stream.puts " t.add #{row[1].to_s.inspect}, #{row[0]}"
19
+ end
20
+ stream.puts " end"
21
+ stream.puts
22
+ end
23
+ end
24
+
25
+ def ignore_tables_with_enum_table
26
+ ignore_tables_without_enum_table + @connection.enum_tables << 'enum_tables'
27
+ end
28
+
29
+ private
30
+
31
+ def enum_table_column(stream, table_name, column_name, defaults)
32
+ column = @connection.columns(table_name).find { |c| c.name == column_name }
33
+ custom_attributes = {}
34
+ COLUMN_ATTRIBUTES.each do |attribute|
35
+ value = column.send(attribute)
36
+ value == defaults[attribute] or
37
+ custom_attributes[attribute] = value
38
+ end
39
+ if custom_attributes.present?
40
+ formatted = custom_attributes.map { |k, v| "#{k}: #{v.inspect}" }.join(', ')
41
+ stream.puts " t.#{column_name} #{formatted}"
42
+ end
43
+ end
44
+
45
+ COLUMN_ATTRIBUTES = [:default, :type, :limit, :null, :precision, :scale]
46
+ end
47
+ end
48
+
49
+ # This is not loaded in enum_table.rb as it's only needed when dumping the
50
+ # schema. Instead, we make rake tasks load this file explicitly.
51
+ ActiveRecord::SchemaDumper.send :include, EnumTable::SchemaDumper
@@ -0,0 +1,86 @@
1
+ module EnumTable
2
+ module SchemaStatements
3
+ def create_enum_table(table_name, options={})
4
+ table = NewTable.new(self, table_name, options)
5
+ yield table if block_given?
6
+ table._create
7
+ end
8
+
9
+ def change_enum_table(table_name)
10
+ yield Table.new(self, table_name)
11
+ end
12
+
13
+ def drop_enum_table(table_name)
14
+ drop_table table_name
15
+ execute "DELETE FROM enum_tables WHERE table_name = '#{table_name}'"
16
+ end
17
+
18
+ def enum_tables
19
+ return [] if !table_exists?('enum_tables')
20
+ execute("SELECT table_name FROM enum_tables").map do |row|
21
+ row[0]
22
+ end.sort
23
+ end
24
+
25
+ DEFAULT_ID_ATTRIBUTES = {type: :integer, limit: 1, null: false}.freeze
26
+ DEFAULT_VALUE_ATTRIBUTES = {type: :string, limit: 255, null: false}.freeze
27
+
28
+ class NewTable
29
+ def initialize(connection, name, options)
30
+ @connection = connection
31
+ @name = name
32
+ @options = options
33
+ @id = DEFAULT_ID_ATTRIBUTES.dup
34
+ @value = DEFAULT_VALUE_ATTRIBUTES.dup
35
+ @adds = []
36
+ values = options.delete(:values) and
37
+ values.each { |args| add(*args) }
38
+ end
39
+
40
+ def _create
41
+ @connection.create_table @name, @options.merge(id: false) do |t|
42
+ t.column :id, @id.delete(:type), @id
43
+ t.column :value, @value.delete(:type), @value
44
+ end
45
+ unless @connection.table_exists?(:enum_tables)
46
+ @connection.create_table :enum_tables, id: false, force: true do |t|
47
+ t.string :table_name, null: false
48
+ end
49
+ end
50
+ @connection.execute "INSERT INTO enum_tables(table_name) VALUES('#{@name}')"
51
+ table = Table.new(@connection, @name, 0)
52
+ @adds.each { |args| table.add(*args) }
53
+ end
54
+
55
+ def id(options)
56
+ @id.update(options)
57
+ end
58
+
59
+ def value(options)
60
+ @value.update(options)
61
+ end
62
+
63
+ def add(*args)
64
+ @adds << args
65
+ end
66
+ end
67
+
68
+ class Table
69
+ def initialize(connection, name, max_id=nil)
70
+ @connection = connection
71
+ @name = name
72
+ @max_id = @connection.execute("SELECT max(id) FROM #{@name}").to_a[0][0] || 0
73
+ end
74
+
75
+ def add(value, id=nil)
76
+ id ||= @max_id + 1
77
+ @max_id = id if id > @max_id
78
+ @connection.execute "INSERT INTO #{@name}(id, value) VALUES(#{id}, '#{value}')"
79
+ end
80
+
81
+ def remove(value)
82
+ @connection.execute "DELETE FROM #{@name} WHERE value = '#{value}'"
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,11 @@
1
+ module EnumTable
2
+ VERSION = [0, 0, 1]
3
+
4
+ class << VERSION
5
+ include Comparable
6
+
7
+ def to_s
8
+ join('.')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ sqlite3:
2
+ database: ':memory:'
3
+ mysql:
4
+ username: root
5
+ password:
6
+ database: db_nazi_test
7
+ mysql2:
8
+ username: root
9
+ password:
10
+ database: db_nazi_test
11
+ postgresql:
12
+ username: postgres
13
+ password:
14
+ database: db_nazi_test
15
+ min_messages: warning
16
+ jdbcmysql:
17
+ username: root
18
+ password:
19
+ database: db_nazi_test
@@ -0,0 +1,578 @@
1
+ require_relative '../test_helper'
2
+
3
+ describe EnumTable do
4
+ use_database
5
+
6
+ before do
7
+ connection.create_table :users do |t|
8
+ t.integer :gender_id
9
+ t.integer :status_id
10
+ t.string :user_type
11
+ end
12
+ end
13
+
14
+ before { Object.const_set :User, Class.new(ActiveRecord::Base) }
15
+ after { Object.send :remove_const, :User }
16
+
17
+ describe '.enum' do
18
+ before do
19
+ connection.create_table(:user_genders) { |t| t.string :value }
20
+ connection.execute "INSERT INTO user_genders(id, value) VALUES (1, 'female'), (2, 'male')"
21
+ end
22
+
23
+ it "defines an enum by a conventionally named table by default" do
24
+ User.enum :gender
25
+ User.enums[:gender].value(1).must_equal(:female)
26
+ end
27
+
28
+ it "returns the reflection" do
29
+ reflection = User.enum :gender
30
+ reflection.must_be_kind_of EnumTable::Reflection
31
+ reflection.name.must_equal :gender
32
+ end
33
+
34
+ it "accepts the :table name as a string" do
35
+ connection.create_table(:custom_table) { |t| t.string :value }
36
+ connection.execute "INSERT INTO custom_table(id, value) VALUES (1, 'male'), (2, 'female')"
37
+ User.enum :gender, table: 'custom_table'
38
+ User.enums[:gender].value(1).must_equal(:male)
39
+ end
40
+
41
+ it "accepts the :table name as a symbol" do
42
+ connection.create_table(:custom_table) { |t| t.string :value }
43
+ connection.execute "INSERT INTO custom_table(id, value) VALUES (1, 'male'), (2, 'female')"
44
+ User.enum :gender, table: :custom_table
45
+ User.enums[:gender].value(1).must_equal(:male)
46
+ end
47
+
48
+ it "accepts the :table directly as a hash" do
49
+ User.enum :gender, table: {male: 1, female: 2}
50
+ User.enums[:gender].value(1).must_equal :male
51
+ end
52
+
53
+ it "accepts the :table as an array" do
54
+ User.enum :gender, table: [:male, :female]
55
+ User.enums[:gender].value(1).must_equal :male
56
+ end
57
+
58
+ it "raises an ArgumentError if :table is something else" do
59
+ ->{ User.enum :gender, table: Object.new }.must_raise ArgumentError, /invalid :table specifier/
60
+ end
61
+
62
+ it "passes other options to the Reflection" do
63
+ User.enum :gender, id_name: :gender_number
64
+ enum = User.enums[:gender]
65
+ enum.id_name.must_equal :gender_number
66
+ end
67
+
68
+ describe "on a subclass" do
69
+ before do
70
+ User.inheritance_column = :user_type
71
+ Object.const_set :Subuser, Class.new(User)
72
+ end
73
+
74
+ after do
75
+ Object.send :remove_const, :Subuser
76
+ end
77
+
78
+ it "makes any values in the superclass available in the subclass" do
79
+ User.enum :gender, table: {female: 1}
80
+ Subuser.enum :gender, table: {male: 2}
81
+ Subuser.reflect_on_enum(:gender).id(:female).must_equal 1
82
+ end
83
+
84
+ it "makes any values added in the subclass not available to the superclass" do
85
+ User.enum :gender, table: {female: 1}
86
+ Subuser.enum :gender, table: {male: 2}
87
+ User.reflect_on_enum(:gender).id(:male).must_be_nil
88
+ end
89
+
90
+ it "inherits options from the superclass that aren't given for the subclass" do
91
+ User.enum :gender, table: {female: 1, male: 2}, type: :string, id_name: :status_id
92
+ Subuser.enum :gender
93
+ reflection = Subuser.reflect_on_enum(:gender)
94
+ reflection.id(:female).must_equal 1
95
+ reflection.type.must_equal :string
96
+ reflection.id_name.must_equal :status_id
97
+ end
98
+
99
+ it "inherits options from the superclass if no enum call is made in the subclass" do
100
+ User.enum :gender, table: {female: 1, male: 2}
101
+ Subuser.reflect_on_enum(:gender).id(:female).must_equal 1
102
+ end
103
+
104
+ it "allows overriding the :type option in the subclass" do
105
+ User.enum :gender, type: :symbol
106
+ Subuser.enum :gender, type: :string
107
+ User.reflect_on_enum(:gender).type.must_equal :symbol
108
+ Subuser.reflect_on_enum(:gender).type.must_equal :string
109
+ end
110
+
111
+ it "allows overriding the :id_name option in the subclass" do
112
+ User.enum :gender, id_name: :status_id, type: :symbol
113
+ Subuser.enum :gender, id_name: :status_id, type: :string
114
+ User.reflect_on_enum(:gender).type.must_equal :symbol
115
+ Subuser.reflect_on_enum(:gender).type.must_equal :string
116
+ end
117
+ end
118
+ end
119
+
120
+ describe ".reflect_on_enum" do
121
+ before { User.enum :gender, table: {} }
122
+
123
+ it "returns the reflection for the named enum" do
124
+ reflection = User.reflect_on_enum(:gender)
125
+ reflection.name.must_equal :gender
126
+ end
127
+
128
+ it "returns nil if there is no such enum" do
129
+ User.reflect_on_enum(:invalid).must_be_nil
130
+ end
131
+ end
132
+
133
+ describe ".enum_id" do
134
+ before { User.enum :gender, table: {female: 1} }
135
+
136
+ it "raises an ArgumentError if the enum name is invalid" do
137
+ ->{ User.enum_id(:bad) }.must_raise ArgumentError
138
+ end
139
+
140
+ it "returns the id for the given enum value" do
141
+ User.enum_id(:gender, :female).must_equal 1
142
+ end
143
+ end
144
+
145
+ describe ".initialize_attributes" do
146
+ before { User.enum :gender, table: {female: 1, male: 2} }
147
+
148
+ it "converts enums to their underlying IDs" do
149
+ attributes = User.initialize_attributes('gender' => 'female')
150
+ attributes.must_equal('gender_id' => 1)
151
+ end
152
+
153
+ it "does not prevent optimistic locking from working, which also uses this internal method" do
154
+ attributes = User.initialize_attributes('lock_version' => nil)
155
+ attributes.must_equal('lock_version' => 0)
156
+ end
157
+
158
+ it "should favor the ID if both the id and value are present in the attributes hash (so enums override columns)" do
159
+ attributes = User.initialize_attributes('gender_id' => 1, 'gender' => :male)
160
+ attributes['gender_id'].must_equal 1
161
+ attributes.key?('gender').must_equal false
162
+ end
163
+ end
164
+
165
+ describe "#enum_id" do
166
+ before { User.enum :gender, table: {female: 1} }
167
+
168
+ it "raises an ArgumentError if the enum name is invalid" do
169
+ user = User.new
170
+ ->{ user.enum_id(:bad) }.must_raise ArgumentError
171
+ end
172
+
173
+ it "returns the id for the given enum value" do
174
+ user = User.new
175
+ user.enum_id(:gender, :female).must_equal 1
176
+ end
177
+ end
178
+
179
+ describe "#read_enum" do
180
+ before { User.enum :gender, table: {female: 1, male: 2} }
181
+
182
+ it "raises an ArgumentError if the enum name is invalid" do
183
+ user = User.new
184
+ ->{ user.read_enum(:bad) }.must_raise ArgumentError
185
+ end
186
+
187
+ it "returns the value mapped to the id" do
188
+ user = User.new(gender_id: 1)
189
+ user.read_enum(:gender).must_equal :female
190
+ end
191
+
192
+ it "returns nil if the id is not mapped" do
193
+ user = User.new(gender_id: 3)
194
+ user.read_enum(:gender).must_be_nil
195
+ end
196
+
197
+ describe "when loading an existing record" do
198
+ before do
199
+ connection.execute "INSERT INTO users(id, gender_id) VALUES(1, 1)"
200
+ end
201
+
202
+ it "returns the correct value" do
203
+ user = User.find(1)
204
+ user.read_enum(:gender).must_equal :female
205
+ end
206
+ end
207
+ end
208
+
209
+ describe "#write_enum" do
210
+ before { User.enum :gender, table: {female: 1, male: 2} }
211
+
212
+ it "raises an ArgumentError if the enum name is invalid" do
213
+ user = User.new
214
+ ->{ user.write_enum(:bad, :female) }.must_raise ArgumentError
215
+ end
216
+
217
+ it "sets the id to the id mapped to the given value" do
218
+ user = User.new
219
+ user.write_enum(:gender, :female)
220
+ user.gender_id.must_equal 1
221
+ end
222
+
223
+ it "sets the id to nil if the given value is not mapped to an id" do
224
+ user = User.new
225
+ user.write_enum(:gender, :other)
226
+ user.gender_id.must_be_nil
227
+ end
228
+ end
229
+
230
+ describe "#read_attribute" do
231
+ before { User.enum :gender, table: {female: 1, male: 2} }
232
+
233
+ it "reads enums" do
234
+ user = User.new(gender_id: 1)
235
+ user.read_attribute(:gender).must_equal :female
236
+ end
237
+
238
+ it "allows string names for enums" do
239
+ user = User.new(gender_id: 1)
240
+ user.read_attribute('gender').must_equal :female
241
+ end
242
+
243
+ it "still reads attributes" do
244
+ user = User.new(gender_id: 1)
245
+ user.read_attribute(:gender_id).must_equal 1
246
+ end
247
+ end
248
+
249
+ describe "#write_attribute" do
250
+ before { User.enum :gender, table: {female: 1, male: 2} }
251
+
252
+ it "writes enums" do
253
+ user = User.new
254
+ user.write_attribute(:gender, :female)
255
+ user.gender_id.must_equal 1
256
+ end
257
+
258
+ it "allows string names for enums" do
259
+ user = User.new
260
+ user.write_attribute('gender', :female)
261
+ user.gender_id.must_equal 1
262
+ end
263
+
264
+ it "still writes attributes" do
265
+ user = User.new
266
+ user.write_attribute(:gender_id, 1)
267
+ user.gender_id.must_equal 1
268
+ end
269
+ end
270
+
271
+ describe "#query_enum" do
272
+ before { User.enum :gender, table: {female: 1, male: 2} }
273
+
274
+ it "raises an ArgumentError if the enum name is invalid" do
275
+ user = User.new
276
+ ->{ user.query_enum(:bad) }.must_raise ArgumentError
277
+ end
278
+
279
+ it "returns true if the is mapped to a value" do
280
+ user = User.new(gender_id: 1)
281
+ user.query_enum(:gender).must_equal true
282
+ end
283
+
284
+ it "returns false if the given value is not mapped to an id" do
285
+ user = User.new(gender_id: 3)
286
+ user.query_enum(:gender).must_equal false
287
+ end
288
+ end
289
+
290
+ describe "#enum_changed?" do
291
+ before do
292
+ User.enum :gender, table: {female: 1, male: 2}
293
+ User.create(gender_id: 1)
294
+ end
295
+
296
+ it "raises an ArgumentError if the enum name is invalid" do
297
+ user = User.first
298
+ ->{ user.enum_changed?(:bad) }.must_raise ArgumentError
299
+ end
300
+
301
+ it "returns true if the enum value changed" do
302
+ user = User.first
303
+ user.gender = :male
304
+ user.enum_changed?(:gender).must_equal true
305
+ end
306
+
307
+ it "returns true if the id attribute changed" do
308
+ user = User.first
309
+ user.gender_id = 2
310
+ user.enum_changed?(:gender).must_equal true
311
+ end
312
+
313
+ it "returns false if the attribute value has not changed" do
314
+ user = User.first
315
+ user.enum_changed?(:gender).must_equal false
316
+ end
317
+ end
318
+
319
+ describe "#enum_was" do
320
+ before do
321
+ User.enum :gender, table: {female: 1, male: 2}
322
+ User.create(gender_id: 1)
323
+ end
324
+
325
+ it "raises an ArgumentError if the enum name is invalid" do
326
+ user = User.first
327
+ ->{ user.enum_was(:bad) }.must_raise ArgumentError
328
+ end
329
+
330
+ it "returns the old value if the enum value changed" do
331
+ user = User.first
332
+ user.gender = :male
333
+ user.enum_was(:gender).must_equal :female
334
+ end
335
+
336
+ it "returns the old value if the id attribute changed" do
337
+ user = User.first
338
+ user.gender_id = 2
339
+ user.enum_was(:gender).must_equal :female
340
+ end
341
+
342
+ it "returns the current value if the enum has not changed" do
343
+ user = User.first
344
+ user.enum_was(:gender).must_equal :female
345
+ end
346
+ end
347
+
348
+ describe "#enum_change" do
349
+ before do
350
+ User.enum :gender, table: {female: 1, male: 2}
351
+ User.create(gender_id: 1)
352
+ end
353
+
354
+ it "raises an ArgumentError if the enum name is invalid" do
355
+ user = User.first
356
+ ->{ user.enum_change(:bad) }.must_raise ArgumentError
357
+ end
358
+
359
+ it "returns the old and new values if the enum value changed" do
360
+ user = User.first
361
+ user.gender = :male
362
+ user.enum_change(:gender).must_equal [:female, :male]
363
+ end
364
+
365
+ it "returns the old and new values if the enum id changed" do
366
+ user = User.first
367
+ user.gender_id = 2
368
+ user.enum_change(:gender).must_equal [:female, :male]
369
+ end
370
+
371
+ it "returns nil if the enum has not changed" do
372
+ user = User.first
373
+ user.enum_change(:gender).must_be_nil
374
+ end
375
+ end
376
+
377
+ describe "#ENUM" do
378
+ before { User.enum :gender, table: {female: 1, male: 2} }
379
+
380
+ it "returns the enum value" do
381
+ user = User.new(gender_id: 1)
382
+ user.gender.must_equal :female
383
+ end
384
+ end
385
+
386
+ describe "#ENUM=" do
387
+ before { User.enum :gender, table: {female: 1, male: 2} }
388
+
389
+ it "sets the enum value" do
390
+ user = User.new
391
+ user.gender = :female
392
+ user.gender_id.must_equal 1
393
+ end
394
+ end
395
+
396
+ describe "#ENUM?" do
397
+ before { User.enum :gender, table: {female: 1, male: 2} }
398
+
399
+ it "returns true if the enum value is present" do
400
+ user = User.new(gender_id: nil)
401
+ user.gender?.must_equal false
402
+
403
+ user = User.new(gender_id: 1)
404
+ user.gender?.must_equal true
405
+ end
406
+ end
407
+
408
+ describe "#ENUM_changed?" do
409
+ before do
410
+ User.enum :gender, table: {female: 1, male: 2}
411
+ User.create(gender_id: 1)
412
+ end
413
+
414
+ it "returns the changed flag for the enum" do
415
+ user = User.first
416
+ user.gender_changed?.must_equal false
417
+
418
+ user.gender_id = 2
419
+ user.gender_changed?.must_equal true
420
+ end
421
+ end
422
+
423
+ describe "#ENUM_was" do
424
+ before do
425
+ User.enum :gender, table: {female: 1, male: 2}
426
+ User.create(gender_id: 1)
427
+ end
428
+
429
+ it "returns the changed flag for the enum" do
430
+ user = User.first
431
+ user.gender_was.must_equal :female
432
+ end
433
+ end
434
+
435
+ describe "#ENUM_change" do
436
+ before do
437
+ User.enum :gender, table: {female: 1, male: 2}
438
+ User.create(gender_id: 1)
439
+ end
440
+
441
+ it "returns the old and new values for the enum" do
442
+ user = User.first
443
+ user.gender_change.must_be_nil
444
+
445
+ user.gender_id = 2
446
+ user.gender_change.must_equal [:female, :male]
447
+ end
448
+ end
449
+
450
+ describe "roundtripping" do
451
+ it "roundtrips a value through write and read" do
452
+ User.enum :gender, table: {female: 1, male: 2}
453
+ user = User.new
454
+ user.gender = :female
455
+ user.gender.must_equal :female
456
+ end
457
+
458
+ it "roundtrips a value through persistence" do
459
+ User.enum :gender, table: {female: 1, male: 2}
460
+ User.create(gender: :female)
461
+ User.first.gender.must_equal :female
462
+ end
463
+
464
+ it "supports strings values" do
465
+ User.enum :gender, table: {female: 1, male: 2}, type: :string
466
+ User.create(gender: 'female')
467
+ User.first.gender.must_equal 'female'
468
+ end
469
+ end
470
+
471
+ describe ".where" do
472
+ it "supports filtering by enums with symbol keys" do
473
+ User.enum :gender, table: {female: 1, male: 2}
474
+ female = User.create(gender_id: 1)
475
+ male = User.create(gender_id: 2)
476
+ User.where(gender: :female).all.must_equal [female]
477
+ end
478
+
479
+ it "supports filtering by enums with string keys" do
480
+ User.enum :gender, table: {female: 1, male: 2}
481
+ female = User.create(gender_id: 1)
482
+ male = User.create(gender_id: 2)
483
+ User.where('gender' => :female).all.must_equal [female]
484
+ end
485
+
486
+ it "supports filtering by multiple values" do
487
+ User.enum :gender, table: {female: 1, male: 2, other: 3}
488
+ female = User.create(gender_id: 1)
489
+ male = User.create(gender_id: 2)
490
+ other = User.create(gender_id: 3)
491
+ User.where(gender: [:female, :male]).all.must_equal [female, male]
492
+ end
493
+
494
+ it "still supports filtering by other attributes" do
495
+ User.enum :gender, table: {female: 1, male: 2}
496
+ female1 = User.create(gender_id: 1, status_id: 1)
497
+ male1 = User.create(gender_id: 2, status_id: 1)
498
+ male2 = User.create(gender_id: 2, status_id: 2)
499
+ User.where(gender: :male, status_id: 1).all.must_equal [male1]
500
+ end
501
+ end
502
+
503
+ describe "dynamic finders" do
504
+ it "support retrieval by enums" do
505
+ User.enum :gender, table: {female: 1, male: 2}
506
+ female = User.create(gender_id: 1)
507
+ male = User.create(gender_id: 2)
508
+
509
+ User.find_by_gender(:female).must_equal female
510
+ User.find_all_by_gender(:female).must_equal [female]
511
+ end
512
+ end
513
+
514
+ describe "when the inheritance column is an enum" do
515
+ before do
516
+ connection.add_column :users, :type_id, :integer
517
+ User.enum :type, table: {Admin: 1, Member: 2}
518
+ Object.const_set :Admin, Class.new(User)
519
+ Object.const_set :Member, Class.new(User)
520
+ end
521
+
522
+ after do
523
+ Object.send :remove_const, :Admin
524
+ Object.send :remove_const, :Member
525
+
526
+ # Instantiating STI classes goes through ActiveSupport::Dependencies.
527
+ ActiveSupport::Dependencies.clear
528
+ end
529
+
530
+ it "sets the type ID when instantiating" do
531
+ admin = Admin.create
532
+ admin.type_id.must_equal 1
533
+ end
534
+
535
+ it "instantiates the correct class through the superclass" do
536
+ admin = Admin.create
537
+ user = User.find(admin.id)
538
+ user.class.must_equal Admin
539
+ user.id.must_equal admin.id
540
+ end
541
+
542
+ it "finds and instantiates the correct class through the subclass" do
543
+ admin = Admin.create
544
+ found = Admin.find(admin.id)
545
+ found.class.must_equal Admin
546
+ found.id.must_equal admin.id
547
+ end
548
+
549
+ it "filters correctly when finding through the subclass" do
550
+ admin = Admin.create
551
+ Admin.find(admin.id).must_equal admin
552
+ Member.find_by_id(admin.id).must_be_nil
553
+ end
554
+ end
555
+
556
+ describe "when an enum has the same name as a column" do
557
+ before do
558
+ connection.add_column :users, :gender, :string
559
+ User.enum :gender, table: {female: 1, male: 2}
560
+ end
561
+
562
+ # TODO: It's probably desirable to write the column if it's present, for
563
+ # transitioning to an enum.
564
+ it "only writes the enum id" do
565
+ User.create(gender_id: 1)
566
+ results = connection.execute("SELECT gender_id, gender FROM users").to_a
567
+ results.size.must_equal 1
568
+ results[0][0].must_equal 1
569
+ results[0][1].must_equal nil
570
+ end
571
+
572
+ it "favors the enum when loading" do
573
+ connection.execute "INSERT INTO users(gender_id, gender) VALUES(1, 'male')"
574
+ User.first.gender_id.must_equal 1
575
+ User.first.gender.must_equal :female
576
+ end
577
+ end
578
+ end