Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func init() {
Aliases: []string{"-i"},
Description: "Creates the config file in the root directory",
Callback: func(args []string) {
handleInit()
handleInit(args)
},
},
{
Expand Down
73 changes: 54 additions & 19 deletions cli/getConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import (
"log"
"os"
"slices"
"strings"

"gopkg.in/yaml.v3"
)

var LogLevels = []string{
Expand All @@ -17,46 +20,78 @@ var LogLevels = []string{
}

type Config struct {
Database DatabaseConfig `json:"database"`
Schema string `json:"schema"`
Output OutputConfig `json:"output"`
Log []string `json:"log"`
ClientName string `json:"client_name" yaml:"client_name"`
EmbedMigrations *bool `json:"embed_migrations" yaml:"embed_migrations"`
Database DatabaseConfig `json:"database" yaml:"database"`
Schema string `json:"schema" yaml:"schema"`
Output OutputConfig `json:"output" yaml:"output"`
Log []string `json:"log" yaml:"log"`
}

type DatabaseConfig struct {
URLEnv string `json:"url_env"`
DirectURLEnv string `json:"direct_url_env"`
URLEnv string `json:"url_env" yaml:"url_env"`
DirectURLEnv string `json:"direct_url_env" yaml:"direct_url_env"`
}

type OutputConfig struct {
Client string `json:"client"`
Migrations string `json:"migrations"`
Client string `json:"client" yaml:"client"`
Migrations string `json:"migrations" yaml:"migrations"`
}

func GetConfig() *Config {
var config Config
configFile, err := os.ReadFile("phi.json")
var foundFiles []string
candidateFiles := []string{"phi.yml", "phi.yaml", "phi.json"}

for _, f := range candidateFiles {
if _, err := os.Stat(f); err == nil {
foundFiles = append(foundFiles, f)
}
}

if len(foundFiles) > 1 {
log.Fatalf("multiple configuration files found (%s). Please keep only one configuration file in the project directory.", strings.Join(foundFiles, ", "))
return nil
}

if len(foundFiles) == 0 {
log.Fatal("configuration file not found (expected phi.yml, phi.yaml, or phi.json)")
return nil
}

foundFile := foundFiles[0]
configFile, err := os.ReadFile(foundFile)
if err != nil {
log.Fatal("phi.json not found")
log.Fatalf("failed to read %s: %v", foundFile, err)
return nil
}

err = json.Unmarshal(configFile, &config)
var config Config
if strings.HasSuffix(foundFile, ".json") {
err = json.Unmarshal(configFile, &config)
} else {
err = yaml.Unmarshal(configFile, &config)
}

if err != nil {
log.Fatal(err)
log.Fatalf("failed to parse %s: %v", foundFile, err)
return nil
}
// hasAll := false

// Apply default values if omitted
if config.ClientName == "" {
config.ClientName = "phi"
}
if config.EmbedMigrations == nil {
defaultEmbed := true
config.EmbedMigrations = &defaultEmbed
}

for _, l := range config.Log {
if !slices.Contains(LogLevels, l) && l != "all" {
log.Fatalf("invalid log level in phi.json: %q (must be one of: query, info, warn, error, all)", l)
log.Fatalf("invalid log level in %s: %q (must be one of: query, info, warn, error, all)", foundFile, l)
return nil
}
}
// if hasAll && len(config.Log) > 1 {
// log.Fatal("invalid log configuration: 'all' must be the only log level specified")
// return nil
// }

return &config
}
19 changes: 12 additions & 7 deletions cli/handleGenerate.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,21 @@ func handleGenerate() {
return
}

relDir, err := filepath.Rel(config.Output.Client, config.Output.Migrations)
var embedRelDir string
if err == nil && !strings.HasPrefix(relDir, "..") && !filepath.IsAbs(relDir) {
embedRelDir = filepath.ToSlash(filepath.Join(relDir, "*.sql"))
} else {
fmt.Printf("[WARNING]: Migrations directory %q is not a subdirectory of client output directory %q. Go's //go:embed does not support parent directory paths ('..'). Embedded migrations will be disabled.\n",
config.Output.Migrations, config.Output.Client)
if config.EmbedMigrations == nil || *config.EmbedMigrations {
relDir, err := filepath.Rel(config.Output.Client, config.Output.Migrations)
if err == nil && !strings.HasPrefix(relDir, "..") && !filepath.IsAbs(relDir) {
embedRelDir = filepath.ToSlash(filepath.Join(relDir, "*.sql"))
} else {
fmt.Printf("[WARNING]: Migrations directory %q is not a subdirectory of client output directory %q. Go's //go:embed does not support parent directory paths ('..'). Embedded migrations will be disabled.\n",
config.Output.Migrations, config.Output.Client)
}
}

pkgName := filepath.Base(config.Output.Client)
pkgName := config.ClientName
if pkgName == "" {
pkgName = filepath.Base(config.Output.Client)
}
if pkgName == "." || pkgName == "" {
pkgName = "phi"
}
Expand Down
87 changes: 77 additions & 10 deletions cli/handleInit.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,96 @@ package cli
import (
"fmt"
"os"
"path/filepath"
"strings"
)

func handleInit() {
err := os.WriteFile("phi.json", []byte(configFileContent), 0644)
if err != nil {
fmt.Printf("Error writing phi.json: %v\n", err)
func handleInit(args []string) {
format := "yml"
targetDir := "."

if len(args) == 1 {
arg := strings.ToLower(args[0])
if arg == "yml" || arg == "yaml" || arg == "json" {
format = arg
} else {
targetDir = args[0]
}
} else if len(args) >= 2 {
arg0 := strings.ToLower(args[0])
if arg0 == "yml" || arg0 == "yaml" || arg0 == "json" {
format = arg0
targetDir = args[1]
} else {
targetDir = args[0]
}
}

if err := os.MkdirAll(targetDir, 0755); err != nil {
fmt.Printf("Error creating directory %s: %v\n", targetDir, err)
os.Exit(1)
}

filename := "phi." + format
outPath := filepath.Join(targetDir, filename)

var content string
if format == "json" {
content = jsonConfigTemplate
} else {
content = ymlConfigTemplate
}

if err := os.WriteFile(outPath, []byte(strings.TrimSpace(content)+"\n"), 0644); err != nil {
fmt.Printf("Error writing %s: %v\n", outPath, err)
os.Exit(1)
}
fmt.Println("creating phi.json ....")

fmt.Printf("Created configuration file: %s\n", outPath)
}

var configFileContent string = `
var ymlConfigTemplate string = `
# Name of the generated Go client package (default: "phi")
client_name: phi

# Enable Go 1.16+ embedded migrations (//go:embed) inside client
embed_migrations: true

database:
# Environment variable for runtime client database connections
url_env: DATABASE_URL
# Environment variable for migration direct DDL connections
direct_url_env: DATABASE_DIRECT_URL

# Path to your Prisma schema definition file
schema: ./schema.prisma

output:
# Output directory for generated Go client code
client: ./phi
# Output directory for Goose-compatible .sql migration files
migrations: ./phi/migrations

# Logging levels: none, query, warn, error, info, all
log:
- none
`

var jsonConfigTemplate string = `
{
"client_name": "phi",
"embed_migrations": true,
"database": {
"url_env": "DATABASE_URL",
"direct_url_env": "DATABASE_DIRECT_URL"
},

"schema": "./schema.prisma",

"output": {
"client": "./phi",
"migrations": "./phi/migrations"
}
},
"log": [
"none"
]
}
`
`
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/lib/pq v1.12.3
github.com/pressly/goose/v3 v3.27.1
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.49.1
)

Expand All @@ -33,7 +34,6 @@ require (
golang.org/x/sync v0.21.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/text v0.39.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.72.1 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
Expand Down
14 changes: 0 additions & 14 deletions integration/phi.json

This file was deleted.

15 changes: 15 additions & 0 deletions integration/phi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
client_name: phi
embed_migrations: true

database:
url_env: DATABASE_URL
direct_url_env: DATABASE_DIRECT_URL

schema: ./schema.prisma

output:
client: ./phi
migrations: ./phi/migrations

log:
- none
Loading