package repository import ( "app-cloudep-trade-service/internal/domain" "app-cloudep-trade-service/internal/domain/repository" "app-cloudep-trade-service/internal/domain/wallet" "app-cloudep-trade-service/internal/model" "context" "database/sql" "errors" "fmt" "time" "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/shopspring/decimal" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/sqlx" ) type WalletRepositoryParam struct { WalletModel model.WalletModel TxConn sqlx.SqlConn } type WalletRepository struct { WalletRepositoryParam } func (repo *WalletRepository) Transaction(ctx context.Context, fn func(tx sqlx.Session) error) error { // 取得原生的 *sql.DB db, err := repo.TxConn.RawDB() if err != nil { return err } // 定義事務選項 txOptions := &sql.TxOptions{ Isolation: sql.LevelReadCommitted, ReadOnly: false, } // 開啟事務 tx, err := db.BeginTx(ctx, txOptions) if err != nil { return err } // 使用 sqlx.Session 包裹事務 session := sqlx.NewSessionFromTx(tx) // 執行傳入的操作 if err := fn(session); err != nil { // 若有錯誤則回滾 err := tx.Rollback() if err != nil { // 錯誤代碼 06-021-22 e := domain.CommentErrorL( domain.WalletTxErrorCode, logx.WithContext(ctx), []logx.LogField{ {Key: "func", Value: "WalletModel.Transaction.Rollback"}, {Key: "err", Value: err}, }, "failed to find balance into mongo:").Wrap(err) return e } // 裡面那一層會紀錄 return err } // 提交事務 return tx.Commit() } // GetUserWalletOperator 取得本地操作使用者錢包的操作運算元 func (repo *WalletRepository) GetUserWalletOperator(uid, currency string, opts ...repository.Option) repository.UserWalletOperator { db := repo.TxConn // 看是否有最新的DB 連線要傳入,做 tx for _, fn := range opts { db = fn() } return NewUserWalletOperator(uid, currency, repo.WalletModel, db) } // Create 創建錢包,如果有相同的就跳過不建立 func (repo *WalletRepository) Create(ctx context.Context, uid, currency, brand string) ([]*model.Wallet, error) { wallets := make([]*model.Wallet, 0, len(wallet.AllBalanceTypes)) // 建立個人所有種類的錢包 now := time.Now().UTC().UnixNano() for _, item := range wallet.AllBalanceTypes { balance := decimal.Zero wallets = append(wallets, &model.Wallet{ Brand: brand, Currency: currency, Uid: uid, Balance: balance, WalletType: item, CreatedAt: now, UpdatedAt: now, }) } _, err := repo.WalletModel.InsertMany(ctx, wallets) if err != nil { // 錯誤代碼 06-021-20 e := domain.CommentErrorL( domain.CreateWalletErrorCode, logx.WithContext(ctx), []logx.LogField{ {Key: "param", Value: fmt.Sprintf("uid: %s, currency:%s, brand:%s", uid, currency, brand)}, {Key: "func", Value: "WalletModel.InsertMany"}, {Key: "err", Value: err}, }, "failed to insert wallet into mysql:").Wrap(err) return nil, e } return wallets, nil } func (repo *WalletRepository) Balances(ctx context.Context, req repository.BalanceReq) ([]model.Wallet, error) { data, err := repo.WalletModel.Balances(ctx, model.BalanceReq{ UID: req.UID, Currency: req.Currency, Kind: req.BalanceType, }, false, repo.TxConn) if err != nil { if errors.Is(sqlc.ErrNotFound, err) { // 錯誤代碼 06-031-23 return nil, domain.NotFoundError(domain.WalletBalanceNotFound, "balance not found") } // 錯誤代碼 06-021-20 e := domain.CommentErrorL( domain.CreateWalletErrorCode, logx.WithContext(ctx), []logx.LogField{ {Key: "param", Value: req}, {Key: "func", Value: "WalletModel.Balances"}, {Key: "err", Value: err}, }, "failed to get balance") return nil, e } return data, nil } func NewWalletRepository(param WalletRepositoryParam) repository.WalletRepository { return &WalletRepository{ WalletRepositoryParam: param, } }