225 lines
5.4 KiB
Go
225 lines
5.4 KiB
Go
package dbml
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
|
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
|
)
|
|
|
|
// Writer implements the writers.Writer interface for DBML format
|
|
type Writer struct {
|
|
options *writers.WriterOptions
|
|
}
|
|
|
|
// NewWriter creates a new DBML writer with the given options
|
|
func NewWriter(options *writers.WriterOptions) *Writer {
|
|
return &Writer{
|
|
options: options,
|
|
}
|
|
}
|
|
|
|
// WriteDatabase writes a Database model to DBML format
|
|
func (w *Writer) WriteDatabase(db *models.Database) error {
|
|
content := w.databaseToDBML(db)
|
|
|
|
if w.options.OutputPath != "" {
|
|
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
|
}
|
|
|
|
// If no output path, print to stdout
|
|
fmt.Print(content)
|
|
return nil
|
|
}
|
|
|
|
// WriteSchema writes a Schema model to DBML format
|
|
func (w *Writer) WriteSchema(schema *models.Schema) error {
|
|
content := w.schemaToDBML(schema)
|
|
|
|
if w.options.OutputPath != "" {
|
|
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
|
}
|
|
|
|
fmt.Print(content)
|
|
return nil
|
|
}
|
|
|
|
// WriteTable writes a Table model to DBML format
|
|
func (w *Writer) WriteTable(table *models.Table) error {
|
|
content := w.tableToDBML(table, table.Schema)
|
|
|
|
if w.options.OutputPath != "" {
|
|
return os.WriteFile(w.options.OutputPath, []byte(content), 0644)
|
|
}
|
|
|
|
fmt.Print(content)
|
|
return nil
|
|
}
|
|
|
|
// databaseToDBML converts a Database to DBML format string
|
|
func (w *Writer) databaseToDBML(d *models.Database) string {
|
|
var result string
|
|
|
|
// Add database comment if exists
|
|
if d.Description != "" {
|
|
result += fmt.Sprintf("// %s\n", d.Description)
|
|
}
|
|
if d.Comment != "" {
|
|
result += fmt.Sprintf("// %s\n", d.Comment)
|
|
}
|
|
if d.Description != "" || d.Comment != "" {
|
|
result += "\n"
|
|
}
|
|
|
|
// Process each schema
|
|
for _, schema := range d.Schemas {
|
|
result += w.schemaToDBML(schema)
|
|
}
|
|
|
|
// Add relationships
|
|
result += "\n// Relationships\n"
|
|
for _, schema := range d.Schemas {
|
|
for _, table := range schema.Tables {
|
|
for _, constraint := range table.Constraints {
|
|
if constraint.Type == models.ForeignKeyConstraint {
|
|
result += w.constraintToDBML(constraint, schema.Name, table.Name)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// schemaToDBML converts a Schema to DBML format string
|
|
func (w *Writer) schemaToDBML(schema *models.Schema) string {
|
|
var result string
|
|
|
|
if schema.Description != "" {
|
|
result += fmt.Sprintf("// Schema: %s - %s\n", schema.Name, schema.Description)
|
|
}
|
|
|
|
// Process tables
|
|
for _, table := range schema.Tables {
|
|
result += w.tableToDBML(table, schema.Name)
|
|
result += "\n"
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// tableToDBML converts a Table to DBML format string
|
|
func (w *Writer) tableToDBML(t *models.Table, schemaName string) string {
|
|
var result string
|
|
|
|
// Table definition
|
|
tableName := fmt.Sprintf("%s.%s", schemaName, t.Name)
|
|
result += fmt.Sprintf("Table %s {\n", tableName)
|
|
|
|
// Add columns
|
|
for _, column := range t.Columns {
|
|
result += fmt.Sprintf(" %s %s", column.Name, column.Type)
|
|
|
|
// Add column attributes
|
|
attrs := make([]string, 0)
|
|
if column.IsPrimaryKey {
|
|
attrs = append(attrs, "primary key")
|
|
}
|
|
if column.NotNull && !column.IsPrimaryKey {
|
|
attrs = append(attrs, "not null")
|
|
}
|
|
if column.AutoIncrement {
|
|
attrs = append(attrs, "increment")
|
|
}
|
|
if column.Default != nil {
|
|
attrs = append(attrs, fmt.Sprintf("default: %v", column.Default))
|
|
}
|
|
|
|
if len(attrs) > 0 {
|
|
result += fmt.Sprintf(" [%s]", strings.Join(attrs, ", "))
|
|
}
|
|
|
|
if column.Comment != "" {
|
|
result += fmt.Sprintf(" // %s", column.Comment)
|
|
}
|
|
result += "\n"
|
|
}
|
|
|
|
// Add indexes
|
|
indexCount := 0
|
|
for _, index := range t.Indexes {
|
|
if indexCount == 0 {
|
|
result += "\n indexes {\n"
|
|
}
|
|
indexAttrs := make([]string, 0)
|
|
if index.Unique {
|
|
indexAttrs = append(indexAttrs, "unique")
|
|
}
|
|
if index.Name != "" {
|
|
indexAttrs = append(indexAttrs, fmt.Sprintf("name: '%s'", index.Name))
|
|
}
|
|
if index.Type != "" {
|
|
indexAttrs = append(indexAttrs, fmt.Sprintf("type: %s", index.Type))
|
|
}
|
|
|
|
result += fmt.Sprintf(" (%s)", strings.Join(index.Columns, ", "))
|
|
if len(indexAttrs) > 0 {
|
|
result += fmt.Sprintf(" [%s]", strings.Join(indexAttrs, ", "))
|
|
}
|
|
result += "\n"
|
|
indexCount++
|
|
}
|
|
if indexCount > 0 {
|
|
result += " }\n"
|
|
}
|
|
|
|
// Add table note
|
|
if t.Description != "" || t.Comment != "" {
|
|
note := t.Description
|
|
if note != "" && t.Comment != "" {
|
|
note += " - "
|
|
}
|
|
note += t.Comment
|
|
result += fmt.Sprintf("\n Note: '%s'\n", note)
|
|
}
|
|
|
|
result += "}\n"
|
|
return result
|
|
}
|
|
|
|
// constraintToDBML converts a Constraint to DBML format string
|
|
func (w *Writer) constraintToDBML(c *models.Constraint, schemaName, tableName string) string {
|
|
if c.Type != models.ForeignKeyConstraint || c.ReferencedTable == "" {
|
|
return ""
|
|
}
|
|
|
|
fromTable := fmt.Sprintf("%s.%s", schemaName, tableName)
|
|
toTable := fmt.Sprintf("%s.%s", c.ReferencedSchema, c.ReferencedTable)
|
|
|
|
// Determine relationship cardinality
|
|
// For foreign keys, it's typically many-to-one
|
|
relationship := ">"
|
|
|
|
fromCols := strings.Join(c.Columns, ", ")
|
|
toCols := strings.Join(c.ReferencedColumns, ", ")
|
|
|
|
result := fmt.Sprintf("Ref: %s.(%s) %s %s.(%s)", fromTable, fromCols, relationship, toTable, toCols)
|
|
|
|
// Add actions
|
|
actions := make([]string, 0)
|
|
if c.OnDelete != "" {
|
|
actions = append(actions, fmt.Sprintf("ondelete: %s", c.OnDelete))
|
|
}
|
|
if c.OnUpdate != "" {
|
|
actions = append(actions, fmt.Sprintf("onupdate: %s", c.OnUpdate))
|
|
}
|
|
if len(actions) > 0 {
|
|
result += fmt.Sprintf(" [%s]", strings.Join(actions, ", "))
|
|
}
|
|
|
|
result += "\n"
|
|
return result
|
|
}
|