alkstore 0.1.0

The alkstore contract crate: one reactive store trait surface — notify, streams, durable queues, TTL locks, outbox, scheduler — implemented by the alkstore-sqlite/-postgres/-mem engine crates; no driver dependencies
Documentation
//! The stream mechanism handle (ADR-019 §1; ADR-015).
//!
//! Publish/read/trim ops live on the stream-scoped handle — placement
//! mirroring the honker-rs starting artifact; the transactional twins
//! ride the `TxHandle` (ADR-021 §1).

use serde_json::Value;

use crate::Result;
use crate::event_receiver::EventReceiver;
use crate::future::BoxedFuture;
use crate::stream::StreamEvent;

/// The stream-scoped handle: publish, cursor reads, offsets, trim, and
/// the durable subscription.
pub trait StreamHandle: Send + Sync {
    /// The stream name the handle was constructed with.
    fn name(&self) -> &str;

    /// Append an event to the stream's durable log (auto-commit).
    /// Returns the assigned offset — engine-assigned, monotone per
    /// stream, immutable.
    fn publish<'a>(&'a self, payload: Value) -> BoxedFuture<'a, Result<i64>>;

    /// Append a keyed event — [`StreamHandle::publish`]'s keyed twin.
    /// The key is carried metadata (stored, round-tripped, no
    /// engine-enforced behavioral role); the ordering guarantee stays
    /// global FIFO by offset per stream (ADR-015 §1). A present key
    /// must be non-empty (`InvalidName`). Returns the assigned
    /// offset.
    fn publish_with_key<'a>(
        &'a self,
        key: Option<String>,
        payload: Value,
    ) -> BoxedFuture<'a, Result<i64>>;

    /// Cursor read: events with `offset > ` cursor, `offset ASC`
    /// (global FIFO — ADR-015 §4), up to `limit`. `limit` is an
    /// extent argument (ADR-023 §2): `limit <= 0` reads nothing —
    /// the empty `Vec`. A read from a
    /// trimmed-away region resumes at the trim horizon's first
    /// remaining row.
    fn read_since<'a>(
        &'a self,
        offset: i64,
        limit: i64,
    ) -> BoxedFuture<'a, Result<Vec<StreamEvent>>>;

    /// Cursor read from a consumer's stored checkpoint (absent
    /// consumer = 0). `consumer` is a consumer-local identifier
    /// (non-empty only — `InvalidName`). `limit` is an extent
    /// argument (ADR-023 §2): `limit <= 0` reads nothing — the
    /// empty `Vec`.
    fn read_from_consumer<'a>(
        &'a self,
        consumer: &str,
        limit: i64,
    ) -> BoxedFuture<'a, Result<Vec<StreamEvent>>>;

    /// Save a consumer's checkpoint — always explicit (no
    /// auto-checkpoint cadence). Monotone: a save below the stored
    /// checkpoint is a silent no-op (ADR-019 §6); the `Err` arm
    /// carries `Database` only (ADR-021 §5). `consumer` is a
    /// consumer-local identifier (non-empty only — `InvalidName`).
    fn save_offset<'a>(&'a self, consumer: &str, offset: i64) -> BoxedFuture<'a, Result<()>>;

    /// Inspect a consumer's stored checkpoint; absent consumer = 0
    /// (the pre-save state, ADR-019 §1). `consumer` is a consumer-local
    /// identifier (non-empty only — `InvalidName`).
    fn get_offset<'a>(&'a self, consumer: &str) -> BoxedFuture<'a, Result<i64>>;

    /// Bounded growth, consumer-invoked: delete events with
    /// `offset <= horizon` (exact boundary; ADR-015 §5). The horizon
    /// is a boundary argument (ADR-023 §2) — total: a negative
    /// horizon deletes nothing, idempotently. Surviving
    /// events keep their offsets (gaps legal, never renumbered); trim
    /// emits no dedicated wake and no notify (on SQLite the
    /// `data_version` watcher may still fire on the trim commit — any
    /// committed write bumps it; a spurious hint, contract-legal).
    /// Returns the deleted-row count.
    fn trim_to<'a>(&'a self, horizon: i64) -> BoxedFuture<'a, Result<i64>>;

    /// Durable consumption: attach a consumer that reads to the
    /// current tail, resumes after restart from the stored offset,
    /// and saves checkpoints explicitly (no `save_every`, no
    /// save-on-drop). `consumer` is a consumer-local identifier
    /// (non-empty only).
    fn subscribe<'a>(&'a self, consumer: &str) -> BoxedFuture<'a, Result<Box<dyn EventReceiver>>>;
}