package postgres import ( "context" "fmt" "time" "github.com/genex/chain-indexer/internal/domain/entity" "github.com/genex/chain-indexer/internal/domain/repository" "gorm.io/gorm" ) // Compile-time check: PostgresTransactionRepository implements repository.TransactionRepository. var _ repository.TransactionRepository = (*PostgresTransactionRepository)(nil) // chainTxModel is the GORM persistence model for the chain_transactions table. type chainTxModel struct { Hash string `gorm:"column:hash;primaryKey"` BlockHeight int64 `gorm:"column:block_height;not null"` FromAddr string `gorm:"column:from_addr;not null"` ToAddr string `gorm:"column:to_addr;not null"` Amount string `gorm:"column:amount;not null;default:0"` Status string `gorm:"column:status;not null;default:confirmed"` CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` } func (chainTxModel) TableName() string { return "chain_transactions" } func (m *chainTxModel) toEntity() *entity.ChainTransaction { return &entity.ChainTransaction{ Hash: m.Hash, BlockHeight: m.BlockHeight, From: m.FromAddr, To: m.ToAddr, Amount: m.Amount, Status: m.Status, Timestamp: m.CreatedAt, } } func chainTxFromEntity(e *entity.ChainTransaction) *chainTxModel { return &chainTxModel{ Hash: e.Hash, BlockHeight: e.BlockHeight, FromAddr: e.From, ToAddr: e.To, Amount: e.Amount, Status: e.Status, } } // PostgresTransactionRepository is the GORM-backed implementation of // repository.TransactionRepository. type PostgresTransactionRepository struct { db *gorm.DB } // NewPostgresTransactionRepository creates a new repository backed by PostgreSQL via GORM. func NewPostgresTransactionRepository(db *gorm.DB) *PostgresTransactionRepository { return &PostgresTransactionRepository{db: db} } func (r *PostgresTransactionRepository) Save(ctx context.Context, tx *entity.ChainTransaction) error { if tx == nil { return fmt.Errorf("transaction must not be nil") } model := chainTxFromEntity(tx) return r.db.WithContext(ctx).Save(model).Error } func (r *PostgresTransactionRepository) SaveBatch(ctx context.Context, txs []*entity.ChainTransaction) error { if len(txs) == 0 { return nil } models := make([]chainTxModel, len(txs)) for i, tx := range txs { models[i] = *chainTxFromEntity(tx) } return r.db.WithContext(ctx).Save(&models).Error } func (r *PostgresTransactionRepository) FindByHash(ctx context.Context, hash string) (*entity.ChainTransaction, error) { var model chainTxModel err := r.db.WithContext(ctx).Where("hash = ?", hash).First(&model).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil, nil } return nil, err } return model.toEntity(), nil } func (r *PostgresTransactionRepository) FindByBlock(ctx context.Context, blockHeight int64) ([]*entity.ChainTransaction, error) { var models []chainTxModel err := r.db.WithContext(ctx).Where("block_height = ?", blockHeight).Find(&models).Error if err != nil { return nil, err } result := make([]*entity.ChainTransaction, len(models)) for i := range models { result[i] = models[i].toEntity() } return result, nil }