From 1b59dabaeb80380e903c930ee95e5d4b96f107cf Mon Sep 17 00:00:00 2001 From: BA Date: Thu, 16 Oct 2025 23:12:07 +0800 Subject: [PATCH] Implement tern template support --- internal/compiler/compile.go | 5 ++++ internal/migrations/migrations.go | 40 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/internal/compiler/compile.go b/internal/compiler/compile.go index 84fbb20a3c..11e4e95bbc 100644 --- a/internal/compiler/compile.go +++ b/internal/compiler/compile.go @@ -38,6 +38,11 @@ func (c *Compiler) parseCatalog(schemas []string) error { continue } contents := migrations.RemoveRollbackStatements(string(blob)) + contents, err = migrations.TransformStatements(filepath.Dir(filename), contents) + if err != nil { + merr.Add(filename, contents, 0, err) + continue + } c.schema = append(c.schema, contents) stmts, err := c.parser.Parse(strings.NewReader(contents)) if err != nil { diff --git a/internal/migrations/migrations.go b/internal/migrations/migrations.go index 4ade6045a4..6db4173a2d 100644 --- a/internal/migrations/migrations.go +++ b/internal/migrations/migrations.go @@ -2,6 +2,11 @@ package migrations import ( "bufio" + "errors" + "fmt" + "os" + "path" + "regexp" "strings" ) @@ -37,3 +42,38 @@ func IsDown(filename string) bool { // Remove golang-migrate rollback files. return strings.HasSuffix(filename, ".down.sql") } + +var ternTemplateRegex *regexp.Regexp + +// tern: {{ template "filepath" . }} +func TransformStatements(pwd, content string) (string, error) { + if !strings.Contains(content, "{{ template \"") { + return content, nil + } + + var err error + var processed string + + if ternTemplateRegex == nil { + defer func() { + if r := recover(); r != nil { + fmt.Printf("failed to compile regexp: %v\n", r) + } + // It is tested, just recovering for it's technically possible to panic + }() + ternTemplateRegex = regexp.MustCompile(`\{\{ template \"(.+)\" \. \}\}`) + } + + processed = ternTemplateRegex.ReplaceAllStringFunc(content, func(match string) string { + filePath := ternTemplateRegex.FindStringSubmatch(match)[1] + filePath = path.Join(pwd, filePath) + read, err := os.ReadFile(filePath) + if err != nil { + err = errors.Join(err, fmt.Errorf("error reading file %s: %w", filePath, err)) + return match + } + return string(read) + }) + + return processed, err +}