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, err := NewMigrationWriter(&writers.WriterOptions{}) if err != nil { t.Fatalf("Failed to create writer: %v", err) } 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_WithAudit(t *testing.T) { // Current database (empty) current := models.InitDatabase("testdb") currentSchema := models.InitSchema("public") current.Schemas = append(current.Schemas, currentSchema) // Model database (with table to audit) model := models.InitDatabase("testdb") modelSchema := models.InitSchema("public") table := models.InitTable("users", "public") idCol := models.InitColumn("id", "users", "public") idCol.Type = "integer" idCol.IsPrimaryKey = true table.Columns["id"] = idCol nameCol := models.InitColumn("name", "users", "public") nameCol.Type = "text" table.Columns["name"] = nameCol passwordCol := models.InitColumn("password", "users", "public") passwordCol.Type = "text" table.Columns["password"] = passwordCol modelSchema.Tables = append(modelSchema.Tables, table) model.Schemas = append(model.Schemas, modelSchema) // Configure audit auditConfig := NewAuditConfig() auditConfig.AuditSchema = "public" tableConfig := auditConfig.EnableTableAudit("public", "users") tableConfig.EncryptedColumns = []string{"password"} // Generate migration with audit var buf bytes.Buffer options := &writers.WriterOptions{ Metadata: map[string]interface{}{ "audit_config": auditConfig, }, } writer, err := NewMigrationWriter(options) if err != nil { t.Fatalf("Failed to create writer: %v", err) } writer.writer = &buf err = writer.WriteMigration(model, current) if err != nil { t.Fatalf("WriteMigration failed: %v", err) } output := buf.String() t.Logf("Generated migration with audit:\n%s", output) // Verify audit tables if !strings.Contains(output, "CREATE TABLE IF NOT EXISTS public.atevent") { t.Error("Migration missing atevent table") } if !strings.Contains(output, "CREATE TABLE IF NOT EXISTS public.atdetail") { t.Error("Migration missing atdetail table") } // Verify audit function if !strings.Contains(output, "CREATE OR REPLACE FUNCTION public.ft_audit_users()") { t.Error("Migration missing audit function") } // Verify audit trigger if !strings.Contains(output, "CREATE TRIGGER t_audit_users") { t.Error("Migration missing audit trigger") } // Verify encrypted column handling if !strings.Contains(output, "'****************'") { t.Error("Migration missing encrypted column handling") } } func TestTemplateExecutor_CreateTable(t *testing.T) { executor, err := NewTemplateExecutor() if err != nil { t.Fatalf("Failed to create executor: %v", err) } data := CreateTableData{ SchemaName: "public", TableName: "test_table", Columns: []ColumnData{ {Name: "id", Type: "integer", NotNull: true}, {Name: "name", Type: "text", Default: "'unknown'"}, }, } sql, err := executor.ExecuteCreateTable(data) if err != nil { t.Fatalf("Failed to execute template: %v", err) } t.Logf("Generated SQL:\n%s", sql) if !strings.Contains(sql, "CREATE TABLE IF NOT EXISTS public.test_table") { t.Error("SQL missing CREATE TABLE statement") } if !strings.Contains(sql, "id integer NOT NULL") { t.Error("SQL missing id column definition") } if !strings.Contains(sql, "name text DEFAULT 'unknown'") { t.Error("SQL missing name column definition") } } func TestTemplateExecutor_AuditFunction(t *testing.T) { executor, err := NewTemplateExecutor() if err != nil { t.Fatalf("Failed to create executor: %v", err) } data := AuditFunctionData{ SchemaName: "public", FunctionName: "ft_audit_users", TableName: "users", TablePrefix: "NULL", PrimaryKey: "id", AuditSchema: "public", UserFunction: "current_user", AuditInsert: true, AuditUpdate: true, AuditDelete: true, UpdateCondition: "old.name IS DISTINCT FROM new.name", UpdateColumns: []AuditColumnData{ {Name: "name", OldValue: "old.name::text", NewValue: "new.name::text"}, }, DeleteColumns: []AuditColumnData{ {Name: "name", OldValue: "old.name::text"}, }, } sql, err := executor.ExecuteAuditFunction(data) if err != nil { t.Fatalf("Failed to execute template: %v", err) } t.Logf("Generated SQL:\n%s", sql) if !strings.Contains(sql, "CREATE OR REPLACE FUNCTION public.ft_audit_users()") { t.Error("SQL missing function definition") } if !strings.Contains(sql, "IF TG_OP = 'INSERT'") { t.Error("SQL missing INSERT handling") } if !strings.Contains(sql, "ELSIF TG_OP = 'UPDATE'") { t.Error("SQL missing UPDATE handling") } if !strings.Contains(sql, "ELSIF TG_OP = 'DELETE'") { t.Error("SQL missing DELETE handling") } }