gcx/backend/services/trading-service/internal/infrastructure/postgres/trade_repository.go

147 lines
4.5 KiB
Go

package postgres
import (
"context"
"fmt"
"time"
"github.com/genex/trading-service/internal/domain/entity"
"github.com/genex/trading-service/internal/domain/repository"
"github.com/genex/trading-service/internal/domain/vo"
"gorm.io/gorm"
)
// Compile-time check: PostgresTradeRepository implements repository.TradeRepository.
var _ repository.TradeRepository = (*PostgresTradeRepository)(nil)
// tradeModel is the GORM persistence model for the trades table.
type tradeModel struct {
ID string `gorm:"column:id;primaryKey"`
BuyOrderID string `gorm:"column:buy_order_id;not null"`
SellOrderID string `gorm:"column:sell_order_id;not null"`
CouponID string `gorm:"column:coupon_id;not null"`
BuyerID string `gorm:"column:buyer_id;not null"`
SellerID string `gorm:"column:seller_id;not null"`
Price float64 `gorm:"column:price;not null"`
Quantity int `gorm:"column:quantity;not null;default:1"`
BuyerFee float64 `gorm:"column:buyer_fee;not null;default:0"`
SellerFee float64 `gorm:"column:seller_fee;not null;default:0"`
Status string `gorm:"column:status;not null;default:pending"`
TxHash *string `gorm:"column:tx_hash"`
SettledAt *time.Time `gorm:"column:settled_at"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
}
func (tradeModel) TableName() string { return "trades" }
func (m *tradeModel) toEntity() *entity.Trade {
return &entity.Trade{
ID: m.ID,
CouponID: m.CouponID,
BuyOrderID: m.BuyOrderID,
SellOrderID: m.SellOrderID,
BuyerID: m.BuyerID,
SellerID: m.SellerID,
Price: vo.MustNewPrice(m.Price),
Quantity: m.Quantity,
BuyerFee: m.BuyerFee,
SellerFee: m.SellerFee,
CreatedAt: m.CreatedAt,
}
}
func tradeFromEntity(e *entity.Trade) *tradeModel {
return &tradeModel{
ID: e.ID,
BuyOrderID: e.BuyOrderID,
SellOrderID: e.SellOrderID,
CouponID: e.CouponID,
BuyerID: e.BuyerID,
SellerID: e.SellerID,
Price: e.Price.Float64(),
Quantity: e.Quantity,
BuyerFee: e.BuyerFee,
SellerFee: e.SellerFee,
Status: "pending",
CreatedAt: e.CreatedAt,
}
}
// PostgresTradeRepository is the GORM-backed implementation of repository.TradeRepository.
type PostgresTradeRepository struct {
db *gorm.DB
}
// NewPostgresTradeRepository creates a new repository backed by PostgreSQL via GORM.
func NewPostgresTradeRepository(db *gorm.DB) *PostgresTradeRepository {
return &PostgresTradeRepository{db: db}
}
func (r *PostgresTradeRepository) Save(ctx context.Context, trade *entity.Trade) error {
if trade == nil {
return fmt.Errorf("trade must not be nil")
}
model := tradeFromEntity(trade)
return r.db.WithContext(ctx).Save(model).Error
}
func (r *PostgresTradeRepository) FindByID(ctx context.Context, id string) (*entity.Trade, error) {
var model tradeModel
err := r.db.WithContext(ctx).Where("id = ?", id).First(&model).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, fmt.Errorf("trade not found: %s", id)
}
return nil, err
}
return model.toEntity(), nil
}
func (r *PostgresTradeRepository) FindByOrderID(ctx context.Context, orderID string) ([]*entity.Trade, error) {
var models []tradeModel
err := r.db.WithContext(ctx).
Where("buy_order_id = ? OR sell_order_id = ?", orderID, orderID).
Order("created_at DESC").
Find(&models).Error
if err != nil {
return nil, err
}
result := make([]*entity.Trade, len(models))
for i := range models {
result[i] = models[i].toEntity()
}
return result, nil
}
func (r *PostgresTradeRepository) FindRecent(ctx context.Context, limit int) ([]*entity.Trade, error) {
var models []tradeModel
err := r.db.WithContext(ctx).Order("created_at DESC").Limit(limit).Find(&models).Error
if err != nil {
return nil, err
}
result := make([]*entity.Trade, len(models))
for i := range models {
result[i] = models[i].toEntity()
}
return result, nil
}
func (r *PostgresTradeRepository) FindByCouponID(ctx context.Context, couponID string) ([]*entity.Trade, error) {
var models []tradeModel
err := r.db.WithContext(ctx).Where("coupon_id = ?", couponID).Order("created_at DESC").Find(&models).Error
if err != nil {
return nil, err
}
result := make([]*entity.Trade, len(models))
for i := range models {
result[i] = models[i].toEntity()
}
return result, nil
}
func (r *PostgresTradeRepository) Count(ctx context.Context) (int64, error) {
var count int64
err := r.db.WithContext(ctx).Model(&tradeModel{}).Count(&count).Error
return count, err
}