So far so good
This commit is contained in:
250
pkg/writers/gorm/template_data.go
Normal file
250
pkg/writers/gorm/template_data.go
Normal file
@@ -0,0 +1,250 @@
|
||||
package gorm
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
)
|
||||
|
||||
// TemplateData represents the data passed to the template for code generation
|
||||
type TemplateData struct {
|
||||
PackageName string
|
||||
Imports []string
|
||||
Models []*ModelData
|
||||
Config *MethodConfig
|
||||
}
|
||||
|
||||
// ModelData represents a single model/struct in the template
|
||||
type ModelData struct {
|
||||
Name string
|
||||
TableName string // schema.table format
|
||||
SchemaName string
|
||||
TableNameOnly string // just table name without schema
|
||||
Comment string
|
||||
Fields []*FieldData
|
||||
Config *MethodConfig
|
||||
PrimaryKeyField string // Name of the primary key field
|
||||
IDColumnName string // Name of the ID column in database
|
||||
Prefix string // 3-letter prefix
|
||||
}
|
||||
|
||||
// FieldData represents a single field in a struct
|
||||
type FieldData struct {
|
||||
Name string // Go field name (PascalCase)
|
||||
Type string // Go type
|
||||
GormTag string // Complete gorm tag
|
||||
JSONTag string // JSON tag
|
||||
Comment string // Field comment
|
||||
}
|
||||
|
||||
// MethodConfig controls which helper methods to generate
|
||||
type MethodConfig struct {
|
||||
GenerateTableName bool
|
||||
GenerateSchemaName bool
|
||||
GenerateTableNameOnly bool
|
||||
GenerateGetID bool
|
||||
GenerateGetIDStr bool
|
||||
GenerateSetID bool
|
||||
GenerateUpdateID bool
|
||||
GenerateGetIDName bool
|
||||
GenerateGetPrefix bool
|
||||
}
|
||||
|
||||
// DefaultMethodConfig returns a MethodConfig with all methods enabled
|
||||
func DefaultMethodConfig() *MethodConfig {
|
||||
return &MethodConfig{
|
||||
GenerateTableName: true,
|
||||
GenerateSchemaName: true,
|
||||
GenerateTableNameOnly: true,
|
||||
GenerateGetID: true,
|
||||
GenerateGetIDStr: true,
|
||||
GenerateSetID: true,
|
||||
GenerateUpdateID: true,
|
||||
GenerateGetIDName: true,
|
||||
GenerateGetPrefix: true,
|
||||
}
|
||||
}
|
||||
|
||||
// NewTemplateData creates a new TemplateData with the given package name and config
|
||||
func NewTemplateData(packageName string, config *MethodConfig) *TemplateData {
|
||||
if config == nil {
|
||||
config = DefaultMethodConfig()
|
||||
}
|
||||
|
||||
return &TemplateData{
|
||||
PackageName: packageName,
|
||||
Imports: make([]string, 0),
|
||||
Models: make([]*ModelData, 0),
|
||||
Config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// AddModel adds a model to the template data
|
||||
func (td *TemplateData) AddModel(model *ModelData) {
|
||||
model.Config = td.Config
|
||||
td.Models = append(td.Models, model)
|
||||
}
|
||||
|
||||
// AddImport adds an import to the template data (deduplicates automatically)
|
||||
func (td *TemplateData) AddImport(importPath string) {
|
||||
// Check if already exists
|
||||
for _, imp := range td.Imports {
|
||||
if imp == importPath {
|
||||
return
|
||||
}
|
||||
}
|
||||
td.Imports = append(td.Imports, importPath)
|
||||
}
|
||||
|
||||
// FinalizeImports sorts and organizes imports
|
||||
func (td *TemplateData) FinalizeImports() {
|
||||
// Sort imports alphabetically
|
||||
sort.Strings(td.Imports)
|
||||
}
|
||||
|
||||
// NewModelData creates a new ModelData from a models.Table
|
||||
func NewModelData(table *models.Table, schema string, typeMapper *TypeMapper) *ModelData {
|
||||
tableName := table.Name
|
||||
if schema != "" {
|
||||
tableName = schema + "." + table.Name
|
||||
}
|
||||
|
||||
// Generate model name: singularize and convert to PascalCase
|
||||
singularTable := Singularize(table.Name)
|
||||
modelName := SnakeCaseToPascalCase(singularTable)
|
||||
|
||||
// Add "Model" prefix if not already present
|
||||
if !hasModelPrefix(modelName) {
|
||||
modelName = "Model" + modelName
|
||||
}
|
||||
|
||||
model := &ModelData{
|
||||
Name: modelName,
|
||||
TableName: tableName,
|
||||
SchemaName: schema,
|
||||
TableNameOnly: table.Name,
|
||||
Comment: formatComment(table.Description, table.Comment),
|
||||
Fields: make([]*FieldData, 0),
|
||||
Prefix: GeneratePrefix(table.Name),
|
||||
}
|
||||
|
||||
// Find primary key
|
||||
for _, col := range table.Columns {
|
||||
if col.IsPrimaryKey {
|
||||
model.PrimaryKeyField = SnakeCaseToPascalCase(col.Name)
|
||||
model.IDColumnName = col.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Convert columns to fields (sorted by sequence or name)
|
||||
columns := sortColumns(table.Columns)
|
||||
for _, col := range columns {
|
||||
field := columnToField(col, table, typeMapper)
|
||||
model.Fields = append(model.Fields, field)
|
||||
}
|
||||
|
||||
return model
|
||||
}
|
||||
|
||||
// columnToField converts a models.Column to FieldData
|
||||
func columnToField(col *models.Column, table *models.Table, typeMapper *TypeMapper) *FieldData {
|
||||
fieldName := SnakeCaseToPascalCase(col.Name)
|
||||
goType := typeMapper.SQLTypeToGoType(col.Type, col.NotNull)
|
||||
gormTag := typeMapper.BuildGormTag(col, table)
|
||||
jsonTag := col.Name // Use column name for JSON tag
|
||||
|
||||
return &FieldData{
|
||||
Name: fieldName,
|
||||
Type: goType,
|
||||
GormTag: gormTag,
|
||||
JSONTag: jsonTag,
|
||||
Comment: formatComment(col.Description, col.Comment),
|
||||
}
|
||||
}
|
||||
|
||||
// AddRelationshipField adds a relationship field to the model
|
||||
func (md *ModelData) AddRelationshipField(field *FieldData) {
|
||||
md.Fields = append(md.Fields, field)
|
||||
}
|
||||
|
||||
// formatComment combines description and comment into a single comment string
|
||||
func formatComment(description, comment string) string {
|
||||
if description != "" && comment != "" {
|
||||
return description + " - " + comment
|
||||
}
|
||||
if description != "" {
|
||||
return description
|
||||
}
|
||||
return comment
|
||||
}
|
||||
|
||||
// hasModelPrefix checks if a name already has "Model" prefix
|
||||
func hasModelPrefix(name string) bool {
|
||||
return len(name) >= 5 && name[:5] == "Model"
|
||||
}
|
||||
|
||||
// sortColumns sorts columns by sequence, then by name
|
||||
func sortColumns(columns map[string]*models.Column) []*models.Column {
|
||||
result := make([]*models.Column, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
result = append(result, col)
|
||||
}
|
||||
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
// Sort by sequence if both have it
|
||||
if result[i].Sequence > 0 && result[j].Sequence > 0 {
|
||||
return result[i].Sequence < result[j].Sequence
|
||||
}
|
||||
|
||||
// Put primary keys first
|
||||
if result[i].IsPrimaryKey != result[j].IsPrimaryKey {
|
||||
return result[i].IsPrimaryKey
|
||||
}
|
||||
|
||||
// Otherwise sort alphabetically
|
||||
return result[i].Name < result[j].Name
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// LoadMethodConfigFromMetadata loads method configuration from metadata map
|
||||
func LoadMethodConfigFromMetadata(metadata map[string]interface{}) *MethodConfig {
|
||||
config := DefaultMethodConfig()
|
||||
|
||||
if metadata == nil {
|
||||
return config
|
||||
}
|
||||
|
||||
// Load each setting from metadata if present
|
||||
if val, ok := metadata["generate_table_name"].(bool); ok {
|
||||
config.GenerateTableName = val
|
||||
}
|
||||
if val, ok := metadata["generate_schema_name"].(bool); ok {
|
||||
config.GenerateSchemaName = val
|
||||
}
|
||||
if val, ok := metadata["generate_table_name_only"].(bool); ok {
|
||||
config.GenerateTableNameOnly = val
|
||||
}
|
||||
if val, ok := metadata["generate_get_id"].(bool); ok {
|
||||
config.GenerateGetID = val
|
||||
}
|
||||
if val, ok := metadata["generate_get_id_str"].(bool); ok {
|
||||
config.GenerateGetIDStr = val
|
||||
}
|
||||
if val, ok := metadata["generate_set_id"].(bool); ok {
|
||||
config.GenerateSetID = val
|
||||
}
|
||||
if val, ok := metadata["generate_update_id"].(bool); ok {
|
||||
config.GenerateUpdateID = val
|
||||
}
|
||||
if val, ok := metadata["generate_get_id_name"].(bool); ok {
|
||||
config.GenerateGetIDName = val
|
||||
}
|
||||
if val, ok := metadata["generate_get_prefix"].(bool); ok {
|
||||
config.GenerateGetPrefix = val
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
Reference in New Issue
Block a user