lazy_migrate 0.1.1 → 0.3.0
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/tests.yaml +43 -0
- data/.gitignore +4 -0
- data/.travis.yml +6 -0
- data/Appraisals +14 -0
- data/Gemfile.lock +150 -5
- data/Guardfile +39 -0
- data/README.md +56 -6
- data/Rakefile +1 -3
- data/bin/exe/lazy_migrate +14 -1
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/rails_5_1_5.gemfile +8 -0
- data/gemfiles/rails_5_1_5.gemfile.lock +170 -0
- data/gemfiles/rails_5_2_4_3.gemfile +8 -0
- data/gemfiles/rails_5_2_4_3.gemfile.lock +178 -0
- data/gemfiles/rails_6_0_3_4.gemfile +8 -0
- data/gemfiles/rails_6_0_3_4.gemfile.lock +194 -0
- data/github/demo.gif +0 -0
- data/lazy_migrate.gemspec +8 -2
- data/lib/lazy_migrate.rb +6 -2
- data/lib/lazy_migrate/client.rb +123 -0
- data/lib/lazy_migrate/migration.rb +14 -0
- data/lib/lazy_migrate/migrator_adapter.rb +144 -0
- data/lib/lazy_migrate/migrator_adapter_factory.rb +24 -0
- data/lib/lazy_migrate/new_migrator_adapter.rb +90 -0
- data/lib/lazy_migrate/old_migrator_adapter.rb +97 -0
- data/lib/lazy_migrate/version.rb +2 -1
- data/lib/tasks/lazy_migrate.rake +10 -0
- data/sorbet/config +2 -0
- data/sorbet/rbi/gems/actioncable.rbi +393 -0
- data/sorbet/rbi/gems/actionmailer.rbi +425 -0
- data/sorbet/rbi/gems/actionpack.rbi +3230 -0
- data/sorbet/rbi/gems/actionview.rbi +1153 -0
- data/sorbet/rbi/gems/activejob.rbi +282 -0
- data/sorbet/rbi/gems/activemodel.rbi +742 -0
- data/sorbet/rbi/gems/activerecord.rbi +4004 -0
- data/sorbet/rbi/gems/activestorage.rbi +174 -0
- data/sorbet/rbi/gems/activesupport.rbi +2300 -0
- data/sorbet/rbi/gems/appraisal.rbi +151 -0
- data/sorbet/rbi/gems/arel.rbi +1253 -0
- data/sorbet/rbi/gems/byebug.rbi +1041 -0
- data/sorbet/rbi/gems/coderay.rbi +92 -0
- data/sorbet/rbi/gems/concurrent-ruby.rbi +1586 -0
- data/sorbet/rbi/gems/crass.rbi +93 -0
- data/sorbet/rbi/gems/erubi.rbi +27 -0
- data/sorbet/rbi/gems/globalid.rbi +99 -0
- data/sorbet/rbi/gems/i18n.rbi +192 -0
- data/sorbet/rbi/gems/loofah.rbi +131 -0
- data/sorbet/rbi/gems/mail.rbi +1092 -0
- data/sorbet/rbi/gems/marcel.rbi +13 -0
- data/sorbet/rbi/gems/method_source.rbi +64 -0
- data/sorbet/rbi/gems/mini_mime.rbi +52 -0
- data/sorbet/rbi/gems/minitest.rbi +282 -0
- data/sorbet/rbi/gems/nio4r.rbi +68 -0
- data/sorbet/rbi/gems/nokogiri.rbi +1011 -0
- data/sorbet/rbi/gems/pastel.rbi +119 -0
- data/sorbet/rbi/gems/pry-byebug.rbi +155 -0
- data/sorbet/rbi/gems/pry.rbi +1949 -0
- data/sorbet/rbi/gems/rack-test.rbi +162 -0
- data/sorbet/rbi/gems/rack.rbi +525 -0
- data/sorbet/rbi/gems/rails-dom-testing.rbi +68 -0
- data/sorbet/rbi/gems/rails-html-sanitizer.rbi +92 -0
- data/sorbet/rbi/gems/railties.rbi +724 -0
- data/sorbet/rbi/gems/rake.rbi +666 -0
- data/sorbet/rbi/gems/rspec-core.rbi +1939 -0
- data/sorbet/rbi/gems/rspec-expectations.rbi +1123 -0
- data/sorbet/rbi/gems/rspec-mocks.rbi +1090 -0
- data/sorbet/rbi/gems/rspec-support.rbi +280 -0
- data/sorbet/rbi/gems/rspec.rbi +15 -0
- data/sorbet/rbi/gems/sprockets-rails.rbi +106 -0
- data/sorbet/rbi/gems/sprockets.rbi +755 -0
- data/sorbet/rbi/gems/sqlite3.rbi +354 -0
- data/sorbet/rbi/gems/thor.rbi +580 -0
- data/sorbet/rbi/gems/thread_safe.rbi +82 -0
- data/sorbet/rbi/gems/tty-color.rbi +44 -0
- data/sorbet/rbi/gems/tty-cursor.rbi +72 -0
- data/sorbet/rbi/gems/tty-prompt.rbi +531 -0
- data/sorbet/rbi/gems/tty-reader.rbi +176 -0
- data/sorbet/rbi/gems/tty-screen.rbi +66 -0
- data/sorbet/rbi/gems/tzinfo.rbi +406 -0
- data/sorbet/rbi/gems/websocket-driver.rbi +103 -0
- data/sorbet/rbi/gems/websocket-extensions.rbi +29 -0
- data/sorbet/rbi/gems/wisper.rbi +130 -0
- data/sorbet/rbi/hidden-definitions/errors.txt +7584 -0
- data/sorbet/rbi/hidden-definitions/hidden.rbi +13328 -0
- data/sorbet/rbi/sorbet-typed/lib/actionmailer/all/actionmailer.rbi +13 -0
- data/sorbet/rbi/sorbet-typed/lib/actionpack/all/actionpack.rbi +954 -0
- data/sorbet/rbi/sorbet-typed/lib/actionview/all/actionview.rbi +321 -0
- data/sorbet/rbi/sorbet-typed/lib/activemodel/all/activemodel.rbi +597 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/<6/activerecord.rbi +13 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/>=5.2/activerecord.rbi +16 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/>=5/activerecord.rbi +53 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/all/activerecord.rbi +1454 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/all/model_schema.rbi +79 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/all/sanitization.rbi +36 -0
- data/sorbet/rbi/sorbet-typed/lib/activerecord/~>5.2.0/activerecord.rbi +447 -0
- data/sorbet/rbi/sorbet-typed/lib/activestorage/<=6.1/activestorage.rbi +82 -0
- data/sorbet/rbi/sorbet-typed/lib/activestorage/all/activestorage.rbi +177 -0
- data/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +1431 -0
- data/sorbet/rbi/sorbet-typed/lib/minitest/all/minitest.rbi +108 -0
- data/sorbet/rbi/sorbet-typed/lib/railties/all/railties.rbi +25 -0
- data/sorbet/rbi/todo.rbi +18 -0
- data/sorbet/rbi/user-defined/activerecord.rbi +56 -0
- metadata +182 -5
- data/lib/lazy_migrate/migrator.rb +0 -186
data/github/demo.gif
ADDED
Binary file
|
data/lazy_migrate.gemspec
CHANGED
@@ -24,13 +24,19 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
25
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
26
|
end
|
27
|
-
spec.bindir = "exe"
|
28
|
-
spec.executables =
|
27
|
+
spec.bindir = "bin/exe"
|
28
|
+
spec.executables = ['lazy_migrate']
|
29
29
|
spec.require_paths = ["lib"]
|
30
30
|
|
31
|
+
spec.add_development_dependency "appraisal"
|
31
32
|
spec.add_development_dependency "bundler", "~> 2.0"
|
33
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.9.0'
|
34
|
+
spec.add_development_dependency "rails", "~> 6.0.3"
|
32
35
|
spec.add_development_dependency "rake", "~> 13.0"
|
33
36
|
spec.add_development_dependency "rspec", "~> 3.0"
|
37
|
+
spec.add_development_dependency 'sqlite3', '~> 1.4.2'
|
38
|
+
spec.add_development_dependency 'sorbet'
|
34
39
|
|
40
|
+
spec.add_runtime_dependency 'sorbet-runtime'
|
35
41
|
spec.add_runtime_dependency 'tty-prompt', '~> 0.22.0'
|
36
42
|
end
|
data/lib/lazy_migrate.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
+
# typed: strict
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require "lazy_migrate/version"
|
4
|
-
require "lazy_migrate/
|
5
|
+
require "lazy_migrate/client"
|
5
6
|
|
6
7
|
module LazyMigrate
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { void }
|
7
11
|
def self.run
|
8
|
-
|
12
|
+
Client.run
|
9
13
|
end
|
10
14
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'tty-prompt'
|
5
|
+
require 'active_record'
|
6
|
+
require 'rails'
|
7
|
+
require 'lazy_migrate/migrator_adapter_factory'
|
8
|
+
|
9
|
+
module LazyMigrate
|
10
|
+
class Client
|
11
|
+
class << self
|
12
|
+
MIGRATE = 'migrate'
|
13
|
+
ROLLBACK = 'rollback'
|
14
|
+
UP = 'up'
|
15
|
+
DOWN = 'down'
|
16
|
+
REDO = 'redo'
|
17
|
+
BRING_TO_TOP = 'bring to top'
|
18
|
+
|
19
|
+
def run
|
20
|
+
migrator_adapter = MigratorAdapterFactory.create_migrator_adapter
|
21
|
+
|
22
|
+
loop do
|
23
|
+
catch(:done) do
|
24
|
+
on_done = -> { throw :done }
|
25
|
+
|
26
|
+
prompt.ok("\nDatabase: #{ActiveRecord::Base.connection_config[:database]}\n")
|
27
|
+
|
28
|
+
select_migration_prompt(on_done: on_done, migrator_adapter: migrator_adapter)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
rescue TTY::Reader::InputInterrupt
|
32
|
+
puts
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def prompt
|
38
|
+
TTY::Prompt.new(active_color: :bright_green)
|
39
|
+
end
|
40
|
+
|
41
|
+
def select_migration_prompt(on_done:, migrator_adapter:)
|
42
|
+
prompt.select('Pick a migration') do |menu|
|
43
|
+
migrator_adapter.find_migrations.each { |migration|
|
44
|
+
name = render_migration_option(migration)
|
45
|
+
|
46
|
+
menu.choice(
|
47
|
+
name,
|
48
|
+
-> {
|
49
|
+
select_action_prompt(
|
50
|
+
on_done: on_done,
|
51
|
+
migrator_adapter: migrator_adapter,
|
52
|
+
migration: migration,
|
53
|
+
)
|
54
|
+
}
|
55
|
+
)
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def select_action_prompt(on_done:, migrator_adapter:, migration:)
|
61
|
+
if !migration.has_file
|
62
|
+
prompt.select("\nFile not found for migration version.") do |menu|
|
63
|
+
menu.choice('remove version from version table', -> { migrator_adapter.remove_version_from_table(migration.version) })
|
64
|
+
menu.choice('cancel', -> {})
|
65
|
+
end
|
66
|
+
on_done.()
|
67
|
+
end
|
68
|
+
|
69
|
+
option_map = obtain_option_map(migrator_adapter: migrator_adapter, on_done: on_done)
|
70
|
+
|
71
|
+
prompt.select("\nWhat would you like to do for #{migration.version} #{name}?") do |menu|
|
72
|
+
option_map.each do |label, on_press|
|
73
|
+
menu.choice(label, -> {
|
74
|
+
with_unsafe_error_capture { on_press.(migration) }
|
75
|
+
migrator_adapter.dump_schema
|
76
|
+
on_done.()
|
77
|
+
})
|
78
|
+
end
|
79
|
+
|
80
|
+
menu.choice('cancel', on_done)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def obtain_option_map(migrator_adapter:, on_done:)
|
85
|
+
{
|
86
|
+
MIGRATE => ->(migration) { migrator_adapter.migrate(migration.version) },
|
87
|
+
ROLLBACK => ->(migration) { migrator_adapter.rollback(migration.version) },
|
88
|
+
UP => ->(migration) { migrator_adapter.up(migration.version) },
|
89
|
+
DOWN => ->(migration) { migrator_adapter.down(migration.version) },
|
90
|
+
REDO => ->(migration) { migrator_adapter.redo(migration.version) },
|
91
|
+
BRING_TO_TOP => ->(migration) { migrator_adapter.bring_to_top(migration: migration, ask_for_rerun: -> { ask_for_rerun(on_done) }) },
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def ask_for_rerun(on_done)
|
96
|
+
prompt.select("\nMigration has been run. Would you like to `down` the migration before moving it, and then run it again after?") do |menu|
|
97
|
+
menu.choice('yes, down and re-run the migration', -> { true })
|
98
|
+
menu.choice('no, just bump the version without migrating anything', -> { false })
|
99
|
+
menu.choice('cancel', -> { on_done.() })
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def render_migration_option(migration)
|
104
|
+
"#{
|
105
|
+
migration.status.ljust(6)
|
106
|
+
}#{
|
107
|
+
migration.version.to_s.ljust(16)
|
108
|
+
}#{
|
109
|
+
(migration.current ? 'current' : '').ljust(9)
|
110
|
+
}#{
|
111
|
+
migration.name
|
112
|
+
}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def with_unsafe_error_capture
|
116
|
+
yield
|
117
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
118
|
+
# I am aware you should not rescue 'Exception' exceptions but I think this is is an 'exceptional' use case
|
119
|
+
prompt.error("\n#{e.class}: #{e.message}\n#{e.backtrace.take(5).join("\n")}")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'sorbet-runtime'
|
5
|
+
|
6
|
+
module LazyMigrate
|
7
|
+
class Migration < T::Struct
|
8
|
+
prop :status, String
|
9
|
+
const :version, Integer
|
10
|
+
const :name, String
|
11
|
+
prop :has_file, T::Boolean
|
12
|
+
prop :current, T::Boolean
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'lazy_migrate/migration'
|
5
|
+
|
6
|
+
module LazyMigrate
|
7
|
+
class MigratorAdapter
|
8
|
+
extend T::Sig
|
9
|
+
extend T::Helpers
|
10
|
+
|
11
|
+
abstract!
|
12
|
+
|
13
|
+
sig { void }
|
14
|
+
def initialize; end
|
15
|
+
|
16
|
+
# bring_to_top updates the version of a migration to bring it to the top of the
|
17
|
+
# migration list. If the migration had already been up'd it will mark the
|
18
|
+
# new migration file as upped as well. The former version number will be
|
19
|
+
# removed from the schema_migrations table. The user chooses whether
|
20
|
+
# they want to down the migration before moving it.
|
21
|
+
sig { params(migration: LazyMigrate::Migration, ask_for_rerun: T.proc.returns(T::Boolean)).void }
|
22
|
+
def bring_to_top(migration:, ask_for_rerun:)
|
23
|
+
initial_version = migration.version
|
24
|
+
initial_status = migration.status
|
25
|
+
initial_filename = self.find_filename_for_migration(migration)
|
26
|
+
|
27
|
+
if initial_filename.nil?
|
28
|
+
raise("No file found for migration #{initial_version}")
|
29
|
+
end
|
30
|
+
|
31
|
+
re_run = initial_status == 'up' && ask_for_rerun.()
|
32
|
+
|
33
|
+
if re_run
|
34
|
+
self.down(initial_version)
|
35
|
+
end
|
36
|
+
|
37
|
+
last = self.last_version
|
38
|
+
new_version = ActiveRecord::Migration.new.next_migration_number(last ? last + 1 : 0).to_i
|
39
|
+
new_filename = replace_version_in_filename(initial_filename, new_version)
|
40
|
+
File.rename(initial_filename, new_filename)
|
41
|
+
|
42
|
+
if re_run
|
43
|
+
self.up(new_version)
|
44
|
+
elsif initial_status == 'up'
|
45
|
+
ActiveRecord::SchemaMigration.create(version: new_version)
|
46
|
+
ActiveRecord::SchemaMigration.find_by(version: initial_version)&.destroy!
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
sig { params(filename: String, new_version: Integer).returns(String) }
|
51
|
+
def replace_version_in_filename(filename, new_version)
|
52
|
+
basename = File.basename(filename)
|
53
|
+
dir = File.dirname(filename)
|
54
|
+
name_after_version = T.must(basename.split('_')[1..]).join('_')
|
55
|
+
new_basename = "#{new_version}_#{name_after_version}"
|
56
|
+
File.join(dir, new_basename)
|
57
|
+
end
|
58
|
+
|
59
|
+
sig { void }
|
60
|
+
def dump_schema
|
61
|
+
return if !ActiveRecord::Base.dump_schema_after_migration
|
62
|
+
|
63
|
+
# ripped from https://github.com/rails/rails/blob/5-1-stable/activerecord/lib/active_record/railties/databases.rake
|
64
|
+
filename = ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema.rb")
|
65
|
+
File.open(filename, "w:utf-8") do |file|
|
66
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
sig { returns(T::Array[LazyMigrate::Migration]) }
|
71
|
+
def find_migrations
|
72
|
+
self.load_migration_paths
|
73
|
+
current_version = self.last_version
|
74
|
+
|
75
|
+
self.find_migration_tuples
|
76
|
+
.reverse
|
77
|
+
.map { |status, str_version, name|
|
78
|
+
# This depends on how rails reports a file is missing.
|
79
|
+
# This is no doubt subject to change so be wary.
|
80
|
+
has_file = name != '********** NO FILE **********'
|
81
|
+
version = str_version.to_i
|
82
|
+
current = version == current_version
|
83
|
+
|
84
|
+
LazyMigrate::Migration.new(
|
85
|
+
status: status,
|
86
|
+
version: version,
|
87
|
+
name: name,
|
88
|
+
has_file: has_file,
|
89
|
+
current: current,
|
90
|
+
)
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
sig { void }
|
95
|
+
def load_migration_paths
|
96
|
+
# silencing cos we might be re-initializing some constants and rails
|
97
|
+
# doesn't like that
|
98
|
+
Kernel.silence_warnings do
|
99
|
+
ActiveRecord::Migrator.migrations_paths.each do |path|
|
100
|
+
Dir[Rails.application.root.join("#{path}/**/*.rb")].each { |file| load file }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
sig { params(arr: T::Array[Integer], value: Integer).returns(T.nilable(Integer)) }
|
106
|
+
def previous_value(arr, value)
|
107
|
+
arr.sort.select { |v| v < value }.last
|
108
|
+
end
|
109
|
+
|
110
|
+
sig { params(version: Integer).void }
|
111
|
+
def remove_version_from_table(version)
|
112
|
+
ActiveRecord::SchemaMigration.find_by!(version: version).destroy!
|
113
|
+
end
|
114
|
+
|
115
|
+
sig { abstract.params(version: Integer).void }
|
116
|
+
def up(version); end
|
117
|
+
|
118
|
+
sig { abstract.params(version: Integer).void }
|
119
|
+
def down(version); end
|
120
|
+
|
121
|
+
sig { abstract.params(version: Integer).void }
|
122
|
+
def redo(version); end
|
123
|
+
|
124
|
+
sig { abstract.params(version: Integer).void }
|
125
|
+
def migrate(version); end
|
126
|
+
|
127
|
+
sig { abstract.params(version: Integer).void }
|
128
|
+
def rollback(version); end
|
129
|
+
|
130
|
+
protected
|
131
|
+
|
132
|
+
sig { abstract.returns(T::Array[[String, String, String]]) }
|
133
|
+
def find_migration_tuples; end
|
134
|
+
|
135
|
+
sig { abstract.params(version: Integer).returns(T.nilable(Integer)) }
|
136
|
+
def find_previous_version(version); end
|
137
|
+
|
138
|
+
sig { abstract.params(migration: LazyMigrate::Migration).returns(T.nilable(String)) }
|
139
|
+
def find_filename_for_migration(migration); end
|
140
|
+
|
141
|
+
sig { abstract.returns(T.nilable(Integer)) }
|
142
|
+
def last_version; end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "lazy_migrate/old_migrator_adapter"
|
5
|
+
require "lazy_migrate/new_migrator_adapter"
|
6
|
+
|
7
|
+
module LazyMigrate
|
8
|
+
class MigratorAdapterFactory
|
9
|
+
class << self
|
10
|
+
# unfortunately the code is a little different from 5.2 onwards compared to previous
|
11
|
+
# versions, and we want to do more than just invoke the db:migrate rake
|
12
|
+
# commands so we're returning a different adapter depending on the rails
|
13
|
+
# version
|
14
|
+
def create_migrator_adapter
|
15
|
+
if Rails.version > '5.2.0'
|
16
|
+
LazyMigrate::NewMigratorAdapter.new
|
17
|
+
else
|
18
|
+
LazyMigrate::OldMigratorAdapter.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'lazy_migrate/migrator_adapter'
|
5
|
+
require 'lazy_migrate/migration'
|
6
|
+
|
7
|
+
module LazyMigrate
|
8
|
+
class NewMigratorAdapter < MigratorAdapter
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig { returns(ActiveRecord::MigrationContext) }
|
12
|
+
attr_accessor :context
|
13
|
+
|
14
|
+
sig { void }
|
15
|
+
def initialize
|
16
|
+
# TODO: consider making this a method rather than an instance variable
|
17
|
+
# considering how cheap it is to obtain
|
18
|
+
@context = T.let(
|
19
|
+
ActiveRecord::MigrationContext.instance_method(:initialize).arity == 2 ?
|
20
|
+
ActiveRecord::MigrationContext.new(Rails.root.join('db', 'migrate'), ActiveRecord::SchemaMigration) :
|
21
|
+
ActiveRecord::MigrationContext.new(Rails.root.join('db', 'migrate')),
|
22
|
+
ActiveRecord::MigrationContext,
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
sig { override.params(version: Integer).void }
|
27
|
+
def up(version)
|
28
|
+
context.run(:up, version)
|
29
|
+
end
|
30
|
+
|
31
|
+
sig { override.params(version: Integer).void }
|
32
|
+
def down(version)
|
33
|
+
context.run(:down, version)
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { override.params(version: Integer).void }
|
37
|
+
def redo(version)
|
38
|
+
down(version)
|
39
|
+
up(version)
|
40
|
+
end
|
41
|
+
|
42
|
+
sig { override.params(version: Integer).void }
|
43
|
+
def migrate(version)
|
44
|
+
context.up(version)
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { override.params(version: Integer).void }
|
48
|
+
def rollback(version)
|
49
|
+
# for some reason in https://github.com/rails/rails/blob/5-2-stable/activerecord/lib/active_record/migration.rb#L1221
|
50
|
+
# we stop before the selected version. I have no idea why.
|
51
|
+
|
52
|
+
previous_version = find_previous_version(version)
|
53
|
+
|
54
|
+
if previous_version.nil?
|
55
|
+
# rails excludes the given version when calling .down so we need to
|
56
|
+
# just down this instead
|
57
|
+
down(version)
|
58
|
+
else
|
59
|
+
context.down(previous_version)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
# example: [['up', '20200715030339', 'Add unique index to table']]
|
66
|
+
sig { override.returns(T::Array[[String, String, String]]) }
|
67
|
+
def find_migration_tuples
|
68
|
+
context.migrations_status
|
69
|
+
end
|
70
|
+
|
71
|
+
sig { override.params(version: Integer).returns(T.nilable(Integer)) }
|
72
|
+
def find_previous_version(version)
|
73
|
+
versions = context.migrations.map(&:version)
|
74
|
+
|
75
|
+
return nil if version == versions.first
|
76
|
+
|
77
|
+
previous_value(versions, version)
|
78
|
+
end
|
79
|
+
|
80
|
+
sig { override.params(migration: LazyMigrate::Migration).returns(T.nilable(String)) }
|
81
|
+
def find_filename_for_migration(migration)
|
82
|
+
context.migrations.find { |m| m.version == migration.version }&.filename
|
83
|
+
end
|
84
|
+
|
85
|
+
sig { override.returns(T.nilable(Integer)) }
|
86
|
+
def last_version
|
87
|
+
context.migrations.last&.version
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'lazy_migrate/migrator_adapter'
|
5
|
+
|
6
|
+
module ActiveRecord
|
7
|
+
class Migrator
|
8
|
+
module Compatibility
|
9
|
+
class V5_1 < ActiveRecord::Migrator
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module LazyMigrate
|
16
|
+
class OldMigratorAdapter < MigratorAdapter
|
17
|
+
extend T::Sig
|
18
|
+
|
19
|
+
sig { override.params(version: Integer).void }
|
20
|
+
def up(version)
|
21
|
+
ActiveRecord::Migrator::Compatibility::V5_1.run(:up, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
|
22
|
+
end
|
23
|
+
|
24
|
+
sig { override.params(version: Integer).void }
|
25
|
+
def down(version)
|
26
|
+
ActiveRecord::Migrator::Compatibility::V5_1.run(:down, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
|
27
|
+
end
|
28
|
+
|
29
|
+
sig { override.params(version: Integer).void }
|
30
|
+
def redo(version)
|
31
|
+
down(version)
|
32
|
+
up(version)
|
33
|
+
end
|
34
|
+
|
35
|
+
sig { override.params(version: Integer).void }
|
36
|
+
def migrate(version)
|
37
|
+
ActiveRecord::Migrator::Compatibility::V5_1.migrate(base_paths, version)
|
38
|
+
end
|
39
|
+
|
40
|
+
sig { override.params(version: Integer).void }
|
41
|
+
def rollback(version)
|
42
|
+
previous_version = find_previous_version(version)
|
43
|
+
|
44
|
+
if previous_version.nil?
|
45
|
+
# rails excludes the given version when calling .migrate so we need to
|
46
|
+
# just down this instead
|
47
|
+
down(version)
|
48
|
+
else
|
49
|
+
ActiveRecord::Migrator::Compatibility::V5_1.migrate(base_paths, previous_version)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
# example: [['up', '20200715030339', 'Add unique index to table']]
|
56
|
+
sig { override.returns(T::Array[[String, String, String]]) }
|
57
|
+
def find_migration_tuples
|
58
|
+
ActiveRecord::Migrator::Compatibility::V5_1.migrations_status(base_paths)
|
59
|
+
end
|
60
|
+
|
61
|
+
sig { override.params(version: Integer).returns(T.nilable(Integer)) }
|
62
|
+
def find_previous_version(version)
|
63
|
+
versions = ActiveRecord::Migrator::Compatibility::V5_1.get_all_versions
|
64
|
+
|
65
|
+
return nil if version == versions.first
|
66
|
+
|
67
|
+
previous_value(versions, version)
|
68
|
+
end
|
69
|
+
|
70
|
+
sig { override.params(migration: LazyMigrate::Migration).returns(T.nilable(String)) }
|
71
|
+
def find_filename_for_migration(migration)
|
72
|
+
migrations.find { |m| m.version == migration.version }&.filename
|
73
|
+
end
|
74
|
+
|
75
|
+
sig { override.returns(T.nilable(Integer)) }
|
76
|
+
def last_version
|
77
|
+
ActiveRecord::Migrator::Compatibility::V5_1.get_all_versions.last
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
sig { returns(T::Array[String]) }
|
83
|
+
def base_paths
|
84
|
+
ActiveRecord::Tasks::DatabaseTasks.migrations_paths
|
85
|
+
end
|
86
|
+
|
87
|
+
sig { returns(T::Array[String]) }
|
88
|
+
def migration_files
|
89
|
+
ActiveRecord::Migrator::Compatibility::V5_1.migration_files(base_paths)
|
90
|
+
end
|
91
|
+
|
92
|
+
sig { returns(T::Array[ActiveRecord::MigrationProxy]) }
|
93
|
+
def migrations
|
94
|
+
ActiveRecord::Migrator::Compatibility::V5_1.migrations(base_paths)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|