Skip to content

Getting started

Install

pip install 'rhizodat[postgres,clickhouse,drevo,iceberg]'

Each store's driver is an extra: install only those you use. rhizodat[ingest] adds file imports, rhizodat[mcp] the MCP server, rhizodat[native] the core in Rust (rhizodat_native, prebuilt wheels for Linux and macOS). Embedded drevo (drevo:///) needs drevo-py, which is not on PyPI yet and is built from source.

Run the stores

The repository's compose.yaml runs every store on 127.0.0.1 with empty, throw-away data:

docker compose --profile clickhouse up -d --wait

The first entity

An order whose money lives in PostgreSQL and whose links live in the graph. Each write is one atomic meta-transaction over both stores; every version is kept, so the order can be read as it was at any moment:

"""Quickstart: one entity, two stores, every version kept.

An order's money lives in PostgreSQL and its links in the drevo graph. Each
write is one atomic meta-transaction over both; reads see any past moment.
"""

import time
from datetime import UTC, datetime
from decimal import Decimal

from _stores import GRAPH, JOURNAL, PG

from rhizodat import Rhizodat, entity


@entity(stores={"pg": ["status", "amount"], "graph": ["customer"]}, name="shop.Order")
class Order:
    status: str
    amount: Decimal
    customer: str


with Rhizodat(stores={"pg": PG, "graph": GRAPH}, journal=JOURNAL) as dat:
    orders = dat.repository(Order)

    order = Order(status="new", amount=Decimal("10.00"), customer="ada")
    orders.add(order)  # one meta-transaction across PostgreSQL and drevo
    before = datetime.now(UTC)
    time.sleep(0.01)  # the update must come after `before`

    order.status = "paid"
    orders.update(order)

    print(orders.get(order.dat_id).status)  # paid
    print(orders.get(order.dat_id, as_of=before).status)  # new
    print([v.status for v in orders.history(order.dat_id)])  # ['new', 'paid']
python examples/quickstart.py

Next: more examples, or how the meta-transactions behind this work.