| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- package repository
- import (
- "context"
- "errors"
- "fmt"
- "time"
- "github.com/Wei-Shaw/sub2api/internal/service"
- )
- // userPlatformQuotaServiceAdapter 将 repository 层的 userPlatformQuotaRepository
- // 适配为 service.UserPlatformQuotaRepository 接口(返回 *service.UserPlatformQuotaRecord)。
- type userPlatformQuotaServiceAdapter struct {
- inner *userPlatformQuotaRepository
- }
- // NewUserPlatformQuotaServiceAdapter 将 UserPlatformQuotaRepository 实现包装为
- // 满足 service.UserPlatformQuotaRepository 接口的适配器。
- func NewUserPlatformQuotaServiceAdapter(repo UserPlatformQuotaRepository) service.UserPlatformQuotaRepository {
- impl, ok := repo.(*userPlatformQuotaRepository)
- if !ok {
- // 非标准实现(如测试 fake),通过通用适配器包装
- return &genericUserPlatformQuotaAdapter{inner: repo}
- }
- return &userPlatformQuotaServiceAdapter{inner: impl}
- }
- func (a *userPlatformQuotaServiceAdapter) GetByUserPlatform(ctx context.Context, userID int64, platform string) (*service.UserPlatformQuotaRecord, error) {
- rec, err := a.inner.GetByUserPlatform(ctx, userID, platform)
- if err != nil || rec == nil {
- return nil, err
- }
- return toServiceRecord(rec), nil
- }
- // IncrementUsageWithReset 原子累加 cost 到 (user, platform) 三个窗口的用量。
- func (a *userPlatformQuotaServiceAdapter) IncrementUsageWithReset(ctx context.Context, userID int64, platform string, cost float64, now time.Time) error {
- return a.inner.IncrementUsageWithReset(ctx, userID, platform, cost, now)
- }
- // ListByUser 查询用户的所有平台配额记录。
- func (a *userPlatformQuotaServiceAdapter) ListByUser(ctx context.Context, userID int64) ([]service.UserPlatformQuotaRecord, error) {
- rows, err := a.inner.ListByUser(ctx, userID)
- if err != nil {
- return nil, err
- }
- out := make([]service.UserPlatformQuotaRecord, len(rows))
- for i, r := range rows {
- out[i] = service.UserPlatformQuotaRecord{
- UserID: r.UserID,
- Platform: r.Platform,
- DailyLimitUSD: r.DailyLimitUSD,
- WeeklyLimitUSD: r.WeeklyLimitUSD,
- MonthlyLimitUSD: r.MonthlyLimitUSD,
- DailyUsageUSD: r.DailyUsageUSD,
- WeeklyUsageUSD: r.WeeklyUsageUSD,
- MonthlyUsageUSD: r.MonthlyUsageUSD,
- DailyWindowStart: r.DailyWindowStart,
- WeeklyWindowStart: r.WeeklyWindowStart,
- MonthlyWindowStart: r.MonthlyWindowStart,
- }
- }
- return out, nil
- }
- // BulkInsertInitial 将 service.UserPlatformQuotaRecord 切片转换后调用底层 repo。
- func (a *userPlatformQuotaServiceAdapter) BulkInsertInitial(ctx context.Context, records []service.UserPlatformQuotaRecord) error {
- repoRecords := make([]UserPlatformQuotaRecord, len(records))
- for i, r := range records {
- repoRecords[i] = UserPlatformQuotaRecord{
- UserID: r.UserID,
- Platform: r.Platform,
- DailyLimitUSD: r.DailyLimitUSD,
- WeeklyLimitUSD: r.WeeklyLimitUSD,
- MonthlyLimitUSD: r.MonthlyLimitUSD,
- }
- }
- return a.inner.BulkInsertInitial(ctx, repoRecords)
- }
- // UpsertForUser 全量替换该用户所有平台限额。
- func (a *userPlatformQuotaServiceAdapter) UpsertForUser(ctx context.Context, userID int64, records []service.UserPlatformQuotaRecord) error {
- repoRecords := toRepoRecords(records)
- return a.inner.UpsertForUser(ctx, userID, repoRecords)
- }
- // ResetExpiredWindow 转发至 repository.ResetExpiredWindow,并将 repository sentinel 包装为 service sentinel。
- func (a *userPlatformQuotaServiceAdapter) ResetExpiredWindow(ctx context.Context, userID int64, platform string, window string, newStart time.Time) error {
- err := a.inner.ResetExpiredWindow(ctx, userID, platform, window, newStart)
- if errors.Is(err, ErrUserPlatformQuotaNotFound) {
- return fmt.Errorf("%w: %w", service.ErrUserPlatformQuotaNotFound, err)
- }
- return err
- }
- // BatchSnapshotUsage 转换 []service.UserPlatformQuotaSnapshot → []UserPlatformQuotaSnapshot,
- // 调底层 repo,并将 repository FK sentinel 包装为 service sentinel。
- func (a *userPlatformQuotaServiceAdapter) BatchSnapshotUsage(ctx context.Context, snapshots []service.UserPlatformQuotaSnapshot, now time.Time) error {
- repoSnaps := make([]UserPlatformQuotaSnapshot, len(snapshots))
- for i, s := range snapshots {
- repoSnaps[i] = UserPlatformQuotaSnapshot{
- UserID: s.UserID,
- Platform: s.Platform,
- DailyUsageUSD: s.DailyUsageUSD,
- WeeklyUsageUSD: s.WeeklyUsageUSD,
- MonthlyUsageUSD: s.MonthlyUsageUSD,
- DailyWindowStart: s.DailyWindowStart,
- WeeklyWindowStart: s.WeeklyWindowStart,
- MonthlyWindowStart: s.MonthlyWindowStart,
- }
- }
- err := a.inner.BatchSnapshotUsage(ctx, repoSnaps, now)
- if errors.Is(err, ErrUserPlatformQuotaFKViolation) {
- return fmt.Errorf("%w: %v", service.ErrUserPlatformQuotaFKViolation, err)
- }
- return err
- }
- // genericUserPlatformQuotaAdapter 通过通用接口适配(用于测试 fake 或非标准实现)。
- type genericUserPlatformQuotaAdapter struct {
- inner UserPlatformQuotaRepository
- }
- func (a *genericUserPlatformQuotaAdapter) GetByUserPlatform(ctx context.Context, userID int64, platform string) (*service.UserPlatformQuotaRecord, error) {
- rec, err := a.inner.GetByUserPlatform(ctx, userID, platform)
- if err != nil || rec == nil {
- return nil, err
- }
- return toServiceRecord(rec), nil
- }
- // IncrementUsageWithReset 原子累加 cost(通用 adapter 实现)。
- func (a *genericUserPlatformQuotaAdapter) IncrementUsageWithReset(ctx context.Context, userID int64, platform string, cost float64, now time.Time) error {
- return a.inner.IncrementUsageWithReset(ctx, userID, platform, cost, now)
- }
- // ListByUser 查询用户的所有平台配额记录(通用 adapter 实现)。
- func (a *genericUserPlatformQuotaAdapter) ListByUser(ctx context.Context, userID int64) ([]service.UserPlatformQuotaRecord, error) {
- rows, err := a.inner.ListByUser(ctx, userID)
- if err != nil {
- return nil, err
- }
- out := make([]service.UserPlatformQuotaRecord, len(rows))
- for i, r := range rows {
- out[i] = service.UserPlatformQuotaRecord{
- UserID: r.UserID,
- Platform: r.Platform,
- DailyLimitUSD: r.DailyLimitUSD,
- WeeklyLimitUSD: r.WeeklyLimitUSD,
- MonthlyLimitUSD: r.MonthlyLimitUSD,
- DailyUsageUSD: r.DailyUsageUSD,
- WeeklyUsageUSD: r.WeeklyUsageUSD,
- MonthlyUsageUSD: r.MonthlyUsageUSD,
- DailyWindowStart: r.DailyWindowStart,
- WeeklyWindowStart: r.WeeklyWindowStart,
- MonthlyWindowStart: r.MonthlyWindowStart,
- }
- }
- return out, nil
- }
- // BulkInsertInitial 将 service.UserPlatformQuotaRecord 切片转换后调用底层 generic repo。
- func (a *genericUserPlatformQuotaAdapter) BulkInsertInitial(ctx context.Context, records []service.UserPlatformQuotaRecord) error {
- repoRecords := make([]UserPlatformQuotaRecord, len(records))
- for i, r := range records {
- repoRecords[i] = UserPlatformQuotaRecord{
- UserID: r.UserID,
- Platform: r.Platform,
- DailyLimitUSD: r.DailyLimitUSD,
- WeeklyLimitUSD: r.WeeklyLimitUSD,
- MonthlyLimitUSD: r.MonthlyLimitUSD,
- }
- }
- return a.inner.BulkInsertInitial(ctx, repoRecords)
- }
- // UpsertForUser 全量替换(通用 adapter 实现)。
- func (a *genericUserPlatformQuotaAdapter) UpsertForUser(ctx context.Context, userID int64, records []service.UserPlatformQuotaRecord) error {
- repoRecords := toRepoRecords(records)
- return a.inner.UpsertForUser(ctx, userID, repoRecords)
- }
- // ResetExpiredWindow 转发至 repository.ResetExpiredWindow(通用 adapter),并包装 sentinel。
- func (a *genericUserPlatformQuotaAdapter) ResetExpiredWindow(ctx context.Context, userID int64, platform string, window string, newStart time.Time) error {
- err := a.inner.ResetExpiredWindow(ctx, userID, platform, window, newStart)
- if errors.Is(err, ErrUserPlatformQuotaNotFound) {
- return fmt.Errorf("%w: %w", service.ErrUserPlatformQuotaNotFound, err)
- }
- return err
- }
- // BatchSnapshotUsage 转换 []service.UserPlatformQuotaSnapshot → []UserPlatformQuotaSnapshot(通用 adapter),
- // 并将 repository FK sentinel 包装为 service sentinel。
- func (a *genericUserPlatformQuotaAdapter) BatchSnapshotUsage(ctx context.Context, snapshots []service.UserPlatformQuotaSnapshot, now time.Time) error {
- repoSnaps := make([]UserPlatformQuotaSnapshot, len(snapshots))
- for i, s := range snapshots {
- repoSnaps[i] = UserPlatformQuotaSnapshot{
- UserID: s.UserID,
- Platform: s.Platform,
- DailyUsageUSD: s.DailyUsageUSD,
- WeeklyUsageUSD: s.WeeklyUsageUSD,
- MonthlyUsageUSD: s.MonthlyUsageUSD,
- DailyWindowStart: s.DailyWindowStart,
- WeeklyWindowStart: s.WeeklyWindowStart,
- MonthlyWindowStart: s.MonthlyWindowStart,
- }
- }
- err := a.inner.BatchSnapshotUsage(ctx, repoSnaps, now)
- if errors.Is(err, ErrUserPlatformQuotaFKViolation) {
- return fmt.Errorf("%w: %v", service.ErrUserPlatformQuotaFKViolation, err)
- }
- return err
- }
- // toServiceRecord 将 repository.UserPlatformQuotaRecord 转换为 service.UserPlatformQuotaRecord。
- func toServiceRecord(rec *UserPlatformQuotaRecord) *service.UserPlatformQuotaRecord {
- return &service.UserPlatformQuotaRecord{
- UserID: rec.UserID,
- Platform: rec.Platform,
- DailyLimitUSD: rec.DailyLimitUSD,
- WeeklyLimitUSD: rec.WeeklyLimitUSD,
- MonthlyLimitUSD: rec.MonthlyLimitUSD,
- DailyUsageUSD: rec.DailyUsageUSD,
- WeeklyUsageUSD: rec.WeeklyUsageUSD,
- MonthlyUsageUSD: rec.MonthlyUsageUSD,
- DailyWindowStart: rec.DailyWindowStart,
- WeeklyWindowStart: rec.WeeklyWindowStart,
- MonthlyWindowStart: rec.MonthlyWindowStart,
- }
- }
- // toRepoRecords 将 service.UserPlatformQuotaRecord 切片转换为 repository.UserPlatformQuotaRecord(含 limit 字段,含 usage/window_start)。
- func toRepoRecords(records []service.UserPlatformQuotaRecord) []UserPlatformQuotaRecord {
- out := make([]UserPlatformQuotaRecord, len(records))
- for i, r := range records {
- out[i] = UserPlatformQuotaRecord{
- UserID: r.UserID,
- Platform: r.Platform,
- DailyLimitUSD: r.DailyLimitUSD,
- WeeklyLimitUSD: r.WeeklyLimitUSD,
- MonthlyLimitUSD: r.MonthlyLimitUSD,
- DailyUsageUSD: r.DailyUsageUSD,
- WeeklyUsageUSD: r.WeeklyUsageUSD,
- MonthlyUsageUSD: r.MonthlyUsageUSD,
- DailyWindowStart: r.DailyWindowStart,
- WeeklyWindowStart: r.WeeklyWindowStart,
- MonthlyWindowStart: r.MonthlyWindowStart,
- }
- }
- return out
- }
|