package pgsql import ( "bytes" "strings" "testing" "git.warky.dev/wdevs/relspecgo/pkg/models" "git.warky.dev/wdevs/relspecgo/pkg/writers" ) func TestWriteMigration_NewTable(t *testing.T) { // Current database (empty) current := models.InitDatabase("testdb") currentSchema := models.InitSchema("public") current.Schemas = append(current.Schemas, currentSchema) // Model database (with new table) model := models.InitDatabase("testdb") modelSchema := models.InitSchema("public") table := models.InitTable("users", "public") idCol := models.InitColumn("id", "users", "public") idCol.Type = "integer" idCol.NotNull = true table.Columns["id"] = idCol nameCol := models.InitColumn("name", "users", "public") nameCol.Type = "text" table.Columns["name"] = nameCol modelSchema.Tables = append(modelSchema.Tables, table) model.Schemas = append(model.Schemas, modelSchema) // Generate migration var buf bytes.Buffer writer := NewMigrationWriter(&writers.WriterOptions{}) writer.writer = &buf err := writer.WriteMigration(model, current) if err != nil { t.Fatalf("WriteMigration failed: %v", err) } output := buf.String() t.Logf("Generated migration:\n%s", output) // Verify CREATE TABLE is present if !strings.Contains(output, "CREATE TABLE") { t.Error("Migration missing CREATE TABLE statement") } if !strings.Contains(output, "users") { t.Error("Migration missing table name 'users'") } } func TestWriteMigration_AddColumn(t *testing.T) { // Current database (with table but missing column) current := models.InitDatabase("testdb") currentSchema := models.InitSchema("public") currentTable := models.InitTable("users", "public") idCol := models.InitColumn("id", "users", "public") idCol.Type = "integer" currentTable.Columns["id"] = idCol currentSchema.Tables = append(currentSchema.Tables, currentTable) current.Schemas = append(current.Schemas, currentSchema) // Model database (with additional column) model := models.InitDatabase("testdb") modelSchema := models.InitSchema("public") modelTable := models.InitTable("users", "public") idCol2 := models.InitColumn("id", "users", "public") idCol2.Type = "integer" modelTable.Columns["id"] = idCol2 emailCol := models.InitColumn("email", "users", "public") emailCol.Type = "text" modelTable.Columns["email"] = emailCol modelSchema.Tables = append(modelSchema.Tables, modelTable) model.Schemas = append(model.Schemas, modelSchema) // Generate migration var buf bytes.Buffer writer := NewMigrationWriter(&writers.WriterOptions{}) writer.writer = &buf err := writer.WriteMigration(model, current) if err != nil { t.Fatalf("WriteMigration failed: %v", err) } output := buf.String() t.Logf("Generated migration:\n%s", output) // Verify ADD COLUMN is present if !strings.Contains(output, "ADD COLUMN") { t.Error("Migration missing ADD COLUMN statement") } if !strings.Contains(output, "email") { t.Error("Migration missing column name 'email'") } } func TestWriteMigration_ChangeColumnType(t *testing.T) { // Current database (with integer column) current := models.InitDatabase("testdb") currentSchema := models.InitSchema("public") currentTable := models.InitTable("users", "public") idCol := models.InitColumn("id", "users", "public") idCol.Type = "integer" currentTable.Columns["id"] = idCol currentSchema.Tables = append(currentSchema.Tables, currentTable) current.Schemas = append(current.Schemas, currentSchema) // Model database (changed to bigint) model := models.InitDatabase("testdb") modelSchema := models.InitSchema("public") modelTable := models.InitTable("users", "public") idCol2 := models.InitColumn("id", "users", "public") idCol2.Type = "bigint" modelTable.Columns["id"] = idCol2 modelSchema.Tables = append(modelSchema.Tables, modelTable) model.Schemas = append(model.Schemas, modelSchema) // Generate migration var buf bytes.Buffer writer := NewMigrationWriter(&writers.WriterOptions{}) writer.writer = &buf err := writer.WriteMigration(model, current) if err != nil { t.Fatalf("WriteMigration failed: %v", err) } output := buf.String() t.Logf("Generated migration:\n%s", output) // Verify ALTER COLUMN TYPE is present if !strings.Contains(output, "ALTER COLUMN") { t.Error("Migration missing ALTER COLUMN statement") } if !strings.Contains(output, "TYPE bigint") { t.Error("Migration missing TYPE bigint") } } func TestWriteMigration_AddForeignKey(t *testing.T) { // Current database (two tables, no relationship) current := models.InitDatabase("testdb") currentSchema := models.InitSchema("public") usersTable := models.InitTable("users", "public") idCol := models.InitColumn("id", "users", "public") idCol.Type = "integer" usersTable.Columns["id"] = idCol postsTable := models.InitTable("posts", "public") postIdCol := models.InitColumn("id", "posts", "public") postIdCol.Type = "integer" postsTable.Columns["id"] = postIdCol userIdCol := models.InitColumn("user_id", "posts", "public") userIdCol.Type = "integer" postsTable.Columns["user_id"] = userIdCol currentSchema.Tables = append(currentSchema.Tables, usersTable, postsTable) current.Schemas = append(current.Schemas, currentSchema) // Model database (with foreign key) model := models.InitDatabase("testdb") modelSchema := models.InitSchema("public") modelUsersTable := models.InitTable("users", "public") modelIdCol := models.InitColumn("id", "users", "public") modelIdCol.Type = "integer" modelUsersTable.Columns["id"] = modelIdCol modelPostsTable := models.InitTable("posts", "public") modelPostIdCol := models.InitColumn("id", "posts", "public") modelPostIdCol.Type = "integer" modelPostsTable.Columns["id"] = modelPostIdCol modelUserIdCol := models.InitColumn("user_id", "posts", "public") modelUserIdCol.Type = "integer" modelPostsTable.Columns["user_id"] = modelUserIdCol // Add foreign key constraint fkConstraint := &models.Constraint{ Name: "fk_posts_users", Type: models.ForeignKeyConstraint, Columns: []string{"user_id"}, ReferencedTable: "users", ReferencedSchema: "public", ReferencedColumns: []string{"id"}, OnDelete: "CASCADE", OnUpdate: "CASCADE", } modelPostsTable.Constraints["fk_posts_users"] = fkConstraint modelSchema.Tables = append(modelSchema.Tables, modelUsersTable, modelPostsTable) model.Schemas = append(model.Schemas, modelSchema) // Generate migration var buf bytes.Buffer writer := NewMigrationWriter(&writers.WriterOptions{}) writer.writer = &buf err := writer.WriteMigration(model, current) if err != nil { t.Fatalf("WriteMigration failed: %v", err) } output := buf.String() t.Logf("Generated migration:\n%s", output) // Verify FOREIGN KEY is present if !strings.Contains(output, "FOREIGN KEY") { t.Error("Migration missing FOREIGN KEY statement") } if !strings.Contains(output, "ON DELETE CASCADE") { t.Error("Migration missing ON DELETE CASCADE") } } func TestWriteMigration_AddIndex(t *testing.T) { // Current database (table without index) current := models.InitDatabase("testdb") currentSchema := models.InitSchema("public") currentTable := models.InitTable("users", "public") emailCol := models.InitColumn("email", "users", "public") emailCol.Type = "text" currentTable.Columns["email"] = emailCol currentSchema.Tables = append(currentSchema.Tables, currentTable) current.Schemas = append(current.Schemas, currentSchema) // Model database (with unique index) model := models.InitDatabase("testdb") modelSchema := models.InitSchema("public") modelTable := models.InitTable("users", "public") modelEmailCol := models.InitColumn("email", "users", "public") modelEmailCol.Type = "text" modelTable.Columns["email"] = modelEmailCol // Add unique index index := &models.Index{ Name: "uk_users_email", Unique: true, Columns: []string{"email"}, Type: "btree", } modelTable.Indexes["uk_users_email"] = index modelSchema.Tables = append(modelSchema.Tables, modelTable) model.Schemas = append(model.Schemas, modelSchema) // Generate migration var buf bytes.Buffer writer := NewMigrationWriter(&writers.WriterOptions{}) writer.writer = &buf err := writer.WriteMigration(model, current) if err != nil { t.Fatalf("WriteMigration failed: %v", err) } output := buf.String() t.Logf("Generated migration:\n%s", output) // Verify CREATE UNIQUE INDEX is present if !strings.Contains(output, "CREATE UNIQUE INDEX") { t.Error("Migration missing CREATE UNIQUE INDEX statement") } if !strings.Contains(output, "uk_users_email") { t.Error("Migration missing index name") } }