pub trait Document:
Serialize
+ DeserializeOwned
+ 'static {
const COLLECTION: &'static str;
const VERSION: u32;
// Provided methods
fn migrate(_dynamic: Dynamic, from_version: u32) -> Result<Self> { ... }
fn historical_schemas() -> Vec<(u32, DynamicSchema)> { ... }
fn indexes() -> Vec<IndexSpec> { ... }
}Expand description
The trait every user document type implements.
Document types are serde::Serialize + DeserializeOwned so
they round-trip through postcard. Each implementation provides
two associated constants:
COLLECTION— the collection name under which records of this type are stored. The catalog resolves it to a numericcollection_idat registration time; the codec takes that id as an argument toencode/decode.VERSION— the type’s schema version. Stored in every record’s header; the decoder routes a stored- version mismatch throughDocument::migrate.
Document is 'static so type-erased catalog rows can carry the
collection name as &'static str. M5 ships hand-impls; M9
introduces a #[derive(obj::Document)] proc macro.
Required Associated Constants§
Sourceconst COLLECTION: &'static str
const COLLECTION: &'static str
The collection name this document type stores into.
Must be a stable, application-chosen identifier. The
catalog resolves it to a collection_id on first
registration; subsequent opens reuse the existing id.
Sourceconst VERSION: u32
const VERSION: u32
The schema version of this Document implementation.
Bump on any breaking change (added/removed/renamed fields, changed semantics). The decoder enforces:
header.type_version < VERSION→ dispatch throughDocument::migrate.header.type_version == VERSION→ decode directly.header.type_version > VERSION→Error::SchemaVersionFromFuture.
Provided Methods§
Sourcefn migrate(_dynamic: Dynamic, from_version: u32) -> Result<Self>
fn migrate(_dynamic: Dynamic, from_version: u32) -> Result<Self>
Transform an older stored record into Self.
The codec calls migrate when a stored
record’s type_version is strictly less than VERSION.
dynamic is a structured Dynamic view of the older
record — the codec walks the on-disk payload through the
schema registered for from_version (see
historical_schemas) and
hands the resulting map-shaped Dynamic to this method.
Concrete overrides read the fields they care about with
Dynamic::get /
Dynamic::get_str /
Dynamic::deserialize
and construct the target Self.
from_version is the on-disk type_version — always < Self::VERSION when this is invoked by the codec.
§Default body
Returns Error::SchemaMigrationNotImplemented. Real types
override this method to handle older versions.
§Errors
User overrides MAY return any Error variant. The default
returns Error::SchemaMigrationNotImplemented.
Sourcefn historical_schemas() -> Vec<(u32, DynamicSchema)>
fn historical_schemas() -> Vec<(u32, DynamicSchema)>
Schemas for stored records of OLDER type_versions than
VERSION.
Returns a list of (version, schema) pairs sorted strictly
ascending by version. The codec consults this list whenever
it observes header.type_version < Self::VERSION:
- Look up the matching
version. - Walk the on-disk payload bytes through
Dynamic::from_postcard_bytesusing the registeredschema. - Hand the resulting structured
Dynamictomigratealong with the stored version.
A miss (no entry for the stored version) surfaces as
Error::SchemaNotRegistered.
The default body returns an empty list — a Document with
no historical_schemas() cannot migrate any older payload.
§Ordering
The returned slice MUST be sorted strictly ascending by version. The codec debug-asserts on read; out-of-order entries are a programming bug.
§Power-of-ten posture
- Rule 9. Static dispatch — concrete
Documentimplementations return their ownVec<(u32, DynamicSchema)>; the codec never reaches for adyn Trait. - Rule 7. Empty default is intentional — a
Documentthat has never been versioned cannot have historical schemas.
Sourcefn indexes() -> Vec<IndexSpec>
fn indexes() -> Vec<IndexSpec>
Declared secondary indexes for this Document type.
Default body returns the empty vector — no indexes. Override
to declare per-collection indexes; the catalog reconciler
(M7 #57) compares this list against the catalog’s stored
descriptors on the FIRST WriteTxn::collection::<T>() call
per process per collection and:
- declares specs absent from the catalog,
- flips active descriptors absent from this list to
DroppedPending, - leaves unchanged matches alone (idempotent).
The reconciler runs inside the user’s WAL transaction so a rolled-back txn leaves the catalog clean.
&self is intentionally not taken — indexes are a
type-level property of the Document, not a per-instance
one.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".