package repository import ( "context" "fmt" "time" "github.com/prabhupadasays/spsays-bff/internal/model" ) // SadhnaRepo wraps Postgres access for sadhna_logs — the chanting half of // a day's sādhana. The posting half lives in the posts table and is read // via PostRepo.PostedDates, so this repo stays small. type SadhnaRepo struct{ pg *Postgres } func NewSadhnaRepo(pg *Postgres) *SadhnaRepo { return &SadhnaRepo{pg: pg} } // UpsertToday records (or updates) the given day's chanting progress for // the user. The caller passes the UTC calendar date explicitly (rather // than relying on the DB's CURRENT_DATE) so day bucketing stays identical // to PostedDates' `AT TIME ZONE 'UTC'`. chantDone is decided by the caller // — rounds_completed >= the user's current target — and frozen into the // row so later target changes don't rewrite past days. Returns the row. func (r *SadhnaRepo) UpsertToday(ctx context.Context, userID string, logDate time.Time, rounds int, chantDone bool) (*model.SadhnaLog, error) { var l model.SadhnaLog err := r.pg.Pool.QueryRow(ctx, ` INSERT INTO sadhna_logs (user_id, log_date, rounds_completed, chant_done) VALUES ($1, $2, $3, $4) ON CONFLICT (user_id, log_date) DO UPDATE SET rounds_completed = EXCLUDED.rounds_completed, chant_done = EXCLUDED.chant_done, updated_at = now() RETURNING id, user_id, log_date, rounds_completed, chant_done, created_at, updated_at`, userID, logDate, rounds, chantDone, ).Scan(&l.ID, &l.UserID, &l.LogDate, &l.RoundsCompleted, &l.ChantDone, &l.CreatedAt, &l.UpdatedAt) if err != nil { return nil, fmt.Errorf("upsert sadhna log: %w", err) } return &l, nil } // ListSince returns the user's sadhna logs on or after `since`, newest // first. The window bounds the streak/growth computation; a few hundred // rows at most. func (r *SadhnaRepo) ListSince(ctx context.Context, userID string, since time.Time) ([]model.SadhnaLog, error) { rows, err := r.pg.Pool.Query(ctx, ` SELECT id, user_id, log_date, rounds_completed, chant_done, created_at, updated_at FROM sadhna_logs WHERE user_id = $1 AND log_date >= $2 ORDER BY log_date DESC`, userID, since, ) if err != nil { return nil, fmt.Errorf("list sadhna logs: %w", err) } defer rows.Close() var out []model.SadhnaLog for rows.Next() { var l model.SadhnaLog if err := rows.Scan(&l.ID, &l.UserID, &l.LogDate, &l.RoundsCompleted, &l.ChantDone, &l.CreatedAt, &l.UpdatedAt); err != nil { return nil, fmt.Errorf("scan sadhna log: %w", err) } out = append(out, l) } return out, rows.Err() }