55 lines
1.7 KiB
Go
55 lines
1.7 KiB
Go
package repository
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
"gorm.io/gorm"
|
||
|
|
)
|
||
|
|
|
||
|
|
// DueLot is a lot whose expiry has passed and that still holds something.
|
||
|
|
type DueLot struct {
|
||
|
|
ID uuid.UUID
|
||
|
|
CustomerID uuid.UUID
|
||
|
|
Currency string
|
||
|
|
Remaining int64
|
||
|
|
ExpiresAt time.Time
|
||
|
|
// The description of the row that created the lot, for the EXPIRE row's.
|
||
|
|
SourceDescription string
|
||
|
|
}
|
||
|
|
|
||
|
|
// WalletExpiryRepository finds what the expiry job has to do (docs/prd-point-coin.md
|
||
|
|
// F12). Balances only change through WalletProcessor.
|
||
|
|
type WalletExpiryRepository interface {
|
||
|
|
// ListDueLots returns up to limit lots due at asOf, the longest overdue first. It
|
||
|
|
// takes no lock: locking a lot before its wallet would deadlock against payments,
|
||
|
|
// which lock the wallet first. WalletProcessor.ExpireLot locks and reads again.
|
||
|
|
ListDueLots(ctx context.Context, asOf time.Time, limit int) ([]DueLot, error)
|
||
|
|
}
|
||
|
|
|
||
|
|
type walletExpiryRepository struct {
|
||
|
|
db *gorm.DB
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewWalletExpiryRepository(db *gorm.DB) WalletExpiryRepository {
|
||
|
|
return &walletExpiryRepository{db: db}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *walletExpiryRepository) ListDueLots(ctx context.Context, asOf time.Time, limit int) ([]DueLot, error) {
|
||
|
|
var lots []DueLot
|
||
|
|
err := DBFromContext(ctx, r.db).WithContext(ctx).Raw(`
|
||
|
|
SELECT l.id, l.customer_id, l.currency, l.remaining_amount AS remaining, l.expires_at,
|
||
|
|
t.description AS source_description
|
||
|
|
FROM wallet_lots l
|
||
|
|
JOIN wallet_transactions t ON t.id = l.source_transaction_id
|
||
|
|
WHERE l.remaining_amount > 0 AND l.expires_at <= ?
|
||
|
|
ORDER BY l.expires_at, l.id
|
||
|
|
LIMIT ?`, asOf, limit).Scan(&lots).Error
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to list due wallet lots: %w", err)
|
||
|
|
}
|
||
|
|
return lots, nil
|
||
|
|
}
|