Skip to content

Instantly share code, notes, and snippets.

@illiafox
Created June 18, 2022 09:00
Show Gist options
  • Save illiafox/c2eb6de45f6529fb4f2537a1542f4a87 to your computer and use it in GitHub Desktop.
Save illiafox/c2eb6de45f6529fb4f2537a1542f4a87 to your computer and use it in GitHub Desktop.
да
func (s balanceStorage) ChangeBalance(ctx context.Context, userID int64, amount int64, desc string) error {
// acquire connection
c, err := s.pool.Acquire(ctx)
if err != nil {
return errors.NewInternal(err, "acquire connection")
}
defer c.Release()
// begin transaction
tx, err := c.Begin(ctx)
if err != nil {
return errors.NewInternal(err, "begin transaction")
}
defer tx.Rollback(ctx) // ignore error on rollback
//
var balance, balanceID int64
// get balance
err = tx.QueryRow(ctx, "SELECT balance_id,balance FROM balances WHERE user_id = $1 FOR UPDATE", userID).Scan(&balanceID, &balance)
if err != nil {
if err == pgx.ErrNoRows { // no rows -> balance not found
if amount < 0 { // we can't create new balance with negative amount
return fmt.Errorf("balance with user id %d not found", userID)
}
// create new balance
err = tx.QueryRow(ctx,
"INSERT INTO balances (user_id,balance) VALUES ($1,$2) RETURNING balance_id", userID, amount,
).Scan(&balanceID)
} else { // internal error
return errors.NewInternal(err, "query: get balance for update")
}
} else { // if balance found
balance += amount
if balance < 0 { // check whether there is enough money to proceed change
return fmt.Errorf("insufficient funds: missing %.2f", float64(-balance)/100)
}
// update existing balance
_, err = tx.Exec(ctx, "UPDATE balances SET balance = $1 WHERE balance_id = $2", balance, balanceID)
if err != nil {
return errors.NewInternal(err, "exec: update balance")
}
//
}
// create record
_, err = tx.Exec(ctx, `INSERT INTO transactions (balance_id,action,description)
VALUES ($1,$2,$3,$4)`, balanceID, amount, desc)
if err != nil {
return errors.NewInternal(err, "exec: create record")
}
// commit transaction
err = tx.Commit(ctx)
if err != nil {
return errors.NewInternal(err, "commit transaction")
}
//
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment