PostgreSQL Store
Production MetadataStore backed by PostgreSQL using Grove ORM.
The store/postgres package provides a production-ready MetadataStore for collections, documents, and chunks using PostgreSQL and the Grove ORM.
Installation
go get github.com/xraph/weave/store/postgresSetup
import (
"github.com/xraph/grove"
"github.com/xraph/grove/drivers/pgdriver"
pgstore "github.com/xraph/weave/store/postgres"
)
db, err := grove.Open(pgdriver.Open("postgres://user:pass@localhost:5432/mydb?sslmode=disable"))
if err != nil {
log.Fatal(err)
}
store := pgstore.New(db)Pass the store to the engine:
eng, err := engine.New(
engine.WithStore(store),
engine.WithVectorStore(pgvec.New(pool)), // see pgvector doc
engine.WithEmbedder(emb),
)Migrations
Call store.Migrate(ctx) before starting the engine to create the required tables:
if err := store.Migrate(ctx); err != nil {
log.Fatal("migrate:", err)
}This is idempotent — running it on an already-migrated database is safe. Migrations use Grove's pgmigrate driver internally.
Schema
The PostgreSQL store creates three tables:
| Table | Description |
|---|---|
weave_collections | Collection metadata — name, model, chunk config, counters |
weave_documents | Document records — state, hashes, source info |
weave_chunks | Chunk text and byte offsets |
All tables include tenant_id and app_id columns for multi-tenant isolation.
Connection pool configuration
The PostgreSQL store accepts any *grove.DB opened with the pgdriver. Configure the underlying connection pool via Grove's driver options:
db, err := grove.Open(pgdriver.Open(dsn,
pgdriver.WithMaxOpenConns(25),
pgdriver.WithMaxIdleConns(5),
pgdriver.WithConnMaxLifetime(5 * time.Minute),
))Lifecycle
| Method | Behaviour |
|---|---|
Migrate(ctx) | Creates tables and indexes if they don't exist |
Ping(ctx) | Verifies database connectivity |
Close() | Closes the underlying *grove.DB |
Forge extension
When using Weave as a Forge extension with Grove integration, you can let the extension auto-construct the store from a shared grove.DB:
ext := extension.New(
extension.WithGroveDatabase(""), // use default grove.DB from DI
)Or provide an explicit store:
ext := extension.New(
extension.WithStore(store),
extension.WithDisableMigrate(), // disable auto-migration if needed
)