@molecule/api-ai-vector-store-pgvector
v1.0.2
Published
PostgreSQL pgvector provider for molecule.dev — vector similarity search with pgvector
Maintainers
Readme
@molecule/api-ai-vector-store-pgvector
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
PostgreSQL pgvector vector store provider for molecule.dev.
Stores each molecule collection as its own Postgres table (default prefix
mol_vectors_) with HNSW indexes, using the pgvector extension.
Quick Start
import { setProvider, requireProvider } from '@molecule/api-ai-vector-store'
import { provider } from '@molecule/api-ai-vector-store-pgvector'
setProvider(provider) // at startup — lazy; reads DATABASE_URL / opens its pool on first use
// or pass explicit config: setProvider(createProvider({ connectionString }))Type
provider
Installation
npm install @molecule/api-ai-vector-store-pgvector @molecule/api-ai-vector-store pg pgvector
npm install -D @types/pgAPI
Interfaces
PgvectorConfig
Configuration for the pgvector vector store provider.
interface PgvectorConfig {
/** PostgreSQL connection string (e.g. `postgresql://user:pass@host:5432/db`). Falls back to `DATABASE_URL` env var. */
connectionString?: string
/** Schema to use for vector store tables. Defaults to `'public'`. */
schema?: string
/** Table name prefix for vector store tables. Defaults to `'mol_vectors_'`. */
tablePrefix?: string
/** Default distance metric for new collections. Defaults to `'cosine'`. */
defaultMetric?: DistanceMetric
/** Connection pool size. Defaults to 5. */
poolSize?: number
}Functions
clampTopK(value)
[M7-2] Coerce a requested topK into a bounded positive integer for SAFE interpolation into
the LIMIT clause (it is not a bound $N parameter). topK is typed number, but a caller
forwarding an untrusted value (e.g. req.body.topK cast to any) could otherwise inject SQL
or request an unbounded scan. Non-finite / < 1 falls back to the default 10; capped at 10_000.
function clampTopK(value: unknown): numbervalue— The caller-suppliedtopK(untyped at runtime).
Returns: A safe integer in [1, 10000].
createProvider(config)
Creates a pgvector vector store provider instance.
function createProvider(config?: PgvectorConfig): PgvectorProviderconfig— PostgreSQL + pgvector configuration.
Returns: An AIVectorStoreProvider backed by PostgreSQL with pgvector.
Constants
provider
The provider implementation.
const provider: AIVectorStoreProviderCore Interface
Implements @molecule/api-ai-vector-store interface.
Bond Wiring
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-ai-vector-store'
import { provider } from '@molecule/api-ai-vector-store-pgvector'
export function setupAiVectorStorePgvector(): void {
setProvider(provider)
}Injection Notes
Requirements
Peer dependencies:
@molecule/api-ai-vector-store>=1.0.1
Runtime Dependencies
@molecule/api-ai-vector-storepgpgvectorOwns its own
pg.Pool— it does NOT go through the@molecule/api-databasebond. Connection comes fromconfig.connectionStringor theDATABASE_URLenv var;poolSize(default 5) is independent of the app's database pool.Requires the pgvector extension. On first use it runs
CREATE EXTENSION IF NOT EXISTS vector— the connecting role must be allowed to create extensions, otherwise installvectorup front via a migration/DBA.Auto-creates its tables: a
mol_vectors_collectionsregistry plus onemol_vectors_<collection>table (+ HNSW index) per collection — no migration needed beyond the extension.topKis clamped to [1, 10000] before hitting SQL.
E2E Tests
Integration checklist — drive the real flow (no mocks): upsert real
vectors, run real query calls, and verify through the FEATURE this store
powers (semantic search / RAG retrieval / related-items) plus direct property
checks on the returned VectorSearchResult[]. Adapt each item to this app's
actual corpus/screens and check every box off. A box you can't check is an
integration bug to fix — not a skip:
- [ ]
upsertrecords (each with a stableid+metadata), thenquerywith an embedding: results come back ranked byscore(highest first), the semantically closest stored item is result #1 and unrelated items rank lower — the whole point.scoreis a sane similarity (bounded, ~0–1, higher = closer) and each hit'srecord.id/record.metadatacome back intact. - [ ]
topKis honored: a query withtopK: kreturns AT MOST k results, best-first — never more, never unordered. - [ ] Metadata
filterworks: aquerycarrying aMetadataFilter(e.g.{ field: 'userId', operator: 'eq', value }) returns only records matching the filter and never leaks non-matching ones. - [ ] Collection/namespace ISOLATION: a
queryscoped to onecollectionnever returns another collection's vectors — the multi-tenant boundary that keeps one user's private docs out of another's results. Confirm with two collections (or two owner ids) that a scoped query returns only its own. - [ ]
deleteremoves a record: afterdelete({ collection, ids })the vector stops appearing inqueryresults (andfetchomits it). - [ ] The feature built on the store returns MEANING-ranked results
end-to-end in the UI — a semantic-search / RAG / related-items query
surfaces the relevant items first, not a keyword or insertion-order match.
This store does NOT embed text itself, so confirm it composes with
@molecule/api-ai-embeddings(query text → embedding →query). - [ ] Every
upsert/queryruns SERVER-SIDE — the provider/store key stays on the server and never ships in the browser bundle (the package is server-only; a client import throws by design).
