Skip to content

Commit 7f0f622

Browse files
committed
Make generated output files optional
1 parent 91aca1d commit 7f0f622

File tree

12 files changed

+1621
-53
lines changed

12 files changed

+1621
-53
lines changed

cmd/generate.go

Lines changed: 80 additions & 51 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-
)
493-
if err != nil {
494-
log.Printf("Failed to export png: %v\n", err)
495-
}
496-
}()
487+
if pngPath := config.GetOutputPath("png"); pngPath != "" {
488+
go func() {
489+
pngErr := internal.PgmodelerExportPNG(
490+
ctx,
491+
dbmPath,
492+
filepath.Join(wd, pngPath),
493+
)
494+
if pngErr != nil {
495+
log.Printf("Failed to export png: %v\n", pngErr)
496+
}
497+
}()
498+
}
499+
500+
if svgPath := config.GetOutputPath("svg"); svgPath != "" {
501+
go func() {
502+
svgErr := internal.PgmodelerExportSVG(
503+
ctx,
504+
dbmPath,
505+
filepath.Join(wd, svgPath),
506+
)
507+
if svgErr != nil {
508+
log.Printf("Failed to export svg: %v\n", svgErr)
509+
}
510+
}()
511+
}
497512

498513
for _, role := range config.Roles {
499514
_, err = targetConn.Exec(ctx, fmt.Sprintf("CREATE ROLE %q WITH LOGIN;", role.Name))
@@ -502,55 +517,69 @@ 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

525+
var output string
526+
510527
if initial {
511528
// If we are developing the schema initially, there will be no diffs,
512529
// and we want to copy over the schema file to the initial migration file
513530
var input []byte
514-
input, err = os.ReadFile(filepath.Join(wd, fmt.Sprintf("%s.sql", config.ModelName)))
531+
input, err = os.ReadFile(tmpSQLPath)
515532
if err != nil {
516533
return "", fmt.Errorf("failed to read sql file: %w", err)
517534
}
535+
output = string(input)
536+
} else {
537+
err = executeMigrateSQL(migrationsDir, migrateConn)
538+
if err != nil {
539+
return "", fmt.Errorf("failed to execute migrate sql: %w", err)
540+
}
518541

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)
525-
}
542+
var statements string
543+
statements, err = internal.Diff(
544+
ctx,
545+
postgresConn,
546+
migrateConn,
547+
targetConn,
548+
)
549+
if err != nil {
550+
return "", fmt.Errorf("failed to diff: %w", err)
551+
}
526552

527-
statements, err := internal.Diff(
528-
ctx,
529-
postgresConn,
530-
migrateConn,
531-
targetConn,
532-
)
533-
if err != nil {
534-
return "", fmt.Errorf("failed to diff: %w", err)
535-
}
553+
var extraStatements string
554+
extraStatements, err = generateMissingPermissionStatements(ctx, tmpDir, statements, targetConn, migrateConn)
555+
if err != nil {
556+
return "", fmt.Errorf("failed to generate missing permission statements: %w", err)
557+
}
536558

537-
extraStatements, err := generateMissingPermissionStatements(ctx, tmpDir, statements, targetConn, migrateConn)
538-
if err != nil {
539-
return "", fmt.Errorf("failed to generate missing permission statements: %w", err)
559+
if statements != "" {
560+
output += statements
561+
}
562+
if statements != "" && extraStatements != "" {
563+
output += "\n\n"
564+
}
565+
if extraStatements != "" {
566+
output += "-- Statements generated automatically, please review:\n" + extraStatements
567+
}
568+
if output != "" {
569+
output += "\n"
570+
}
540571
}
541572

542-
var output string
543-
if statements != "" {
544-
output += statements
545-
}
546-
if statements != "" && extraStatements != "" {
547-
output += "\n\n"
548-
}
549-
if extraStatements != "" {
550-
output += "-- Statements generated automatically, please review:\n" + extraStatements
551-
}
552-
if output != "" {
553-
output += "\n"
573+
// Copy SQL to output path if enabled
574+
if sqlPath := config.GetOutputPath("sql"); sqlPath != "" {
575+
sqlContent, readErr := os.ReadFile(tmpSQLPath)
576+
if readErr != nil {
577+
return "", fmt.Errorf("failed to read sql file: %w", readErr)
578+
}
579+
err = os.WriteFile(filepath.Join(wd, sqlPath), sqlContent, 0o644) //nolint:gosec
580+
if err != nil {
581+
return "", fmt.Errorf("failed to write sql output file: %w", err)
582+
}
554583
}
555584

556585
return output, nil
@@ -569,8 +598,8 @@ func executeMigrateSQL(migrationsDir string, migrateConn *pgx.Conn) error {
569598
return nil
570599
}
571600

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)))
601+
func executeTargetSQL(ctx context.Context, sqlPath string, targetConn *pgx.Conn) error {
602+
targetSQL, err := os.ReadFile(sqlPath)
574603
if err != nil {
575604
return fmt.Errorf("failed to read target sql: %w", err)
576605
}
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/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".
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+
return ""
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: {}

0 commit comments

Comments
 (0)