Files
plumber/internal/store/postgres.go
T
codegirl007 247fb05281 Replace scs postgresstore with a sqlc-backed SessionStore.
Keep scs for cookies and session API while sessions DDL and queries live in the same sqlc stack as the rest of Postgres.
2026-08-22 07:11:47 -07:00

77 lines
1.8 KiB
Go

package store
import (
"database/sql"
"fmt"
"net/url"
"strings"
"time"
_ "github.com/jackc/pgx/v5/stdlib"
)
// applySchema runs semicolon-separated DDL statements.
func applySchema(db *sql.DB, schema string) error {
for _, stmt := range strings.Split(schema, ";") {
stmt = strings.TrimSpace(stmt)
if stmt == "" {
continue
}
if _, err := db.Exec(stmt); err != nil {
return fmt.Errorf("%w: %s", err, stmt)
}
}
return nil
}
// postgresDSN normalizes DATABASE_URL for pgx (sslmode default, strip unsupported params).
func postgresDSN(raw string) (string, error) {
u, err := url.Parse(raw)
if err != nil {
return "", fmt.Errorf("DATABASE_URL: %w", err)
}
switch u.Scheme {
case "postgres", "postgresql":
default:
return "", fmt.Errorf("DATABASE_URL must be a postgres URL")
}
q := u.Query()
if strings.EqualFold(q.Get("sslrootcert"), "system") {
q.Del("sslrootcert")
}
q.Del("sslnegotiation")
if q.Get("sslmode") == "" {
q.Set("sslmode", "verify-full")
}
u.RawQuery = q.Encode()
return u.String(), nil
}
// OpenPostgres connects to Postgres, applies schema/migrations, and starts session cleanup.
func OpenPostgres(databaseURL, schema string) (*sql.DB, *SessionStore, error) {
dsn, err := postgresDSN(databaseURL)
if err != nil {
return nil, nil, err
}
db, err := sql.Open("pgx", dsn)
if err != nil {
return nil, nil, err
}
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(5)
if err := db.Ping(); err != nil {
_ = db.Close()
return nil, nil, fmt.Errorf("postgres ping: %w", err)
}
if err := applySchema(db, schema); err != nil {
_ = db.Close()
return nil, nil, fmt.Errorf("apply schema: %w", err)
}
if err := migrateUserProfileColumns(db); err != nil {
_ = db.Close()
return nil, nil, fmt.Errorf("migrate profile columns: %w", err)
}
sessions := NewSessionStore(db, 5*time.Minute)
return db, sessions, nil
}