package postgres import ( "context" "fmt" "net/url" "strings" "gitea.maximumdirect.net/ejr/weatherapi/internal/platform/config" "gitea.maximumdirect.net/ejr/weatherapi/internal/platform/datasource" "github.com/jackc/pgx/v5/pgxpool" ) type Factory struct{} func (Factory) Driver() string { return "postgres" } func (Factory) Open(ctx context.Context, cfg config.DatabaseConfig) (datasource.DataSource, error) { dsn, err := buildDSN(cfg.Params.URI, cfg.Params.Username, cfg.Params.Password) if err != nil { return nil, fmt.Errorf("open postgres datasource %q: %w", cfg.Name, err) } pool, err := pgxpool.New(ctx, dsn) if err != nil { return nil, fmt.Errorf("open postgres datasource %q: %w", cfg.Name, err) } if err := pool.Ping(ctx); err != nil { pool.Close() return nil, fmt.Errorf("open postgres datasource %q: ping: %w", cfg.Name, err) } return &DataSource{pool: pool}, nil } type DataSource struct { pool *pgxpool.Pool } func (d *DataSource) Pool() *pgxpool.Pool { if d == nil { return nil } return d.pool } func (d *DataSource) Close() { if d == nil || d.pool == nil { return } d.pool.Close() } func buildDSN(uri, username, password string) (string, error) { u, err := url.Parse(strings.TrimSpace(uri)) if err != nil { return "", fmt.Errorf("invalid params.uri: %w", err) } if strings.TrimSpace(u.Scheme) == "" { return "", fmt.Errorf("invalid params.uri: missing scheme") } if strings.TrimSpace(u.Host) == "" { return "", fmt.Errorf("invalid params.uri: missing host") } u.User = url.UserPassword(strings.TrimSpace(username), strings.TrimSpace(password)) return u.String(), nil }