diff --git a/service/account.go b/service/account.go index 6ff2213..a19dd1a 100644 --- a/service/account.go +++ b/service/account.go @@ -109,8 +109,17 @@ func (s AccountImpl) UpdateName(user *types.User, id string, name string) (*type return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest) } + tx, err := s.db.Beginx() + err = db.TransformAndLogDbError("account Update", nil, err) + if err != nil { + return nil, err + } + defer func() { + _ = tx.Rollback() + }() + var account types.Account - err = s.db.Get(&account, `SELECT * FROM account WHERE user_id = ? AND id = ?`, user.Id, uuid) + err = tx.Get(&account, `SELECT * FROM account WHERE user_id = ? AND id = ?`, user.Id, uuid) err = db.TransformAndLogDbError("account Update", nil, err) if err != nil { if err == db.ErrNotFound { @@ -124,7 +133,7 @@ func (s AccountImpl) UpdateName(user *types.User, id string, name string) (*type account.UpdatedAt = ×tamp account.UpdatedBy = &user.Id - r, err := s.db.NamedExec(` + r, err := tx.NamedExec(` UPDATE account SET name = :name, @@ -137,6 +146,12 @@ func (s AccountImpl) UpdateName(user *types.User, id string, name string) (*type return nil, err } + err = tx.Commit() + err = db.TransformAndLogDbError("account Update", nil, err) + if err != nil { + return nil, err + } + return &account, nil } @@ -192,8 +207,17 @@ func (s AccountImpl) Delete(user *types.User, id string) error { return fmt.Errorf("could not parse Id: %w", ErrBadRequest) } + tx, err := s.db.Beginx() + err = db.TransformAndLogDbError("account Delete", nil, err) + if err != nil { + return err + } + defer func() { + _ = tx.Rollback() + }() + transactionsCount := 0 - err = s.db.Get(&transactionsCount, `SELECT COUNT(*) FROM "transaction" WHERE user_id = ? AND account_id = ?`, user.Id, uuid) + err = tx.Get(&transactionsCount, `SELECT COUNT(*) FROM "transaction" WHERE user_id = ? AND account_id = ?`, user.Id, uuid) err = db.TransformAndLogDbError("account Delete", nil, err) if err != nil { return err @@ -202,10 +226,17 @@ func (s AccountImpl) Delete(user *types.User, id string) error { return fmt.Errorf("account has transactions, cannot delete: %w", ErrBadRequest) } - res, err := s.db.Exec("DELETE FROM account WHERE id = ? and user_id = ?", uuid, user.Id) + res, err := tx.Exec("DELETE FROM account WHERE id = ? and user_id = ?", uuid, user.Id) err = db.TransformAndLogDbError("account Delete", res, err) if err != nil { return err } + + err = tx.Commit() + err = db.TransformAndLogDbError("account Delete", nil, err) + if err != nil { + return err + } + return nil } diff --git a/service/transaction.go b/service/transaction.go index 0b462a0..eb2c2d7 100644 --- a/service/transaction.go +++ b/service/transaction.go @@ -58,12 +58,21 @@ func (s TransactionImpl) Add(user *types.User, transactionInput types.Transactio return nil, ErrUnauthorized } - transaction, err := s.validateAndEnrichTransaction(nil, user.Id, transactionInput) + tx, err := s.db.Beginx() + err = db.TransformAndLogDbError("transaction Add", nil, err) + if err != nil { + return nil, err + } + defer func() { + _ = tx.Rollback() + }() + + transaction, err := s.validateAndEnrichTransaction(tx, nil, user.Id, transactionInput) if err != nil { return nil, err } - r, err := s.db.NamedExec(` + r, err := tx.NamedExec(` INSERT INTO "transaction" (id, user_id, account_id, treasure_chest_id, value, timestamp, note, error, created_at, created_by) VALUES (:id, :user_id, :account_id, :treasure_chest_id, :value, :timestamp, :note, :error, :created_at, :created_by)`, transaction) err = db.TransformAndLogDbError("transaction Insert", r, err) @@ -72,27 +81,33 @@ func (s TransactionImpl) Add(user *types.User, transactionInput types.Transactio } if transaction.AccountId != nil { - r, err = s.db.Exec(` + r, err = tx.Exec(` UPDATE account SET current_balance = current_balance + ? WHERE id = ? AND user_id = ?`, transaction.Value, transaction.AccountId, user.Id) - err = db.TransformAndLogDbError("transaction Update", r, err) + err = db.TransformAndLogDbError("transaction Add", r, err) if err != nil { return nil, err } } if transaction.TreasureChestId != nil { - r, err = s.db.Exec(` + r, err = tx.Exec(` UPDATE treasure_chest SET current_balance = current_balance + ? WHERE id = ? AND user_id = ?`, transaction.Value, transaction.TreasureChestId, user.Id) - err = db.TransformAndLogDbError("transaction Update", r, err) + err = db.TransformAndLogDbError("transaction Add", r, err) if err != nil { return nil, err } } + err = tx.Commit() + err = db.TransformAndLogDbError("transaction Add", nil, err) + if err != nil { + return nil, err + } + return transaction, nil } @@ -107,8 +122,17 @@ func (s TransactionImpl) Update(user *types.User, input types.TransactionInput) return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest) } + tx, err := s.db.Beginx() + err = db.TransformAndLogDbError("transaction Update", nil, err) + if err != nil { + return nil, err + } + defer func() { + _ = tx.Rollback() + }() + transaction := &types.Transaction{} - err = s.db.Get(transaction, `SELECT * FROM "transaction" WHERE user_id = ? AND id = ?`, user.Id, uuid) + err = tx.Get(transaction, `SELECT * FROM "transaction" WHERE user_id = ? AND id = ?`, user.Id, uuid) err = db.TransformAndLogDbError("transaction Update", nil, err) if err != nil { if err == db.ErrNotFound { @@ -118,7 +142,7 @@ func (s TransactionImpl) Update(user *types.User, input types.TransactionInput) } if transaction.AccountId != nil { - r, err := s.db.Exec(` + r, err := tx.Exec(` UPDATE account SET current_balance = current_balance - ? WHERE id = ? AND user_id = ?`, transaction.Value, transaction.AccountId, user.Id) @@ -128,7 +152,7 @@ func (s TransactionImpl) Update(user *types.User, input types.TransactionInput) } } if transaction.TreasureChestId != nil { - r, err := s.db.Exec(` + r, err := tx.Exec(` UPDATE treasure_chest SET current_balance = current_balance - ? WHERE id = ? AND user_id = ?`, transaction.Value, transaction.TreasureChestId, user.Id) @@ -138,13 +162,13 @@ func (s TransactionImpl) Update(user *types.User, input types.TransactionInput) } } - transaction, err = s.validateAndEnrichTransaction(transaction, user.Id, input) + transaction, err = s.validateAndEnrichTransaction(tx, transaction, user.Id, input) if err != nil { return nil, err } if transaction.AccountId != nil { - r, err := s.db.Exec(` + r, err := tx.Exec(` UPDATE account SET current_balance = current_balance + ? WHERE id = ? AND user_id = ?`, transaction.Value, transaction.AccountId, user.Id) @@ -154,7 +178,7 @@ func (s TransactionImpl) Update(user *types.User, input types.TransactionInput) } } if transaction.TreasureChestId != nil { - r, err := s.db.Exec(` + r, err := tx.Exec(` UPDATE treasure_chest SET current_balance = current_balance + ? WHERE id = ? AND user_id = ?`, transaction.Value, transaction.TreasureChestId, user.Id) @@ -164,7 +188,7 @@ func (s TransactionImpl) Update(user *types.User, input types.TransactionInput) } } - r, err := s.db.NamedExec(` + r, err := tx.NamedExec(` UPDATE "transaction" SET account_id = :account_id, @@ -182,6 +206,12 @@ func (s TransactionImpl) Update(user *types.User, input types.TransactionInput) return nil, err } + err = tx.Commit() + err = db.TransformAndLogDbError("transaction Update", nil, err) + if err != nil { + return nil, err + } + return transaction, nil } @@ -236,7 +266,16 @@ func (s TransactionImpl) Delete(user *types.User, id string) error { return fmt.Errorf("could not parse Id: %w", ErrBadRequest) } - r, err := s.db.Exec(` + tx, err := s.db.Beginx() + err = db.TransformAndLogDbError("transaction Delete", nil, err) + if err != nil { + return nil + } + defer func() { + _ = tx.Rollback() + }() + + r, err := tx.Exec(` UPDATE account SET current_balance = current_balance - (SELECT value FROM "transaction" WHERE id = ? AND user_id = ?) WHERE id = (SELECT account_id FROM "transaction" WHERE id = ? AND user_id = ?) @@ -245,7 +284,7 @@ func (s TransactionImpl) Delete(user *types.User, id string) error { if err != nil && err != db.ErrNotFound { return err } - r, err = s.db.Exec(` + r, err = tx.Exec(` UPDATE treasure_chest SET current_balance = current_balance - (SELECT value FROM "transaction" WHERE id = ? AND user_id = ?) WHERE id = (SELECT treasure_chest_id FROM "transaction" WHERE id = ? AND user_id = ?) @@ -255,12 +294,18 @@ func (s TransactionImpl) Delete(user *types.User, id string) error { return err } - r, err = s.db.Exec("DELETE FROM \"transaction\" WHERE id = ? AND user_id = ?", uuid, user.Id) + r, err = tx.Exec("DELETE FROM \"transaction\" WHERE id = ? AND user_id = ?", uuid, user.Id) err = db.TransformAndLogDbError("transaction Delete", r, err) if err != nil { return err } + err = tx.Commit() + err = db.TransformAndLogDbError("transaction RecalculateBalances", nil, err) + if err != nil { + return err + } + return nil } @@ -365,7 +410,7 @@ func (s TransactionImpl) RecalculateBalances(user *types.User) error { return nil } -func (s TransactionImpl) validateAndEnrichTransaction(oldTransaction *types.Transaction, userId uuid.UUID, input types.TransactionInput) (*types.Transaction, error) { +func (s TransactionImpl) validateAndEnrichTransaction(tx *sqlx.Tx, oldTransaction *types.Transaction, userId uuid.UUID, input types.TransactionInput) (*types.Transaction, error) { var ( id uuid.UUID @@ -403,7 +448,7 @@ func (s TransactionImpl) validateAndEnrichTransaction(oldTransaction *types.Tran return nil, fmt.Errorf("could not parse accountId: %w", ErrBadRequest) } accountUuid = &temp - err = s.db.Get(&rowCount, `SELECT COUNT(*) FROM account WHERE id = ? AND user_id = ?`, accountUuid, userId) + err = tx.Get(&rowCount, `SELECT COUNT(*) FROM account WHERE id = ? AND user_id = ?`, accountUuid, userId) err = db.TransformAndLogDbError("transaction validate", nil, err) if err != nil { return nil, err @@ -422,7 +467,7 @@ func (s TransactionImpl) validateAndEnrichTransaction(oldTransaction *types.Tran return nil, fmt.Errorf("could not parse treasureChestId: %w", ErrBadRequest) } treasureChestUuid = &temp - err = s.db.Get(&rowCount, `SELECT COUNT(*) FROM treasure_chest WHERE id = ? AND user_id = ?`, treasureChestUuid, userId) + err = tx.Get(&rowCount, `SELECT COUNT(*) FROM treasure_chest WHERE id = ? AND user_id = ?`, treasureChestUuid, userId) err = db.TransformAndLogDbError("transaction validate", nil, err) if err != nil { return nil, err diff --git a/service/treasure_chest.go b/service/treasure_chest.go index e867ea0..fec63db 100644 --- a/service/treasure_chest.go +++ b/service/treasure_chest.go @@ -117,8 +117,17 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name string return nil, fmt.Errorf("could not parse Id: %w", ErrBadRequest) } + tx, err := s.db.Beginx() + err = db.TransformAndLogDbError("treasureChest Update", nil, err) + if err != nil { + return nil, err + } + defer func() { + _ = tx.Rollback() + }() + treasureChest := &types.TreasureChest{} - err = s.db.Get(treasureChest, `SELECT * FROM treasure_chest WHERE user_id = ? AND id = ?`, user.Id, id) + err = tx.Get(treasureChest, `SELECT * FROM treasure_chest WHERE user_id = ? AND id = ?`, user.Id, id) err = db.TransformAndLogDbError("treasureChest Update", nil, err) if err != nil { if err == db.ErrNotFound { @@ -134,7 +143,7 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name string return nil, err } var childCount int - err = s.db.Get(&childCount, `SELECT COUNT(*) FROM treasure_chest WHERE user_id = ? AND parent_id = ?`, user.Id, id) + err = tx.Get(&childCount, `SELECT COUNT(*) FROM treasure_chest WHERE user_id = ? AND parent_id = ?`, user.Id, id) err = db.TransformAndLogDbError("treasureChest Update", nil, err) if err != nil { return nil, err @@ -152,7 +161,7 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name string treasureChest.UpdatedAt = ×tamp treasureChest.UpdatedBy = &user.Id - r, err := s.db.NamedExec(` + r, err := tx.NamedExec(` UPDATE treasure_chest SET parent_id = :parent_id, @@ -167,6 +176,12 @@ func (s TreasureChestImpl) Update(user *types.User, idStr, parentId, name string return nil, err } + err = tx.Commit() + err = db.TransformAndLogDbError("treasureChest Update", nil, err) + if err != nil { + return nil, err + } + return treasureChest, nil } @@ -222,8 +237,17 @@ func (s TreasureChestImpl) Delete(user *types.User, idStr string) error { return fmt.Errorf("could not parse Id: %w", ErrBadRequest) } + tx, err := s.db.Beginx() + err = db.TransformAndLogDbError("treasureChest Delete", nil, err) + if err != nil { + return nil + } + defer func() { + _ = tx.Rollback() + }() + childCount := 0 - err = s.db.Get(&childCount, `SELECT COUNT(*) FROM treasure_chest WHERE user_id = ? AND parent_id = ?`, user.Id, id) + err = tx.Get(&childCount, `SELECT COUNT(*) FROM treasure_chest WHERE user_id = ? AND parent_id = ?`, user.Id, id) err = db.TransformAndLogDbError("treasureChest Delete", nil, err) if err != nil { return err @@ -234,7 +258,7 @@ func (s TreasureChestImpl) Delete(user *types.User, idStr string) error { } transactionsCount := 0 - err = s.db.Get(&transactionsCount, `SELECT COUNT(*) FROM "transaction" WHERE user_id = ? AND treasure_chest_id = ?`, user.Id, id) + err = tx.Get(&transactionsCount, `SELECT COUNT(*) FROM "transaction" WHERE user_id = ? AND treasure_chest_id = ?`, user.Id, id) err = db.TransformAndLogDbError("treasureChest Delete", nil, err) if err != nil { return err @@ -243,12 +267,18 @@ func (s TreasureChestImpl) Delete(user *types.User, idStr string) error { return fmt.Errorf("treasure chest has transactions: %w", ErrBadRequest) } - r, err := s.db.Exec(`DELETE FROM treasure_chest WHERE id = ? AND user_id = ?`, id, user.Id) + r, err := tx.Exec(`DELETE FROM treasure_chest WHERE id = ? AND user_id = ?`, id, user.Id) err = db.TransformAndLogDbError("treasureChest Delete", r, err) if err != nil { return err } + err = tx.Commit() + err = db.TransformAndLogDbError("treasureChest Delete", nil, err) + if err != nil { + return err + } + return nil }