package sqlite import ( "bytes" "embed" "fmt" "text/template" "git.warky.dev/wdevs/relspecgo/pkg/models" "git.warky.dev/wdevs/relspecgo/pkg/writers" ) //go:embed templates/*.tmpl var templateFS embed.FS // TemplateExecutor manages and executes SQLite SQL templates type TemplateExecutor struct { templates *template.Template options *writers.WriterOptions } // NewTemplateExecutor creates a new template executor for SQLite func NewTemplateExecutor(opts *writers.WriterOptions) (*TemplateExecutor, error) { // Create template with SQLite-specific functions funcMap := GetTemplateFuncs(opts) tmpl, err := template.New("").Funcs(funcMap).ParseFS(templateFS, "templates/*.tmpl") if err != nil { return nil, fmt.Errorf("failed to parse templates: %w", err) } return &TemplateExecutor{ templates: tmpl, options: opts, }, nil } // Template data structures // TableTemplateData contains data for table template type TableTemplateData struct { Schema string Name string Columns []*models.Column PrimaryKey *models.Constraint } // IndexTemplateData contains data for index template type IndexTemplateData struct { Schema string Table string Name string Columns []string } // ConstraintTemplateData contains data for constraint templates type ConstraintTemplateData struct { Schema string Table string Name string Columns []string Expression string ForeignSchema string ForeignTable string ForeignColumns []string OnDelete string OnUpdate string } // Execute methods // ExecutePragmaForeignKeys executes the pragma foreign keys template func (te *TemplateExecutor) ExecutePragmaForeignKeys() (string, error) { var buf bytes.Buffer err := te.templates.ExecuteTemplate(&buf, "pragma_foreign_keys.tmpl", nil) if err != nil { return "", fmt.Errorf("failed to execute pragma_foreign_keys template: %w", err) } return buf.String(), nil } // ExecuteCreateTable executes the create table template func (te *TemplateExecutor) ExecuteCreateTable(data TableTemplateData) (string, error) { var buf bytes.Buffer err := te.templates.ExecuteTemplate(&buf, "create_table.tmpl", data) if err != nil { return "", fmt.Errorf("failed to execute create_table template: %w", err) } return buf.String(), nil } // ExecuteCreateIndex executes the create index template func (te *TemplateExecutor) ExecuteCreateIndex(data IndexTemplateData) (string, error) { var buf bytes.Buffer err := te.templates.ExecuteTemplate(&buf, "create_index.tmpl", data) if err != nil { return "", fmt.Errorf("failed to execute create_index template: %w", err) } return buf.String(), nil } // ExecuteCreateUniqueConstraint executes the create unique constraint template func (te *TemplateExecutor) ExecuteCreateUniqueConstraint(data ConstraintTemplateData) (string, error) { var buf bytes.Buffer err := te.templates.ExecuteTemplate(&buf, "create_unique_constraint.tmpl", data) if err != nil { return "", fmt.Errorf("failed to execute create_unique_constraint template: %w", err) } return buf.String(), nil } // ExecuteCreateCheckConstraint executes the create check constraint template func (te *TemplateExecutor) ExecuteCreateCheckConstraint(data ConstraintTemplateData) (string, error) { var buf bytes.Buffer err := te.templates.ExecuteTemplate(&buf, "create_check_constraint.tmpl", data) if err != nil { return "", fmt.Errorf("failed to execute create_check_constraint template: %w", err) } return buf.String(), nil } // ExecuteCreateForeignKey executes the create foreign key template func (te *TemplateExecutor) ExecuteCreateForeignKey(data ConstraintTemplateData) (string, error) { var buf bytes.Buffer err := te.templates.ExecuteTemplate(&buf, "create_foreign_key.tmpl", data) if err != nil { return "", fmt.Errorf("failed to execute create_foreign_key template: %w", err) } return buf.String(), nil } // Helper functions to build template data from models // BuildTableTemplateData builds TableTemplateData from a models.Table func BuildTableTemplateData(schema string, table *models.Table) TableTemplateData { // Get sorted columns columns := make([]*models.Column, 0, len(table.Columns)) for _, col := range table.Columns { columns = append(columns, col) } // Find primary key constraint var pk *models.Constraint for _, constraint := range table.Constraints { if constraint.Type == models.PrimaryKeyConstraint { pk = constraint break } } // If no explicit primary key constraint, build one from columns with IsPrimaryKey=true if pk == nil { pkCols := []string{} for _, col := range table.Columns { if col.IsPrimaryKey { pkCols = append(pkCols, col.Name) } } if len(pkCols) > 0 { pk = &models.Constraint{ Name: "pk_" + table.Name, Type: models.PrimaryKeyConstraint, Columns: pkCols, } } } return TableTemplateData{ Schema: schema, Name: table.Name, Columns: columns, PrimaryKey: pk, } }