init
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
package economy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ارزها.
|
||||
const (
|
||||
CurrencyCoin = "coin"
|
||||
CurrencyTicket = "ticket"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInsufficient = errors.New("insufficient balance")
|
||||
ErrBadCurrency = errors.New("invalid currency")
|
||||
)
|
||||
|
||||
// column نام ستون موجودی را برای یک ارز برمیگرداند.
|
||||
func column(currency string) (string, error) {
|
||||
switch currency {
|
||||
case CurrencyCoin:
|
||||
return "coins", nil
|
||||
case CurrencyTicket:
|
||||
return "tickets", nil
|
||||
}
|
||||
return "", ErrBadCurrency
|
||||
}
|
||||
|
||||
// adjustTx موجودی را داخل یک تراکنش تغییر داده و در دفتر ثبت میکند.
|
||||
// برای delta منفی، اگر موجودی کافی نباشد ErrInsufficient برمیگرداند (بدون تغییر).
|
||||
func adjustTx(ctx context.Context, tx *sql.Tx, userID int64, currency string, delta int64, reason, ref string) error {
|
||||
col, err := column(currency)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var res sql.Result
|
||||
if delta < 0 {
|
||||
// فقط در صورت کفایت موجودی کم کن (اتمیک)
|
||||
res, err = tx.ExecContext(ctx,
|
||||
fmt.Sprintf("UPDATE users SET %s = %s + ? WHERE id = ? AND %s >= ?", col, col, col),
|
||||
delta, userID, -delta)
|
||||
} else {
|
||||
res, err = tx.ExecContext(ctx,
|
||||
fmt.Sprintf("UPDATE users SET %s = %s + ? WHERE id = ?", col, col),
|
||||
delta, userID)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, _ := res.RowsAffected()
|
||||
if n == 0 {
|
||||
return ErrInsufficient
|
||||
}
|
||||
_, err = tx.ExecContext(ctx,
|
||||
"INSERT INTO wallet_tx (user_id, amount, reason, ref, currency) VALUES (?, ?, ?, ?, ?)",
|
||||
userID, delta, reason, ref, currency)
|
||||
return err
|
||||
}
|
||||
|
||||
// Adjust موجودی را در یک تراکنش مستقل تغییر میدهد.
|
||||
func (s *Service) Adjust(ctx context.Context, userID int64, currency string, delta int64, reason, ref string) error {
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
if err := adjustTx(ctx, tx, userID, currency, delta, reason, ref); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
Reference in New Issue
Block a user