Files
digital-psychology/apps/api/internal/repository/imagecard_repo.go
T
jackyu66gitandCursor bd22d9dddd feat: P1 合盘/星座/问答与测测完整设计包及模拟器取证工具
落地 synastry/star/ask API 与 H5 页面,补齐 cece-frontend-re complete-design 证据文档,并加入 Android 模拟器截图抓取脚本。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 11:37:53 +08:00

78 lines
2.0 KiB
Go

package repository
import (
"context"
"errors"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
const imageCardDailyFree = 3
// ImageCardRepo tracks daily draw quotas.
type ImageCardRepo struct {
Pool *pgxpool.Pool
}
// UsedToday returns how many free draws used today.
func (r *ImageCardRepo) UsedToday(ctx context.Context, userID uuid.UUID, day time.Time) (int, error) {
var n int
err := r.Pool.QueryRow(ctx, `
SELECT used FROM image_card_quotas
WHERE user_id=$1 AND day=$2::date`,
userID, day.Format("2006-01-02"),
).Scan(&n)
if errors.Is(err, pgx.ErrNoRows) {
return 0, nil
}
return n, err
}
// TryConsume increments today's used count when under free limit.
// Returns remaining after consume. ErrQuotaExhausted when free tier is out.
func (r *ImageCardRepo) TryConsume(ctx context.Context, userID uuid.UUID, day time.Time) (remaining int, err error) {
dayStr := day.Format("2006-01-02")
var used int
err = r.Pool.QueryRow(ctx, `
INSERT INTO image_card_quotas(user_id, day, used)
VALUES ($1, $2::date, 1)
ON CONFLICT (user_id, day) DO UPDATE
SET used = image_card_quotas.used + 1
WHERE image_card_quotas.used < $3
RETURNING used`,
userID, dayStr, imageCardDailyFree,
).Scan(&used)
if errors.Is(err, pgx.ErrNoRows) {
return 0, ErrQuotaExhausted
}
if err != nil {
return 0, err
}
return imageCardDailyFree - used, nil
}
// RemainingToday without consuming.
func (r *ImageCardRepo) RemainingToday(ctx context.Context, userID uuid.UUID, day time.Time, unlimited bool) (int, error) {
if unlimited {
return 99, nil
}
used, err := r.UsedToday(ctx, userID, day)
if err != nil {
return 0, err
}
left := imageCardDailyFree - used
if left < 0 {
left = 0
}
return left, nil
}
// DailyFreeLimit is the free-tier cap.
func DailyFreeLimit() int { return imageCardDailyFree }
// ErrQuotaExhausted means free daily draws are used up.
var ErrQuotaExhausted = errors.New("今日免费次数已用完")