feat: add web push and sadhna tracker
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user