auradefi 0.1.1
PyPI GitHub

SqlModelLedger

auradefi.ledger.backends.sqlmodel · source

LedgerPort over host-owned SQLModel sessions (SPEC §8).

Every public method validates tenant_id FIRST (non-empty, non-whitespace str, else auradefi.errors.TenantIsolationError) before touching any session, then runs one session/commit per call. Per-tenant monotonic seqs come from TenantSeqRow (first value 1). The counter lives in the DB, so a second binding over the same engine continues the sequence.

__init__

__init__(self, session_factory: Callable[[], Session]) -> None

Bind the HOST's session factory. ZERO I/O happens here.

The constructor stores the factory and nothing else: no engine is built, no connection opened, no DDL emitted. An empty database stays empty until the HOST creates the schema itself.

Parameters

session_factoryrequired, Callable[[], Session]

none

upsert

upsert(self, tenant_id: str, txns: Sequence[LedgerTransaction]) -> list[SyncEvent]

Insert or update txns in one tenant's store (SPEC §6.4).

Diffs via auradefi.ledger.upsert.classify; new/changed rows are written with the tenant's next monotonic seq from TenantSeqRow (first 1) and emit ADDED events ascending by seq. Payload-identical redelivery emits no event and bumps no seq, UNLESS the STORED row is removed, in which case the txn is resurrected (removed=False, bumped seq, ADDED). Resurrection keys on the STORED removed flag; incoming bookkeeping is never adopted. Duplicate ids within txns raise auradefi.errors.ValidationError before any write.

Parameters

tenant_idrequired, str

none

txnsrequired, Sequence[LedgerTransaction]

none

Raises

ValidationError

sync

sync(self, tenant_id: str, cursor: str | None = None, limit: int = 100) -> SyncPage

Page of changes since cursor, ascending seq (SPEC §6.4).

Pages rows with last_modified_seq > decode_cursor(cursor) ascending: REMOVED iff the stored row is removed, else ADDED. next_cursor encodes the last event's seq, or the decoded input when the page is empty; has_more is accurate. A malformed cursor raises auradefi.errors.CursorError; a limit below 1 raises auradefi.errors.ValidationError.

Parameters

tenant_idrequired, str

none

cursoroptional, str | None, default None

none

limitoptional, int, default 100

none

Raises

CursorError, ValidationError

get

get(self, tenant_id: str, txn_id: str) -> LedgerTransaction

Fetch one transaction within THIS tenant (rule #6).

Raises auradefi.errors.NotFoundError when the id does not exist in this tenant. Another tenant's transaction is indistinguishable from a missing one.

Parameters

tenant_idrequired, str

none

txn_idrequired, str

none

Raises

NotFoundError

mark_removed

mark_removed(self, tenant_id: str, txn_ids: Sequence[str]) -> list[SyncEvent]

Mark transactions removed (reorg semantics), one tenant.

Any unknown id raises auradefi.errors.NotFoundError BEFORE any write. Live rows get removed=True with a bumped seq and emit REMOVED events ascending by seq; an already-removed id is a silent no-op (no event, no seq bump).

Parameters

tenant_idrequired, str

none

txn_idsrequired, Sequence[str]

none

Raises

NotFoundError

apply_reorg

apply_reorg(self, tenant_id: str, plan: ReorgPlan) -> list[SyncEvent]

Apply a ReorgPlan: mark_removed then upsert, atomically.

Duplicate ids within plan.add raise auradefi.errors.ValidationError BEFORE any write. Both halves run INSIDE ONE session/commit: a failure anywhere rolls the whole plan back. The tenant is never left half-reorged. Returns REMOVED then ADDED events ascending by seq.

Parameters

tenant_idrequired, str

none

planrequired, ReorgPlan

none

Raises

ValidationError