Address PR review: graceful shutdown, Role/NewUser, drop SQLite.

This commit is contained in:
2026-08-21 23:40:59 -07:00
parent d167b9216a
commit 3391cce7bd
13 changed files with 152 additions and 337 deletions
+10 -33
View File
@@ -11,11 +11,7 @@ import (
_ "github.com/jackc/pgx/v5/stdlib"
)
const (
dialectSQLite = "sqlite"
dialectPostgres = "postgres"
)
// rebind converts ? placeholders to Postgres $1, $2, ... form.
func rebind(query string) string {
n := 0
var b strings.Builder
@@ -31,13 +27,12 @@ func rebind(query string) string {
return b.String()
}
// q rebinds SQL placeholders for Postgres.
func (s *Store) q(query string) string {
if s.dialect == dialectPostgres {
return rebind(query)
}
return query
return rebind(query)
}
// applySchema runs semicolon-separated DDL statements, skipping PRAGMA lines.
func applySchema(db *sql.DB, schema string) error {
for _, stmt := range strings.Split(schema, ";") {
stmt = strings.TrimSpace(stmt)
@@ -55,6 +50,7 @@ func applySchema(db *sql.DB, schema string) error {
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 {
@@ -77,16 +73,8 @@ func postgresDSN(raw string) (string, error) {
return u.String(), nil
}
// OpenPostgres connects to Postgres, applies schema/migrations, and starts session cleanup.
func OpenPostgres(databaseURL, schema string) (*Store, error) {
return openPostgres(databaseURL, schema, 5*time.Minute)
}
// OpenPostgresWithoutSessionCleanup opens Postgres without a session cleanup goroutine (for tests).
func OpenPostgresWithoutSessionCleanup(databaseURL, schema string) (*Store, error) {
return openPostgres(databaseURL, schema, 0)
}
func openPostgres(databaseURL, schema string, sessionCleanup time.Duration) (*Store, error) {
dsn, err := postgresDSN(databaseURL)
if err != nil {
return nil, err
@@ -105,26 +93,15 @@ func openPostgres(databaseURL, schema string, sessionCleanup time.Duration) (*St
_ = db.Close()
return nil, fmt.Errorf("apply schema: %w", err)
}
if err := applySessionsSchema(db, dialectPostgres); err != nil {
if err := applySessionsSchema(db); err != nil {
_ = db.Close()
return nil, fmt.Errorf("apply sessions schema: %w", err)
}
if err := migrateUserProfileColumns(db, dialectPostgres); err != nil {
if err := migrateUserProfileColumns(db); err != nil {
_ = db.Close()
return nil, fmt.Errorf("migrate profile columns: %w", err)
}
st := &Store{db: db, dialect: dialectPostgres}
st.initSessionStore(sessionCleanup)
st := &Store{db: db}
st.initSessionStore(5 * time.Minute)
return st, nil
}
// Connect uses PlanetScale Postgres when DATABASE_URL is set, otherwise SQLite.
func Connect(databaseURL, sqlitePath, schema string) (*Store, error) {
if strings.TrimSpace(databaseURL) != "" {
return OpenPostgres(databaseURL, schema)
}
if sqlitePath == "" {
sqlitePath = "data.db"
}
return Open(sqlitePath, schema)
}