cic-chain-events/internal/store/postgres.go

141 lines
3.0 KiB
Go

package store
import (
"context"
"fmt"
"os"
"time"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/jackc/tern/v2/migrate"
"github.com/knadh/goyesql/v2"
"github.com/zerodha/logf"
)
const (
schemaTable = "schema_version"
)
type (
queries struct {
CommitBlock string `query:"commit-block"`
GetMissingBlocks string `query:"get-missing-blocks"`
GetSearchBounds string `query:"get-search-bounds"`
InitSyncerMeta string `query:"init-syncer-meta"`
SetSearchLowerBound string `query:"set-search-lower-bound"`
}
PostgresStoreOpts struct {
DSN string
MigrationsFolderPath string
InitialLowerBound uint64
Logg logf.Logger
Queries goyesql.Queries
}
)
type PostgresStore struct {
logg logf.Logger
pool *pgxpool.Pool
queries queries
}
func NewPostgresStore(o PostgresStoreOpts) (Store[pgx.Rows], error) {
postgresStore := &PostgresStore{
logg: o.Logg,
}
if err := goyesql.ScanToStruct(&postgresStore.queries, o.Queries, nil); err != nil {
return nil, fmt.Errorf("failed to scan queries %v", err)
}
parsedConfig, err := pgxpool.ParseConfig(o.DSN)
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
dbPool, err := pgxpool.NewWithConfig(ctx, parsedConfig)
if err != nil {
return nil, err
}
conn, err := dbPool.Acquire(ctx)
if err != nil {
return nil, err
}
defer conn.Release()
migrator, err := migrate.NewMigrator(ctx, conn.Conn(), schemaTable)
if err != nil {
return nil, err
}
if err := migrator.LoadMigrations(os.DirFS(o.MigrationsFolderPath)); err != nil {
return nil, err
}
if err := migrator.Migrate(ctx); err != nil {
return nil, err
}
_, err = dbPool.Exec(ctx, postgresStore.queries.InitSyncerMeta, o.InitialLowerBound)
if err != nil {
return nil, err
}
postgresStore.pool = dbPool
return postgresStore, nil
}
func (s *PostgresStore) GetSearchBounds(ctx context.Context, batchSize uint64, headCursor uint64, headBlockLag uint64) (uint64, uint64, error) {
var (
lowerBound uint64
upperBound uint64
)
if err := s.pool.QueryRow(
ctx,
s.queries.GetSearchBounds,
batchSize,
headCursor,
headBlockLag,
).Scan(&lowerBound, &upperBound); err != nil {
s.logg.Error("pgx error", "error", err)
return 0, 0, err
}
return lowerBound, upperBound, nil
}
func (s *PostgresStore) GetMissingBlocks(ctx context.Context, lowerBound uint64, upperBound uint64) (pgx.Rows, error) {
rows, err := s.pool.Query(ctx, s.queries.GetMissingBlocks, lowerBound, upperBound)
if err != nil {
return nil, err
}
return rows, nil
}
func (s *PostgresStore) SetSearchLowerBound(ctx context.Context, newLowerBound uint64) error {
_, err := s.pool.Exec(ctx, s.queries.SetSearchLowerBound, newLowerBound)
if err != nil {
return err
}
return nil
}
func (s *PostgresStore) CommitBlock(ctx context.Context, block uint64) error {
_, err := s.pool.Exec(ctx, s.queries.CommitBlock, block)
if err != nil {
return err
}
return nil
}