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 }