Replace Postgres with SQLite
Ten members and a handful of songs a week never needed a database server,
and the server was the last thing making this a two-container deployment.
modernc.org/sqlite is pure Go, so CGO_ENABLED=0 survives and the dependency
count is unchanged: pgx out, sqlite in.
The port stayed small because the driver matches $1-style placeholders
against argument ordinals exactly as pgx does, so no query needed rewriting
for parameters. What did change:
- timestamptz becomes timestamp holding UTC 'YYYY-MM-DD HH:MM:SS'. The
declared type is what makes the driver return time.Time, and the
fixed-width UTC string is what makes ordering and comparison against
datetime('now') mean what they say.
- interval has no equivalent: sessions.idle_ttl is seconds, and the review
edit window travels as a SQLite date modifier string.
- No stddev_pop, so the divisive and unified boards spell the population
formula out, guarded with max(0.0, ...) because cancellation returns a
tiny negative when every score is identical.
- foreign_keys is off by default, so the cascades only exist because the
pragma is set on every connection.
Drops the postgres service, its healthcheck, the depends_on gate, the
startup retry loop and POSTGRES_PASSWORD. ./storage is now the whole
backup. Tests get a fresh database file per test and run everywhere
instead of skipping without TEST_DATABASE_URL.
This commit is contained in:
@@ -41,12 +41,12 @@ func (a *app) adminDashboard(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Unused invites are the ones with a job to do; spent ones are counted, not listed. Truncating
|
||||
// a list silently reads as "that's all of them".
|
||||
if err := a.pool.QueryRow(r.Context(),
|
||||
`select count(*)::int from invites where not is_valid`).Scan(&d.SpentCount); err != nil {
|
||||
if err := a.db.QueryRowContext(r.Context(),
|
||||
`select count(*) from invites where not is_valid`).Scan(&d.SpentCount); err != nil {
|
||||
adminError(w, "invites", err)
|
||||
return
|
||||
}
|
||||
rows, err := a.pool.Query(r.Context(),
|
||||
rows, err := a.db.QueryContext(r.Context(),
|
||||
`select id, code, is_valid, created_at from invites where is_valid order by created_at desc`)
|
||||
if err != nil {
|
||||
adminError(w, "invites", err)
|
||||
@@ -67,7 +67,7 @@ func (a *app) adminDashboard(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
rows, err = a.pool.Query(r.Context(),
|
||||
rows, err = a.db.QueryContext(r.Context(),
|
||||
`select id, name, email, banned, created_at from users order by created_at`)
|
||||
if err != nil {
|
||||
adminError(w, "users", err)
|
||||
@@ -91,8 +91,8 @@ func (a *app) adminDashboard(w http.ResponseWriter, r *http.Request) {
|
||||
adminError(w, "songs", err)
|
||||
return
|
||||
}
|
||||
if err := a.pool.QueryRow(r.Context(),
|
||||
`select count(*)::int from reports where resolved_at is null`).Scan(&d.OpenCount); err != nil {
|
||||
if err := a.db.QueryRowContext(r.Context(),
|
||||
`select count(*) from reports where resolved_at is null`).Scan(&d.OpenCount); err != nil {
|
||||
adminError(w, "reports", err)
|
||||
return
|
||||
}
|
||||
@@ -116,7 +116,7 @@ func (a *app) inviteLink(code string) string {
|
||||
|
||||
func (a *app) createInvite(w http.ResponseWriter, r *http.Request) {
|
||||
code := inviteCode()
|
||||
if _, err := a.pool.Exec(r.Context(), `insert into invites (code) values ($1)`, code); err != nil {
|
||||
if _, err := a.db.ExecContext(r.Context(), `insert into invites (code) values ($1)`, code); err != nil {
|
||||
adminError(w, "invites", err)
|
||||
return
|
||||
}
|
||||
@@ -136,14 +136,14 @@ func (a *app) toggleBan(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
var banned bool
|
||||
err = a.pool.QueryRow(r.Context(),
|
||||
err = a.db.QueryRowContext(r.Context(),
|
||||
`update users set banned = not banned where id = $1 returning banned`, id).Scan(&banned)
|
||||
if err != nil {
|
||||
adminError(w, "users", err)
|
||||
return
|
||||
}
|
||||
if banned {
|
||||
if _, err := a.pool.Exec(r.Context(), `delete from sessions where user_id = $1`, id); err != nil {
|
||||
if _, err := a.db.ExecContext(r.Context(), `delete from sessions where user_id = $1`, id); err != nil {
|
||||
adminError(w, "users", err)
|
||||
return
|
||||
}
|
||||
@@ -173,12 +173,12 @@ func (a *app) resetPassword(w http.ResponseWriter, r *http.Request) {
|
||||
adminError(w, "auth", err)
|
||||
return
|
||||
}
|
||||
if _, err := a.pool.Exec(r.Context(),
|
||||
if _, err := a.db.ExecContext(r.Context(),
|
||||
`update users set password_hash = $2 where id = $1`, id, string(hash)); err != nil {
|
||||
adminError(w, "auth", err)
|
||||
return
|
||||
}
|
||||
if _, err := a.pool.Exec(r.Context(), `delete from sessions where user_id = $1`, id); err != nil {
|
||||
if _, err := a.db.ExecContext(r.Context(), `delete from sessions where user_id = $1`, id); err != nil {
|
||||
adminError(w, "auth", err)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user