From 08c8828bb095fe3c291595fe440b9b35e712d2ce Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Wed, 24 Jun 2026 23:42:49 +0100 Subject: [PATCH] refactor(db): set UTC timezone in pool config and add Querier docs Set UTC timezone in pgxpool config to ensure consistent timestamp handling. Add detailed doc comment to Querier interface clarifying QueryRow vs Querier distinction. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- backend/db/db.go | 7 ++++++- backend/db/db_dev.go | 7 ++++++- backend/db/proxy.go | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/backend/db/db.go b/backend/db/db.go index 315118a..366b374 100644 --- a/backend/db/db.go +++ b/backend/db/db.go @@ -23,7 +23,12 @@ func Connect() error { getEnv("POSTGRES_DB"), ) - pool, err := pgxpool.New(context.Background(), dsn) + poolCfg, err := pgxpool.ParseConfig(dsn) + if err != nil { + return err + } + poolCfg.ConnConfig.RuntimeParams["timezone"] = "UTC" + pool, err := pgxpool.NewWithConfig(context.Background(), poolCfg) if err != nil { return err } diff --git a/backend/db/db_dev.go b/backend/db/db_dev.go index 3724cf0..ffca459 100644 --- a/backend/db/db_dev.go +++ b/backend/db/db_dev.go @@ -22,7 +22,12 @@ func Connect() error { getEnv("POSTGRES_DB"), ) - pool, err := pgxpool.New(context.Background(), dsn) + poolCfg, err := pgxpool.ParseConfig(dsn) + if err != nil { + return err + } + poolCfg.ConnConfig.RuntimeParams["timezone"] = "UTC" + pool, err := pgxpool.NewWithConfig(context.Background(), poolCfg) if err != nil { return err } diff --git a/backend/db/proxy.go b/backend/db/proxy.go index 82863c1..8a30fa6 100644 --- a/backend/db/proxy.go +++ b/backend/db/proxy.go @@ -11,6 +11,20 @@ import ( // Querier is implemented by *pgxpool.Pool, pgx.Tx, and *PoolProxy. // Fixture functions and internal helpers that need to run queries should // accept Querier to remain decoupled from transaction state. +// +// DISTINCTION: QueryRow vs Querier +// - QueryRow() (lowercase 'r') is a METHOD on Querier. It returns pgx.Row. +// Call it like: row := q.QueryRow(ctx, sql, args...) +// - Querier (uppercase 'Q') is an INTERFACE. It declares the QueryRow method. +// Accept Querier when a helper must work with both pool + transactions. +// - pgx.Row (singular) is the RETURN TYPE of QueryRow(). It is NOT a Querier. +// pgx.Row only has Scan(). You cannot pass a pgx.Row where Querier is expected. +// +// Common mistake: +// // WRONG — pgx.Row does not implement Querier: +// func helper(ctx, row pgx.Row) { ... } +// // CORRECT — accept Querier, call QueryRow inside: +// func helper(ctx, q db.Querier) { row := q.QueryRow(ctx, sql, args...); ... } type Querier interface { Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error) Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)