Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rename and rename_belongs_to for migrations. #366

Merged
merged 3 commits into from
May 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions db/migrations/20200513065134_test_rename_columns.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class TestRenameColumns::V20200513065134 < Avram::Migrator::Migration::V1
def migrate
create table_for(RenamableOwner) do
primary_key id : Int64
add_timestamps
end

create table_for(Renamable) do
primary_key id : Int64
add_timestamps
add thingies : JSON::Any
add gsm_number : String
add_belongs_to boss : RenamableOwner, on_delete: :cascade
end

alter table_for(Renamable) do
rename :gsm_number, :mobile
rename_belongs_to :boss, :owner
rename :thingies, :options
end
end

def rollback
drop table_for(Renamable)
drop table_for(RenamableOwner)
end
end
22 changes: 14 additions & 8 deletions spec/migrator/alter_table_statement_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@ describe Avram::Migrator::AlterTableStatement do
add future_time : Time, default: Time.local
add new_id : UUID, default: UUID.new("46d9b2f0-0718-4d4c-a5a1-5af81d5b11e0")
add numbers : Array(Int32), fill_existing_with: [1]
rename :old_name, :new_name
rename_belongs_to :owner, :boss
remove :old_column
remove_belongs_to :employee
end

built.statements.first.should eq <<-SQL
built.statements.size.should eq 11

built.statements[0].should eq "ALTER TABLE users RENAME COLUMN old_name TO new_name;"
built.statements[1].should eq "ALTER TABLE users RENAME COLUMN owner_id TO boss_id;"

built.statements[2].should eq <<-SQL
ALTER TABLE users
ADD name text,
ADD email text,
Expand All @@ -39,13 +46,12 @@ describe Avram::Migrator::AlterTableStatement do
DROP employee_id;
SQL

built.statements.size.should eq 9
built.statements[1].should eq "CREATE UNIQUE INDEX users_age_index ON users USING btree (age);"
built.statements[2].should eq "CREATE INDEX users_num_index ON users USING btree (num);"
built.statements[3].should eq "UPDATE users SET email = '[email protected]';"
built.statements[4].should eq "ALTER TABLE users ALTER COLUMN email SET NOT NULL;"
built.statements[5].should eq "UPDATE users SET updated_at = NOW();"
built.statements[6].should eq "ALTER TABLE users ALTER COLUMN updated_at SET NOT NULL;"
built.statements[3].should eq "CREATE UNIQUE INDEX users_age_index ON users USING btree (age);"
built.statements[4].should eq "CREATE INDEX users_num_index ON users USING btree (num);"
built.statements[5].should eq "UPDATE users SET email = '[email protected]';"
built.statements[6].should eq "ALTER TABLE users ALTER COLUMN email SET NOT NULL;"
built.statements[7].should eq "UPDATE users SET updated_at = NOW();"
built.statements[8].should eq "ALTER TABLE users ALTER COLUMN updated_at SET NOT NULL;"
end

it "does not build statements if nothing is altered" do
Expand Down
41 changes: 33 additions & 8 deletions src/avram/migrator/alter_table_statement.cr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Avram::Migrator::AlterTableStatement
include Avram::Migrator::MissingOnDeleteWithBelongsToError

getter rows = [] of String
getter renamed_rows = [] of String
getter dropped_rows = [] of String
getter fill_existing_with_statements = [] of String
getter change_type_statements = [] of String
Expand Down Expand Up @@ -60,17 +61,18 @@ class Avram::Migrator::AlterTableStatement
end

def alter_statements : Array(String)
if (rows + dropped_rows).empty?
[] of String
else
statement = String.build do |statement|
alterations = renamed_rows.map do |statement|
"ALTER TABLE #{@table_name} #{statement};"
end
unless (rows + dropped_rows).empty?
alterations << String.build do |statement|
statement << "ALTER TABLE #{@table_name}"
statement << "\n"
statement << (rows + dropped_rows).join(",\n")
statement << ';'
end
[statement]
end
alterations
end

# Adds a references column and index given a model class and references option.
Expand Down Expand Up @@ -166,13 +168,36 @@ class Avram::Migrator::AlterTableStatement
]
end

def remove(name : Symbol)
dropped_rows << " DROP #{name.to_s}"
{% symbol_expected_message = "%s expected a symbol like ':user', instead got: '%s'" %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really cool idea 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was really happy with that one. 😊


macro rename(old_name, new_name)
{% for name in {old_name, new_name} %}
{% unless name.is_a?(SymbolLiteral) %}
{% raise symbol_expected_message % {"rename", name} %}
{% end %}
{% end %}
renamed_rows << "RENAME COLUMN #{{{old_name}}} TO #{{{new_name}}}"
end

macro rename_belongs_to(old_association_name, new_association_name)
{% for association_name in {old_association_name, new_association_name} %}
{% unless association_name.is_a?(SymbolLiteral) %}
{% raise symbol_expected_message % {"rename_belongs_to", association_name} %}
{% end %}
{% end %}
rename {{old_association_name}}_id, {{new_association_name}}_id
end

macro remove(name)
{% unless name.is_a?(SymbolLiteral) %}
{% raise symbol_expected_message % {"remove", name} %}
{% end %}
dropped_rows << " DROP #{{{name}}}"
end

macro remove_belongs_to(association_name)
{% unless association_name.is_a?(SymbolLiteral) %}
{% raise "remove_belongs_to expected a symbol like ':user', instead got: '#{association_name}'" %}
{% raise symbol_expected_message % {"remove_belongs_to", association_name} %}
{% end %}
remove {{ association_name }}_id
end
Expand Down