147 lines
4.5 KiB
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
|
|
}
|