Files
amcs/internal/store/db.go
Hein db7b152852
Some checks failed
CI / build-and-test (push) Failing after -31m25s
refactor(store): replace project and skill models with generated models
* Update project creation and retrieval to use generated models
* Modify skill addition and listing to utilize generated models
* Refactor thought handling to incorporate generated models
* Adjust tool annotations to align with new model structure
* Update API calls in the UI to use new ResolveSpec-based endpoints
* Enhance stats retrieval logic to aggregate thought metadata
2026-04-26 12:56:32 +02:00

134 lines
3.3 KiB
Go

package store
import (
"context"
"database/sql"
"fmt"
"time"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
pgxvec "github.com/pgvector/pgvector-go/pgx"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
"git.warky.dev/wdevs/amcs/internal/config"
)
type DB struct {
pool *pgxpool.Pool
bun *bun.DB
}
func New(ctx context.Context, cfg config.DatabaseConfig) (*DB, error) {
poolConfig, err := pgxpool.ParseConfig(cfg.URL)
if err != nil {
return nil, fmt.Errorf("parse database config: %w", err)
}
poolConfig.MaxConns = cfg.MaxConns
poolConfig.MinConns = cfg.MinConns
poolConfig.MaxConnLifetime = cfg.MaxConnLifetime
poolConfig.MaxConnIdleTime = cfg.MaxConnIdleTime
poolConfig.AfterConnect = func(ctx context.Context, conn *pgx.Conn) error {
return pgxvec.RegisterTypes(ctx, conn)
}
pool, err := pgxpool.NewWithConfig(ctx, poolConfig)
if err != nil {
return nil, fmt.Errorf("create database pool: %w", err)
}
bunSQLDB := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(cfg.URL)))
bunSQLDB.SetMaxOpenConns(int(cfg.MaxConns))
bunSQLDB.SetMaxIdleConns(int(cfg.MinConns))
bunSQLDB.SetConnMaxLifetime(cfg.MaxConnLifetime)
bunSQLDB.SetConnMaxIdleTime(cfg.MaxConnIdleTime)
db := &DB{
pool: pool,
bun: bun.NewDB(bunSQLDB, pgdialect.New()),
}
if err := db.Ping(ctx); err != nil {
if db.bun != nil {
_ = db.bun.Close()
}
pool.Close()
return nil, err
}
return db, nil
}
func (db *DB) Close() {
if db == nil {
return
}
if db.bun != nil {
_ = db.bun.Close()
}
if db.pool != nil {
db.pool.Close()
}
}
func (db *DB) Ping(ctx context.Context) error {
if err := db.pool.Ping(ctx); err != nil {
return fmt.Errorf("ping database: %w", err)
}
return nil
}
func (db *DB) Ready(ctx context.Context) error {
readyCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
return db.Ping(readyCtx)
}
func (db *DB) VerifyRequirements(ctx context.Context) error {
var hasVector bool
if err := db.pool.QueryRow(ctx, `select exists(select 1 from pg_extension where extname = 'vector')`).Scan(&hasVector); err != nil {
return fmt.Errorf("verify vector extension: %w", err)
}
if !hasVector {
return fmt.Errorf("vector extension is not installed")
}
var hasMatchThoughts bool
if err := db.pool.QueryRow(ctx, `select exists(select 1 from pg_proc where proname = 'match_thoughts')`).Scan(&hasMatchThoughts); err != nil {
return fmt.Errorf("verify match_thoughts function: %w", err)
}
if !hasMatchThoughts {
return fmt.Errorf("match_thoughts function is missing")
}
var hasEmbeddings bool
if err := db.pool.QueryRow(ctx, `select exists(select 1 from pg_tables where schemaname = 'public' and tablename = 'embeddings')`).Scan(&hasEmbeddings); err != nil {
return fmt.Errorf("verify embeddings table: %w", err)
}
if !hasEmbeddings {
return fmt.Errorf("embeddings table is missing — run migrations")
}
var hasStoredFiles bool
if err := db.pool.QueryRow(ctx, `select exists(select 1 from pg_tables where schemaname = 'public' and tablename = 'stored_files')`).Scan(&hasStoredFiles); err != nil {
return fmt.Errorf("verify stored_files table: %w", err)
}
if !hasStoredFiles {
return fmt.Errorf("stored_files table is missing — run migrations")
}
return nil
}
func (db *DB) Bun() *bun.DB {
if db == nil {
return nil
}
return db.bun
}