diff --git a/spec/avram/migrator/alter_table_statement_spec.cr b/spec/avram/migrator/alter_table_statement_spec.cr index fc466c0c9..3862fcc9d 100644 --- a/spec/avram/migrator/alter_table_statement_spec.cr +++ b/spec/avram/migrator/alter_table_statement_spec.cr @@ -89,6 +89,27 @@ describe Avram::Migrator::AlterTableStatement do built.statements[2].should eq "ALTER TABLE ONLY test_defaults ALTER COLUMN money SET DEFAULT '29.99';" end + it "changes defaults after changing the type" do + built = Avram::Migrator::AlterTableStatement.new(:users).build do + change_type id : Int64 + change_default id : Int64, default: 54 + end + built.statements.size.should eq 2 + built.statements[0].should eq "ALTER TABLE users ALTER COLUMN id SET DATA TYPE bigint;" + built.statements[1].should eq "ALTER TABLE ONLY users ALTER COLUMN id SET DEFAULT '54';" + end + + it "can change column nullability" do + built = Avram::Migrator::AlterTableStatement.new(:users).build do + forbid_nulls_for :id + allow_nulls_for :age + end + + built.statements.size.should eq 2 + built.statements[0].should eq "ALTER TABLE users ALTER COLUMN id SET NOT NULL;" + built.statements[1].should eq "ALTER TABLE users ALTER COLUMN age DROP NOT NULL;" + end + describe "fill_existing_with" do it "fills existing with value and sets column to be non-null for non-null types" do built = Avram::Migrator::AlterTableStatement.new(:users).build do diff --git a/src/avram/migrator/alter_table_statement.cr b/src/avram/migrator/alter_table_statement.cr index c9620da9b..221cf3d8b 100644 --- a/src/avram/migrator/alter_table_statement.cr +++ b/src/avram/migrator/alter_table_statement.cr @@ -11,6 +11,7 @@ class Avram::Migrator::AlterTableStatement getter fill_existing_with_statements = [] of String getter change_type_statements = [] of String getter change_default_statements = [] of String + getter change_nullability_statements = [] of String private getter? if_exists : Bool = false def initialize(@table_name : TableName, *, @if_exists : Bool = false) @@ -80,6 +81,30 @@ class Avram::Migrator::AlterTableStatement add_change_default_statement %column end + # Change the column's nullability from whatever it is currently to true. + # ``` + # alter table_for(User) do + # allow_nulls_for :email + # end + # ``` + macro allow_nulls_for(column_name) + change_nullability_statements << build_nullability_statement({{column_name.id.stringify}}, true) + end + + # Change the column's nullability from whatever it is currently to false. + # ``` + # alter table_for(User) do + # forbid_nulls_for :email + # end + # ``` + macro forbid_nulls_for(column_name) + change_nullability_statements << build_nullability_statement({{column_name.id.stringify}}, false) + end + + def build_nullability_statement(column_name, nullability) + "ALTER TABLE #{@table_name} ALTER COLUMN #{column_name} #{nullability ? "DROP" : "SET"} NOT NULL;" + end + def add_change_type_statement(column : ::Avram::Migrator::Columns::Base) change_type_statements << column.build_change_type_statement(@table_name) end @@ -114,7 +139,7 @@ class Avram::Migrator::AlterTableStatement end def statements - alter_statements + change_default_statements + change_type_statements + index_statements + fill_existing_with_statements + alter_statements + change_type_statements + change_default_statements + change_nullability_statements + index_statements + fill_existing_with_statements end def if_exists_statement