| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893 |
- using Invercargill.DataStructures;
- using InvercargillSql;
- using InvercargillSql.Migrations;
- using InvercargillSql.Dialects;
- using InvercargillSql.Orm;
- /**
- * Test migrations for testing the migration system
- */
- public class V001_CreateUsers : Migration {
- public override int version { get { return 1; } }
- public override string name { get { return "CreateUsers"; } }
-
- public override void up(MigrationBuilder b) throws SqlError {
- b.create_table("users", t => {
- // Type inferred from generic parameter - no redundant type_int() needed
- t.column<int64?>("id")
- .primary_key()
- .auto_increment();
- t.column<string>("name")
- .not_null();
- t.column<string>("email")
- .unique();
-
- // Index created within table builder using fluent API
- t.index("idx_users_email").on_column("email");
- });
- }
-
- public override void down(MigrationBuilder b) throws SqlError {
- b.drop_table("users"); // Indexes dropped automatically with table
- }
- }
- public class V002_AddAgeColumn : Migration {
- public override int version { get { return 2; } }
- public override string name { get { return "AddAgeColumn"; } }
-
- public override void up(MigrationBuilder b) throws SqlError {
- b.alter_table("users", t => {
- // Type inferred from generic parameter - no redundant type_int() needed
- t.add_column<int?>("age");
- });
- }
-
- public override void down(MigrationBuilder b) throws SqlError {
- b.alter_table("users", t => {
- t.drop_column("age");
- });
- }
- }
- /**
- * Migration demonstrating index operations in alter table
- */
- public class V003_AddIndexOnName : Migration {
- public override int version { get { return 3; } }
- public override string name { get { return "AddIndexOnName"; } }
-
- public override void up(MigrationBuilder b) throws SqlError {
- b.alter_table("users", t => {
- // Create index using alter table builder
- t.create_index("idx_users_name").on_column("name");
- });
- }
-
- public override void down(MigrationBuilder b) throws SqlError {
- b.alter_table("users", t => {
- t.drop_index("idx_users_name");
- });
- }
- }
- /**
- * Migration tests for Invercargill-Sql library.
- */
- public int main(string[] args) {
- print("=== Invercargill-Sql Migration Tests ===\n\n");
-
- try {
- // SQL generation tests
- test_create_table_sql();
- test_drop_table_sql();
- test_create_index_sql();
- test_create_unique_index_sql();
- test_add_column_sql();
- test_drop_column_sql();
- test_rename_column_sql();
-
- // MigrationBuilder tests
- test_migration_builder_create_table();
- test_migration_builder_create_table_with_indexes();
- test_migration_builder_alter_table();
- test_migration_builder_alter_table_with_indexes();
-
- // Index builder tests
- test_index_builder_single_column();
- test_index_builder_composite();
- test_index_builder_unique();
-
- // Foreign Key tests
- test_fk_creation_with_auto_generated_name();
- test_fk_creation_with_explicit_name();
- test_fk_on_delete_actions();
- test_fk_on_update_actions();
- test_fk_in_alter_table_add_column();
-
- // Indexed column tests
- test_indexed_with_auto_generated_name();
- test_indexed_with_custom_name();
- test_unique_indexed_creates_unique_index();
- test_drop_index_on();
-
- // MigrationRunner tests
- test_migration_runner_registration();
- test_migration_runner_migrate_to_latest();
- test_migration_runner_migrate_to_version();
- test_migration_runner_rollback();
- test_migration_runner_rollback_all();
-
- print("\n=== All migration tests passed! ===\n");
- return 0;
- } catch (Error e) {
- printerr("\n=== Test failed: %s ===\n", e.message);
- return 1;
- }
- }
- void test_create_table_sql() throws SqlError {
- print("Test: CREATE TABLE SQL generation... ");
-
- var dialect = new SqliteDialect();
- var op = new CreateTableOperation() { table_name = "test" };
- op.columns.add(new ColumnDefinition() {
- name = "id",
- column_type = ColumnType.INT_64,
- is_primary_key = true,
- auto_increment = true
- });
- op.columns.add(new ColumnDefinition() {
- name = "name",
- column_type = ColumnType.TEXT,
- is_required = true
- });
-
- var sql = dialect.create_table_sql(op);
- assert("CREATE TABLE test" in sql);
- assert("id" in sql);
- assert("INTEGER" in sql);
- assert("PRIMARY KEY" in sql);
- assert("name" in sql);
- assert("TEXT" in sql);
- assert("NOT NULL" in sql);
-
- print("PASSED\n");
- }
- void test_drop_table_sql() throws SqlError {
- print("Test: DROP TABLE SQL generation... ");
-
- var dialect = new SqliteDialect();
- var op = new DropTableOperation() { table_name = "test" };
- var sql = dialect.drop_table_sql(op);
- assert(sql == "DROP TABLE IF EXISTS test");
-
- print("PASSED\n");
- }
- void test_create_index_sql() throws SqlError {
- print("Test: CREATE INDEX SQL generation... ");
-
- var dialect = new SqliteDialect();
- var op = new CreateIndexOperation() {
- index_name = "idx_test",
- table_name = "test",
- is_unique = false
- };
- op.columns.add("name");
- var sql = dialect.create_index_sql(op);
- assert("CREATE INDEX idx_test ON test (name)" == sql);
-
- print("PASSED\n");
- }
- void test_create_unique_index_sql() throws SqlError {
- print("Test: CREATE UNIQUE INDEX SQL generation... ");
-
- var dialect = new SqliteDialect();
- var op = new CreateIndexOperation() {
- index_name = "idx_unique",
- table_name = "test",
- is_unique = true
- };
- op.columns.add("email");
- var sql = dialect.create_index_sql(op);
- assert("CREATE UNIQUE INDEX idx_unique ON test (email)" == sql);
-
- print("PASSED\n");
- }
- void test_add_column_sql() throws SqlError {
- print("Test: ADD COLUMN SQL generation... ");
-
- var dialect = new SqliteDialect();
- var op = new AddColumnOperation() {
- table_name = "users",
- column = new ColumnDefinition() {
- name = "age",
- column_type = ColumnType.INT_32
- }
- };
- var sql = dialect.add_column_sql(op);
- assert("ALTER TABLE users ADD COLUMN age" in sql);
- assert("INTEGER" in sql);
-
- print("PASSED\n");
- }
- void test_drop_column_sql() throws SqlError {
- print("Test: DROP COLUMN SQL generation... ");
-
- var dialect = new SqliteDialect();
- var op = new DropColumnOperation() {
- table_name = "users",
- column_name = "age"
- };
- var sql = dialect.drop_column_sql(op);
- assert("ALTER TABLE users DROP COLUMN age" == sql);
-
- print("PASSED\n");
- }
- void test_rename_column_sql() throws SqlError {
- print("Test: RENAME COLUMN SQL generation... ");
-
- var dialect = new SqliteDialect();
- var op = new RenameColumnOperation() {
- table_name = "users",
- old_name = "old_name",
- new_name = "new_name"
- };
- var sql = dialect.rename_column_sql(op);
- assert("ALTER TABLE users RENAME COLUMN old_name TO new_name" == sql);
-
- print("PASSED\n");
- }
- void test_migration_builder_create_table() throws SqlError {
- print("Test: MigrationBuilder create_table... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- // Type inferred from generic parameter - cleaner API
- builder.create_table("users", t => {
- t.column<int64?>("id").primary_key().auto_increment();
- t.column<string>("name").not_null();
- });
-
- var ops = builder.get_operations();
- assert(ops.length == 1);
-
- var op = ops[0] as CreateTableOperation;
- assert(op != null);
- assert(op.table_name == "users");
- assert(op.columns.length == 2);
-
- print("PASSED\n");
- }
- void test_migration_builder_create_table_with_indexes() throws SqlError {
- print("Test: MigrationBuilder create_table with indexes... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- // Create table with indexes defined inline
- builder.create_table("users", t => {
- t.column<int64?>("id").primary_key().auto_increment();
- t.column<string>("email").not_null();
- t.column<string>("name").not_null();
-
- // Single column index
- t.index("idx_email").on_column("email");
-
- // Composite unique index
- t.index("idx_email_name").on_columns("email", "name").unique();
- });
-
- var ops = builder.get_operations();
- // Should have 1 create table + 2 create index operations
- assert(ops.length == 3);
-
- var table_op = ops[0] as CreateTableOperation;
- assert(table_op != null);
- assert(table_op.table_name == "users");
-
- var idx1_op = ops[1] as CreateIndexOperation;
- assert(idx1_op != null);
- assert(idx1_op.index_name == "idx_email");
- assert(idx1_op.is_unique == false);
-
- var idx2_op = ops[2] as CreateIndexOperation;
- assert(idx2_op != null);
- assert(idx2_op.index_name == "idx_email_name");
- assert(idx2_op.is_unique == true);
-
- print("PASSED\n");
- }
- void test_migration_builder_alter_table() throws SqlError {
- print("Test: MigrationBuilder alter_table... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- // Type inferred from generic parameter - cleaner API
- builder.alter_table("users", t => {
- t.add_column<string>("email").not_null();
- t.drop_column("old_column");
- t.rename_column("old_name", "new_name");
- });
-
- var ops = builder.get_operations();
- assert(ops.length == 3);
-
- assert(ops[0] is AddColumnOperation);
- assert(ops[1] is DropColumnOperation);
- assert(ops[2] is RenameColumnOperation);
-
- print("PASSED\n");
- }
- void test_migration_builder_alter_table_with_indexes() throws SqlError {
- print("Test: MigrationBuilder alter_table with indexes... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.alter_table("users", t => {
- t.add_column<string>("phone");
-
- // Create index on new column
- t.create_index("idx_phone").on_column("phone");
-
- // Drop old index
- t.drop_index("idx_old_email");
- });
-
- var ops = builder.get_operations();
- assert(ops.length == 3);
-
- assert(ops[0] is AddColumnOperation);
- assert(ops[1] is CreateIndexOperation);
- assert(ops[2] is DropIndexOperation);
-
- print("PASSED\n");
- }
- void test_index_builder_single_column() throws SqlError {
- print("Test: IndexBuilder single column... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.create_table("test", t => {
- t.column<string>("name").not_null();
- t.index("idx_name").on_column("name");
- });
-
- var ops = builder.get_operations();
- var idx_op = ops[1] as CreateIndexOperation;
- assert(idx_op != null);
- assert(idx_op.index_name == "idx_name");
- assert(idx_op.columns.length == 1);
- assert(idx_op.columns[0] == "name");
- assert(idx_op.is_unique == false);
-
- print("PASSED\n");
- }
- void test_index_builder_composite() throws SqlError {
- print("Test: IndexBuilder composite... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.create_table("test", t => {
- t.column<string>("col1").not_null();
- t.column<string>("col2").not_null();
- t.column<string>("col3").not_null();
-
- t.index("idx_composite").on_columns("col1", "col2", "col3");
- });
-
- var ops = builder.get_operations();
- var idx_op = ops[1] as CreateIndexOperation;
- assert(idx_op != null);
- assert(idx_op.index_name == "idx_composite");
- assert(idx_op.columns.length == 3);
- assert(idx_op.columns[0] == "col1");
- assert(idx_op.columns[1] == "col2");
- assert(idx_op.columns[2] == "col3");
-
- print("PASSED\n");
- }
- void test_index_builder_unique() throws SqlError {
- print("Test: IndexBuilder unique... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.create_table("test", t => {
- t.column<string>("email").not_null();
- t.index("uq_email").on_column("email").unique();
- });
-
- var ops = builder.get_operations();
- var idx_op = ops[1] as CreateIndexOperation;
- assert(idx_op != null);
- assert(idx_op.index_name == "uq_email");
- assert(idx_op.is_unique == true);
-
- print("PASSED\n");
- }
- void test_migration_runner_registration() throws SqlError {
- print("Test: MigrationRunner registration... ");
-
- var conn = ConnectionFactory.create_and_open("sqlite::memory:");
- var dialect = new SqliteDialect();
-
- var runner = new MigrationRunner(conn, dialect);
- runner.register_migration(new V001_CreateUsers());
- runner.register_migration(new V002_AddAgeColumn());
-
- // Verify migrations are registered - current version should be 0
- var current = runner.get_current_version();
- assert(current == 0); // No migrations applied yet
-
- print("PASSED\n");
- conn.close();
- }
- void test_migration_runner_migrate_to_latest() throws SqlError {
- print("Test: MigrationRunner migrate_to_latest... ");
-
- var conn = ConnectionFactory.create_and_open("sqlite::memory:");
- var dialect = new SqliteDialect();
-
- var runner = new MigrationRunner(conn, dialect);
- runner.register_migration(new V001_CreateUsers());
- runner.register_migration(new V002_AddAgeColumn());
-
- runner.migrate_to_latest();
-
- var current = runner.get_current_version();
- assert(current == 2);
-
- // Verify table was created
- var cmd = conn.create_command("SELECT name FROM sqlite_master WHERE type='table' AND name='users'");
- var results = cmd.execute_query();
- assert(results.any());
-
- print("PASSED\n");
- conn.close();
- }
- void test_migration_runner_migrate_to_version() throws SqlError {
- print("Test: MigrationRunner migrate_to_version... ");
-
- var conn = ConnectionFactory.create_and_open("sqlite::memory:");
- var dialect = new SqliteDialect();
-
- var runner = new MigrationRunner(conn, dialect);
- runner.register_migration(new V001_CreateUsers());
- runner.register_migration(new V002_AddAgeColumn());
-
- // Migrate to version 1 only
- runner.migrate_to(1);
- assert(runner.get_current_version() == 1);
-
- // Then migrate to version 2
- runner.migrate_to(2);
- assert(runner.get_current_version() == 2);
-
- print("PASSED\n");
- conn.close();
- }
- void test_migration_runner_rollback() throws SqlError {
- print("Test: MigrationRunner rollback... ");
-
- var conn = ConnectionFactory.create_and_open("sqlite::memory:");
- var dialect = new SqliteDialect();
-
- var runner = new MigrationRunner(conn, dialect);
- runner.register_migration(new V001_CreateUsers());
- runner.register_migration(new V002_AddAgeColumn());
-
- runner.migrate_to_latest();
- assert(runner.get_current_version() == 2);
-
- // Rollback one step
- runner.rollback(1);
- assert(runner.get_current_version() == 1);
-
- print("PASSED\n");
- conn.close();
- }
- void test_migration_runner_rollback_all() throws SqlError {
- print("Test: MigrationRunner rollback_all... ");
-
- var conn = ConnectionFactory.create_and_open("sqlite::memory:");
- var dialect = new SqliteDialect();
-
- var runner = new MigrationRunner(conn, dialect);
- runner.register_migration(new V001_CreateUsers());
- runner.register_migration(new V002_AddAgeColumn());
-
- runner.migrate_to_latest();
- assert(runner.get_current_version() == 2);
-
- // Rollback all
- runner.rollback_all();
- assert(runner.get_current_version() == 0);
-
- print("PASSED\n");
- conn.close();
- }
- // ========== Foreign Key Tests ==========
- void test_fk_creation_with_auto_generated_name() throws SqlError {
- print("Test: FK creation with auto-generated name... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.create_table("orders", t => {
- t.column<int64?>("id").primary_key().auto_increment();
- t.column<int64?>("user_id")
- .not_null()
- .references("users", "id");
- });
-
- var ops = builder.get_operations();
- assert(ops.length == 1);
-
- var table_op = ops[0] as CreateTableOperation;
- assert(table_op != null);
-
- // Debug: print constraint count
- if (table_op.constraints.length != 1) {
- print("\n DEBUG: constraints.length = %u (expected 1)\n", table_op.constraints.length);
- }
-
- assert(table_op.constraints.length == 1);
-
- var constraint = table_op.constraints.get(0);
- assert(constraint.constraint_type == "FOREIGN KEY");
- assert(constraint.name == "fk_orders_user_id"); // Auto-generated name
- assert(constraint.reference_table == "users");
- assert(constraint.reference_columns.get(0) == "id");
- assert(constraint.columns.get(0) == "user_id");
-
- // Verify SQL contains proper FOREIGN KEY clause
- var sql = dialect.create_table_sql(table_op);
- assert("FOREIGN KEY" in sql);
- assert("REFERENCES users (id)" in sql);
- assert("fk_orders_user_id" in sql);
-
- print("PASSED\n");
- }
- void test_fk_creation_with_explicit_name() throws SqlError {
- print("Test: FK creation with explicit name... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.create_table("orders", t => {
- t.column<int64?>("id").primary_key().auto_increment();
- t.column<int64?>("user_id")
- .not_null()
- .references("users", "id")
- .name("custom_fk_orders_users");
- });
-
- var ops = builder.get_operations();
- var table_op = ops[0] as CreateTableOperation;
- assert(table_op != null);
-
- var constraint = table_op.constraints.get(0);
- assert(constraint.name == "custom_fk_orders_users"); // Custom name
-
- var sql = dialect.create_table_sql(table_op);
- assert("custom_fk_orders_users" in sql);
-
- print("PASSED\n");
- }
- void test_fk_on_delete_actions() throws SqlError {
- print("Test: FK ON DELETE actions... ");
-
- var dialect = new SqliteDialect();
-
- // Test CASCADE
- var builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_delete_cascade();
- });
- var ops = builder.get_operations();
- var table_op = ops[0] as CreateTableOperation;
- var constraint = table_op.constraints.get(0);
- assert(constraint.on_delete_action == ReferentialAction.CASCADE);
- var sql = dialect.create_table_sql(table_op);
- assert("ON DELETE CASCADE" in sql);
-
- // Test SET NULL
- builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_delete_set_null();
- });
- ops = builder.get_operations();
- table_op = ops[0] as CreateTableOperation;
- constraint = table_op.constraints.get(0);
- assert(constraint.on_delete_action == ReferentialAction.SET_NULL);
- sql = dialect.create_table_sql(table_op);
- assert("ON DELETE SET NULL" in sql);
-
- // Test SET DEFAULT
- builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_delete_set_default();
- });
- ops = builder.get_operations();
- table_op = ops[0] as CreateTableOperation;
- constraint = table_op.constraints.get(0);
- assert(constraint.on_delete_action == ReferentialAction.SET_DEFAULT);
- sql = dialect.create_table_sql(table_op);
- assert("ON DELETE SET DEFAULT" in sql);
-
- // Test NO ACTION
- builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_delete_no_action();
- });
- ops = builder.get_operations();
- table_op = ops[0] as CreateTableOperation;
- constraint = table_op.constraints.get(0);
- assert(constraint.on_delete_action == ReferentialAction.NO_ACTION);
-
- // Test RESTRICT
- builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_delete_restrict();
- });
- ops = builder.get_operations();
- table_op = ops[0] as CreateTableOperation;
- constraint = table_op.constraints.get(0);
- assert(constraint.on_delete_action == ReferentialAction.RESTRICT);
- sql = dialect.create_table_sql(table_op);
- assert("ON DELETE RESTRICT" in sql);
-
- print("PASSED\n");
- }
- void test_fk_on_update_actions() throws SqlError {
- print("Test: FK ON UPDATE actions... ");
-
- var dialect = new SqliteDialect();
-
- // Test CASCADE
- var builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_update_cascade();
- });
- var ops = builder.get_operations();
- var table_op = ops[0] as CreateTableOperation;
- var constraint = table_op.constraints.get(0);
- assert(constraint.on_update_action == ReferentialAction.CASCADE);
- var sql = dialect.create_table_sql(table_op);
- assert("ON UPDATE CASCADE" in sql);
-
- // Test SET NULL
- builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_update_set_null();
- });
- ops = builder.get_operations();
- table_op = ops[0] as CreateTableOperation;
- constraint = table_op.constraints.get(0);
- assert(constraint.on_update_action == ReferentialAction.SET_NULL);
- sql = dialect.create_table_sql(table_op);
- assert("ON UPDATE SET NULL" in sql);
-
- // Test SET DEFAULT
- builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_update_set_default();
- });
- ops = builder.get_operations();
- table_op = ops[0] as CreateTableOperation;
- constraint = table_op.constraints.get(0);
- assert(constraint.on_update_action == ReferentialAction.SET_DEFAULT);
- sql = dialect.create_table_sql(table_op);
- assert("ON UPDATE SET DEFAULT" in sql);
-
- // Test NO ACTION
- builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_update_no_action();
- });
- ops = builder.get_operations();
- table_op = ops[0] as CreateTableOperation;
- constraint = table_op.constraints.get(0);
- assert(constraint.on_update_action == ReferentialAction.NO_ACTION);
-
- // Test RESTRICT
- builder = new MigrationBuilder(dialect);
- builder.create_table("orders", t => {
- t.column<int64?>("user_id")
- .references("users", "id")
- .on_update_restrict();
- });
- ops = builder.get_operations();
- table_op = ops[0] as CreateTableOperation;
- constraint = table_op.constraints.get(0);
- assert(constraint.on_update_action == ReferentialAction.RESTRICT);
- sql = dialect.create_table_sql(table_op);
- assert("ON UPDATE RESTRICT" in sql);
-
- print("PASSED\n");
- }
- void test_fk_in_alter_table_add_column() throws SqlError {
- print("Test: FK in ALTER TABLE add column... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.alter_table("orders", t => {
- t.add_column<int64?>("product_id")
- .not_null()
- .references("products", "id")
- .on_delete_restrict();
- });
-
- var ops = builder.get_operations();
- assert(ops.length == 1);
-
- var add_col_op = ops[0] as AddColumnOperation;
- assert(add_col_op != null);
- assert(add_col_op.foreign_key_constraint != null);
-
- var fk = add_col_op.foreign_key_constraint;
- assert(fk.constraint_type == "FOREIGN KEY");
- assert(fk.reference_table == "products");
- assert(fk.reference_columns.get(0) == "id");
- assert(fk.on_delete_action == ReferentialAction.RESTRICT);
-
- // Verify SQL contains inline REFERENCES clause
- var sql = dialect.add_column_sql(add_col_op);
- assert("REFERENCES products (id)" in sql);
- assert("ON DELETE RESTRICT" in sql);
-
- print("PASSED\n");
- }
- // ========== Indexed Column Tests ==========
- void test_indexed_with_auto_generated_name() throws SqlError {
- print("Test: indexed() with auto-generated name... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.create_table("users", t => {
- t.column<int64?>("id").primary_key().auto_increment();
- t.column<string>("email")
- .not_null()
- .indexed();
- });
-
- var ops = builder.get_operations();
- // Should have 1 create table + 1 create index operation
- assert(ops.length == 2);
-
- var table_op = ops[0] as CreateTableOperation;
- assert(table_op != null);
-
- var idx_op = ops[1] as CreateIndexOperation;
- assert(idx_op != null);
- assert(idx_op.index_name == "idx_users_email"); // Auto-generated name
- assert(idx_op.table_name == "users");
- assert(idx_op.columns.length == 1);
- assert(idx_op.columns.get(0) == "email");
- assert(idx_op.is_unique == false);
-
- print("PASSED\n");
- }
- void test_indexed_with_custom_name() throws SqlError {
- print("Test: indexed() with custom name... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.create_table("users", t => {
- t.column<int64?>("id").primary_key().auto_increment();
- t.column<string>("email")
- .not_null()
- .indexed("idx_users_email_address");
- });
-
- var ops = builder.get_operations();
- assert(ops.length == 2);
-
- var idx_op = ops[1] as CreateIndexOperation;
- assert(idx_op != null);
- assert(idx_op.index_name == "idx_users_email_address"); // Custom name
-
- print("PASSED\n");
- }
- void test_unique_indexed_creates_unique_index() throws SqlError {
- print("Test: unique().indexed() creates UNIQUE index... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.create_table("users", t => {
- t.column<int64?>("id").primary_key().auto_increment();
- t.column<string>("email")
- .not_null()
- .unique()
- .indexed();
- });
-
- var ops = builder.get_operations();
- assert(ops.length == 2);
-
- var idx_op = ops[1] as CreateIndexOperation;
- assert(idx_op != null);
- assert(idx_op.is_unique == true); // Uniqueness inferred from column's unique() flag
-
- var sql = dialect.create_index_sql(idx_op);
- assert("CREATE UNIQUE INDEX" in sql);
-
- print("PASSED\n");
- }
- void test_drop_index_on() throws SqlError {
- print("Test: drop_index_on() generates correct DropIndexOperation... ");
-
- var dialect = new SqliteDialect();
- var builder = new MigrationBuilder(dialect);
-
- builder.alter_table("users", t => {
- t.drop_index_on("email");
- });
-
- var ops = builder.get_operations();
- assert(ops.length == 1);
-
- var drop_op = ops[0] as DropIndexOperation;
- assert(drop_op != null);
- assert(drop_op.index_name == "idx_users_email"); // Auto-generated name
- assert(drop_op.table_name == "users");
-
- print("PASSED\n");
- }
|