2019-07-27 10:40:30 +02:00
|
|
|
package postgres
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"database/sql"
|
|
|
|
|
"fmt"
|
2021-09-24 02:49:41 -07:00
|
|
|
"net/url"
|
2024-11-26 15:40:34 +06:00
|
|
|
"path/filepath"
|
2021-08-30 15:09:09 +03:00
|
|
|
"strconv"
|
|
|
|
|
|
2021-07-27 17:39:21 +02:00
|
|
|
"github.com/go-jet/jet/v2/generator/metadata"
|
|
|
|
|
"github.com/go-jet/jet/v2/generator/template"
|
2020-06-27 18:48:19 +02:00
|
|
|
"github.com/go-jet/jet/v2/postgres"
|
2019-07-27 10:40:30 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// DBConnection contains postgres connection details
|
|
|
|
|
type DBConnection struct {
|
2026-02-16 13:04:00 +01:00
|
|
|
Host string
|
|
|
|
|
Port int
|
|
|
|
|
User string
|
|
|
|
|
// #nosec G117 -- password is used only for the local development
|
2019-07-27 10:40:30 +02:00
|
|
|
Password string
|
|
|
|
|
SslMode string
|
|
|
|
|
Params string
|
|
|
|
|
|
|
|
|
|
DBName string
|
|
|
|
|
SchemaName string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate generates jet files at destination dir from database connection details
|
2021-07-27 17:39:21 +02:00
|
|
|
func Generate(destDir string, dbConn DBConnection, genTemplate ...template.Template) (err error) {
|
2021-10-04 10:46:46 +02:00
|
|
|
dsn := fmt.Sprintf("postgresql://%s:%s@%s:%s/%s?sslmode=%s",
|
2021-10-22 18:08:05 +02:00
|
|
|
url.PathEscape(dbConn.User),
|
|
|
|
|
url.PathEscape(dbConn.Password),
|
2021-10-04 10:46:46 +02:00
|
|
|
dbConn.Host,
|
|
|
|
|
strconv.Itoa(dbConn.Port),
|
2021-10-22 18:08:05 +02:00
|
|
|
url.PathEscape(dbConn.DBName),
|
2021-10-04 10:46:46 +02:00
|
|
|
dbConn.SslMode,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return GenerateDSN(dsn, dbConn.SchemaName, destDir, genTemplate...)
|
2021-08-30 15:09:09 +03:00
|
|
|
}
|
2021-07-27 17:39:21 +02:00
|
|
|
|
2021-10-04 10:46:46 +02:00
|
|
|
// GenerateDSN generates jet files using dsn connection string
|
2023-07-21 13:20:44 +02:00
|
|
|
func GenerateDSN(dsn, schema, destDir string, templates ...template.Template) error {
|
2026-03-23 10:41:10 -03:00
|
|
|
_, err := url.Parse(dsn)
|
2023-07-21 13:20:44 +02:00
|
|
|
if err != nil {
|
2026-03-23 10:41:10 -03:00
|
|
|
return fmt.Errorf("failed to parse as DSN: %w", err)
|
2023-07-21 13:20:44 +02:00
|
|
|
}
|
2026-03-23 10:41:10 -03:00
|
|
|
|
2023-07-21 13:20:44 +02:00
|
|
|
db, err := openConnection(dsn)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("failed to open db connection: %w", err)
|
2021-08-30 15:09:09 +03:00
|
|
|
}
|
2023-07-21 14:11:31 +02:00
|
|
|
defer db.Close()
|
2021-07-27 17:39:21 +02:00
|
|
|
|
2026-03-23 10:41:10 -03:00
|
|
|
var dbName string
|
|
|
|
|
err = db.QueryRow("SELECT current_database()").Scan(&dbName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("failed to get current database name: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if dbName == "" {
|
|
|
|
|
return fmt.Errorf("database name is required")
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-04 10:46:46 +02:00
|
|
|
fmt.Println("Retrieving schema information...")
|
2026-03-23 10:41:10 -03:00
|
|
|
return GenerateDB(db, schema, filepath.Join(destDir, dbName), templates...)
|
2025-01-17 14:49:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GenerateDB generates jet files using the provided *sql.DB
|
2025-01-21 14:06:34 -05:00
|
|
|
func GenerateDB(db *sql.DB, schema, destDir string, templates ...template.Template) error {
|
2021-10-04 10:46:46 +02:00
|
|
|
generatorTemplate := template.Default(postgres.Dialect)
|
|
|
|
|
if len(templates) > 0 {
|
|
|
|
|
generatorTemplate = templates[0]
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-21 13:20:44 +02:00
|
|
|
schemaMetadata, err := metadata.GetSchema(db, &postgresQuerySet{}, schema)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("failed to get '%s' schema metadata: %w", schema, err)
|
|
|
|
|
}
|
2021-10-04 10:46:46 +02:00
|
|
|
|
2025-01-21 14:06:34 -05:00
|
|
|
err = template.ProcessSchema(destDir, schemaMetadata, generatorTemplate)
|
2023-07-21 13:20:44 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("failed to generate schema %s: %d", schemaMetadata.Name, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
2019-07-27 10:40:30 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-21 13:20:44 +02:00
|
|
|
func openConnection(dsn string) (*sql.DB, error) {
|
2023-03-28 13:16:57 +02:00
|
|
|
fmt.Println("Connecting to postgres database...")
|
2019-07-27 10:40:30 +02:00
|
|
|
|
2021-08-30 15:09:09 +03:00
|
|
|
db, err := sql.Open("postgres", dsn)
|
2023-07-21 13:20:44 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to open db connection: %w", err)
|
|
|
|
|
}
|
2019-07-27 10:40:30 +02:00
|
|
|
|
|
|
|
|
err = db.Ping()
|
2023-07-21 13:20:44 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to ping database: %w", err)
|
|
|
|
|
}
|
2019-07-27 10:40:30 +02:00
|
|
|
|
2023-07-21 13:20:44 +02:00
|
|
|
return db, nil
|
2019-07-27 10:40:30 +02:00
|
|
|
}
|