Skip to content

Commit 3deb338

Browse files
authored
Merge pull request #46 from printeers/configurable-output-files
Make generated output files optional
2 parents a0b9cf1 + 98fc879 commit 3deb338

File tree

14 files changed

+1579
-52
lines changed

14 files changed

+1579
-52
lines changed

cmd/generate.go

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ var (
487487
modelContent = ""
488488
)
489489

490-
//nolint:cyclop
490+
//nolint:cyclop,gocognit
491491
func generateMigrationStatements(
492492
ctx context.Context,
493493
config *configuration.Config,
@@ -501,25 +501,41 @@ func generateMigrationStatements(
501501
) (string, error) {
502502
log.Println("Generating migration statements")
503503

504-
err := internal.PgModelerExportToFile(
505-
ctx,
506-
filepath.Join(wd, fmt.Sprintf("%s.dbm", config.ModelName)),
507-
filepath.Join(wd, fmt.Sprintf("%s.sql", config.ModelName)),
508-
)
504+
dbmPath := filepath.Join(wd, fmt.Sprintf("%s.dbm", config.ModelName))
505+
// Generate SQL file in tmpDir for internal use during migration generation
506+
tmpSQLPath := filepath.Join(tmpDir, fmt.Sprintf("%s.sql", config.ModelName))
507+
508+
err := internal.PgmodelerExportSQL(ctx, dbmPath, tmpSQLPath)
509509
if err != nil {
510510
return "", fmt.Errorf("failed to export model: %w", err)
511511
}
512512

513-
go func() {
514-
err = internal.PgModelerExportToPng(
515-
ctx,
516-
filepath.Join(wd, fmt.Sprintf("%s.dbm", config.ModelName)),
517-
filepath.Join(wd, fmt.Sprintf("%s.png", config.ModelName)),
518-
)
513+
// Copy SQL to output path if enabled
514+
if sqlPath := config.GetOutputPath("sql"); sqlPath != "" {
515+
var sqlContent []byte
516+
sqlContent, err = os.ReadFile(tmpSQLPath)
517+
if err != nil {
518+
return "", fmt.Errorf("failed to read sql file: %w", err)
519+
}
520+
err = os.WriteFile(filepath.Join(wd, sqlPath), sqlContent, 0o644) //nolint:gosec
521+
if err != nil {
522+
return "", fmt.Errorf("failed to write sql output file: %w", err)
523+
}
524+
}
525+
526+
if pngPath := config.GetOutputPath("png"); pngPath != "" {
527+
err = internal.PgmodelerExportPNG(ctx, dbmPath, filepath.Join(wd, pngPath))
528+
if err != nil {
529+
return "", fmt.Errorf("failed to export png: %w", err)
530+
}
531+
}
532+
533+
if svgPath := config.GetOutputPath("svg"); svgPath != "" {
534+
err = internal.PgmodelerExportSVG(ctx, dbmPath, filepath.Join(wd, svgPath))
519535
if err != nil {
520-
log.Printf("Failed to export png: %v\n", err)
536+
return "", fmt.Errorf("failed to export svg: %w", err)
521537
}
522-
}()
538+
}
523539

524540
for _, role := range config.Roles {
525541
_, err = targetConn.Exec(ctx, fmt.Sprintf("CREATE ROLE %q WITH LOGIN;", role.Name))
@@ -528,28 +544,20 @@ func generateMigrationStatements(
528544
}
529545
}
530546

531-
err = executeTargetSQL(ctx, config, wd, targetConn)
547+
err = executeTargetSQL(ctx, tmpSQLPath, targetConn)
532548
if err != nil {
533549
return "", fmt.Errorf("failed to execute target sql: %w", err)
534550
}
535551

536-
if initial {
537-
// If we are developing the schema initially, there will be no diffs,
538-
// and we want to copy over the schema file to the initial migration file
539-
var input []byte
540-
input, err = os.ReadFile(filepath.Join(wd, fmt.Sprintf("%s.sql", config.ModelName)))
552+
// Apply existing migrations to the migrate database (skip if no migrations exist yet)
553+
if !initial {
554+
err = executeMigrateSQL(migrationsDir, migrateConn)
541555
if err != nil {
542-
return "", fmt.Errorf("failed to read sql file: %w", err)
556+
return "", fmt.Errorf("failed to execute migrate sql: %w", err)
543557
}
544-
545-
return string(input), nil
546-
}
547-
548-
err = executeMigrateSQL(migrationsDir, migrateConn)
549-
if err != nil {
550-
return "", fmt.Errorf("failed to execute migrate sql: %w", err)
551558
}
552559

560+
// Generate diff between migrate database (with existing migrations) and target database (with full schema)
553561
statements, err := internal.Diff(
554562
ctx,
555563
postgresConn,
@@ -595,8 +603,8 @@ func executeMigrateSQL(migrationsDir string, migrateConn *pgx.Conn) error {
595603
return nil
596604
}
597605

598-
func executeTargetSQL(ctx context.Context, config *configuration.Config, wd string, targetConn *pgx.Conn) error {
599-
targetSQL, err := os.ReadFile(filepath.Join(wd, fmt.Sprintf("%s.sql", config.ModelName)))
606+
func executeTargetSQL(ctx context.Context, sqlPath string, targetConn *pgx.Conn) error {
607+
targetSQL, err := os.ReadFile(sqlPath)
600608
if err != nil {
601609
return fmt.Errorf("failed to read target sql: %w", err)
602610
}
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)