Weave

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/postgres

Setup

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:

TableDescription
weave_collectionsCollection metadata — name, model, chunk config, counters
weave_documentsDocument records — state, hashes, source info
weave_chunksChunk 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

MethodBehaviour
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
)

On this page