package api import ( "context" "errors" "github.com/jackc/pgx/v5" "git.dcrubro.com/dcrubro/hammy-backend/internal/db" ) // PgKeyStore adapts the sqlc-generated queries to the KeyStore interface. // // The indirection earns its keep twice: the middleware is testable without a // database, and adding an unrelated column to api.keys does not ripple into the // auth package. type PgKeyStore struct { Q *db.Queries } func (s PgKeyStore) KeyByHash(ctx context.Context, hash []byte) (KeyRecord, error) { row, err := s.Q.KeyByHash(ctx, hash) if err != nil { // pgx returns ErrNoRows for an empty :one result. Translate it so the // middleware never has to know which driver is underneath. if errors.Is(err, pgx.ErrNoRows) { return KeyRecord{}, ErrKeyNotFound } return KeyRecord{}, err } rec := KeyRecord{ ID: row.ID, OwnerID: row.OwnerID, Scopes: row.Scopes, QuotaTier: row.QuotaTier, Status: row.Status, OwnerStatus: row.OwnerStatus, } // pgx maps a nullable timestamptz to pgtype.Timestamptz, which carries its // own validity flag rather than being nil. db.Time does the conversion so // pgtype never leaks past this adapter. rec.ExpiresAt = db.Time(row.ExpiresAt) return rec, nil }