First working version

This commit is contained in:
Eden Kirin
2025-10-31 14:36:41 +01:00
parent f8edfc0fc1
commit f9f67b6c93
22 changed files with 2277 additions and 0 deletions

240
cmd/entity-maker/main.go Normal file
View File

@ -0,0 +1,240 @@
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"github.com/entity-maker/entity-maker/internal/config"
"github.com/entity-maker/entity-maker/internal/database"
"github.com/entity-maker/entity-maker/internal/generator"
"github.com/entity-maker/entity-maker/internal/naming"
"github.com/entity-maker/entity-maker/internal/prompt"
"github.com/fatih/color"
)
func main() {
if err := run(); err != nil {
prompt.PrintError(err.Error())
os.Exit(1)
}
}
func run() error {
// Parse command line flags
var (
dbHost = flag.String("host", "", "Database host")
dbPort = flag.Int("port", 0, "Database port")
dbName = flag.String("db", "", "Database name")
dbSchema = flag.String("schema", "", "Database schema")
dbUser = flag.String("user", "", "Database user")
dbPassword = flag.String("password", "", "Database password")
dbTable = flag.String("table", "", "Database table name")
outputDir = flag.String("output", "", "Output directory")
entityName = flag.String("entity", "", "Entity name override")
)
flag.Parse()
// Print header
header := color.New(color.FgCyan, color.Bold)
header.Println("\n╔════════════════════════════════════════╗")
header.Println("║ Entity Maker for TelevendCore ║")
header.Println("╚════════════════════════════════════════╝")
// Load configuration
cfg, err := config.Load()
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
// Prompt for parameters
prompt.PrintHeader("Database Connection")
// Override config with command line flags if provided
if *dbHost != "" {
cfg.DBHost = *dbHost
}
if *dbPort != 0 {
cfg.DBPort = *dbPort
}
if *dbName != "" {
cfg.DBName = *dbName
}
if *dbSchema != "" {
cfg.DBSchema = *dbSchema
}
if *dbUser != "" {
cfg.DBUser = *dbUser
}
if *dbPassword != "" {
cfg.DBPassword = *dbPassword
}
if *dbTable != "" {
cfg.DBTable = *dbTable
}
if *outputDir != "" {
cfg.OutputDir = *outputDir
}
if *entityName != "" {
cfg.EntityName = *entityName
}
// Prompt for missing parameters
cfg.DBHost, err = prompt.PromptString("Database host", cfg.DBHost, false)
if err != nil {
return err
}
cfg.DBPort, err = prompt.PromptInt("Database port", cfg.DBPort, false)
if err != nil {
return err
}
cfg.DBName, err = prompt.PromptString("Database name", cfg.DBName, true)
if err != nil {
return err
}
cfg.DBSchema, err = prompt.PromptString("Database schema", cfg.DBSchema, false)
if err != nil {
return err
}
cfg.DBUser, err = prompt.PromptString("Database user", cfg.DBUser, false)
if err != nil {
return err
}
cfg.DBPassword, err = prompt.PromptString("Database password", cfg.DBPassword, false)
if err != nil {
return err
}
cfg.DBTable, err = prompt.PromptString("Table name", cfg.DBTable, true)
if err != nil {
return err
}
cfg.OutputDir, err = prompt.PromptDirectory("Output directory", cfg.OutputDir, true)
if err != nil {
return err
}
cfg.EntityName, err = prompt.PromptString("Entity name (optional)", cfg.EntityName, false)
if err != nil {
return err
}
// Save configuration
if err := cfg.Save(); err != nil {
prompt.PrintError(fmt.Sprintf("Failed to save config: %v", err))
// Don't fail, just warn
} else {
prompt.PrintSuccess("Configuration saved")
}
// Connect to database
prompt.PrintHeader("Connecting to Database")
dbClient, err := database.NewClient(database.Config{
Host: cfg.DBHost,
Port: cfg.DBPort,
Database: cfg.DBName,
Schema: cfg.DBSchema,
User: cfg.DBUser,
Password: cfg.DBPassword,
})
if err != nil {
return fmt.Errorf("database connection failed: %w", err)
}
defer dbClient.Close()
prompt.PrintSuccess(fmt.Sprintf("Connected to %s@%s:%d/%s", cfg.DBUser, cfg.DBHost, cfg.DBPort, cfg.DBName))
// Check if table exists
exists, err := dbClient.TableExists(cfg.DBTable)
if err != nil {
return fmt.Errorf("failed to check table existence: %w", err)
}
if !exists {
return fmt.Errorf("table '%s' does not exist in schema '%s'", cfg.DBTable, cfg.DBSchema)
}
prompt.PrintSuccess(fmt.Sprintf("Found table '%s'", cfg.DBTable))
// Introspect table
prompt.PrintHeader("Introspecting Table")
tableInfo, err := dbClient.IntrospectTable(cfg.DBTable)
if err != nil {
return fmt.Errorf("failed to introspect table: %w", err)
}
prompt.PrintSuccess(fmt.Sprintf("Found %d columns", len(tableInfo.Columns)))
prompt.PrintSuccess(fmt.Sprintf("Found %d foreign keys", len(tableInfo.ForeignKeys)))
prompt.PrintSuccess(fmt.Sprintf("Found %d enum types", len(tableInfo.EnumTypes)))
// Create generation context
ctx := generator.NewContext(tableInfo, cfg.EntityName)
// Create output directory
moduleName := naming.SingularizeTableName(cfg.DBTable)
moduleDir := filepath.Join(cfg.OutputDir, moduleName)
if err := os.MkdirAll(moduleDir, 0755); err != nil {
return fmt.Errorf("failed to create output directory: %w", err)
}
prompt.PrintSuccess(fmt.Sprintf("Created directory: %s", moduleDir))
// Generate files
prompt.PrintHeader("Generating Files")
files := map[string]func(*generator.Context) (string, error){
"table.py": generator.GenerateTable,
"model.py": generator.GenerateModel,
"filter.py": generator.GenerateFilter,
"load_options.py": generator.GenerateLoadOptions,
"repository.py": generator.GenerateRepository,
"manager.py": generator.GenerateManager,
"factory.py": generator.GenerateFactory,
"mapper.py": generator.GenerateMapper,
"__init__.py": generator.GenerateInit,
}
// Add enum.py if there are enum types
if len(tableInfo.EnumTypes) > 0 {
files["enum.py"] = generator.GenerateEnum
}
// Generate and write each file
for filename, genFunc := range files {
content, err := genFunc(ctx)
if err != nil {
return fmt.Errorf("failed to generate %s: %w", filename, err)
}
filePath := filepath.Join(moduleDir, filename)
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
return fmt.Errorf("failed to write %s: %w", filename, err)
}
prompt.PrintSuccess(fmt.Sprintf("Generated %s", filename))
}
// Print summary
prompt.PrintHeader("Summary")
fmt.Printf("\n")
fmt.Printf(" Entity name: %s\n", color.GreenString(ctx.EntityName))
fmt.Printf(" Module name: %s\n", color.GreenString(ctx.ModuleName))
fmt.Printf(" Output dir: %s\n", color.GreenString(moduleDir))
fmt.Printf(" Files: %s\n", color.GreenString("%d files generated", len(files)))
fmt.Printf("\n")
success := color.New(color.FgGreen, color.Bold)
success.Println("✓ Code generation completed successfully!")
fmt.Println()
return nil
}