declare_schema 0.5.0 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/declare_schema_build.yml +60 -0
- data/.gitignore +1 -0
- data/Appraisals +21 -4
- data/CHANGELOG.md +46 -0
- data/Gemfile +1 -2
- data/Gemfile.lock +4 -6
- data/README.md +3 -3
- data/Rakefile +17 -4
- data/bin/declare_schema +1 -1
- data/declare_schema.gemspec +1 -1
- data/gemfiles/rails_4_mysql.gemfile +22 -0
- data/gemfiles/{rails_4.gemfile → rails_4_sqlite.gemfile} +1 -2
- data/gemfiles/rails_5_mysql.gemfile +22 -0
- data/gemfiles/{rails_5.gemfile → rails_5_sqlite.gemfile} +1 -2
- data/gemfiles/rails_6_mysql.gemfile +22 -0
- data/gemfiles/{rails_6.gemfile → rails_6_sqlite.gemfile} +2 -3
- data/lib/declare_schema/command.rb +10 -3
- data/lib/declare_schema/model.rb +1 -1
- data/lib/declare_schema/model/field_spec.rb +18 -14
- data/lib/declare_schema/model/foreign_key_definition.rb +36 -25
- data/lib/declare_schema/model/table_options_definition.rb +8 -6
- data/lib/declare_schema/version.rb +1 -1
- data/lib/generators/declare_schema/migration/migrator.rb +80 -34
- data/spec/lib/declare_schema/field_spec_spec.rb +69 -0
- data/spec/lib/declare_schema/generator_spec.rb +4 -2
- data/spec/lib/declare_schema/interactive_primary_key_spec.rb +8 -2
- data/spec/lib/declare_schema/migration_generator_spec.rb +286 -158
- data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +93 -0
- data/spec/lib/declare_schema/model/index_definition_spec.rb +4 -5
- data/spec/lib/declare_schema/model/table_options_definition_spec.rb +19 -29
- data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +17 -22
- data/spec/support/acceptance_spec_helpers.rb +3 -3
- metadata +15 -10
- data/.travis.yml +0 -37
data/lib/declare_schema/model.rb
CHANGED
@@ -88,7 +88,7 @@ module DeclareSchema
|
|
88
88
|
add_formatting_for_field(name, type)
|
89
89
|
add_validations_for_field(name, type, args, options)
|
90
90
|
add_index_for_field(name, args, options)
|
91
|
-
field_specs[name] = ::DeclareSchema::Model::FieldSpec.new(self, name, type, options)
|
91
|
+
field_specs[name] = ::DeclareSchema::Model::FieldSpec.new(self, name, type, position: field_specs.size, **options)
|
92
92
|
attr_order << name unless attr_order.include?(name)
|
93
93
|
end
|
94
94
|
|
@@ -13,7 +13,6 @@ module DeclareSchema
|
|
13
13
|
MYSQL_TEXT_LIMITS_ASCENDING = [MYSQL_TINYTEXT_LIMIT, MYSQL_TEXT_LIMIT, MYSQL_MEDIUMTEXT_LIMIT, MYSQL_LONGTEXT_LIMIT].freeze
|
14
14
|
|
15
15
|
class << self
|
16
|
-
# method for easy stubbing in tests
|
17
16
|
def mysql_text_limits?
|
18
17
|
if defined?(@mysql_text_limits)
|
19
18
|
@mysql_text_limits
|
@@ -33,7 +32,8 @@ module DeclareSchema
|
|
33
32
|
|
34
33
|
attr_reader :model, :name, :type, :position, :options
|
35
34
|
|
36
|
-
def initialize(model, name, type,
|
35
|
+
def initialize(model, name, type, position: 0, **options)
|
36
|
+
# TODO: TECH-5116
|
37
37
|
# Invoca change - searching for the primary key was causing an additional database read on every model load. Assume
|
38
38
|
# "id" which works for invoca.
|
39
39
|
# raise ArgumentError, "you cannot provide a field spec for the primary key" if name == model.primary_key
|
@@ -43,9 +43,8 @@ module DeclareSchema
|
|
43
43
|
@name = name.to_sym
|
44
44
|
type.is_a?(Symbol) or raise ArgumentError, "type must be a Symbol; got #{type.inspect}"
|
45
45
|
@type = type
|
46
|
-
|
46
|
+
@position = position
|
47
47
|
@options = options
|
48
|
-
|
49
48
|
case type
|
50
49
|
when :text
|
51
50
|
@options[:default] and raise "default may not be given for :text field #{model}##{@name}"
|
@@ -54,11 +53,20 @@ module DeclareSchema
|
|
54
53
|
end
|
55
54
|
when :string
|
56
55
|
@options[:limit] or raise "limit must be given for :string field #{model}##{@name}: #{@options.inspect}; do you want `limit: 255`?"
|
56
|
+
when :bigint
|
57
|
+
@type = :integer
|
58
|
+
@options = options.merge(limit: 8)
|
59
|
+
end
|
60
|
+
|
61
|
+
if type.in?([:text, :string])
|
62
|
+
if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
|
63
|
+
@options[:charset] ||= model.table_options[:charset] || Generators::DeclareSchema::Migration::Migrator.default_charset
|
64
|
+
@options[:collation] ||= model.table_options[:collation] || Generators::DeclareSchema::Migration::Migrator.default_collation
|
65
|
+
end
|
57
66
|
else
|
58
|
-
@options[:collation] and raise "collation may only given for :string and :text fields"
|
59
67
|
@options[:charset] and raise "charset may only given for :string and :text fields"
|
68
|
+
@options[:collation] and raise "collation may only given for :string and :text fields"
|
60
69
|
end
|
61
|
-
@position = position_option || model.field_specs.length
|
62
70
|
end
|
63
71
|
|
64
72
|
TYPE_SYNONYMS = { timestamp: :datetime }.freeze
|
@@ -105,16 +113,12 @@ module DeclareSchema
|
|
105
113
|
@options[:default]
|
106
114
|
end
|
107
115
|
|
108
|
-
def
|
109
|
-
|
110
|
-
(@options[:collation] || model.table_options[:collation] || Generators::DeclareSchema::Migration::Migrator.default_collation).to_s
|
111
|
-
end
|
116
|
+
def charset
|
117
|
+
@options[:charset]
|
112
118
|
end
|
113
119
|
|
114
|
-
def
|
115
|
-
|
116
|
-
(@options[:charset] || model.table_options[:charset] || Generators::DeclareSchema::Migration::Migrator.default_charset).to_s
|
117
|
-
end
|
120
|
+
def collation
|
121
|
+
@options[:collation]
|
118
122
|
end
|
119
123
|
|
120
124
|
def same_type?(col_spec)
|
@@ -5,21 +5,21 @@ module DeclareSchema
|
|
5
5
|
class ForeignKeyDefinition
|
6
6
|
include Comparable
|
7
7
|
|
8
|
-
attr_reader :constraint_name, :model, :foreign_key, :options, :on_delete_cascade
|
8
|
+
attr_reader :constraint_name, :model, :foreign_key, :foreign_key_name, :options, :on_delete_cascade
|
9
9
|
|
10
10
|
def initialize(model, foreign_key, options = {})
|
11
11
|
@model = model
|
12
|
-
@foreign_key = foreign_key.presence
|
12
|
+
@foreign_key = foreign_key.to_s.presence
|
13
13
|
@options = options
|
14
14
|
|
15
15
|
@child_table = model.table_name # unless a table rename, which would happen when a class is renamed??
|
16
|
-
@parent_table_name = options[:parent_table]
|
17
|
-
@foreign_key_name = options[:foreign_key] ||
|
18
|
-
@index_name = options[:index_name] || model.connection.index_name(model.table_name, column:
|
19
|
-
@constraint_name = options[:constraint_name] || @index_name || ''
|
20
|
-
@on_delete_cascade = options[:dependent] == :delete
|
16
|
+
@parent_table_name = options[:parent_table]&.to_s
|
17
|
+
@foreign_key_name = options[:foreign_key]&.to_s || @foreign_key
|
18
|
+
@index_name = options[:index_name]&.to_s || model.connection.index_name(model.table_name, column: @foreign_key_name)
|
21
19
|
|
22
20
|
# Empty constraint lets mysql generate the name
|
21
|
+
@constraint_name = options[:constraint_name]&.to_s || @index_name&.to_s || ''
|
22
|
+
@on_delete_cascade = options[:dependent] == :delete
|
23
23
|
end
|
24
24
|
|
25
25
|
class << self
|
@@ -28,11 +28,12 @@ module DeclareSchema
|
|
28
28
|
constraints = show_create_table.split("\n").map { |line| line.strip if line['CONSTRAINT'] }.compact
|
29
29
|
|
30
30
|
constraints.map do |fkc|
|
31
|
-
options = {}
|
32
31
|
name, foreign_key, parent_table = fkc.match(/CONSTRAINT `([^`]*)` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)`/).captures
|
33
|
-
options
|
34
|
-
|
35
|
-
|
32
|
+
options = {
|
33
|
+
constraint_name: name,
|
34
|
+
parent_table: parent_table,
|
35
|
+
foreign_key: foreign_key
|
36
|
+
}
|
36
37
|
options[:dependent] = :delete if fkc['ON DELETE CASCADE']
|
37
38
|
|
38
39
|
new(model, foreign_key, options)
|
@@ -40,21 +41,37 @@ module DeclareSchema
|
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
44
|
+
# returns the parent class as a Class object
|
45
|
+
# or nil if no :class_name option given
|
46
|
+
def parent_class
|
47
|
+
if (class_name = options[:class_name])
|
48
|
+
if class_name.is_a?(Class)
|
49
|
+
class_name
|
50
|
+
else
|
51
|
+
class_name.to_s.constantize
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
43
56
|
def parent_table_name
|
44
57
|
@parent_table_name ||=
|
45
|
-
|
46
|
-
|
47
|
-
klass.try(:table_name)
|
48
|
-
end || foreign_key.sub(/_id\z/, '').camelize.constantize.table_name
|
58
|
+
parent_class&.try(:table_name) ||
|
59
|
+
foreign_key.sub(/_id\z/, '').camelize.constantize.table_name
|
49
60
|
end
|
50
61
|
|
51
|
-
attr_writer :parent_table_name
|
52
|
-
|
53
62
|
def to_add_statement
|
54
|
-
|
55
|
-
|
63
|
+
"add_foreign_key(#{@child_table.inspect}, #{parent_table_name.inspect}, " +
|
64
|
+
"column: #{@foreign_key_name.inspect}, name: #{@constraint_name.inspect})"
|
65
|
+
end
|
66
|
+
|
67
|
+
def <=>(rhs)
|
68
|
+
key <=> rhs.send(:key)
|
56
69
|
end
|
57
70
|
|
71
|
+
alias eql? ==
|
72
|
+
|
73
|
+
private
|
74
|
+
|
58
75
|
def key
|
59
76
|
@key ||= [@child_table, parent_table_name, @foreign_key_name, @on_delete_cascade].map(&:to_s)
|
60
77
|
end
|
@@ -62,12 +79,6 @@ module DeclareSchema
|
|
62
79
|
def hash
|
63
80
|
key.hash
|
64
81
|
end
|
65
|
-
|
66
|
-
def <=>(rhs)
|
67
|
-
key <=> rhs.key
|
68
|
-
end
|
69
|
-
|
70
|
-
alias eql? ==
|
71
82
|
end
|
72
83
|
end
|
73
84
|
end
|
@@ -26,12 +26,14 @@ module DeclareSchema
|
|
26
26
|
|
27
27
|
def mysql_table_options(connection, table_name)
|
28
28
|
database = connection.current_database
|
29
|
-
defaults = connection.select_one(<<~EOS)
|
29
|
+
defaults = connection.select_one(<<~EOS) or raise "no defaults found for table #{table_name}"
|
30
30
|
SELECT CCSA.character_set_name, CCSA.collation_name
|
31
|
-
FROM information_schema
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
FROM information_schema.TABLES as T
|
32
|
+
JOIN information_schema.COLLATION_CHARACTER_SET_APPLICABILITY as CCSA
|
33
|
+
ON CCSA.collation_name = T.table_collation
|
34
|
+
WHERE
|
35
|
+
T.table_schema = '#{connection.quote_string(database)}' AND
|
36
|
+
T.table_name = '#{connection.quote_string(table_name)}'
|
35
37
|
EOS
|
36
38
|
|
37
39
|
defaults["character_set_name"] or raise "character_set_name missing from #{defaults.inspect}"
|
@@ -75,7 +77,7 @@ module DeclareSchema
|
|
75
77
|
alias to_s settings
|
76
78
|
|
77
79
|
def alter_table_statement
|
78
|
-
statement = "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name)} #{to_s}
|
80
|
+
statement = "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name)} #{to_s}"
|
79
81
|
"execute #{statement.inspect}"
|
80
82
|
end
|
81
83
|
end
|
@@ -37,11 +37,9 @@ module Generators
|
|
37
37
|
|
38
38
|
def field_specs
|
39
39
|
i = 0
|
40
|
-
foreign_keys.
|
41
|
-
|
42
|
-
h[v] = ::DeclareSchema::Model::FieldSpec.new(self, v, :integer, position: i, null: false)
|
40
|
+
foreign_keys.each_with_object({}) do |v, result|
|
41
|
+
result[v] = ::DeclareSchema::Model::FieldSpec.new(self, v, :integer, position: i, null: false)
|
43
42
|
i += 1
|
44
|
-
h
|
45
43
|
end
|
46
44
|
end
|
47
45
|
|
@@ -73,8 +71,8 @@ module Generators
|
|
73
71
|
class Migrator
|
74
72
|
class Error < RuntimeError; end
|
75
73
|
|
76
|
-
DEFAULT_CHARSET =
|
77
|
-
DEFAULT_COLLATION =
|
74
|
+
DEFAULT_CHARSET = "utf8mb4"
|
75
|
+
DEFAULT_COLLATION = "utf8mb4_bin"
|
78
76
|
|
79
77
|
@ignore_models = []
|
80
78
|
@ignore_tables = []
|
@@ -84,9 +82,18 @@ module Generators
|
|
84
82
|
@default_collation = DEFAULT_COLLATION
|
85
83
|
|
86
84
|
class << self
|
87
|
-
attr_accessor :ignore_models, :ignore_tables, :disable_indexing, :disable_constraints
|
88
|
-
|
89
|
-
|
85
|
+
attr_accessor :ignore_models, :ignore_tables, :disable_indexing, :disable_constraints
|
86
|
+
attr_reader :active_record_class, :default_charset, :default_collation, :before_generating_migration_callback
|
87
|
+
|
88
|
+
def default_charset=(charset)
|
89
|
+
charset.is_a?(String) or raise ArgumentError, "charset must be a string (got #{charset.inspect})"
|
90
|
+
@default_charset = charset
|
91
|
+
end
|
92
|
+
|
93
|
+
def default_collation=(collation)
|
94
|
+
collation.is_a?(String) or raise ArgumentError, "collation must be a string (got #{collation.inspect})"
|
95
|
+
@default_collation = collation
|
96
|
+
end
|
90
97
|
|
91
98
|
def active_record_class
|
92
99
|
@active_record_class.is_a?(Class) or @active_record_class = @active_record_class.to_s.constantize
|
@@ -379,7 +386,7 @@ module Generators
|
|
379
386
|
end
|
380
387
|
|
381
388
|
def create_constraints(model)
|
382
|
-
model.constraint_specs.map { |fk| fk.to_add_statement
|
389
|
+
model.constraint_specs.map { |fk| fk.to_add_statement }
|
383
390
|
end
|
384
391
|
|
385
392
|
def create_field(field_spec, field_name_width)
|
@@ -427,7 +434,7 @@ module Generators
|
|
427
434
|
else
|
428
435
|
[":integer"]
|
429
436
|
end
|
430
|
-
"add_column :#{new_table_name}, :#{c},
|
437
|
+
["add_column :#{new_table_name}, :#{c}", *args].join(', ')
|
431
438
|
end
|
432
439
|
undo_adds = to_add.map do |c|
|
433
440
|
"remove_column :#{new_table_name}, :#{c}"
|
@@ -456,8 +463,8 @@ module Generators
|
|
456
463
|
change_spec[:scale] = spec.scale unless spec.scale.nil?
|
457
464
|
change_spec[:null] = spec.null unless spec.null && col.null
|
458
465
|
change_spec[:default] = spec.default unless spec.default.nil? && col.default.nil?
|
459
|
-
change_spec[:collation] = spec.collation unless spec.collation.nil?
|
460
466
|
change_spec[:charset] = spec.charset unless spec.charset.nil?
|
467
|
+
change_spec[:collation] = spec.collation unless spec.collation.nil?
|
461
468
|
|
462
469
|
changes << "change_column :#{new_table_name}, :#{c}, " +
|
463
470
|
([":#{spec.sql_type}"] + format_options(change_spec, spec.sql_type, changing: true)).join(", ")
|
@@ -466,7 +473,7 @@ module Generators
|
|
466
473
|
end
|
467
474
|
end.compact
|
468
475
|
|
469
|
-
index_changes, undo_index_changes = change_indexes(model, current_table_name)
|
476
|
+
index_changes, undo_index_changes = change_indexes(model, current_table_name, to_remove)
|
470
477
|
fk_changes, undo_fk_changes = if ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/)
|
471
478
|
[[], []]
|
472
479
|
else
|
@@ -488,7 +495,7 @@ module Generators
|
|
488
495
|
undo_table_options_changes * "\n"]
|
489
496
|
end
|
490
497
|
|
491
|
-
def change_indexes(model, old_table_name)
|
498
|
+
def change_indexes(model, old_table_name, to_remove)
|
492
499
|
return [[], []] if Migrator.disable_constraints
|
493
500
|
|
494
501
|
new_table_name = model.table_name
|
@@ -501,7 +508,10 @@ module Generators
|
|
501
508
|
end
|
502
509
|
end || i
|
503
510
|
end
|
504
|
-
existing_has_primary_key = existing_indexes.any?
|
511
|
+
existing_has_primary_key = existing_indexes.any? do |i|
|
512
|
+
i.name == ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME &&
|
513
|
+
!i.fields.all? { |f| to_remove.include?(f) } # if we're removing the primary key column(s), the primary key index will be removed too
|
514
|
+
end
|
505
515
|
model_has_primary_key = model_indexes.any? { |i| i.name == ::DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME }
|
506
516
|
|
507
517
|
add_indexes_init = model_indexes - existing_indexes
|
@@ -541,30 +551,31 @@ module Generators
|
|
541
551
|
|
542
552
|
add_fks.map! do |fk|
|
543
553
|
# next if fk.parent.constantize.abstract_class || fk.parent == fk.model.class_name
|
544
|
-
undo_add_fks << remove_foreign_key(old_table_name, fk.
|
554
|
+
undo_add_fks << remove_foreign_key(old_table_name, fk.constraint_name)
|
545
555
|
fk.to_add_statement
|
546
556
|
end.compact
|
547
557
|
|
548
558
|
drop_fks.map! do |fk|
|
549
559
|
undo_drop_fks << fk.to_add_statement
|
550
|
-
remove_foreign_key(new_table_name, fk.
|
560
|
+
remove_foreign_key(new_table_name, fk.constraint_name)
|
551
561
|
end
|
552
562
|
|
553
563
|
[drop_fks + add_fks, undo_add_fks + undo_drop_fks]
|
554
564
|
end
|
555
565
|
|
556
566
|
def remove_foreign_key(old_table_name, fk_name)
|
557
|
-
"remove_foreign_key(
|
567
|
+
"remove_foreign_key(#{old_table_name.inspect}, name: #{fk_name.to_s.inspect})"
|
558
568
|
end
|
559
569
|
|
560
570
|
def format_options(options, type, changing: false)
|
561
571
|
options.map do |k, v|
|
562
|
-
|
563
|
-
next
|
564
|
-
next if k == :null && v == true
|
572
|
+
if !changing && ((k == :limit && type == :decimal) || (k == :null && v == true))
|
573
|
+
next
|
565
574
|
end
|
566
575
|
|
567
|
-
|
576
|
+
if !::DeclareSchema::Model::FieldSpec.mysql_text_limits? && k == :limit && type == :text
|
577
|
+
next
|
578
|
+
end
|
568
579
|
|
569
580
|
if k.is_a?(Symbol)
|
570
581
|
"#{k}: #{v.inspect}"
|
@@ -578,9 +589,9 @@ module Generators
|
|
578
589
|
foreign_key = model.constraint_specs.find { |fk| field_name == fk.foreign_key.to_s }
|
579
590
|
if foreign_key && (parent_table = foreign_key.parent_table_name)
|
580
591
|
parent_columns = connection.columns(parent_table) rescue []
|
581
|
-
pk_limit
|
592
|
+
pk_limit =
|
582
593
|
if (pk_column = parent_columns.find { |column| column.name.to_s == "id" }) # right now foreign keys assume id is the target
|
583
|
-
if Rails::VERSION::MAJOR
|
594
|
+
if Rails::VERSION::MAJOR < 5
|
584
595
|
pk_column.cast_type.limit
|
585
596
|
else
|
586
597
|
pk_column.limit
|
@@ -609,6 +620,16 @@ module Generators
|
|
609
620
|
end
|
610
621
|
end
|
611
622
|
|
623
|
+
# TODO: TECH-4814 remove all methods from here through end of file
|
624
|
+
def default_collation_from_charset(charset)
|
625
|
+
case charset
|
626
|
+
when "utf8"
|
627
|
+
"utf8_general_ci"
|
628
|
+
when "utf8mb4"
|
629
|
+
"utf8mb4_general_ci"
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
612
633
|
def revert_table(table)
|
613
634
|
res = StringIO.new
|
614
635
|
schema_dumper_klass = case Rails::VERSION::MAJOR
|
@@ -618,30 +639,55 @@ module Generators
|
|
618
639
|
ActiveRecord::ConnectionAdapters::SchemaDumper
|
619
640
|
end
|
620
641
|
schema_dumper_klass.send(:new, ActiveRecord::Base.connection).send(:table, table, res)
|
621
|
-
|
642
|
+
|
643
|
+
result = res.string.strip.gsub("\n ", "\n")
|
644
|
+
if connection.class.name.match?(/mysql/i)
|
645
|
+
if !result['options: ']
|
646
|
+
result = result.sub('",', "\", options: \"DEFAULT CHARSET=#{Generators::DeclareSchema::Migration::Migrator.default_charset} "+
|
647
|
+
"COLLATE=#{Generators::DeclareSchema::Migration::Migrator.default_collation}\",")
|
648
|
+
end
|
649
|
+
default_charset = result[/CHARSET=(\w+)/, 1] or raise "unable to find charset in #{result.inspect}"
|
650
|
+
default_collation = result[/COLLATE=(\w+)/, 1] || default_collation_from_charset(default_charset) or
|
651
|
+
raise "unable to find collation in #{result.inspect} or charset #{default_charset.inspect}"
|
652
|
+
result = result.split("\n").map do |line|
|
653
|
+
if line['t.text'] || line['t.string']
|
654
|
+
if !line['charset: ']
|
655
|
+
if line['collation: ']
|
656
|
+
line = line.sub('collation: ', "charset: #{default_charset.inspect}, collation: ")
|
657
|
+
else
|
658
|
+
line += ", charset: #{default_charset.inspect}"
|
659
|
+
end
|
660
|
+
end
|
661
|
+
line['collation: '] or line += ", collation: #{default_collation.inspect}"
|
662
|
+
end
|
663
|
+
line
|
664
|
+
end.join("\n")
|
665
|
+
end
|
666
|
+
result
|
622
667
|
end
|
623
668
|
|
624
|
-
def column_options_from_reverted_table(table,
|
669
|
+
def column_options_from_reverted_table(table, column)
|
625
670
|
revert = revert_table(table)
|
626
|
-
if (md = revert.match(/\s*t\.column\s+"#{
|
671
|
+
if (md = revert.match(/\s*t\.column\s+"#{column}",\s+(:[a-zA-Z0-9_]+)(?:,\s+(.*?)$)?/m))
|
627
672
|
# Ugly migration
|
628
673
|
_, type, options = *md
|
629
|
-
elsif (md = revert.match(/\s*t\.([a-z_]+)\s+"#{
|
674
|
+
elsif (md = revert.match(/\s*t\.([a-z_]+)\s+"#{column}"(?:,\s+(.*?)$)?/m))
|
630
675
|
# Sexy migration
|
631
|
-
_,
|
632
|
-
type = ":#{
|
676
|
+
_, string_type, options = *md
|
677
|
+
type = ":#{string_type}"
|
633
678
|
end
|
679
|
+
type or raise "unable to find column options for #{table}.#{column} in #{revert.inspect}"
|
634
680
|
[type, options]
|
635
681
|
end
|
636
682
|
|
637
|
-
def change_column_back(table,
|
638
|
-
type, options = column_options_from_reverted_table(table,
|
639
|
-
"change_column :#{table}, :#{
|
683
|
+
def change_column_back(table, column)
|
684
|
+
type, options = column_options_from_reverted_table(table, column)
|
685
|
+
["change_column :#{table}, :#{column}, #{type}", options&.strip].compact.join(', ')
|
640
686
|
end
|
641
687
|
|
642
688
|
def revert_column(table, column)
|
643
689
|
type, options = column_options_from_reverted_table(table, column)
|
644
|
-
"add_column :#{table}, :#{column}, #{type}
|
690
|
+
["add_column :#{table}, :#{column}, #{type}", options&.strip].compact.join(', ')
|
645
691
|
end
|
646
692
|
end
|
647
693
|
end
|