From 8687e467c9816ca3766911d7127941827aa1b650 Mon Sep 17 00:00:00 2001 From: "daniel.w" Date: Tue, 29 Oct 2024 16:17:31 +0800 Subject: [PATCH] add wallet database --- Makefile | 11 ++ etc/trade.yaml | 12 ++ ...0230626063528_create_wallet_table.down.sql | 1 + .../20230626063528_create_wallet_table.up.sql | 13 ++ ...26065705_create_transaction_table.down.sql | 1 + ...0626065705_create_transaction_table.up.sql | 20 +++ ...3072305_create_wallet_transaction.down.sql | 1 + ...913072305_create_wallet_transaction.up.sql | 19 +++ .../20230527074947_create_schema.down.sql | 1 + .../20230527074947_create_schema.up.sql | 1 + go.mod | 2 + internal/config/config.go | 12 ++ internal/domain/usecase/wallet.go | 4 + internal/logic/orderservice/utils.go | 15 --- internal/model/transaction_model.go | 24 ++++ internal/model/transaction_model_gen.go | 118 ++++++++++++++++++ internal/model/vars.go | 5 + internal/model/wallet_journal_model.go | 24 ++++ internal/model/wallet_journal_model_gen.go | 102 +++++++++++++++ internal/model/wallet_model.go | 24 ++++ internal/model/wallet_model_gen.go | 112 +++++++++++++++++ internal/svc/inject_mysql.go | 48 +++++++ internal/svc/service_context.go | 8 ++ 23 files changed, 563 insertions(+), 15 deletions(-) create mode 100644 generate/database/mysql/20230626063528_create_wallet_table.down.sql create mode 100644 generate/database/mysql/20230626063528_create_wallet_table.up.sql create mode 100644 generate/database/mysql/20230626065705_create_transaction_table.down.sql create mode 100644 generate/database/mysql/20230626065705_create_transaction_table.up.sql create mode 100644 generate/database/mysql/20230913072305_create_wallet_transaction.down.sql create mode 100644 generate/database/mysql/20230913072305_create_wallet_transaction.up.sql create mode 100644 generate/database/mysql/create/20230527074947_create_schema.down.sql create mode 100644 generate/database/mysql/create/20230527074947_create_schema.up.sql create mode 100644 internal/domain/usecase/wallet.go create mode 100755 internal/model/transaction_model.go create mode 100755 internal/model/transaction_model_gen.go create mode 100644 internal/model/vars.go create mode 100755 internal/model/wallet_journal_model.go create mode 100755 internal/model/wallet_journal_model_gen.go create mode 100755 internal/model/wallet_model.go create mode 100755 internal/model/wallet_model_gen.go create mode 100644 internal/svc/inject_mysql.go diff --git a/Makefile b/Makefile index eac2065..b843793 100644 --- a/Makefile +++ b/Makefile @@ -62,3 +62,14 @@ mock-gen: # 建立 mock 資料 .PHONY: migrate-database migrate-database: migrate -source file://generate/database/mongodb -database 'mongodb://127.0.0.1:27017/digimon_order' up + +.PHONY: gen-my-sql-model +gen-my-sql-model: # 建立 rpc 資料庫 + goctl model mysql ddl -s ./generate/database/mysql/20230626063528_create_wallet_table.up.sql --style $(GO_ZERO_STYLE) -d ./internal/model -i '' + goctl model mysql ddl -s ./generate/database/mysql/20230626065705_create_transaction_table.up.sql --style $(GO_ZERO_STYLE) -d ./internal/model -i '' + goctl model mysql ddl -s ./generate/database/mysql/20230913072305_create_wallet_transaction.up.sql --style $(GO_ZERO_STYLE) -d ./internal/model -i '' + @echo "Generate mysql model files successfully" + +.PHONY: migrate-database +migrate-database: + migrate -source file://generate/database/mysql -database 'mysql://root:yytt@tcp(127.0.0.1:3306)/digimon_wallet' up diff --git a/etc/trade.yaml b/etc/trade.yaml index 595e41c..ccba184 100644 --- a/etc/trade.yaml +++ b/etc/trade.yaml @@ -27,3 +27,15 @@ Mongo: MaxPoolSize: 30 MinPoolSize: 10 MaxConnIdleTime: 30m + +DB: + Host: 127.0.0.1 + Port: 3306 + User: username + Password: password + name: permission + MaxIdleConns: 10 + MaxOpenConns: 200 + ConnMaxLifetime: 10s + InterpolateParams: false + Database: digimon_wallet diff --git a/generate/database/mysql/20230626063528_create_wallet_table.down.sql b/generate/database/mysql/20230626063528_create_wallet_table.down.sql new file mode 100644 index 0000000..c6061d5 --- /dev/null +++ b/generate/database/mysql/20230626063528_create_wallet_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS `wallet`; diff --git a/generate/database/mysql/20230626063528_create_wallet_table.up.sql b/generate/database/mysql/20230626063528_create_wallet_table.up.sql new file mode 100644 index 0000000..7211571 --- /dev/null +++ b/generate/database/mysql/20230626063528_create_wallet_table.up.sql @@ -0,0 +1,13 @@ +CREATE TABLE `wallet` ( + `id` BIGINT(20) AUTO_INCREMENT NOT NULL COMMENT '錢包流水號', + `uid` VARCHAR(50) NOT NULL COMMENT '用戶ID', + `brand` VARCHAR(50) DEFAULT '' NOT NULL COMMENT '品牌名稱', + `currency` VARCHAR(20) NOT NULL COMMENT '幣別(或平台點數)', + `balance` DECIMAL(30, 18) UNSIGNED DEFAULT 0 NOT NULL COMMENT '錢包餘額', + `wallet_type` TINYINT NOT NULL COMMENT '錢包種類: 1=可用, 2=凍結, 3=限制(僅出金)', + `created_at` BIGINT NOT NULL COMMENT '創建時間', + `updated_at` BIGINT NOT NULL COMMENT '更新時間', + PRIMARY KEY (`id`), + UNIQUE INDEX `uq_user_currency_type` (`uid`, `currency`, `wallet_type`), + INDEX `idx_user_currency` (`uid`, `currency`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用戶錢包'; \ No newline at end of file diff --git a/generate/database/mysql/20230626065705_create_transaction_table.down.sql b/generate/database/mysql/20230626065705_create_transaction_table.down.sql new file mode 100644 index 0000000..7285aba --- /dev/null +++ b/generate/database/mysql/20230626065705_create_transaction_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS `transaction`; diff --git a/generate/database/mysql/20230626065705_create_transaction_table.up.sql b/generate/database/mysql/20230626065705_create_transaction_table.up.sql new file mode 100644 index 0000000..0069db9 --- /dev/null +++ b/generate/database/mysql/20230626065705_create_transaction_table.up.sql @@ -0,0 +1,20 @@ +CREATE TABLE `transaction` ( + `id` BIGINT(20) AUTO_INCREMENT NOT NULL COMMENT '交易流水號', + `tx_id` VARCHAR(200) NOT NULL COMMENT '交易 ID', + `order_id` VARCHAR(200) NOT NULL COMMENT '訂單 ID', + `brand` VARCHAR(50) NOT NULL COMMENT '品牌名稱', + `uid` VARCHAR(50) NOT NULL COMMENT '發起 UID', + `to_uid` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '接收方UID', + `type` TINYINT NOT NULL COMMENT '交易類型: 1=提現, 2=充值', + `business_type` TINYINT NOT NULL COMMENT '業務類型', + `currency` VARCHAR(20) NOT NULL COMMENT '幣種', + `amount` DECIMAL(30, 18) UNSIGNED DEFAULT 0 NOT NULL COMMENT '交易金額', + `balance` DECIMAL(30, 18) UNSIGNED DEFAULT 0 NOT NULL COMMENT '交易後餘額', + `before_balance` DECIMAL(30, 18) UNSIGNED DEFAULT 0 NOT NULL COMMENT '交易前餘額', + `status` TINYINT NOT NULL DEFAULT 0 COMMENT '結算狀態', + `create_time` BIGINT NOT NULL COMMENT '創建時間(Unix 時間戳,毫秒)', + PRIMARY KEY (`id`), + UNIQUE INDEX `uk_order_id_type` (`order_id`, `type`), + INDEX `idx_uid` (`uid`), + INDEX `idx_order_id` (`order_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用戶錢包交異動紀錄'; \ No newline at end of file diff --git a/generate/database/mysql/20230913072305_create_wallet_transaction.down.sql b/generate/database/mysql/20230913072305_create_wallet_transaction.down.sql new file mode 100644 index 0000000..d565355 --- /dev/null +++ b/generate/database/mysql/20230913072305_create_wallet_transaction.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS `wallet_transaction`; diff --git a/generate/database/mysql/20230913072305_create_wallet_transaction.up.sql b/generate/database/mysql/20230913072305_create_wallet_transaction.up.sql new file mode 100644 index 0000000..bce7714 --- /dev/null +++ b/generate/database/mysql/20230913072305_create_wallet_transaction.up.sql @@ -0,0 +1,19 @@ +CREATE TABLE `wallet_journal` ( + `id` BIGINT(20) AUTO_INCREMENT NOT NULL COMMENT '錢包賬本流水號', + `transaction_id` BIGINT(20) NOT NULL COMMENT '交易 ID,對應 transaction 表', + `order_id` VARCHAR(200) NOT NULL COMMENT '訂單 ID,對應 order 表', + `brand` VARCHAR(50) NOT NULL COMMENT '品牌名稱', + `uid` VARCHAR(50) NOT NULL COMMENT '用戶 ID', + `wallet_type` TINYINT NOT NULL COMMENT '餘額種類: 1=可用, 2=凍結, 3=限制(僅出金)', + `currency` VARCHAR(20) NOT NULL COMMENT '幣種或平台點數', + `transaction_amount` DECIMAL(30, 18) UNSIGNED DEFAULT 0 NOT NULL COMMENT '交易金額', + `post_transaction_balance` DECIMAL(30, 18) UNSIGNED DEFAULT 0 NOT NULL COMMENT '交易後餘額', + `business_type` TINYINT NOT NULL COMMENT '業務類型', + `status` TINYINT NOT NULL DEFAULT 0 COMMENT '狀態', + `due_time` BIGINT NOT NULL DEFAULT 0 COMMENT 'T+N 執行時間', + `created_at` BIGINT NOT NULL COMMENT '創建時間(Unix 時間戳,毫秒)', + PRIMARY KEY (`id`), + KEY `idx_user_brand` (`uid`, `brand`), + KEY `idx_order_id` (`order_id`), + KEY `idx_status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用戶錢包變動'; \ No newline at end of file diff --git a/generate/database/mysql/create/20230527074947_create_schema.down.sql b/generate/database/mysql/create/20230527074947_create_schema.down.sql new file mode 100644 index 0000000..9b4cb1d --- /dev/null +++ b/generate/database/mysql/create/20230527074947_create_schema.down.sql @@ -0,0 +1 @@ +DROP DATABASE IF EXISTS `digimon_wallet`; \ No newline at end of file diff --git a/generate/database/mysql/create/20230527074947_create_schema.up.sql b/generate/database/mysql/create/20230527074947_create_schema.up.sql new file mode 100644 index 0000000..0fb707a --- /dev/null +++ b/generate/database/mysql/create/20230527074947_create_schema.up.sql @@ -0,0 +1 @@ +CREATE DATABASE IF NOT EXISTS `digimon_wallet`; \ No newline at end of file diff --git a/go.mod b/go.mod index 640d4fa..7bf2ba6 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -33,6 +34,7 @@ require ( github.com/go-openapi/swag v0.22.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect diff --git a/internal/config/config.go b/internal/config/config.go index 516850b..f709818 100755 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -24,4 +24,16 @@ type Config struct { // Compressors []string // EnableStandardReadWriteSplitMode bool } + + DB struct { + User string + Password string + Host string + Port int64 + Database string + MaxIdleConns int + MaxOpenConns int + ConnMaxLifetime time.Duration + InterpolateParams bool + } } diff --git a/internal/domain/usecase/wallet.go b/internal/domain/usecase/wallet.go new file mode 100644 index 0000000..c97721b --- /dev/null +++ b/internal/domain/usecase/wallet.go @@ -0,0 +1,4 @@ +package usecase + +type WalletUseCase interface { +} diff --git a/internal/logic/orderservice/utils.go b/internal/logic/orderservice/utils.go index 02c79fa..ac30a7d 100644 --- a/internal/logic/orderservice/utils.go +++ b/internal/logic/orderservice/utils.go @@ -2,23 +2,8 @@ package orderservicelogic import ( "github.com/shopspring/decimal" - "github.com/zeromicro/go-zero/core/logx" ) -func decimalPtrFromString(val string) *decimal.Decimal { - if val == "" { - return nil - } - dec, err := decimal.NewFromString(val) - if err != nil { - logx.Errorf("Failed to convert string to decimal: %v", err) - - return nil - } - - return &dec -} - // getInt64Value 將 *int64 的值返回,如果為 nil 則返回 0 func getInt64Value(val *int64) int64 { if val == nil { diff --git a/internal/model/transaction_model.go b/internal/model/transaction_model.go new file mode 100755 index 0000000..14cd7cc --- /dev/null +++ b/internal/model/transaction_model.go @@ -0,0 +1,24 @@ +package model + +import "github.com/zeromicro/go-zero/core/stores/sqlx" + +var _ TransactionModel = (*customTransactionModel)(nil) + +type ( + // TransactionModel is an interface to be customized, add more methods here, + // and implement the added methods in customTransactionModel. + TransactionModel interface { + transactionModel + } + + customTransactionModel struct { + *defaultTransactionModel + } +) + +// NewTransactionModel returns a model for the database table. +func NewTransactionModel(conn sqlx.SqlConn) TransactionModel { + return &customTransactionModel{ + defaultTransactionModel: newTransactionModel(conn), + } +} diff --git a/internal/model/transaction_model_gen.go b/internal/model/transaction_model_gen.go new file mode 100755 index 0000000..0322db1 --- /dev/null +++ b/internal/model/transaction_model_gen.go @@ -0,0 +1,118 @@ +// Code generated by goctl. DO NOT EDIT. + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + transactionFieldNames = builder.RawFieldNames(&Transaction{}) + transactionRows = strings.Join(transactionFieldNames, ",") + transactionRowsExpectAutoSet = strings.Join(stringx.Remove(transactionFieldNames, "`id`"), ",") + transactionRowsWithPlaceHolder = strings.Join(stringx.Remove(transactionFieldNames, "`id`"), "=?,") + "=?" +) + +type ( + transactionModel interface { + Insert(ctx context.Context, data *Transaction) (sql.Result, error) + FindOne(ctx context.Context, id int64) (*Transaction, error) + FindOneByOrderIdType(ctx context.Context, orderId string, tp int64) (*Transaction, error) + Update(ctx context.Context, data *Transaction) error + Delete(ctx context.Context, id int64) error + } + + defaultTransactionModel struct { + conn sqlx.SqlConn + table string + } + + Transaction struct { + Id int64 `db:"id"` // 交易流水號 + TxId string `db:"tx_id"` // 交易 ID + OrderId string `db:"order_id"` // 訂單 ID + Brand string `db:"brand"` // 品牌名稱 + Uid string `db:"uid"` // 發起 UID + ToUid string `db:"to_uid"` // 接收方UID + Type int64 `db:"type"` // 交易類型: 1=提現, 2=充值 + BusinessType int64 `db:"business_type"` // 業務類型 + Currency string `db:"currency"` // 幣種 + Amount float64 `db:"amount"` // 交易金額 + Balance float64 `db:"balance"` // 交易後餘額 + BeforeBalance float64 `db:"before_balance"` // 交易前餘額 + Status int64 `db:"status"` // 結算狀態 + CreateTime int64 `db:"create_time"` // 創建時間(Unix 時間戳,毫秒) + } +) + +func newTransactionModel(conn sqlx.SqlConn) *defaultTransactionModel { + return &defaultTransactionModel{ + conn: conn, + table: "`transaction`", + } +} + +func (m *defaultTransactionModel) withSession(session sqlx.Session) *defaultTransactionModel { + return &defaultTransactionModel{ + conn: sqlx.NewSqlConnFromSession(session), + table: "`transaction`", + } +} + +func (m *defaultTransactionModel) Delete(ctx context.Context, id int64) error { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, query, id) + return err +} + +func (m *defaultTransactionModel) FindOne(ctx context.Context, id int64) (*Transaction, error) { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", transactionRows, m.table) + var resp Transaction + err := m.conn.QueryRowCtx(ctx, &resp, query, id) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultTransactionModel) FindOneByOrderIdType(ctx context.Context, orderId string, tp int64) (*Transaction, error) { + var resp Transaction + query := fmt.Sprintf("select %s from %s where `order_id` = ? and `type` = ? limit 1", transactionRows, m.table) + err := m.conn.QueryRowCtx(ctx, &resp, query, orderId, tp) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultTransactionModel) Insert(ctx context.Context, data *Transaction) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, transactionRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.TxId, data.OrderId, data.Brand, data.Uid, data.ToUid, data.Type, data.BusinessType, data.Currency, data.Amount, data.Balance, data.BeforeBalance, data.Status, data.CreateTime) + return ret, err +} + +func (m *defaultTransactionModel) Update(ctx context.Context, newData *Transaction) error { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, transactionRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, newData.TxId, newData.OrderId, newData.Brand, newData.Uid, newData.ToUid, newData.Type, newData.BusinessType, newData.Currency, newData.Amount, newData.Balance, newData.BeforeBalance, newData.Status, newData.CreateTime, newData.Id) + return err +} + +func (m *defaultTransactionModel) tableName() string { + return m.table +} diff --git a/internal/model/vars.go b/internal/model/vars.go new file mode 100644 index 0000000..69ca814 --- /dev/null +++ b/internal/model/vars.go @@ -0,0 +1,5 @@ +package model + +import "github.com/zeromicro/go-zero/core/stores/sqlx" + +var ErrNotFound = sqlx.ErrNotFound diff --git a/internal/model/wallet_journal_model.go b/internal/model/wallet_journal_model.go new file mode 100755 index 0000000..7064fa0 --- /dev/null +++ b/internal/model/wallet_journal_model.go @@ -0,0 +1,24 @@ +package model + +import "github.com/zeromicro/go-zero/core/stores/sqlx" + +var _ WalletJournalModel = (*customWalletJournalModel)(nil) + +type ( + // WalletJournalModel is an interface to be customized, add more methods here, + // and implement the added methods in customWalletJournalModel. + WalletJournalModel interface { + walletJournalModel + } + + customWalletJournalModel struct { + *defaultWalletJournalModel + } +) + +// NewWalletJournalModel returns a model for the database table. +func NewWalletJournalModel(conn sqlx.SqlConn) WalletJournalModel { + return &customWalletJournalModel{ + defaultWalletJournalModel: newWalletJournalModel(conn), + } +} diff --git a/internal/model/wallet_journal_model_gen.go b/internal/model/wallet_journal_model_gen.go new file mode 100755 index 0000000..cb28c73 --- /dev/null +++ b/internal/model/wallet_journal_model_gen.go @@ -0,0 +1,102 @@ +// Code generated by goctl. DO NOT EDIT. + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + walletJournalFieldNames = builder.RawFieldNames(&WalletJournal{}) + walletJournalRows = strings.Join(walletJournalFieldNames, ",") + walletJournalRowsExpectAutoSet = strings.Join(stringx.Remove(walletJournalFieldNames, "`id`"), ",") + walletJournalRowsWithPlaceHolder = strings.Join(stringx.Remove(walletJournalFieldNames, "`id`"), "=?,") + "=?" +) + +type ( + walletJournalModel interface { + Insert(ctx context.Context, data *WalletJournal) (sql.Result, error) + FindOne(ctx context.Context, id int64) (*WalletJournal, error) + Update(ctx context.Context, data *WalletJournal) error + Delete(ctx context.Context, id int64) error + } + + defaultWalletJournalModel struct { + conn sqlx.SqlConn + table string + } + + WalletJournal struct { + Id int64 `db:"id"` // 錢包賬本流水號 + TransactionId int64 `db:"transaction_id"` // 交易 ID,對應 transaction 表 + OrderId string `db:"order_id"` // 訂單 ID,對應 order 表 + Brand string `db:"brand"` // 品牌名稱 + Uid string `db:"uid"` // 用戶 ID + WalletType int64 `db:"wallet_type"` // 餘額種類: 1=可用, 2=凍結, 3=限制(僅出金) + Currency string `db:"currency"` // 幣種或平台點數 + TransactionAmount float64 `db:"transaction_amount"` // 交易金額 + PostTransactionBalance float64 `db:"post_transaction_balance"` // 交易後餘額 + BusinessType int64 `db:"business_type"` // 業務類型 + Status int64 `db:"status"` // 狀態 + DueTime int64 `db:"due_time"` // T+N 執行時間 + CreatedAt int64 `db:"created_at"` // 創建時間(Unix 時間戳,毫秒) + } +) + +func newWalletJournalModel(conn sqlx.SqlConn) *defaultWalletJournalModel { + return &defaultWalletJournalModel{ + conn: conn, + table: "`wallet_journal`", + } +} + +func (m *defaultWalletJournalModel) withSession(session sqlx.Session) *defaultWalletJournalModel { + return &defaultWalletJournalModel{ + conn: sqlx.NewSqlConnFromSession(session), + table: "`wallet_journal`", + } +} + +func (m *defaultWalletJournalModel) Delete(ctx context.Context, id int64) error { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, query, id) + return err +} + +func (m *defaultWalletJournalModel) FindOne(ctx context.Context, id int64) (*WalletJournal, error) { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", walletJournalRows, m.table) + var resp WalletJournal + err := m.conn.QueryRowCtx(ctx, &resp, query, id) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultWalletJournalModel) Insert(ctx context.Context, data *WalletJournal) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, walletJournalRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.TransactionId, data.OrderId, data.Brand, data.Uid, data.WalletType, data.Currency, data.TransactionAmount, data.PostTransactionBalance, data.BusinessType, data.Status, data.DueTime, data.CreatedAt) + return ret, err +} + +func (m *defaultWalletJournalModel) Update(ctx context.Context, data *WalletJournal) error { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, walletJournalRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, data.TransactionId, data.OrderId, data.Brand, data.Uid, data.WalletType, data.Currency, data.TransactionAmount, data.PostTransactionBalance, data.BusinessType, data.Status, data.DueTime, data.CreatedAt, data.Id) + return err +} + +func (m *defaultWalletJournalModel) tableName() string { + return m.table +} diff --git a/internal/model/wallet_model.go b/internal/model/wallet_model.go new file mode 100755 index 0000000..f4349db --- /dev/null +++ b/internal/model/wallet_model.go @@ -0,0 +1,24 @@ +package model + +import "github.com/zeromicro/go-zero/core/stores/sqlx" + +var _ WalletModel = (*customWalletModel)(nil) + +type ( + // WalletModel is an interface to be customized, add more methods here, + // and implement the added methods in customWalletModel. + WalletModel interface { + walletModel + } + + customWalletModel struct { + *defaultWalletModel + } +) + +// NewWalletModel returns a model for the database table. +func NewWalletModel(conn sqlx.SqlConn) WalletModel { + return &customWalletModel{ + defaultWalletModel: newWalletModel(conn), + } +} diff --git a/internal/model/wallet_model_gen.go b/internal/model/wallet_model_gen.go new file mode 100755 index 0000000..c6358c9 --- /dev/null +++ b/internal/model/wallet_model_gen.go @@ -0,0 +1,112 @@ +// Code generated by goctl. DO NOT EDIT. + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + walletFieldNames = builder.RawFieldNames(&Wallet{}) + walletRows = strings.Join(walletFieldNames, ",") + walletRowsExpectAutoSet = strings.Join(stringx.Remove(walletFieldNames, "`id`"), ",") + walletRowsWithPlaceHolder = strings.Join(stringx.Remove(walletFieldNames, "`id`"), "=?,") + "=?" +) + +type ( + walletModel interface { + Insert(ctx context.Context, data *Wallet) (sql.Result, error) + FindOne(ctx context.Context, id int64) (*Wallet, error) + FindOneByUidCurrencyWalletType(ctx context.Context, uid string, currency string, walletType int64) (*Wallet, error) + Update(ctx context.Context, data *Wallet) error + Delete(ctx context.Context, id int64) error + } + + defaultWalletModel struct { + conn sqlx.SqlConn + table string + } + + Wallet struct { + Id int64 `db:"id"` // 錢包流水號 + Uid string `db:"uid"` // 用戶ID + Brand string `db:"brand"` // 品牌名稱 + Currency string `db:"currency"` // 幣別(或平台點數) + Balance float64 `db:"balance"` // 錢包餘額 + WalletType int64 `db:"wallet_type"` // 錢包種類: 1=可用, 2=凍結, 3=限制(僅出金) + CreatedAt int64 `db:"created_at"` // 創建時間 + UpdatedAt int64 `db:"updated_at"` // 更新時間 + } +) + +func newWalletModel(conn sqlx.SqlConn) *defaultWalletModel { + return &defaultWalletModel{ + conn: conn, + table: "`wallet`", + } +} + +func (m *defaultWalletModel) withSession(session sqlx.Session) *defaultWalletModel { + return &defaultWalletModel{ + conn: sqlx.NewSqlConnFromSession(session), + table: "`wallet`", + } +} + +func (m *defaultWalletModel) Delete(ctx context.Context, id int64) error { + query := fmt.Sprintf("delete from %s where `id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, query, id) + return err +} + +func (m *defaultWalletModel) FindOne(ctx context.Context, id int64) (*Wallet, error) { + query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", walletRows, m.table) + var resp Wallet + err := m.conn.QueryRowCtx(ctx, &resp, query, id) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultWalletModel) FindOneByUidCurrencyWalletType(ctx context.Context, uid string, currency string, walletType int64) (*Wallet, error) { + var resp Wallet + query := fmt.Sprintf("select %s from %s where `uid` = ? and `currency` = ? and `wallet_type` = ? limit 1", walletRows, m.table) + err := m.conn.QueryRowCtx(ctx, &resp, query, uid, currency, walletType) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultWalletModel) Insert(ctx context.Context, data *Wallet) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?)", m.table, walletRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.Uid, data.Brand, data.Currency, data.Balance, data.WalletType, data.CreatedAt, data.UpdatedAt) + return ret, err +} + +func (m *defaultWalletModel) Update(ctx context.Context, newData *Wallet) error { + query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, walletRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, newData.Uid, newData.Brand, newData.Currency, newData.Balance, newData.WalletType, newData.CreatedAt, newData.UpdatedAt, newData.Id) + return err +} + +func (m *defaultWalletModel) tableName() string { + return m.table +} diff --git a/internal/svc/inject_mysql.go b/internal/svc/inject_mysql.go new file mode 100644 index 0000000..37c626f --- /dev/null +++ b/internal/svc/inject_mysql.go @@ -0,0 +1,48 @@ +package svc + +import ( + "app-cloudep-trade-service/internal/config" + model "app-cloudep-trade-service/internal/model" + "database/sql" + "fmt" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) + +func mustDSN(c config.Config) string { + // 構建 DSN 字符串 + return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true&interpolateParams=%t", + c.DB.User, + c.DB.Password, + c.DB.Host, + c.DB.Port, + c.DB.Database, + c.DB.InterpolateParams, + ) +} + +func newDatabase(c config.Config) (*sql.DB, error) { + // 創建基礎的 *sql.DB 連接 + db, err := sql.Open("mysql", mustDSN(c)) + if err != nil { + logx.Error(fmt.Errorf("failed to connect to database: %w", err)) + + return nil, err + } + + // 設置數據庫連接池參數 + db.SetMaxIdleConns(c.DB.MaxIdleConns) + db.SetMaxOpenConns(c.DB.MaxOpenConns) + db.SetConnMaxLifetime(c.DB.ConnMaxLifetime) + + return db, nil +} + +// MustWalletModel 連線 wallet 時 +func MustWalletModel(db *sql.DB) model.WalletModel { + // 創建並返回 *sqlx.SqlConn + sqlConn := sqlx.NewSqlConnFromDB(db) + + return model.NewWalletModel(sqlConn) +} diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index 96a4274..ee1e24e 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -3,6 +3,7 @@ package svc import ( "app-cloudep-trade-service/internal/config" duc "app-cloudep-trade-service/internal/domain/usecase" + "app-cloudep-trade-service/internal/model" "app-cloudep-trade-service/internal/usecase" ers "code.30cm.net/digimon/library-go/errs" @@ -15,6 +16,7 @@ type ServiceContext struct { Validate vi.Validate OrderUseCase duc.OrderUseCase + WalletModel model.WalletModel } func NewServiceContext(c config.Config) *ServiceContext { @@ -26,6 +28,11 @@ func NewServiceContext(c config.Config) *ServiceContext { OrderModel: om, }) + mysql, err := newDatabase(c) + if err != nil { + panic("failed to connect to wallet") + } + return &ServiceContext{ Config: c, Validate: vi.MustValidator( @@ -34,5 +41,6 @@ func NewServiceContext(c config.Config) *ServiceContext { ), OrderUseCase: orderUseCase, + WalletModel: MustWalletModel(mysql), } }