From abdb9b4c78e80c95b29533657d5d9fe330092c0d Mon Sep 17 00:00:00 2001 From: Hein Date: Sat, 31 Jan 2026 19:45:24 +0200 Subject: [PATCH] =?UTF-8?q?feat(dbml/reader):=20=F0=9F=8E=89=20Implement?= =?UTF-8?q?=20splitIdentifier=20function=20for=20parsing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/readers/dbml/reader.go | 46 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/pkg/readers/dbml/reader.go b/pkg/readers/dbml/reader.go index f9d869f..3c6fce5 100644 --- a/pkg/readers/dbml/reader.go +++ b/pkg/readers/dbml/reader.go @@ -128,6 +128,46 @@ func (r *Reader) readDirectoryDBML(dirPath string) (*models.Database, error) { return db, nil } +// splitIdentifier splits a dotted identifier while respecting quotes +// Handles cases like: "schema.with.dots"."table"."column" +func splitIdentifier(s string) []string { + var parts []string + var current strings.Builder + inQuote := false + quoteChar := byte(0) + + for i := 0; i < len(s); i++ { + ch := s[i] + + if !inQuote { + switch ch { + case '"', '\'': + inQuote = true + quoteChar = ch + current.WriteByte(ch) + case '.': + if current.Len() > 0 { + parts = append(parts, current.String()) + current.Reset() + } + default: + current.WriteByte(ch) + } + } else { + current.WriteByte(ch) + if ch == quoteChar { + inQuote = false + } + } + } + + if current.Len() > 0 { + parts = append(parts, current.String()) + } + + return parts +} + // stripQuotes removes surrounding quotes and comments from an identifier func stripQuotes(s string) string { s = strings.TrimSpace(s) @@ -409,7 +449,9 @@ func (r *Reader) parseDBML(content string) (*models.Database, error) { // Parse Table definition if matches := tableRegex.FindStringSubmatch(line); matches != nil { tableName := matches[1] - parts := strings.Split(tableName, ".") + // Strip comments/notes before parsing to avoid dots in notes + tableName = strings.TrimSpace(regexp.MustCompile(`\s*\[.*?\]\s*`).ReplaceAllString(tableName, "")) + parts := splitIdentifier(tableName) if len(parts) == 2 { currentSchema = stripQuotes(parts[0]) @@ -814,7 +856,7 @@ func (r *Reader) parseTableRef(ref string) (schema, table string, columns []stri } // Parse schema, table, and optionally column - parts := strings.Split(strings.TrimSpace(ref), ".") + parts := splitIdentifier(strings.TrimSpace(ref)) if len(parts) == 3 { // Format: "schema"."table"."column" schema = stripQuotes(parts[0])