data_migrate 3.2.0 → 11.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 +5 -5
- data/Changelog.md +246 -2
- data/README.md +107 -91
- data/lib/capistrano/data_migrate/migrate.rb +3 -4
- data/lib/data_migrate/config.rb +33 -0
- data/lib/data_migrate/data_migrator.rb +54 -58
- data/lib/data_migrate/data_schema.rb +63 -0
- data/lib/data_migrate/data_schema_migration.rb +23 -6
- data/lib/data_migrate/database_configurations_wrapper.rb +11 -0
- data/lib/data_migrate/database_tasks.rb +290 -0
- data/lib/data_migrate/migration_context.rb +93 -0
- data/lib/data_migrate/rails_helper.rb +91 -0
- data/lib/data_migrate/schema_dumper.rb +38 -0
- data/lib/data_migrate/schema_migration.rb +41 -0
- data/lib/data_migrate/status_service.rb +58 -0
- data/lib/data_migrate/tasks/data_migrate_tasks.rb +107 -0
- data/lib/data_migrate/version.rb +1 -1
- data/lib/data_migrate.rb +20 -7
- data/lib/generators/data_migrate.rb +15 -2
- data/lib/generators/data_migration/data_migration_generator.rb +22 -21
- data/lib/generators/data_migration/templates/data_migration.rb +4 -2
- data/tasks/databases.rake +115 -228
- metadata +64 -42
- data/.gitignore +0 -6
- data/.rspec +0 -3
- data/.travis.yml +0 -17
- data/Appraisals +0 -21
- data/Gemfile +0 -4
- data/Gemfile.rails5 +0 -5
- data/Gemfile.rails5.1 +0 -5
- data/Rakefile +0 -2
- data/data_migrate.gemspec +0 -39
- data/gemfiles/rails_4.0.gemfile +0 -7
- data/gemfiles/rails_4.1.gemfile +0 -7
- data/gemfiles/rails_4.2.gemfile +0 -8
- data/gemfiles/rails_5.0.gemfile +0 -7
- data/gemfiles/rails_5.1.gemfile +0 -7
- data/lib/data_migrate/migration.rb +0 -26
- data/lib/data_migrate/migration_five.rb +0 -26
- data/screenshot.png +0 -0
- data/spec/data_migrate/data_migrator_spec.rb +0 -45
- data/spec/data_migrate/data_schema_migration_spec.rb +0 -16
- data/spec/data_migrate/migration.rb +0 -19
- data/spec/generators/data_migration/data_migration_generator_spec.rb +0 -27
- data/spec/spec_helper.rb +0 -5
- data/tasks/.gitkeep +0 -0
@@ -1,84 +1,80 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "active_record"
|
4
|
+
require "data_migrate/config"
|
4
5
|
|
6
|
+
module DataMigrate
|
5
7
|
class DataMigrator < ActiveRecord::Migrator
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
migrated.delete(version)
|
10
|
-
DataMigrate::DataSchemaMigration.where(:version => version.to_s).delete_all
|
11
|
-
else
|
12
|
-
migrated << version
|
13
|
-
DataMigrate::DataSchemaMigration.create!(:version => version.to_s)
|
14
|
-
end
|
8
|
+
def load_migrated
|
9
|
+
@migrated_versions =
|
10
|
+
DataMigrate::RailsHelper.data_schema_migration.normalized_versions.map(&:to_i).sort
|
15
11
|
end
|
16
12
|
|
17
13
|
class << self
|
18
|
-
def
|
19
|
-
|
20
|
-
# Certain versions of the gem wrote data migration versions into
|
21
|
-
# schema_migrations table. After the fix, it was corrected to write into
|
22
|
-
# data_migrations. However, not to break anything we are going to
|
23
|
-
# get versions from both tables.
|
24
|
-
#
|
25
|
-
# This may cause some problems:
|
26
|
-
# Eg. rake data:versions will show version from the schema_migrations table
|
27
|
-
# which may be a version of actual schema migration and not data migration
|
28
|
-
DataMigrate::DataSchemaMigration.all.map { |x| x.version.to_i }.sort +
|
29
|
-
ActiveRecord::SchemaMigration.all.map { |x| x.version.to_i }.sort
|
30
|
-
else
|
31
|
-
[]
|
32
|
-
end
|
14
|
+
def migrations_paths
|
15
|
+
Array.wrap(DataMigrate.config.data_migrations_path)
|
33
16
|
end
|
34
17
|
|
35
|
-
def
|
36
|
-
|
18
|
+
def create_data_schema_table
|
19
|
+
DataMigrate::RailsHelper.data_schema_migration.create_table
|
37
20
|
end
|
38
21
|
|
39
|
-
def
|
40
|
-
|
22
|
+
def current_version
|
23
|
+
DataMigrate::MigrationContext.new(migrations_paths).current_version
|
41
24
|
end
|
42
25
|
|
43
|
-
|
44
|
-
|
45
|
-
|
26
|
+
##
|
27
|
+
# Compares the given filename with what we expect data migration
|
28
|
+
# filenames to be, eg the "20091231235959_some_name.rb" pattern
|
29
|
+
# @param (String) filename
|
30
|
+
# @return (MatchData)
|
31
|
+
def match(filename)
|
32
|
+
/(\d{14})_(.+)\.rb$/.match(filename)
|
33
|
+
end
|
46
34
|
|
47
|
-
|
48
|
-
|
49
|
-
|
35
|
+
def needs_migration?
|
36
|
+
DataMigrate::DatabaseTasks.pending_migrations.count.positive?
|
37
|
+
end
|
38
|
+
##
|
39
|
+
# Provides the full migrations_path filepath
|
40
|
+
# @return (String)
|
41
|
+
def full_migrations_path
|
42
|
+
File.join(Rails.root, *migrations_paths.split(File::SEPARATOR))
|
50
43
|
end
|
51
44
|
|
52
|
-
|
45
|
+
def migrations_status
|
46
|
+
DataMigrate::MigrationContext.new(migrations_paths).migrations_status
|
47
|
+
end
|
53
48
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
49
|
+
# TODO: this was added to be backward compatible, need to re-evaluate
|
50
|
+
def migrations(_migrations_paths)
|
51
|
+
DataMigrate::MigrationContext.new(_migrations_paths).migrations
|
52
|
+
end
|
58
53
|
|
59
|
-
|
60
|
-
|
61
|
-
|
54
|
+
#TODO: this was added to be backward compatible, need to re-evaluate
|
55
|
+
def run(direction, migration_paths, version)
|
56
|
+
# Ensure all Active Record model cache is reset for each data migration
|
57
|
+
# As recommended in: https://github.com/rails/rails/blob/da21c2e9812e5eb0698fba4a9aa38632fc004432/activerecord/lib/active_record/migration.rb#L467-L470
|
58
|
+
ActiveRecord::Base.descendants.each(&:reset_column_information)
|
62
59
|
|
63
|
-
|
64
|
-
:unique => true,
|
65
|
-
:name => index_name
|
60
|
+
DataMigrate::MigrationContext.new(migration_paths).run(direction, version)
|
66
61
|
end
|
67
62
|
|
68
|
-
def
|
69
|
-
|
70
|
-
# Rails 5.0 and Rails 5.1 of this method with respect to database views.
|
71
|
-
if ActiveRecord.version >= Gem::Version.new('5.0') && ActiveRecord.version < Gem::Version.new('5.1')
|
72
|
-
connection.data_source_exists?(table_name)
|
73
|
-
else
|
74
|
-
connection.table_exists?(schema_migrations_table_name)
|
75
|
-
end
|
63
|
+
def rollback(migrations_path, steps)
|
64
|
+
DataMigrate::MigrationContext.new(migrations_path).rollback(steps)
|
76
65
|
end
|
66
|
+
end
|
77
67
|
|
78
|
-
|
79
|
-
ActiveRecord::Base.configurations[Rails.env || 'development'] || ENV["DATABASE_URL"]
|
80
|
-
end
|
68
|
+
private
|
81
69
|
|
70
|
+
def record_version_state_after_migrating(version)
|
71
|
+
if down?
|
72
|
+
migrated.delete(version)
|
73
|
+
DataMigrate::RailsHelper.data_schema_delete_version(version.to_s)
|
74
|
+
else
|
75
|
+
migrated << version
|
76
|
+
DataMigrate::RailsHelper.data_schema_migration.create_version(version.to_s)
|
77
|
+
end
|
82
78
|
end
|
83
79
|
end
|
84
80
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DataMigrate
|
4
|
+
##
|
5
|
+
# Provides the definition method for data_schema.rb
|
6
|
+
class Data < ActiveRecord::Schema
|
7
|
+
# This method is based on the following two methods
|
8
|
+
# ActiveRecord::Schema#define
|
9
|
+
# ActiveRecord::ConnectionAdapters::SchemaStatements
|
10
|
+
# #assume_migrated_upto_version
|
11
|
+
def define(info)
|
12
|
+
DataMigrate::DataMigrator.create_data_schema_table
|
13
|
+
|
14
|
+
return if info[:version].blank?
|
15
|
+
|
16
|
+
version = info[:version].to_i
|
17
|
+
|
18
|
+
unless migrated.include?(version)
|
19
|
+
execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')"
|
20
|
+
end
|
21
|
+
|
22
|
+
insert(version)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def migrated
|
28
|
+
@migrated ||= select_values("SELECT version FROM #{sm_table}").map(&:to_i)
|
29
|
+
end
|
30
|
+
|
31
|
+
def versions
|
32
|
+
@versions ||= Set.new.tap do |versions|
|
33
|
+
DataMigrate::DataMigrator.migrations_paths.each do |path|
|
34
|
+
Dir.foreach(path) do |file|
|
35
|
+
match_data = DataMigrate::DataMigrator.match(file)
|
36
|
+
versions << match_data[1].to_i if match_data
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def insert(version)
|
43
|
+
inserted = Set.new
|
44
|
+
(versions - migrated).each do |v|
|
45
|
+
if inserted.include?(v)
|
46
|
+
raise "Duplicate data migration #{v}. Please renumber your data " \
|
47
|
+
"migrations to resolve the conflict."
|
48
|
+
elsif v < version
|
49
|
+
execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
|
50
|
+
inserted << v
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def sm_table
|
56
|
+
quote_table_name(table_name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def table_name
|
60
|
+
DataMigrate::RailsHelper.data_schema_migration.table_name
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -1,14 +1,31 @@
|
|
1
1
|
module DataMigrate
|
2
|
-
class DataSchemaMigration <
|
3
|
-
|
2
|
+
class DataSchemaMigration < ActiveRecord::SchemaMigration
|
3
|
+
# In Rails 7.1+, ActiveRecord::SchemaMigration methods are instance methods
|
4
|
+
# So we only load the appropriate methods depending on Rails version.
|
5
|
+
if DataMigrate::RailsHelper.rails_version_equal_to_or_higher_than_7_1
|
4
6
|
def table_name
|
5
|
-
ActiveRecord::Base.table_name_prefix +
|
7
|
+
ActiveRecord::Base.table_name_prefix + DataMigrate.config.data_migrations_table_name + ActiveRecord::Base.table_name_suffix
|
6
8
|
end
|
7
9
|
|
8
|
-
def
|
9
|
-
"
|
10
|
+
def primary_key
|
11
|
+
"version"
|
12
|
+
end
|
13
|
+
else
|
14
|
+
class << self
|
15
|
+
def table_name
|
16
|
+
ActiveRecord::Base.table_name_prefix + DataMigrate.config.data_migrations_table_name + ActiveRecord::Base.table_name_suffix
|
17
|
+
end
|
18
|
+
|
19
|
+
def primary_key
|
20
|
+
"version"
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_version(version)
|
24
|
+
# Note that SchemaMigration.create_version in Rails 7.1 does not
|
25
|
+
# raise an error if validations fail but we retain this behaviour for now.
|
26
|
+
create!(version: version)
|
27
|
+
end
|
10
28
|
end
|
11
29
|
end
|
12
30
|
end
|
13
31
|
end
|
14
|
-
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module DataMigrate
|
2
|
+
# This wrapper is used to differentiate between
|
3
|
+
# a data and schema db config when running migrations
|
4
|
+
class DatabaseConfigurationWrapper
|
5
|
+
attr_reader :db_config
|
6
|
+
|
7
|
+
def initialize(db_config)
|
8
|
+
@db_config = db_config
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "data_migrate/config"
|
4
|
+
|
5
|
+
module DataMigrate
|
6
|
+
##
|
7
|
+
# This class extends DatabaseTasks to add a schema_file method.
|
8
|
+
module DatabaseTasks
|
9
|
+
extend ActiveRecord::Tasks::DatabaseTasks
|
10
|
+
extend self
|
11
|
+
|
12
|
+
if respond_to?(:register_task)
|
13
|
+
register_task(/mysql/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
|
14
|
+
register_task(/trilogy/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
|
15
|
+
register_task(/postgresql/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks")
|
16
|
+
register_task(/sqlite/, "ActiveRecord::Tasks::SQLiteDatabaseTasks")
|
17
|
+
end
|
18
|
+
|
19
|
+
# These method are only introduced in Rails 7.1
|
20
|
+
unless respond_to?(:with_temporary_pool_for_each)
|
21
|
+
def with_temporary_pool_for_each(env: ActiveRecord::Tasks::DatabaseTasks.env, name: nil, &block) # :nodoc:
|
22
|
+
if name
|
23
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: env, name: name)
|
24
|
+
with_temporary_pool(db_config, &block)
|
25
|
+
else
|
26
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env, name: name).each do |db_config|
|
27
|
+
with_temporary_pool(db_config, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def with_temporary_connection(db_config, &block) # :nodoc:
|
33
|
+
with_temporary_pool(db_config) do |pool|
|
34
|
+
pool.with_connection(&block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def migration_class # :nodoc:
|
39
|
+
ActiveRecord::Base
|
40
|
+
end
|
41
|
+
|
42
|
+
def migration_connection # :nodoc:
|
43
|
+
migration_class.connection
|
44
|
+
end
|
45
|
+
|
46
|
+
private def with_temporary_pool(db_config)
|
47
|
+
original_db_config = migration_class.connection_db_config
|
48
|
+
pool = migration_class.connection_handler.establish_connection(db_config)
|
49
|
+
|
50
|
+
yield pool
|
51
|
+
ensure
|
52
|
+
migration_class.connection_handler.establish_connection(original_db_config)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def db_configs_with_versions
|
57
|
+
db_configs_with_versions = Hash.new { |h, k| h[k] = [] }
|
58
|
+
|
59
|
+
with_temporary_pool_for_each do |pool|
|
60
|
+
db_config = pool.db_config
|
61
|
+
if db_config.primary?
|
62
|
+
versions_to_run = DataMigrate::DatabaseTasks.pending_data_migrations.map { |m| m[:version] }
|
63
|
+
target_version = ActiveRecord::Tasks::DatabaseTasks.target_version
|
64
|
+
|
65
|
+
versions_to_run.each do |version|
|
66
|
+
next if target_version && target_version != version
|
67
|
+
db_configs_with_versions[version] << DatabaseConfigurationWrapper.new(db_config)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
db_configs_with_versions
|
73
|
+
end
|
74
|
+
|
75
|
+
def schema_file(_format = nil)
|
76
|
+
File.join(db_dir, "data_schema.rb")
|
77
|
+
end
|
78
|
+
|
79
|
+
def schema_file_type(_format = nil)
|
80
|
+
"data_schema.rb"
|
81
|
+
end
|
82
|
+
|
83
|
+
# This method is removed in Rails 7.0
|
84
|
+
def dump_filename(spec_name, format = ActiveRecord::Base.schema_format)
|
85
|
+
filename = if spec_name == "primary"
|
86
|
+
schema_file_type(format)
|
87
|
+
else
|
88
|
+
"#{spec_name}_#{schema_file_type(format)}"
|
89
|
+
end
|
90
|
+
|
91
|
+
ENV["DATA_SCHEMA"] || File.join(db_dir, filename)
|
92
|
+
end
|
93
|
+
|
94
|
+
def check_schema_file(filename)
|
95
|
+
unless File.exist?(filename)
|
96
|
+
message = +%{#{filename} doesn't exist yet. Run `rake data:migrate` to create it, then try again.}
|
97
|
+
Kernel.abort message
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def pending_migrations
|
102
|
+
sort_migrations(
|
103
|
+
pending_schema_migrations,
|
104
|
+
pending_data_migrations
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
def sort_migrations(*migrations)
|
109
|
+
migrations.flatten.sort { |a, b| sort_string(a) <=> sort_string(b) }
|
110
|
+
end
|
111
|
+
|
112
|
+
def sort_string migration
|
113
|
+
"#{migration[:version]}_#{migration[:kind] == :data ? 1 : 0}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def data_migrations_path
|
117
|
+
::DataMigrate.config.data_migrations_path
|
118
|
+
end
|
119
|
+
|
120
|
+
def run_migration(migration, direction)
|
121
|
+
if migration[:kind] == :data
|
122
|
+
::ActiveRecord::Migration.write("== %s %s" % ['Data', "=" * 71])
|
123
|
+
::DataMigrate::DataMigrator.run(direction, data_migrations_path, migration[:version])
|
124
|
+
else
|
125
|
+
::ActiveRecord::Migration.write("== %s %s" % ['Schema', "=" * 69])
|
126
|
+
::DataMigrate::SchemaMigration.run(
|
127
|
+
direction,
|
128
|
+
::DataMigrate::SchemaMigration.migrations_paths,
|
129
|
+
migration[:version]
|
130
|
+
)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def schema_dump_path(db_config, format = ActiveRecord.schema_format)
|
135
|
+
return ENV["DATA_SCHEMA"] if ENV["DATA_SCHEMA"]
|
136
|
+
|
137
|
+
# We only require a schema.rb file for the primary database
|
138
|
+
return unless db_config.primary?
|
139
|
+
|
140
|
+
File.join(File.dirname(ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(db_config, format)), schema_file_type)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Override this method from `ActiveRecord::Tasks::DatabaseTasks`
|
144
|
+
# to ensure that the sha saved in ar_internal_metadata table
|
145
|
+
# is from the original schema.rb file
|
146
|
+
def schema_sha1(file)
|
147
|
+
ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: "primary"))
|
148
|
+
end
|
149
|
+
|
150
|
+
def forward(step = 1)
|
151
|
+
DataMigrate::DataMigrator.create_data_schema_table
|
152
|
+
migrations = pending_migrations.reverse.pop(step).reverse
|
153
|
+
migrations.each do | pending_migration |
|
154
|
+
if pending_migration[:kind] == :data
|
155
|
+
ActiveRecord::Migration.write("== %s %s" % ["Data", "=" * 71])
|
156
|
+
DataMigrate::DataMigrator.run(:up, data_migrations_path, pending_migration[:version])
|
157
|
+
elsif pending_migration[:kind] == :schema
|
158
|
+
ActiveRecord::Migration.write("== %s %s" % ["Schema", "=" * 69])
|
159
|
+
DataMigrate::SchemaMigration.run(:up, DataMigrate::SchemaMigration.migrations_paths, pending_migration[:version])
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def pending_data_migrations
|
165
|
+
data_migrations = DataMigrate::DataMigrator.migrations(data_migrations_path)
|
166
|
+
data_migrator = DataMigrate::RailsHelper.data_migrator(:up, data_migrations)
|
167
|
+
sort_migrations(
|
168
|
+
data_migrator.pending_migrations.map { |m| { version: m.version, name: m.name, kind: :data } }
|
169
|
+
)
|
170
|
+
end
|
171
|
+
|
172
|
+
def pending_schema_migrations
|
173
|
+
::DataMigrate::SchemaMigration.pending_schema_migrations
|
174
|
+
end
|
175
|
+
|
176
|
+
def past_migrations(sort = nil)
|
177
|
+
data_versions = DataMigrate::RailsHelper.data_schema_migration.table_exists? ? DataMigrate::RailsHelper.data_schema_migration.normalized_versions : []
|
178
|
+
schema_versions = DataMigrate::RailsHelper.schema_migration.normalized_versions
|
179
|
+
migrations = data_versions.map { |v| { version: v.to_i, kind: :data } } + schema_versions.map { |v| { version: v.to_i, kind: :schema } }
|
180
|
+
|
181
|
+
sort&.downcase == "asc" ? sort_migrations(migrations) : sort_migrations(migrations).reverse
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.migrate_with_data
|
185
|
+
DataMigrate::DataMigrator.create_data_schema_table
|
186
|
+
|
187
|
+
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
188
|
+
|
189
|
+
# 7.2 removes the param for db_configs_with_versions in https://github.com/rails/rails/commit/9572fcb4a0bd5396436689a6a42613886871cd81
|
190
|
+
# 7.1 stable backported the change in https://github.com/rails/rails/commit/c53ec4b60980036b43528829d4b0b7457f759224
|
191
|
+
schema_mapped_versions = if Gem::Dependency.new("railties", ">= 7.1.4").match?("railties", Gem.loaded_specs["railties"].version, true)
|
192
|
+
ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions
|
193
|
+
else
|
194
|
+
db_configs = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env)
|
195
|
+
|
196
|
+
ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions(db_configs)
|
197
|
+
end
|
198
|
+
|
199
|
+
data_mapped_versions = DataMigrate::DatabaseTasks.db_configs_with_versions
|
200
|
+
|
201
|
+
mapped_versions = schema_mapped_versions.merge(data_mapped_versions) do |_key, schema_db_configs, data_db_configs|
|
202
|
+
schema_db_configs + data_db_configs
|
203
|
+
end
|
204
|
+
|
205
|
+
mapped_versions.sort.each do |version, db_configs|
|
206
|
+
db_configs.each do |db_config|
|
207
|
+
if is_data_migration = db_config.is_a?(DataMigrate::DatabaseConfigurationWrapper)
|
208
|
+
db_config = db_config.db_config
|
209
|
+
end
|
210
|
+
|
211
|
+
DataMigrate::DatabaseTasks.with_temporary_connection(db_config) do
|
212
|
+
if is_data_migration
|
213
|
+
DataMigrate::DataMigrator.run(:up, DataMigrate::DatabaseTasks.data_migrations_path, version)
|
214
|
+
else
|
215
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate(version)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.prepare_all_with_data
|
223
|
+
seed = false
|
224
|
+
|
225
|
+
each_current_configuration(env) do |db_config|
|
226
|
+
next unless primary?(db_config)
|
227
|
+
|
228
|
+
with_temporary_pool(db_config) do |pool|
|
229
|
+
connection = pool.respond_to?(:lease_connection) ? pool.lease_connection : pool.connection
|
230
|
+
unless database_exists?(connection)
|
231
|
+
create(db_config)
|
232
|
+
if File.exist?(schema_dump_path(db_config))
|
233
|
+
load_schema(db_config, schema_format, nil)
|
234
|
+
load_schema_current(
|
235
|
+
:ruby,
|
236
|
+
ENV["DATA_SCHEMA"]
|
237
|
+
)
|
238
|
+
end
|
239
|
+
|
240
|
+
seed = true
|
241
|
+
end
|
242
|
+
|
243
|
+
migrate_with_data
|
244
|
+
if dump_schema_after_migration?
|
245
|
+
dump_schema(db_config)
|
246
|
+
DataMigrate::Tasks::DataMigrateTasks.dump
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
load_seed if seed
|
252
|
+
end
|
253
|
+
|
254
|
+
private
|
255
|
+
|
256
|
+
def database_exists?(connection)
|
257
|
+
if connection.respond_to?(:database_exists?) # Rails 7.1+
|
258
|
+
connection.database_exists?
|
259
|
+
else
|
260
|
+
connection.table_exists?(ActiveRecord::SchemaMigration.table_name)
|
261
|
+
end
|
262
|
+
rescue ActiveRecord::NoDatabaseError
|
263
|
+
false
|
264
|
+
end
|
265
|
+
|
266
|
+
def primary?(db_config)
|
267
|
+
if db_config.respond_to?(:primary?) # Rails 7.0+
|
268
|
+
db_config.primary?
|
269
|
+
else
|
270
|
+
db_config.name == "primary"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def dump_schema_after_migration?
|
275
|
+
if ActiveRecord.respond_to?(:dump_schema_after_migration)
|
276
|
+
ActiveRecord.dump_schema_after_migration
|
277
|
+
else
|
278
|
+
ActiveRecord::Base.dump_schema_after_migration
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def schema_format
|
283
|
+
if ActiveRecord.respond_to?(:schema_format)
|
284
|
+
ActiveRecord.schema_format
|
285
|
+
else
|
286
|
+
ActiveRecord::Base.schema_format
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module DataMigrate
|
2
|
+
class MigrationContext < ActiveRecord::MigrationContext
|
3
|
+
def initialize(migrations_paths = "db/data")
|
4
|
+
@migrations_paths = migrations_paths || "db/data"
|
5
|
+
end
|
6
|
+
|
7
|
+
def up(target_version = nil)
|
8
|
+
selected_migrations = if block_given?
|
9
|
+
migrations.select { |m| yield m }
|
10
|
+
else
|
11
|
+
migrations
|
12
|
+
end
|
13
|
+
|
14
|
+
data_migrator = DataMigrate::RailsHelper.data_migrator(:up, selected_migrations, DataMigrate::RailsHelper.schema_migration, DataMigrate::RailsHelper.internal_metadata, target_version)
|
15
|
+
data_migrator.migrate
|
16
|
+
end
|
17
|
+
|
18
|
+
def down(target_version = nil)
|
19
|
+
selected_migrations =
|
20
|
+
if block_given?
|
21
|
+
migrations.select { |m| yield m }
|
22
|
+
else
|
23
|
+
migrations
|
24
|
+
end
|
25
|
+
|
26
|
+
data_migrator = DataMigrate::RailsHelper.data_migrator(:down, selected_migrations, DataMigrate::RailsHelper.schema_migration, DataMigrate::RailsHelper.internal_metadata, target_version)
|
27
|
+
data_migrator.migrate
|
28
|
+
end
|
29
|
+
|
30
|
+
def run(direction, target_version)
|
31
|
+
data_migrator = DataMigrate::RailsHelper.data_migrator(direction, migrations, DataMigrate::RailsHelper.schema_migration, DataMigrate::RailsHelper.internal_metadata, target_version)
|
32
|
+
data_migrator.run
|
33
|
+
end
|
34
|
+
|
35
|
+
def current_version
|
36
|
+
get_all_versions.max || 0
|
37
|
+
rescue ActiveRecord::NoDatabaseError
|
38
|
+
end
|
39
|
+
|
40
|
+
def migration_files
|
41
|
+
paths = Array(migrations_paths)
|
42
|
+
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
43
|
+
end
|
44
|
+
|
45
|
+
def migrations_status
|
46
|
+
db_list = DataMigrate::RailsHelper.data_schema_migration.normalized_versions
|
47
|
+
|
48
|
+
file_list = migration_files.map do |file|
|
49
|
+
version, name, scope = parse_migration_filename(file)
|
50
|
+
raise ActiveRecord::IllegalMigrationNameError.new(file) unless version
|
51
|
+
version = DataMigrate::RailsHelper.schema_migration.normalize_migration_number(version)
|
52
|
+
status = db_list.delete(version) ? "up" : "down"
|
53
|
+
[status, version, (name + scope).humanize]
|
54
|
+
end.compact
|
55
|
+
|
56
|
+
db_list.map! do |version|
|
57
|
+
["up", version, "********** NO FILE **********"]
|
58
|
+
end
|
59
|
+
|
60
|
+
(db_list + file_list).sort_by { |_, version, _| version }
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def get_all_versions
|
66
|
+
if DataMigrate::RailsHelper.data_schema_migration.table_exists?
|
67
|
+
DataMigrate::RailsHelper.data_schema_migration.normalized_versions.map(&:to_i)
|
68
|
+
else
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def move(direction, steps)
|
74
|
+
migrator = DataMigrate::RailsHelper.data_migrator(direction, migrations)
|
75
|
+
|
76
|
+
if current_version != 0 && !migrator.current_migration
|
77
|
+
raise ActiveRecord::UnknownMigrationVersionError.new(current_version)
|
78
|
+
end
|
79
|
+
|
80
|
+
start_index =
|
81
|
+
if current_version.zero?
|
82
|
+
0
|
83
|
+
else
|
84
|
+
migrator.migrations.index(migrator.current_migration)
|
85
|
+
end
|
86
|
+
|
87
|
+
finish = migrator.migrations[start_index + steps]
|
88
|
+
version = finish ? finish.version : 0
|
89
|
+
send(direction, version)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|