115 lines
3.2 KiB
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
|
|
}
|