aimdb-persistence
Optional persistence layer for AimDB. Adds long-term record history to any
AimDB database without touching aimdb-core — persistence is implemented as a
buffer subscriber, just like .tap(), keeping it fully within AimDB's
existing producer–consumer architecture.
Overview
aimdb-persistence provides the traits and extension methods that wire a
pluggable storage backend into the AimDB builder and query API:
| Crate component | What it adds |
|---|---|
[PersistenceBackend] trait |
Interface for concrete backends (SQLite, Postgres, …) |
AimDbBuilderPersistExt |
.with_persistence(backend, retention) on the builder |
RecordRegistrarPersistExt |
.persist("my_record::key") on record configuration |
AimDbQueryExt |
.query_latest() / .query_range() on a live AimDb<R> |
For a concrete backend, add aimdb-persistence-sqlite.
Installation
[]
= "0.1"
= "0.1" # or another backend
Optional features:
# Enable structured logging via the `tracing` crate
= { = "0.1", = ["tracing"] }
Quick Start
use Arc;
use Duration;
use AimDbBuilder;
use ;
use SqliteBackend;
use TokioAdapter;
use ;
async
Architecture
AimDB producer / connector
│
▼
┌───────────────┐
│ Record buffer │ ← typed ring / latest / SPMC
└───────┬───────┘
│ tap (side-effect subscriber)
▼
┌────────────────────┐
│ Persistence sub. │ (spawned by .persist())
│ serde_json::to_ │
│ value(&T) │
└────────┬───────────┘
│ async write
▼
┌─────────────────────┐
│ PersistenceBackend │ ← trait object (SqliteBackend, …)
└─────────────────────┘
Key design properties:
- Zero coupling to
aimdb-core— persistence is an optional crate; the core crate has no dependency on storage types. - Runtime-agnostic — the subscriber serialises values synchronously and delegates I/O to the backend trait, which is responsible for its own async strategy.
- Retention via
on_start()hook — a cleanup task is registered duringwith_persistence()and runs once at startup, then every 24 hours.
API Reference
Builder extension
// Configure backend + retention in one call.
builder.with_persistence;
Record registration
builder.;
T must implement serde::Serialize. .with_remote_access() is not
required — the persistence subscriber taps the typed buffer directly.
Query methods
use AimDbQueryExt;
// Latest N values per matching record (pattern supports `*` wildcard).
let latest: = db.query_latest.await?;
// All values in a time range (Unix milliseconds), no row limit.
let range: = db
.query_range
.await?;
// Time range with at most 100 rows per matching record.
let capped: = db
.query_range
.await?;
// Untyped query (returns raw JSON — used by the AimX protocol handler).
use QueryParams;
let raw = db.query_raw.await?;
query_latest applies limit_per_record rows per matching record.
query_range accepts an optional limit_per_record — pass None for all
matching rows, or Some(n) to cap results per record name.
Error Handling
use PersistenceError;
match db..await
Rows that fail to deserialise as T are skipped with a tracing::warn!
(when the tracing feature is enabled) rather than failing the entire query.
Implementing a Custom Backend
use ;
use PersistenceError;
use Value;
Features
| Feature | Default | Description |
|---|---|---|
std |
yes | Enables std-backed types; required for Tokio runtimes |
tracing |
no | Emit structured log events via the tracing crate |
Related Crates
| Crate | Role |
|---|---|
aimdb-persistence-sqlite |
SQLite backend (bundled, WAL mode, dedicated writer thread) |
aimdb-core |
Core AimDB types; Extensions TypeMap |
aimdb-tokio-adapter |
Tokio runtime adapter |
License
See LICENSE.