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: PostgresBlockRepository implements repository.BlockRepository. var _ repository.BlockRepository = (*PostgresBlockRepository)(nil) // blockModel is the GORM persistence model for the blocks table. type blockModel struct { Height int64 `gorm:"column:height;primaryKey"` Hash string `gorm:"column:hash;not null;uniqueIndex"` TxCount int `gorm:"column:tx_count;not null;default:0"` IndexedAt time.Time `gorm:"column:indexed_at;autoCreateTime"` CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` } func (blockModel) TableName() string { return "blocks" } func (m *blockModel) toEntity() *entity.Block { return &entity.Block{ Height: m.Height, Hash: m.Hash, Timestamp: m.IndexedAt, TxCount: m.TxCount, } } func blockFromEntity(e *entity.Block) *blockModel { return &blockModel{ Height: e.Height, Hash: e.Hash, TxCount: e.TxCount, IndexedAt: e.Timestamp, } } // PostgresBlockRepository is the GORM-backed implementation of repository.BlockRepository. type PostgresBlockRepository struct { db *gorm.DB } // NewPostgresBlockRepository creates a new repository backed by PostgreSQL via GORM. func NewPostgresBlockRepository(db *gorm.DB) *PostgresBlockRepository { return &PostgresBlockRepository{db: db} } func (r *PostgresBlockRepository) SaveBlock(ctx context.Context, block *entity.Block) error { if block == nil { return fmt.Errorf("block must not be nil") } model := blockFromEntity(block) return r.db.WithContext(ctx).Save(model).Error } func (r *PostgresBlockRepository) FindByHeight(ctx context.Context, height int64) (*entity.Block, error) { var model blockModel err := r.db.WithContext(ctx).Where("height = ?", height).First(&model).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil, nil } return nil, err } return model.toEntity(), nil } func (r *PostgresBlockRepository) FindLatest(ctx context.Context) (*entity.Block, error) { var model blockModel err := r.db.WithContext(ctx).Order("height DESC").First(&model).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil, nil } return nil, err } return model.toEntity(), nil } func (r *PostgresBlockRepository) FindRange(ctx context.Context, fromHeight, toHeight int64) ([]*entity.Block, error) { var models []blockModel err := r.db.WithContext(ctx). Where("height >= ? AND height <= ?", fromHeight, toHeight). Order("height ASC"). Find(&models).Error if err != nil { return nil, err } result := make([]*entity.Block, len(models)) for i := range models { result[i] = models[i].toEntity() } return result, nil } func (r *PostgresBlockRepository) FindRecent(ctx context.Context, limit int) ([]*entity.Block, error) { var models []blockModel err := r.db.WithContext(ctx).Order("height DESC").Limit(limit).Find(&models).Error if err != nil { return nil, err } result := make([]*entity.Block, len(models)) for i := range models { result[i] = models[i].toEntity() } return result, nil }