Skip to content

PostgreSQL

forze[postgres] implements document storage (read + write), full-text / vector / hub / federated search, transaction coordination, the transactional outbox / inbox, idempotency, and durable execution on PostgreSQL. Persistence stays behind Forze contracts; PostgreSQL tables, indexes, and pools live at the edge.

Install

uv add 'forze[postgres]'

Needs a reachable PostgreSQL. Search engines may need extensions (PGroonga for ranked text, pgvector for similarity).

The client

from forze_postgres import PostgresClient

pg = PostgresClient()

Use RoutedPostgresClient when the tenant or route decides the DSN — see Multi-tenancy.

Wire it

Map each logical spec name to physical relations, register them on the deps module, and open the pool from the lifecycle plan:

from forze.application.execution import DepsRegistry, LifecyclePlan
from forze_postgres import (
    PostgresConfig,
    PostgresDepsModule,
    PostgresDocumentConfig,
    PostgresLifecycleModule,
)

orders_pg = PostgresDocumentConfig(
    write=("public", "orders"),
    read=("public", "orders"),
    bookkeeping_strategy="application",  # or "database" with an UPDATE trigger
)

deps = DepsRegistry.from_modules(
    PostgresDepsModule(client=pg, rw_documents={"orders": orders_pg}, tx={"orders"}),
)
lifecycle = LifecyclePlan.from_modules(
    PostgresLifecycleModule(client=pg, dsn="postgresql://…", config=PostgresConfig()),
)

What it provides

Contract Keyed by Notes
Document query / command DocumentSpec.name (rw_documents, ro_documents) read-write or read-only relations
Search SearchSpec.name (searches, hub_searches, federated_searches) engine="pgroonga", FtsEngine(...), or VectorEngine(...)
Transactions route in the module tx set coordinates Postgres-backed ports on one connection
Analytics AnalyticsSpec.name (analytics) named, parameterized warehouse SQL — optional
Outbox / inbox OutboxSpec.name (outboxes), InboxSpec.name (inboxes) transactional outbox + consumer-side dedup inbox
Idempotency IdempotencySpec.name (idempotencies) co-located store — the record commits inside the business transaction
Procedures ProcedureSpec.name (procedures) named, governed SQL command / compute
Durable execution durable_step / durable_run / durable_schedule step memo, run store, and cron schedules — optional

Notes

  • You own the schema. Forze introspects existing relations; it never creates application tables. Provision read / write / history / search relations (and extensions) with your migration tool first.
  • Bookkeeping. bookkeeping_strategy="application" bumps rev / last_update_at in the write gateway; "database" defers to a BEFORE UPDATE trigger you supply.
  • Routed clients require introspector_cache_partition_key on the deps module so the catalog cache partitions by tenant.
  • Relations can be static (schema, table) tuples or per-tenant resolvers — see Multi-tenancy.