Skip to content

Commit

Permalink
Add support for Rails-style multiple dbs
Browse files Browse the repository at this point in the history
  • Loading branch information
fynsta committed Apr 4, 2024
1 parent 5fe7dec commit 321ec27
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 32 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
- 0.8.0
- Support multiple databases in Rails-style ([@fynsta](https://github.com/fynsta))
- 0.7.0
- Support the presence of multiverse ([@mlohbihler](https://github.com/mlohbihler))
- 0.6.1
Expand Down
6 changes: 5 additions & 1 deletion bin/squasher
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ parser = OptionParser.new do |config|
options[:engine] = value
end

config.on('--databases=DB_KEY,...', 'alternate database configuration keys to be included dbconfig (for multiverse)') do |value|
config.on('--multi-db_format=FORMAT', 'format of the multi-db configuration (rails, multiverse)') do |value|
options[:multi_db_format] = value
end

config.on('--databases=DB_KEY,...', 'alternate database configuration keys to be included') do |value|
options[:databases] = value&.split(",")
end

Expand Down
27 changes: 21 additions & 6 deletions lib/squasher/cleaner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,31 @@ def self.process(*args)
end

def process
Squasher.error(:migration_folder_missing) unless config.migrations_folder?
Squasher.error(:migration_folder_missing) unless config.migrations_folders?

if config.multi_db_format == 'rails'
config.databases.each do |database|
process_database(database)
end
else
process_database
end
end

migration_file = config.migration_file(now_timestamp, MIGRATION_NAME)
if prev_migration
def process_database(database = nil)
migration_file = config.migration_file(now_timestamp, MIGRATION_NAME, database)
if (prev_migration = prev_migration(database))
FileUtils.rm(prev_migration)
end
File.open(migration_file, 'wb') do |stream|
stream << ::Squasher::Render.render(MIGRATION_NAME, config)
end
Squasher.rake("db:migrate", :db_cleaning)

if database.nil?
Squasher.rake("db:migrate", :db_cleaning)
else
Squasher.rake("db:migrate:#{database}", :db_cleaning)
end
end

private
Expand All @@ -27,10 +42,10 @@ def config
Squasher.config
end

def prev_migration
def prev_migration(database = nil)
return @prev_migration if defined?(@prev_migration)

@prev_migration = config.migration_files.detect do |file|
@prev_migration = config.migration_files(database).detect do |file|
File.basename(file).include?(MIGRATION_NAME)
end
end
Expand Down
61 changes: 50 additions & 11 deletions lib/squasher/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ def inspect
end
end

attr_reader :schema_file, :migration_version
attr_reader :schema_file, :migration_version, :multi_db_format, :databases

def initialize
@root_path = Dir.pwd.freeze
@migrations_folder = File.join(@root_path, 'db', 'migrate')
@flags = []
@multi_db_format = nil
@databases = []
set_app_path(@root_path)
end
Expand All @@ -62,6 +62,9 @@ def set(key, value)
elsif key == :sql
@schema_file = File.join(@app_path, 'db', 'structure.sql')
@flags << key
elsif key == :multi_db_format
Squasher.error(:invalid_multi_db_format, value: value) unless %w[rails multiverse].include?(value)
@multi_db_format = value
elsif key == :databases
@databases = value
else
Expand All @@ -73,16 +76,33 @@ def set?(k)
@flags.include?(k)
end

def migration_files
Dir.glob(File.join(migrations_folder, '**.rb'))
def migration_files(database = nil)
Dir.glob(File.join(migrations_folder(database), '**.rb'))
end

def migration_file(timestamp, migration_name)
File.join(migrations_folder, "#{ timestamp }_#{ migration_name }.rb")
def migration_file(timestamp, migration_name, database = nil)
File.join(migrations_folder(database), "#{ timestamp }_#{ migration_name }.rb")
end

def migrations_folder?
Dir.exist?(migrations_folder)
def migrations_folder(database = nil)
return default_migration_folder if database.nil?

migrations_paths = dbconfig['development'][database]['migrations_paths']
return default_migration_folder unless migrations_paths

File.join(@app_path, migrations_paths)
end

def migrations_folders?
if @multi_db_format != 'rails'
Dir.exist?(migrations_folder)
else
@databases.all? { |db| Dir.exist?(migrations_folder(db)) }
end
end

def default_migration_folder
File.join(@root_path, 'db', 'migrate')
end

def dbconfig?
Expand Down Expand Up @@ -115,7 +135,7 @@ def in_app_root(&block)

private

attr_reader :migrations_folder, :dbconfig_file
attr_reader :dbconfig_file

def dbconfig
return @dbconfig if defined?(@dbconfig)
Expand All @@ -126,8 +146,27 @@ def dbconfig
begin
content, soft_error = Render.process(dbconfig_file)
if content.has_key?('development')
@dbconfig = { 'development' => content['development'].merge('database' => 'squasher') }
@databases&.each { |database| @dbconfig[database] = content[database] }
if @multi_db_format == 'rails'
@dbconfig = { 'development' => {} }
@databases.each do |database|
@dbconfig['development'][database] = content['development'][database].merge('database' => "#{database}_squasher")

database_name = content['development'][database]['database']
content['development'].select { |_, v| v['database'] == database_name && v['replica'] }.each do |k, v|
@dbconfig['development'][k] = v.merge('database' => "#{database}_squasher")
end
end
else
@dbconfig = { 'development' => content['development'].merge('database' => 'squasher') }

multiverse_by_default = @multi_db_format.nil? && @databases.any?
if multiverse_by_default
puts "Using multiverse format by default is deprecated and will be removed in the next major release. Please specify --multi-db_format=rails or --multi-db_format=multiverse explicitly."
end
if multiverse_by_default || @multi_db_format == 'multiverse'
@databases&.each { |database| @dbconfig[database] = content[database] }
end
end
end
rescue
end
Expand Down
50 changes: 39 additions & 11 deletions lib/squasher/worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ def process
Squasher.tell(:dry_mode_finished)
Squasher.print(Render.render(:init_schema, config))
else
path = config.migration_file(finish_timestamp, :init_schema)
File.open(path, 'wb') { |io| io << Render.render(:init_schema, config) }
migrations.each { |file| FileUtils.rm(file) }
if config.multi_db_format == 'rails'
config.databases.each do |database|
clean_migrations(database)
end
else
clean_migrations
end
end

Squasher.rake("db:drop") unless Squasher.ask(:keep_database)
Expand All @@ -38,30 +42,48 @@ def config
end

def check!
Squasher.error(:migration_folder_missing) unless config.migrations_folder?
Squasher.error(:migration_folder_missing) unless config.migrations_folders?
Squasher.error(:dbconfig_invalid) unless config.dbconfig?
if migrations.empty?

if config.multi_db_format == 'rails'
config.databases.each do |database|
check_migrations_exist(database)
end
else
check_migrations_exist
end
end

def check_migrations_exist(database = nil)
if migrations(database).empty?
print_date = date.strftime("%Y/%m/%d")
Squasher.error(:no_migrations, :date => print_date)

Squasher.error(:no_migrations, :date => date.strftime("%Y/%m/%d"))
end
end

def migrations
@migrations ||= config.migration_files.select { |file| before_date?(get_timestamp(file)) }.sort
def migrations(database = nil)
config.migration_files(database).select { |file| before_date?(get_timestamp(file)) }.sort
end

def get_timestamp(file)
File.basename(file)[/\A\d+/]
end

def clean_migrations(database = nil)
path = config.migration_file(finish_timestamp(database), :init_schema, database)
File.open(path, 'wb') { |io| io << Render.render(:init_schema, config) }
migrations(database).each { |file| FileUtils.rm(file) }
end

def before_date?(timestamp)
@point ||= date.strftime("%Y%m%d").to_i
return unless timestamp
timestamp[0...8].to_i < @point
end

def finish_timestamp
@finish_timestamp ||= get_timestamp(migrations.last)
def finish_timestamp(database = nil)
get_timestamp(migrations(database).last)
end

def under_squash_env
Expand All @@ -72,7 +94,13 @@ def under_squash_env
return unless Squasher.rake("db:drop db:create", :db_create)
end

return unless Squasher.rake("db:migrate VERSION=#{ finish_timestamp }", :db_migrate)
if config.multi_db_format == 'rails'
config.databases.each do |database|
return unless Squasher.rake("db:migrate:#{ database } VERSION=#{ finish_timestamp(database) }", :db_migrate)
end
else
return unless Squasher.rake("db:migrate VERSION=#{ finish_timestamp }", :db_migrate)
end

yield

Expand Down
6 changes: 3 additions & 3 deletions spec/lib/worker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
let(:worker) { described_class.new(Time.new(2012, 6, 20)) }

specify 'command was run not in application root' do
allow_any_instance_of(Squasher::Config).to receive(:migrations_folder?).and_return(false)
allow_any_instance_of(Squasher::Config).to receive(:migrations_folders?).and_return(false)

expect_exit_with(:migration_folder_missing)
end
Expand All @@ -31,7 +31,7 @@ def expect_exit_with(*args)
worker = described_class.new(Time.new(2014))
allow(worker).to receive(:under_squash_env).and_yield.and_return(true)
new_migration_path = File.join(Dir.tmpdir, 'init_schema.rb')
allow_any_instance_of(Squasher::Config).to receive(:migration_file).with('20131213090719', :init_schema).and_return(new_migration_path)
allow_any_instance_of(Squasher::Config).to receive(:migration_file).with('20131213090719', :init_schema, nil).and_return(new_migration_path)

expect(FileUtils).to receive(:rm).with(File.join(fake_root, 'db', 'migrate', '20131205160936_first_migration.rb'))
expect(FileUtils).to receive(:rm).with(File.join(fake_root, 'db', 'migrate', '20131213090719_second_migration.rb'))
Expand Down Expand Up @@ -60,7 +60,7 @@ def expect_exit_with(*args)
worker = described_class.new(Time.new(2014))
allow(worker).to receive(:under_squash_env).and_yield.and_return(true)
new_migration_path = File.join(Dir.tmpdir, 'init_schema.rb')
allow_any_instance_of(Squasher::Config).to receive(:migration_file).with('20131213090719', :init_schema).and_return(new_migration_path)
allow_any_instance_of(Squasher::Config).to receive(:migration_file).with('20131213090719', :init_schema, nil).and_return(new_migration_path)
expect(FileUtils).to receive(:rm).with(File.join(fake_root, 'db', 'migrate', '20131205160936_first_migration.rb'))
expect(FileUtils).to receive(:rm).with(File.join(fake_root, 'db', 'migrate', '20131213090719_second_migration.rb'))

Expand Down

0 comments on commit 321ec27

Please sign in to comment.