package postgres import ( "context" "git.gocasts.ir/ebhomengo/niki/domain/wallet/entity" "git.gocasts.ir/ebhomengo/niki/pkg/database/postgres" errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg" richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" ) func (db *DB) InsertTransaction(ctx context.Context, transaction entity.Transaction) (balance float64, err error) { const op = richerror.Op("wallet.repo.InsertTransaction") query := `INSERT INTO Transactions (user_id, amount ,currency ,action_type, timestamp) values ($1, $2, $3, $4, $5)` stmt, stErr := db.conn.PrepareStatement(ctx, postgres.StatementKeyWalletInsertTransaction, query) if stErr != nil { err = richerror.New(op).WithErr(stErr).WithKind(richerror.KindUnexpected) return } txHolder, newCtx := postgres.GetDBTxHolderFromContextOrNew(ctx) tx, txErr := txHolder.BeginTx(newCtx, db.conn.Conn()) if txErr != nil { err = richerror.New(op).WithErr(txErr).WithKind(richerror.KindUnexpected) return } defer func() { if tx != nil { if err != nil { if rbErr := tx.Rollback(); rbErr != nil { // log rbErr } } else if cErr := tx.Commit(); cErr != nil { // log cErr } } }() params := []any{transaction.UserID, transaction.Amount, transaction.Currency, transaction.ActionType, transaction.Timestamp} _, execErr := tx.StmtExecContext(newCtx, stmt, params...) if execErr != nil { err = richerror.New(op).WithErr(execErr).WithKind(richerror.KindUnexpected).WithMessage(errmsg.ErrorMsgFailedQuery) return } newBalance, blanceErr := db.UpsertBalance(newCtx, transaction.UserID, transaction.Amount) if blanceErr != nil { err = richerror.New(op).WithErr(blanceErr) return } balance = newBalance return } func (db *DB) UpsertBalance(newCtx context.Context, userID uint64, amount float64) (balance float64, err error) { const op = richerror.Op("wallet.repo.UpdateBalance") txHolder, _ := postgres.GetDBTxHolderFromContextOrNew(newCtx) tx, txErr := txHolder.Conn() if txErr != nil { err = richerror.New(op).WithMessage(errmsg.ErrorMsgFailedQuery).WithKind(richerror.KindUnexpected) return } if tx == nil { err = richerror.New(op).WithMessage(errmsg.ErrorMsgFailedQuery).WithKind(richerror.KindUnexpected) return } upsertQuery := `INSERT INTO wallets (user_id, balance) VALUES ($1, $2) ON CONFLICT (user_id) DO UPDATE SET balance = wallets.balance + $2 RETURNING balance` upsertStmt, stErr := db.conn.PrepareStatement(newCtx, postgres.StatementKeyWalletUpsertBalance, upsertQuery) if stErr != nil { err = richerror.New(op).WithMessage(errmsg.ErrorMsgFailedQuery).WithKind(richerror.KindUnexpected) return } row := tx.StmtQueryRowContext(newCtx, upsertStmt, userID, amount) sErr := row.Scan(&balance) if sErr != nil { err = richerror.New(op).WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected) return } return balance, nil }