mire 0.2.4

A small, generic PostgreSQL event-sourcing library: append-only event streams, aggregates with optimistic concurrency, and subscription-based projections (requires tokio + sqlx)
Documentation
//! Snapshots: a disposable, versioned cache of aggregate state.
//!
//! Replaying a long stream on every load is O(events). A snapshot records the
//! folded state at a known version so a load can seed from it and replay only
//! the tail. Following EventStoreDB/Kurrent's guidance, snapshots here are
//! **purely an optimisation** — never the source of truth:
//!
//! - They are written as events into a separate `<stream>-snapshot` stream, so
//!   the main log stays pure and snapshots ride the same append-only machinery.
//! - Each carries the [`SNAPSHOT_VERSION`](Snapshot::SNAPSHOT_VERSION) it was
//!   produced with. If that doesn't match the current code, the snapshot is
//!   ignored and the aggregate is rebuilt from the full stream — a stale
//!   snapshot can never corrupt state.
//! - If a snapshot is missing or fails to load, loading transparently falls
//!   back to a full replay.
//!
//! Reach for snapshots only once a stream is measurably long; often the better
//! fix is a shorter-lived stream (close the books at a business boundary).

use serde::{Deserialize, Serialize, de::DeserializeOwned};

use crate::{Aggregate, EventData};

/// Reserved stream category for snapshot streams. Domain projections subscribe
/// to their own categories, so they never observe these.
pub(crate) const SNAPSHOT_CATEGORY: &str = "mire_snapshot";

/// Opt-in capability: an [`Aggregate`] whose state can be snapshotted. Requires
/// the state to be (de)serializable. Use
/// [`EventStore::load_snapshotted`](crate::EventStore::load_snapshotted) and
/// [`save_snapshotting`](crate::EventStore::save_snapshotting) for these.
pub trait Snapshot: Aggregate + Serialize + DeserializeOwned {
    /// Bump when the serialized state shape changes. Snapshots written under a
    /// different version are ignored in favour of a full replay.
    const SNAPSHOT_VERSION: i32 = 1;

    /// Automatically write a snapshot each time the stream version crosses a
    /// multiple of this number (on the `save_snapshotting` path). `0` disables
    /// automatic snapshots.
    const SNAPSHOT_FREQUENCY: i64 = 100;
}

/// What we actually persist in the snapshot stream.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct SnapshotEnvelope {
    /// The code [`Snapshot::SNAPSHOT_VERSION`] that produced this snapshot.
    pub snapshot_version: i32,
    /// The aggregate stream version this snapshot reflects.
    pub version: i64,
    /// The serialized aggregate state.
    pub state: serde_json::Value,
}

impl EventData for SnapshotEnvelope {
    fn event_type(&self) -> &'static str {
        "mire.snapshot"
    }
}