Skip to main content

Crate turnframe_store

Crate turnframe_store 

Source
Expand description

turnframe-store: the persistence contract of Turnframe, plus a deterministic in-memory implementation and an executable conformance suite.

It defines what must be durable and with which rules, as seven object-safe traits, and nothing about where: no driver, no SQL. The PostgreSQL adapter is one implementation and is optional. The rules an implementation must honour — total account scoping, a closed error surface, compare-and-swap instead of blind overwrite, immutability, specified ordering — and the all-or-nothing commit model are in docs/persistence.md. conformance::run_all proves an implementation right without reading its code, and MemoryStores is the reference one.

Six traits are split into a …Reader and a …Writer half, aggregated by the trait carrying the historical name, so a caller that must not write can be handed ReadOnlyStores and the compiler keeps it that way. Stores bundles one implementation of each.

TraitModuleWhat it owns
ConversationStoreconversationconversations, user turns, assistant turns as returned, the crash-recovery phase marker
InteractionStoreinteractionpersisted cards: payloads, the one-blocking-per-case slot, compare-and-swap resolution, expiry
CommandJournaljournalidempotency admission and the persisted outcome of every command
EventJournaleventsthe append-only claim ledger, paged exactly once, erasable only by redaction
OutboxStoreoutboxexternal side effects awaiting dispatch, with claim/reschedule semantics
ReplayStorereplayone replay record per turn, upserted as the turn advances
CommitStorecommitthe all-or-nothing write of everything one commit produces

§Example

use turnframe_core::ids::{AccountId, ConversationId};
use turnframe_store::prelude::*;

let stores = Stores::in_memory();
let account = AccountId::from("aurora");
let conversation = ConversationId::new();
let now = chrono::Utc::now();

stores
    .conversations()
    .create_conversation(ConversationRecord::new(
        conversation,
        account.clone(),
        now,
    ))
    .await?;

let loaded = stores
    .conversations()
    .load_conversation(&account, &conversation)
    .await?;
assert_eq!(loaded.account_id, account);

// Another tenant cannot tell it apart from one that never existed.
let other = AccountId::from("other");
assert_eq!(
    stores
        .conversations()
        .load_conversation(&other, &conversation)
        .await,
    Err(StoreError::NotFound)
);

Re-exports§

pub use crate::error::StoreResult;
pub use crate::memory::Clock;
pub use crate::memory::ManualClock;
pub use crate::memory::MemoryStores;
pub use crate::memory::SystemClock;
pub use crate::stores::ReadOnlyStores;
pub use crate::stores::ReadOnlyStoresBuilder;
pub use crate::stores::Stores;
pub use crate::stores::StoresBuilder;

Modules§

commit
The atomicity model: one CommitBundle, one all-or-nothing write (spec §16.3, §23 step N, ADR-006 point 8).
conformance
An executable statement of the persistence contract.
conversation
Conversations, persisted turns and the crash-recovery phase marker (spec §22.3, §23.1).
error
The error surface of the persistence contract.
events
The event journal: the append-only claim ledger (spec §17.1, ADR-012).
interaction
Persistent interactions: immutable payloads, the one-blocking-per-case slot and compare-and-swap resolution (spec §15.5, §15.6).
journal
The command journal: idempotency admission and persisted outcomes (spec §16.2, §23.1, I14).
memory
MemoryStores: one deterministic implementation of every persistence trait, over a single shared state.
outbox
The outbox: external side effects awaiting dispatch (spec §16.4, ADR-007).
prelude
The items an application needs to hold and use a set of stores.
replay
Replay records: one per turn, rewritten as the turn progresses (spec §23.1, I20).
stores
Stores: one value carrying an implementation of every persistence trait.

Enums§

StoreError
Errors raised by persistence adapters.