Skip to content

Commit 6b4904e

Browse files
committed
Make generated output files optional
1 parent 91aca1d commit 6b4904e

File tree

14 files changed

+1577
-51
lines changed

14 files changed

+1577
-51
lines changed

cmd/generate.go

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ var (
461461
modelContent = ""
462462
)
463463

464-
//nolint:cyclop
464+
//nolint:cyclop,gocognit
465465
func generateMigrationStatements(
466466
ctx context.Context,
467467
config *configuration.Config,
@@ -475,25 +475,40 @@ func generateMigrationStatements(
475475
) (string, error) {
476476
log.Println("Generating migration statements")
477477

478-
err := internal.PgModelerExportToFile(
479-
ctx,
480-
filepath.Join(wd, fmt.Sprintf("%s.dbm", config.ModelName)),
481-
filepath.Join(wd, fmt.Sprintf("%s.sql", config.ModelName)),
482-
)
478+
dbmPath := filepath.Join(wd, fmt.Sprintf("%s.dbm", config.ModelName))
479+
// Generate SQL file in tmpDir for internal use during migration generation
480+
tmpSQLPath := filepath.Join(tmpDir, fmt.Sprintf("%s.sql", config.ModelName))
481+
482+
err := internal.PgmodelerExportSQL(ctx, dbmPath, tmpSQLPath)
483483
if err != nil {
484484
return "", fmt.Errorf("failed to export model: %w", err)
485485
}
486486

487-
go func() {
488-
err = internal.PgModelerExportToPng(
489-
ctx,
490-
filepath.Join(wd, fmt.Sprintf("%s.dbm", config.ModelName)),
491-
filepath.Join(wd, fmt.Sprintf("%s.png", config.ModelName)),
492-
)
487+
// Copy SQL to output path if enabled
488+
if sqlPath := config.GetOutputPath("sql"); sqlPath != "" {
489+
sqlContent, readErr := os.ReadFile(tmpSQLPath)
490+
if readErr != nil {
491+
return "", fmt.Errorf("failed to read sql file: %w", readErr)
492+
}
493+
err = os.WriteFile(filepath.Join(wd, sqlPath), sqlContent, 0o644) //nolint:gosec
494+
if err != nil {
495+
return "", fmt.Errorf("failed to write sql output file: %w", err)
496+
}
497+
}
498+
499+
if pngPath := config.GetOutputPath("png"); pngPath != "" {
500+
err = internal.PgmodelerExportPNG(ctx, dbmPath, filepath.Join(wd, pngPath))
493501
if err != nil {
494502
log.Printf("Failed to export png: %v\n", err)
495503
}
496-
}()
504+
}
505+
506+
if svgPath := config.GetOutputPath("svg"); svgPath != "" {
507+
err = internal.PgmodelerExportSVG(ctx, dbmPath, filepath.Join(wd, svgPath))
508+
if err != nil {
509+
log.Printf("Failed to export svg: %v\n", err)
510+
}
511+
}
497512

498513
for _, role := range config.Roles {
499514
_, err = targetConn.Exec(ctx, fmt.Sprintf("CREATE ROLE %q WITH LOGIN;", role.Name))
@@ -502,28 +517,20 @@ func generateMigrationStatements(
502517
}
503518
}
504519

505-
err = executeTargetSQL(ctx, config, wd, targetConn)
520+
err = executeTargetSQL(ctx, tmpSQLPath, targetConn)
506521
if err != nil {
507522
return "", fmt.Errorf("failed to execute target sql: %w", err)
508523
}
509524

510-
if initial {
511-
// If we are developing the schema initially, there will be no diffs,
512-
// and we want to copy over the schema file to the initial migration file
513-
var input []byte
514-
input, err = os.ReadFile(filepath.Join(wd, fmt.Sprintf("%s.sql", config.ModelName)))
525+
// Apply existing migrations to the migrate database (skip if no migrations exist yet)
526+
if !initial {
527+
err = executeMigrateSQL(migrationsDir, migrateConn)
515528
if err != nil {
516-
return "", fmt.Errorf("failed to read sql file: %w", err)
529+
return "", fmt.Errorf("failed to execute migrate sql: %w", err)
517530
}
518-
519-
return string(input), nil
520-
}
521-
522-
err = executeMigrateSQL(migrationsDir, migrateConn)
523-
if err != nil {
524-
return "", fmt.Errorf("failed to execute migrate sql: %w", err)
525531
}
526532

533+
// Generate diff between migrate database (with existing migrations) and target database (with full schema)
527534
statements, err := internal.Diff(
528535
ctx,
529536
postgresConn,
@@ -569,8 +576,8 @@ func executeMigrateSQL(migrationsDir string, migrateConn *pgx.Conn) error {
569576
return nil
570577
}
571578

572-
func executeTargetSQL(ctx context.Context, config *configuration.Config, wd string, targetConn *pgx.Conn) error {
573-
targetSQL, err := os.ReadFile(filepath.Join(wd, fmt.Sprintf("%s.sql", config.ModelName)))
579+
func executeTargetSQL(ctx context.Context, sqlPath string, targetConn *pgx.Conn) error {
580+
targetSQL, err := os.ReadFile(sqlPath)
574581
if err != nil {
575582
return fmt.Errorf("failed to read target sql: %w", err)
576583
}
File renamed without changes.

example/foo.gen.svg

Lines changed: 52 additions & 0 deletions
Loading

example/foo.png

-107 Bytes
Binary file not shown.

example/migrations/001_init.up.sql

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +0,0 @@
1-
-- ** Database generated with pgModeler (PostgreSQL Database Modeler).
2-
-- ** pgModeler version: 1.2.2
3-
-- ** PostgreSQL version: 18.0
4-
-- ** Project Site: pgmodeler.io
5-
-- ** Model Author: ---
6-
7-
SET search_path TO pg_catalog,public;
8-
-- ddl-end --
9-
10-

example/trek.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ db_name: bar
33
roles:
44
- name: alice
55
- name: bob
6+
output:
7+
sql: {}
8+
svg: {}

internal/configuration/config.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ type Config struct {
2424
//nolint:tagliatelle
2525
Roles []Role `yaml:"roles"`
2626
Templates []Template `yaml:"templates"`
27+
Output *Output `yaml:"output"`
2728
}
29+
2830
type Role struct {
2931
Name string `yaml:"name"`
3032
}
@@ -34,6 +36,16 @@ type Template struct {
3436
Content string `yaml:"content"`
3537
}
3638

39+
type OutputFile struct {
40+
Path string `yaml:"path"`
41+
}
42+
43+
type Output struct {
44+
SQL *OutputFile `yaml:"sql"`
45+
PNG *OutputFile `yaml:"png"`
46+
SVG *OutputFile `yaml:"svg"`
47+
}
48+
3749
func ReadConfig(wd string) (*Config, error) {
3850
var config *Config
3951
file, err := os.ReadFile(filepath.Join(wd, "trek.yaml"))
@@ -85,6 +97,38 @@ func (c *Config) validate() (problems []string) {
8597
return problems
8698
}
8799

100+
// GetOutputPath returns the output path for the given type if enabled, or empty string if not.
101+
// The outputType must be one of: "sql", "png", "svg". Panics if an invalid outputType is provided.
102+
func (c *Config) GetOutputPath(outputType string) string {
103+
if c.Output == nil {
104+
return ""
105+
}
106+
107+
var outputFile *OutputFile
108+
109+
switch outputType {
110+
case "sql":
111+
outputFile = c.Output.SQL
112+
case "png":
113+
outputFile = c.Output.PNG
114+
case "svg":
115+
outputFile = c.Output.SVG
116+
default:
117+
panic(fmt.Sprintf("invalid output type: %q", outputType))
118+
}
119+
120+
if outputFile == nil {
121+
return ""
122+
}
123+
124+
if outputFile.Path != "" {
125+
return outputFile.Path
126+
}
127+
128+
// Default path: {model_name}.gen.{ext}
129+
return fmt.Sprintf("%s.gen.%s", c.ModelName, outputType)
130+
}
131+
88132
func ValidateIdentifier(identifier string) bool {
89133
return regexpValidIdentifier.MatchString(identifier)
90134
}

internal/pgmodeler.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"os/exec"
88
)
99

10-
func PgModelerExportToFile(ctx context.Context, input, output string) error {
10+
func PgmodelerExportSQL(ctx context.Context, input, output string) error {
1111
//nolint:gosec
1212
err := os.WriteFile(output, []byte{}, 0o644)
1313
if err != nil {
@@ -35,7 +35,7 @@ func PgModelerExportToFile(ctx context.Context, input, output string) error {
3535
return nil
3636
}
3737

38-
func PgModelerExportToPng(ctx context.Context, input, output string) error {
38+
func PgmodelerExportPNG(ctx context.Context, input, output string) error {
3939
//nolint:gosec
4040
err := os.WriteFile(output, []byte{}, 0o644)
4141
if err != nil {
@@ -60,3 +60,29 @@ func PgModelerExportToPng(ctx context.Context, input, output string) error {
6060

6161
return nil
6262
}
63+
64+
func PgmodelerExportSVG(ctx context.Context, input, output string) error {
65+
//nolint:gosec
66+
err := os.WriteFile(output, []byte{}, 0o644)
67+
if err != nil {
68+
return fmt.Errorf("failed to create output svg: %w", err)
69+
}
70+
//nolint:gosec
71+
cmdPgModeler := exec.CommandContext(
72+
ctx,
73+
"pgmodeler-cli",
74+
"--input",
75+
input,
76+
"--export-to-svg",
77+
"--output",
78+
output,
79+
)
80+
cmdPgModeler.Stderr = os.Stderr
81+
82+
out, err := cmdPgModeler.Output()
83+
if err != nil {
84+
return fmt.Errorf("failed to run pgmodeler: %w %s", err, string(out))
85+
}
86+
87+
return nil
88+
}

internal/templates/trek.yaml.tmpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ model_name: {{.model_name}}
22
db_name: {{.db_name}}
33
roles:{{range .roleNames}}
44
- name: {{.}}{{end}}
5+
output:
6+
sql: {}
7+
svg: {}
Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +0,0 @@
1-
-- ** Database generated with pgModeler (PostgreSQL Database Modeler).
2-
-- ** pgModeler version: 1.2.2
3-
-- ** PostgreSQL version: 18.0
4-
-- ** Project Site: pgmodeler.io
5-
-- ** Model Author: ---
6-
7-
SET search_path TO pg_catalog,public;
8-
-- ddl-end --
9-
10-

0 commit comments

Comments
 (0)