From a3e45c206d26610413e51a7fc8db1a4c7d755d42 Mon Sep 17 00:00:00 2001 From: Hein Date: Sat, 31 Jan 2026 21:19:48 +0200 Subject: [PATCH] =?UTF-8?q?feat(writer):=20=F0=9F=8E=89=20Enhance=20SQL=20?= =?UTF-8?q?execution=20logging=20and=20add=20statement=20type=20detection?= =?UTF-8?q?=20*=20Log=20statement=20type=20during=20execution=20for=20bett?= =?UTF-8?q?er=20debugging=20*=20Introduce=20detectStatementType=20function?= =?UTF-8?q?=20to=20categorize=20SQL=20statements=20*=20Update=20unique=20c?= =?UTF-8?q?onstraint=20naming=20convention=20in=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/readers/dbml/reader.go | 4 +- pkg/readers/dbml/reader_test.go | 10 ++-- pkg/writers/pgsql/writer.go | 88 ++++++++++++++++++++++++++++++++- 3 files changed, 95 insertions(+), 7 deletions(-) diff --git a/pkg/readers/dbml/reader.go b/pkg/readers/dbml/reader.go index b005195..fe15908 100644 --- a/pkg/readers/dbml/reader.go +++ b/pkg/readers/dbml/reader.go @@ -603,8 +603,10 @@ func (r *Reader) parseColumn(line, tableName, schemaName string) (*models.Column column.Default = strings.Trim(defaultVal, "'\"") } else if attr == "unique" { // Create a unique constraint + // Clean table name by removing leading underscores to avoid double underscores + cleanTableName := strings.TrimLeft(tableName, "_") uniqueConstraint := models.InitConstraint( - fmt.Sprintf("uq_%s_%s", tableName, columnName), + fmt.Sprintf("ukey_%s_%s", cleanTableName, columnName), models.UniqueConstraint, ) uniqueConstraint.Schema = schemaName diff --git a/pkg/readers/dbml/reader_test.go b/pkg/readers/dbml/reader_test.go index 8a887e7..1e360dc 100644 --- a/pkg/readers/dbml/reader_test.go +++ b/pkg/readers/dbml/reader_test.go @@ -809,14 +809,14 @@ func TestConstraintNaming(t *testing.T) { t.Fatal("Posts table not found") } - // Test unique constraint naming: uq_table_column - if _, exists := usersTable.Constraints["uq_users_email"]; !exists { - t.Error("Expected unique constraint 'uq_users_email' not found") + // Test unique constraint naming: ukey_table_column + if _, exists := usersTable.Constraints["ukey_users_email"]; !exists { + t.Error("Expected unique constraint 'ukey_users_email' not found") t.Logf("Available constraints: %v", getKeys(usersTable.Constraints)) } - if _, exists := postsTable.Constraints["uq_posts_slug"]; !exists { - t.Error("Expected unique constraint 'uq_posts_slug' not found") + if _, exists := postsTable.Constraints["ukey_posts_slug"]; !exists { + t.Error("Expected unique constraint 'ukey_posts_slug' not found") t.Logf("Available constraints: %v", getKeys(postsTable.Constraints)) } diff --git a/pkg/writers/pgsql/writer.go b/pkg/writers/pgsql/writer.go index 5f8e1b7..6e40786 100644 --- a/pkg/writers/pgsql/writer.go +++ b/pkg/writers/pgsql/writer.go @@ -1410,7 +1410,8 @@ func (w *Writer) executeDatabaseSQL(db *models.Database, connString string) erro continue } - fmt.Fprintf(os.Stderr, "Executing statement %d/%d...\n", i+1, len(statements)) + stmtType := detectStatementType(stmtTrimmed) + fmt.Fprintf(os.Stderr, "Executing statement %d/%d [%s]...\n", i+1, len(statements), stmtType) _, execErr := conn.Exec(ctx, stmt) if execErr != nil { @@ -1545,6 +1546,91 @@ func getCurrentTimestamp() string { return time.Now().Format("2006-01-02 15:04:05") } +// detectStatementType detects the type of SQL statement for logging +func detectStatementType(stmt string) string { + upperStmt := strings.ToUpper(stmt) + + // Check for DO blocks (used for conditional DDL) + if strings.HasPrefix(upperStmt, "DO $$") || strings.HasPrefix(upperStmt, "DO $") { + // Look inside the DO block for the actual operation + if strings.Contains(upperStmt, "ALTER TABLE") && strings.Contains(upperStmt, "ADD CONSTRAINT") { + if strings.Contains(upperStmt, "UNIQUE") { + return "ADD UNIQUE CONSTRAINT" + } else if strings.Contains(upperStmt, "FOREIGN KEY") { + return "ADD FOREIGN KEY" + } else if strings.Contains(upperStmt, "PRIMARY KEY") { + return "ADD PRIMARY KEY" + } else if strings.Contains(upperStmt, "CHECK") { + return "ADD CHECK CONSTRAINT" + } + return "ADD CONSTRAINT" + } + if strings.Contains(upperStmt, "ALTER TABLE") && strings.Contains(upperStmt, "ADD COLUMN") { + return "ADD COLUMN" + } + if strings.Contains(upperStmt, "DROP CONSTRAINT") { + return "DROP CONSTRAINT" + } + return "DO BLOCK" + } + + // Direct DDL statements + if strings.HasPrefix(upperStmt, "CREATE SCHEMA") { + return "CREATE SCHEMA" + } + if strings.HasPrefix(upperStmt, "CREATE SEQUENCE") { + return "CREATE SEQUENCE" + } + if strings.HasPrefix(upperStmt, "CREATE TABLE") { + return "CREATE TABLE" + } + if strings.HasPrefix(upperStmt, "CREATE INDEX") { + return "CREATE INDEX" + } + if strings.HasPrefix(upperStmt, "CREATE UNIQUE INDEX") { + return "CREATE UNIQUE INDEX" + } + if strings.HasPrefix(upperStmt, "ALTER TABLE") { + if strings.Contains(upperStmt, "ADD CONSTRAINT") { + if strings.Contains(upperStmt, "FOREIGN KEY") { + return "ADD FOREIGN KEY" + } else if strings.Contains(upperStmt, "PRIMARY KEY") { + return "ADD PRIMARY KEY" + } else if strings.Contains(upperStmt, "UNIQUE") { + return "ADD UNIQUE CONSTRAINT" + } else if strings.Contains(upperStmt, "CHECK") { + return "ADD CHECK CONSTRAINT" + } + return "ADD CONSTRAINT" + } + if strings.Contains(upperStmt, "ADD COLUMN") { + return "ADD COLUMN" + } + if strings.Contains(upperStmt, "DROP CONSTRAINT") { + return "DROP CONSTRAINT" + } + if strings.Contains(upperStmt, "ALTER COLUMN") { + return "ALTER COLUMN" + } + return "ALTER TABLE" + } + if strings.HasPrefix(upperStmt, "COMMENT ON TABLE") { + return "COMMENT ON TABLE" + } + if strings.HasPrefix(upperStmt, "COMMENT ON COLUMN") { + return "COMMENT ON COLUMN" + } + if strings.HasPrefix(upperStmt, "DROP TABLE") { + return "DROP TABLE" + } + if strings.HasPrefix(upperStmt, "DROP INDEX") { + return "DROP INDEX" + } + + // Default + return "SQL" +} + // quoteIdentifier wraps an identifier in double quotes if necessary // This is needed for identifiers that start with numbers or contain special characters func quoteIdentifier(s string) string {