gcx/backend/services/chain-indexer/internal/infrastructure/postgres/block_repository.go

115 lines
3.2 KiB
Go

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
}