2026-06-23 11:53:00 +08:00

70 lines
2.1 KiB
Go

package mysql
import (
"context"
"database/sql"
"encoding/json"
"errors"
"hyapp/pkg/appcode"
"hyapp/pkg/xerr"
)
type transactionRow struct {
TransactionID string
MetadataJSON string
}
func (r *Repository) lookupTransaction(ctx context.Context, tx *sql.Tx, commandID string, requestHash string, bizType string) (transactionRow, bool, error) {
return r.lookupTransactionWithConflictCode(ctx, tx, commandID, requestHash, bizType, xerr.LedgerConflict)
}
func (r *Repository) lookupTransactionWithConflictCode(ctx context.Context, tx *sql.Tx, commandID string, requestHash string, bizType string, conflictCode xerr.Code) (transactionRow, bool, error) {
row := tx.QueryRowContext(ctx,
`SELECT transaction_id, request_hash, biz_type, COALESCE(CAST(metadata_json AS CHAR), '{}')
FROM wallet_transactions
WHERE app_code = ? AND command_id = ?
FOR UPDATE`,
appcode.FromContext(ctx),
commandID,
)
var txRow transactionRow
var storedHash string
var storedBizType string
if err := row.Scan(&txRow.TransactionID, &storedHash, &storedBizType, &txRow.MetadataJSON); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return transactionRow{}, false, nil
}
return transactionRow{}, false, err
}
if storedHash != requestHash || storedBizType != bizType {
return transactionRow{}, true, xerr.New(conflictCode, "wallet command idempotency conflict")
}
return txRow, true, nil
}
func (r *Repository) insertTransaction(ctx context.Context, tx *sql.Tx, transactionID string, commandID string, bizType string, requestHash string, externalRef string, metadata any, nowMs int64) error {
metadataJSON, err := json.Marshal(metadata)
if err != nil {
return err
}
_, err = tx.ExecContext(ctx,
`INSERT INTO wallet_transactions (
app_code, transaction_id, command_id, biz_type, status, request_hash, external_ref, metadata_json, created_at_ms, updated_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
appcode.FromContext(ctx),
transactionID,
commandID,
bizType,
transactionStatusSucceeded,
requestHash,
externalRef,
string(metadataJSON),
nowMs,
nowMs,
)
return err
}