pub struct Table { /* private fields */ }Expand description
Ties TableRegistry (indexes), WriteQueue (validation, uniqueness, staging) and LogFile
(persistence) into one table API. Deliberately thin: put/patch/delete all delegate their
validation and unique-checking to WriteQueue::stage_put, they do not repeat it here.
Implementations§
Source§impl Table
impl Table
Sourcepub fn open(schema: TableSchema, path: impl AsRef<Path>) -> Result<Self>
pub fn open(schema: TableSchema, path: impl AsRef<Path>) -> Result<Self>
Opens a table with no paired snapshot file — used for catalog operations (drop_field,
declare_index) that reopen a table over its existing log right after rewriting the schema.
snapshot()/needs_snapshot() are no-ops on a table opened this way, same as it never
restores from a snapshot either.
Sourcepub fn open_with_declared_indexes(
schema: TableSchema,
path: impl AsRef<Path>,
declared: &[ExpandedIndex],
) -> Result<Self>
pub fn open_with_declared_indexes( schema: TableSchema, path: impl AsRef<Path>, declared: &[ExpandedIndex], ) -> Result<Self>
Same as Table::open, but the registry also builds every composite or where-scoped
index the catalog declares for this table (catalog::expand_indexes) alongside the sugar
Table::open derives from the schema alone — called by Database, which owns the
catalog Table::open itself has none of.
Sourcepub fn open_with_snapshot(
schema: TableSchema,
path: impl AsRef<Path>,
snapshot_path: impl AsRef<Path>,
schema_hash: &str,
snapshot_every: u64,
) -> Result<(Self, RestoreOutcome)>
pub fn open_with_snapshot( schema: TableSchema, path: impl AsRef<Path>, snapshot_path: impl AsRef<Path>, schema_hash: &str, snapshot_every: u64, ) -> Result<(Self, RestoreOutcome)>
Opens the log at path and restores its registry from snapshot_path via
checkpoint::restore_or_rebuild instead of always scanning the whole log — used by
database::open() at startup. Falls back to a full scan (RestoreOutcome::Rebuilt) exactly
as restore_or_rebuild does when the snapshot is missing, stale, or paired with a different
schema.
snapshot_every mirrors the TS snapshotEvery table option (ADR/0047 line): after this many
operations have been applied since the last snapshot, the next commit writes a fresh
snapshot_path and resets the counter. 0 disables periodic snapshotting for this table.
Sourcepub fn open_with_snapshot_and_declared_indexes(
schema: TableSchema,
path: impl AsRef<Path>,
snapshot_path: impl AsRef<Path>,
schema_hash: &str,
snapshot_every: u64,
readonly: bool,
declared: &[ExpandedIndex],
) -> Result<(Self, RestoreOutcome)>
pub fn open_with_snapshot_and_declared_indexes( schema: TableSchema, path: impl AsRef<Path>, snapshot_path: impl AsRef<Path>, schema_hash: &str, snapshot_every: u64, readonly: bool, declared: &[ExpandedIndex], ) -> Result<(Self, RestoreOutcome)>
Same as Table::open_with_snapshot, but both the restored and the rebuilt registry are
built with declared — the catalog’s fully expanded index list (catalog::expand_indexes)
— via checkpoint::restore_or_rebuild_with_declared.
readonly is the open mode of the database this table belongs to, and it decides one thing
here: whether a log whose tail was left half-written may be cut back to its last complete
line (see LogFile::discard_partial_tail). A readonly handle only fixes
its own idea of where the log ends and leaves the file alone.
Sourcepub fn open_sealed(
schema: TableSchema,
path: impl AsRef<Path>,
snapshot_path: impl AsRef<Path>,
schema_hash: &str,
snapshot_every: u64,
readonly: bool,
declared: &[ExpandedIndex],
sealer: Option<Arc<Sealer>>,
) -> Result<(Self, RestoreOutcome)>
pub fn open_sealed( schema: TableSchema, path: impl AsRef<Path>, snapshot_path: impl AsRef<Path>, schema_hash: &str, snapshot_every: u64, readonly: bool, declared: &[ExpandedIndex], sealer: Option<Arc<Sealer>>, ) -> Result<(Self, RestoreOutcome)>
Table::open_with_snapshot_and_declared_indexes for a table of an encrypted database: its
log lines, snapshot and image files are sealed with sealer, and the registry is rebuilt in
memory from the decrypted lines.
Sourcepub fn set_triggers(&mut self, triggers: Vec<TriggerEntry>)
pub fn set_triggers(&mut self, triggers: Vec<TriggerEntry>)
Attaches the catalog’s trigger declarations naming this table as their source — called by
Database after opening/reopening a table. A trigger whose effect.table differs from
this table’s own name only fires when the write reaches it through
crate::txn::UnitOfWork::commit, which holds every table of the database at once; the
single-table put/patch/delete path below can only write into itself.
pub fn triggers(&self) -> &[TriggerEntry]
Sourcepub fn set_image_dir(&mut self, dir: PathBuf)
pub fn set_image_dir(&mut self, dir: PathBuf)
Overrides the directory image field bytes are written under — called by Database when
options.imageDir names one, resolved relative to the database directory. Left at its
open/open_with_snapshot-computed default (a <table>.images/ sibling of the log file)
otherwise.
pub fn image_dir(&self) -> &Path
Sourcepub fn set_max_image_bytes(&mut self, max: Option<u64>)
pub fn set_max_image_bytes(&mut self, max: Option<u64>)
Refuses, from now on, a write whose image field decodes to more than max bytes. None
accepts any size.
Sourcepub fn set_password_hash_params(&mut self, params: PasswordHashParams)
pub fn set_password_hash_params(&mut self, params: PasswordHashParams)
The Argon2id cost new passwordHash values are made with. Hashes already stored keep theirs.
Sourcepub fn verify_password(
&self,
key: &str,
field: &str,
candidate: &str,
) -> Result<PasswordCheck, TableError>
pub fn verify_password( &self, key: &str, field: &str, candidate: &str, ) -> Result<PasswordCheck, TableError>
Checks candidate against the passwordHash field field of record key, without ever
returning the stored hash. A missing record, a missing or null value and a wrong password
all answer ok: false after the same amount of hashing work.
Sourcepub fn set_link_parsing(&mut self, mode: LinkParsing)
pub fn set_link_parsing(&mut self, mode: LinkParsing)
Overrides when a markdown field’s links get checked against this table’s virtual-path
index — called by Database from options.linkParsing, left at Eager otherwise.
pub fn link_parsing(&self) -> LinkParsing
Sourcepub fn set_validation(&mut self, mode: CatalogValidation)
pub fn set_validation(&mut self, mode: CatalogValidation)
Overrides what a write naming a field the schema does not declare gets — called by
Database from the table’s validation entry, left at Strict otherwise. Warn drops
such a field and lets the rest of the write through; nothing else about validation moves,
so a bad type, a missing required, a primary key that is not there and a reserved _ key
are refused in either mode.
pub fn validation(&self) -> CatalogValidation
Sourcepub fn dropped_field_warnings(&self, document: &Value) -> Vec<String>
pub fn dropped_field_warnings(&self, document: &Value) -> Vec<String>
What a write of document has to say about fields the schema does not declare — empty on a
Strict table, which refuses such a write instead of warning about it.
A channel of its own, deliberately not folded into Table::eager_link_warnings_of: that
one recomputes broken links from the stored record, and a dropped field is not in the
stored record to be found again, so this has to be asked with the document that was
written. Answers the same before and after the write, since it reads nothing but the schema.
Sourcepub fn set_deprecated_fields(&mut self, fields: BTreeMap<String, String>)
pub fn set_deprecated_fields(&mut self, fields: BTreeMap<String, String>)
Hands over the fields the catalog marks deprecated, each against its note — called by
Database after opening/reopening a table, left empty otherwise. Nothing about a write
changes: a deprecated field is declared, so it validates, lands and reads back exactly as
any other; the mark is only ever reported, through Table::deprecated_field_warnings.
A note coming from the catalog is never empty — catalog::parse_catalog refuses
deprecated: "" outright — but a caller building a handle by hand can hand one over, and
Table::deprecated_field_warnings then names the field on its own.
pub fn deprecated_fields(&self) -> &BTreeMap<String, String>
Sourcepub fn deprecated_field_warnings(&self, document: &Value) -> Vec<String>
pub fn deprecated_field_warnings(&self, document: &Value) -> Vec<String>
What a write of document has to say about fields the catalog marks deprecated — one
message per marked field the document names, quoting the note where the catalog gives one.
Independent of Table::validation: deprecated is a mark on the field, not a mode of the
table, so a strict table warns here exactly as a warn one does. A channel of its own,
deliberately not folded into Table::dropped_field_warnings: that one is about a field
the schema does not declare and a strict table refuses the write for, this one about a
field it does declare and every table takes. Answers the same before and after the write,
since it reads nothing but the document and the mark.
Sourcepub fn set_compaction(&mut self, compaction: CatalogCompaction)
pub fn set_compaction(&mut self, compaction: CatalogCompaction)
Arms automatic compaction with the thresholds Database::open resolved for this table —
see Table::compact_if_due for what they are measured against and when.
pub fn compaction(&self) -> CatalogCompaction
Sourcepub fn set_cache(&mut self, cache: CachePolicy)
pub fn set_cache(&mut self, cache: CachePolicy)
Arms this handle’s read cache — the bounded LRU of parsed documents Table::get answers a
repeated read of the same key from. Replaces whatever was cached so far, so re-arming a live
table starts it from cold rather than from documents the old policy admitted.
pub fn cache_policy(&self) -> CachePolicy
Sourcepub fn set_sync(&mut self, sync: CatalogSyncMode)
pub fn set_sync(&mut self, sync: CatalogSyncMode)
Sets how durable this table’s appends are — called by Database from options.sync, left
at Commit otherwise. Commit fsyncs the log on every flush; Never skips the fsync
and leaves the bytes to the kernel, so a crash can lose appends this table already
acknowledged. Nothing else changes: the writes, the registry and the snapshots are the same.
pub fn sync_mode(&self) -> CatalogSyncMode
Sourcepub fn set_cipher(&mut self, cipher: Option<FieldCipher>)
pub fn set_cipher(&mut self, cipher: Option<FieldCipher>)
Sets the keyring put/patch seal cypher fields with and get/query open them with —
called by Database from options.cypher, left at None otherwise, which is fine for a
table whose schema declares no cypher field and an error the moment one tries to write or
read one that does.
Sourcepub fn eager_link_warnings_of(
&self,
key: &str,
) -> Result<Vec<BrokenLink>, TableError>
pub fn eager_link_warnings_of( &self, key: &str, ) -> Result<Vec<BrokenLink>, TableError>
The diagnostics PutOutcome::warnings would carry for the record now stored under key —
empty unless Table::link_parsing is Eager, exactly as Table::put_with_warnings.
It exists for a binding that cannot use put_with_warnings because it stages and flushes in
two separate calls across an FFI boundary and so never holds a PutOutcome; asking here
once the write has landed gives the same answer, and keeps the Eager gate in one place
rather than copied into every binding.
Sourcepub fn broken_links_of(&self, key: &str) -> Result<Vec<BrokenLink>, TableError>
pub fn broken_links_of(&self, key: &str) -> Result<Vec<BrokenLink>, TableError>
On-demand link check for a Lazy table (or any table) — reads key’s current record and
reports every markdown link that does not resolve, regardless of Table::link_parsing.
Sourcepub fn read_image(&self, physical_path: &str) -> Result<Option<Vec<u8>>>
pub fn read_image(&self, physical_path: &str) -> Result<Option<Vec<u8>>>
The bytes stored under physical_path in Table::image_dir, or None when no such file
exists. Refuses anything that is not a content-hash file name this engine wrote, so a caller
cannot read outside the image directory through it.
Sourcepub fn read_image_base64(&self, physical_path: &str) -> Result<Option<String>>
pub fn read_image_base64(&self, physical_path: &str) -> Result<Option<String>>
Table::read_image, with the bytes as the standard base64 an image write takes.
Sourcepub fn list_images(&self) -> Result<Vec<ImageInfo>>
pub fn list_images(&self) -> Result<Vec<ImageInfo>>
Every image file in Table::image_dir with its size and the live records that reference
it, sorted by physical_path. A file nothing references has an empty referenced_by — an
orphan. Files in the directory that are not content-hash file names are ignored.
Sourcepub fn image_usage(&self) -> Result<ImageUsage>
pub fn image_usage(&self) -> Result<ImageUsage>
Totals over Table::list_images: how many image files there are and how many bytes they
take, and how many of them (and how much) no live record references.
Sourcepub fn delete_image(&self, physical_path: &str) -> Result<bool>
pub fn delete_image(&self, physical_path: &str) -> Result<bool>
Deletes the image file stored under physical_path. Refuses while a live record still
references it, so a record never ends up pointing at a missing file; returns false when no
such file existed.
Sourcepub fn snapshot(&mut self) -> Result<()>
pub fn snapshot(&mut self) -> Result<()>
Writes <table>.idx for the registry’s current state and resets the since-last-snapshot
counter — mirrors the TS Table.snapshot(). A no-op on a table opened via Table::open,
which carries no snapshot_path.
Sourcepub fn needs_snapshot(&self) -> bool
pub fn needs_snapshot(&self) -> bool
Whether this table has writes since its last snapshot that close() still needs to flush —
always false on a table opened via Table::open.
Sourcepub fn rotate_cypher_keys(&mut self) -> Result<RotationResult, TableError>
pub fn rotate_cypher_keys(&mut self) -> Result<RotationResult, TableError>
Moves every record of this table onto the cipher’s current write key, eagerly — the counterpart of the lazy rotation a record gets for free on its next organic write.
A record is read, decrypted with whichever key sealed it and written back under the same
primary key, so the plaintext is preserved and nothing new is created. Records already on
the current key are not rewritten at all, which is what makes running this repeatedly cost
one read per record and nothing else. A table declaring no cypher field answers zero
without reading anything.
A field naming a key the keyring does not hold follows the table’s own
MissingKeyPolicy, for the reason a maintenance pass has to: under the default Throw
the run is refused at that record, because silently leaving a record behind is exactly what
an operator running a rotation is trying to rule out; under Omit/Raw it is counted in
RotationResult::skipped and left byte for byte, since neither of those policies yields
a plaintext that could be re-sealed — Omit drops the field and Raw hands back the
envelope, and writing either one back would destroy the value.
Records rotated before a refusal stay rotated: every write lands as a complete record, so a refused run is a partial one, not a broken one, and re-running it after adding the missing key finishes the job. No trigger fires — a rotation changes no value a trigger could be about.
Sourcepub fn compact(&mut self) -> Result<CompactionResult>
pub fn compact(&mut self) -> Result<CompactionResult>
Rewrites the log to keep only the live version of each key, then remaps the registry’s
slots onto the new offsets — see compaction::compact_log. A partitioned table
compacts one partition file at a time and remaps each on its own, so a partition nothing was
written to is left byte for byte as it was; the returned result is their sum.
The snapshot on disk describes the log as it was before the rewrite, so it is deleted before
the first swap and written afresh once every partition has landed — the port of the TS
beforeSwap: removeSnapshot(...) plus the trailing snapshot(). Deleting first is what
keeps a crash mid-compaction honest: whichever log survives, no index claims to pair with it.
Sourcepub fn refresh(&mut self) -> Result<RefreshOutcome>
pub fn refresh(&mut self) -> Result<RefreshOutcome>
Catches up with whatever another process did to this table’s files since this handle last
looked — the port of the TS Table.refresh(). Three things can have happened to a
partition, and each is answered differently:
- nothing — the file is the same size, on the same inode. One
statand no read at all, which is what makes calling this on a read path affordable; - an append — the file grew on the same inode, so everything already applied is still at the offset it was applied at and only the tail past this handle’s watermark is scanned;
- a rewrite — a different inode, or bytes gone from a file this engine only ever appends
to. That is what a foreign
Table::compactleaves behind (it lands throughatomic::write_atomic, so the path gets a brand new file), and it invalidates every offset this registry holds. There is no sound way to scan on from a watermark into a file that was rewritten under it, so the whole registry is rebuilt from the files as they are.
A partition file another process created is opened here too (LogSet::discover) and read in
full, since none of it has ever been seen.
Sourcepub fn set_follow(&mut self, follow: Option<FollowPolicy>)
pub fn set_follow(&mut self, follow: Option<FollowPolicy>)
Sets how often this handle catches up with foreign writes on its own — None to follow
nothing, which is where every constructor starts. Called by Database::open, which resolves
the policy from OpenOptions::follow and OpenOptions::readonly.
pub fn follow(&self) -> Option<FollowPolicy>
Sourcepub fn follow_if_due(&mut self) -> Result<Option<RefreshOutcome>>
pub fn follow_if_due(&mut self) -> Result<Option<RefreshOutcome>>
Catches this handle up when a follow policy is set and its interval has elapsed — the port
of the TS Table.#followIfDue, and what the *_following read methods below run first.
The interval gates the check, not the catching up: once the gate passes, Table::refresh
decides whether anything actually happened, and it costs one stat per log file to find out
that nothing did. The clock is moved on whenever the gate passes, so a table nobody else is
writing to is probed at most once per interval no matter how many reads run in between.
@returns what the catch-up found, or None when no policy is set or the interval has not
elapsed yet.
Sourcepub fn follow_is_due(&self) -> bool
pub fn follow_is_due(&self) -> bool
Whether Table::follow_if_due would reach for the files if it ran now: a policy is set and
its interval has elapsed. Only the gate — a clock comparison against followed_at, no stat
and no read — so this is the cheap half of the follow-aware read path.
It is public because a binding that has to take an exclusive lock to catch up asks this
first, under a shared one, and skips the exclusive lock entirely when the answer is false.
A writable handle resolves to no policy at all, so for it the answer is always false.
Sourcepub fn has_staged_writes(&self) -> bool
pub fn has_staged_writes(&self) -> bool
Whether anything staged is still waiting for Table::flush — the exact condition that
makes that call more than a no-op, and what a read which cannot see the staging window has to
drain before it can answer. Table::query and the aggregates plan over the registry rather
than over the staged writes, which is why Table::query_following flushes and
Table::get_following does not.
Sourcepub fn get_following(
&mut self,
key: &str,
) -> Result<Option<HaysonRecord>, TableError>
pub fn get_following( &mut self, key: &str, ) -> Result<Option<HaysonRecord>, TableError>
Table::get behind Table::follow_if_due — the read path the TS Table.get is, where
the freshness check is part of the read rather than something a caller remembers to do.
It is a second method rather than the behaviour of get itself because catching up needs
&mut self and get deliberately does not: every read that runs inside an already-borrowed
database (integrity checks, unit-of-work reads, drop_field’s residue scan) goes through the
shared-borrow one, and none of those wants a foreign write landing underneath it mid-pass.
Sourcepub fn get_many_following(
&mut self,
keys: &[String],
) -> Result<Vec<Option<HaysonRecord>>, TableError>
pub fn get_many_following( &mut self, keys: &[String], ) -> Result<Vec<Option<HaysonRecord>>, TableError>
Table::get_following for several keys, checking freshness once for the whole batch —
the TS Table.getMany, which calls #followIfDue once and then reads key by key.
Sourcepub fn query_following(
&mut self,
spec: &QuerySpec,
) -> Result<QueryResult, TableError>
pub fn query_following( &mut self, spec: &QuerySpec, ) -> Result<QueryResult, TableError>
Table::query behind Table::follow_if_due — see Table::get_following for why the
follow-aware read is a separate method.
Sourcepub fn aggregate_following(
&mut self,
spec: &QuerySpec,
aggregate: &AggregateSpec,
) -> Result<AggregateResult, TableError>
pub fn aggregate_following( &mut self, spec: &QuerySpec, aggregate: &AggregateSpec, ) -> Result<AggregateResult, TableError>
Table::aggregate behind Table::follow_if_due.
Sourcepub fn aggregate_grouped_following(
&mut self,
spec: &QuerySpec,
aggregate: &AggregateSpec,
) -> Result<GroupedAggregateResult, TableError>
pub fn aggregate_grouped_following( &mut self, spec: &QuerySpec, aggregate: &AggregateSpec, ) -> Result<GroupedAggregateResult, TableError>
Sourcepub fn keys(&self) -> impl Iterator<Item = &String>
pub fn keys(&self) -> impl Iterator<Item = &String>
Every key the table currently holds, in no particular order.
Sourcepub fn has(&self, key: &str) -> bool
pub fn has(&self, key: &str) -> bool
Whether the table holds a record under key, counting a write staged but not yet flushed —
the TS Table.has, which answers from the write queue before it looks at the log.
Sourcepub fn contains_value(&self, field: &str, value: &Value) -> bool
pub fn contains_value(&self, field: &str, value: &Value) -> bool
Whether any live, flushed record holds value on field. field has to be this table’s
primary key or a unique field — every caller reaches this through a relation’s to.field,
which the catalog’s relation parser already restricts to one of those two (ADR-axje/0043) —
anything else always answers false. O(1) via the registry: the primary-key case is
Table::has, the unique-field case is the same lookup assert_unique runs for the
opposite question.
NOTE: registry-only, unlike has() — a record staged but not yet flushed on a unique field
is invisible here, matching the eventual-consistency window the write queue already has.
Sourcepub fn keys_referencing(
&self,
field: &str,
value: &Value,
) -> Result<Vec<String>, TableError>
pub fn keys_referencing( &self, field: &str, value: &Value, ) -> Result<Vec<String>, TableError>
Every live record’s key where field equals value — the reverse of Table::contains_value,
used to find the rows an on_delete relation’s from.field points at. Unlike
contains_value, field is not restricted to the primary key or a unique field: an
exact/sorted index on it (schema index: sugar or a declared one) answers in
O(matches) via the registry; without one this falls back to a full scan, exactly like
check_integrity’s own answer to the same question (catalog::integrity::records_of) —
there is no reverse index guaranteed to exist on a relation’s from.field today.
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
How many live records the table holds — the TS Table.size. Tombstoned keys and superseded
versions are not among them; they are bytes in the log, not records in the registry.
Staged writes are deliberately not counted, exactly as in the TS reference: this is the
registry’s own number, and a key first written in the current staging window joins it when
the write lands. Table::keys leaves them out for the same reason.
pub fn is_empty(&self) -> bool
Sourcepub fn pending(&self, key: &str) -> HashSet<String>
pub fn pending(&self, key: &str) -> HashSet<String>
The fields claimed by writes staged against key but not yet appended — the TS
Table.pending(key). Empty unless a caller staged through Table::stage_put and friends
without flushing yet: put/patch/delete stage and flush inside the one call.
Sourcepub fn stats(&self) -> TableStats
pub fn stats(&self) -> TableStats
The table’s counters, in the shape of the TS TableStats — see TableStats for the
member whose meaning is narrower here than there.
pub fn name(&self) -> &str
pub fn schema(&self) -> &TableSchema
Sourcepub fn declared_indexes(&self) -> &[ExpandedIndex]
pub fn declared_indexes(&self) -> &[ExpandedIndex]
The expanded index set this handle was opened with and has served ever since — the answer
to “what does this table actually index”, as opposed to what the catalog on disk now says.
A reload rebuilds its registry from exactly this list, so it stays true across refresh.
Sourcepub fn get(&self, key: &str) -> Result<Option<HaysonRecord>, TableError>
pub fn get(&self, key: &str) -> Result<Option<HaysonRecord>, TableError>
Reads key, answering from the staging window first — the TS “read your own pending write”.
A staged record is handed back as it was validated, in plaintext, so a cypher field reads
the same before and after the write that carries it lands.
Sourcepub fn history(&self, key: &str) -> Result<TableHistory>
pub fn history(&self, key: &str) -> Result<TableHistory>
Every log line naming key, oldest first — what Table::get answers with is the last of
them.
Reads the log files rather than the registry, because the registry holds exactly one slot per
key (the live one) and nothing that points at a version already overwritten: the cost is a
full scan of this table’s logs, every partition of a partitioned table. Nothing here is
hydrated the way a read is — see HistoryEntry::document.
Writes staged but not flushed are not on disk yet, so they are not in the answer either;
Table::flush first if they should be.
pub fn put( &mut self, document: &Value, force: bool, ) -> Result<HaysonRecord, TableError>
Sourcepub fn put_sealed(
&mut self,
document: &Value,
sealed: &[String],
force: bool,
) -> Result<HaysonRecord, TableError>
pub fn put_sealed( &mut self, document: &Value, sealed: &[String], force: bool, ) -> Result<HaysonRecord, TableError>
Table::put for a record whose cypher fields named in sealed already hold an envelope
this system produced — a backup being restored, or a copy moving a value between databases
without ever holding it in the clear. Those fields reach the log exactly as given; every
other field, cypher or not, takes the ordinary write path and is sealed.
This is the only way to store a cypher field without sealing it, and it is deliberately
not reachable from a document: an ordinary write seals a value that merely looks like an
envelope just like any other, which is the whole point of the entry point existing. Naming a
field here is a claim, checked as far as the keyring allows — see
[crate::crypto::assert_carried_seals] for what is refused and for the one case that is
taken on trust. Do not wire it to untrusted input: nothing below it can tell a caller’s
string from a genuine envelope once the key that would authenticate it is absent.
The record returned is the one that was stored, so a carried field reads back as its
envelope rather than as plaintext — unlike Table::put, which is handed plaintext to
begin with. A later Table::get opens it like any other stored value.
Sourcepub fn put_with_warnings(
&mut self,
document: &Value,
force: bool,
) -> Result<PutOutcome, TableError>
pub fn put_with_warnings( &mut self, document: &Value, force: bool, ) -> Result<PutOutcome, TableError>
Same as Table::put, but the outcome also carries diagnostics — currently only broken
markdown links found while Table::link_parsing is Eager. See PutOutcome for the
shape and why put stays untouched alongside it.
Sourcepub fn stage_put(
&mut self,
document: &Value,
force: bool,
) -> Result<HaysonRecord, TableError>
pub fn stage_put( &mut self, document: &Value, force: bool, ) -> Result<HaysonRecord, TableError>
The staging half of Table::put: validates, claims the record’s fields against everything
else in flight and queues the write — but appends nothing and fires no trigger, both of
which belong to the Table::flush that commits it.
The record is returned as it will be stored, defaults and derived fields included, so a
caller that answers its own user before the write is durable has the same answer put would
have given. Until the flush, Table::get and Table::has read it back and
Table::pending names the fields it claimed.
Sourcepub fn flush(&mut self) -> Result<(), TableError>
pub fn flush(&mut self) -> Result<(), TableError>
Appends every write staged since the last flush, in staging order, then fires the triggers
they earned — the port of the TS WriteQueue.drain(). A no-op on an empty window, so
calling it before a read of committed state costs nothing when there is nothing in flight.
Triggers fire once per key, with the record the key held when the window opened as their
old: a key written twice before a flush is one change as far as an effect is concerned.
Sourcepub fn patch(
&mut self,
key: &str,
changes: &Value,
force: bool,
) -> Result<HaysonRecord, TableError>
pub fn patch( &mut self, key: &str, changes: &Value, force: bool, ) -> Result<HaysonRecord, TableError>
Read-merge-stage: reads the current record, validates changes as a partial record, merges
it over the current one, then stages the merged document as a full put — mirrors the TS
Table.patch, including the “primary key cannot be changed by patch” rule.
Sourcepub fn patch_with_warnings(
&mut self,
key: &str,
changes: &Value,
force: bool,
) -> Result<PutOutcome, TableError>
pub fn patch_with_warnings( &mut self, key: &str, changes: &Value, force: bool, ) -> Result<PutOutcome, TableError>
Same as Table::patch, but the outcome also carries diagnostics — see
Table::put_with_warnings and PutOutcome.
Sourcepub fn stage_patch(
&mut self,
key: &str,
changes: &Value,
force: bool,
) -> Result<HaysonRecord, TableError>
pub fn stage_patch( &mut self, key: &str, changes: &Value, force: bool, ) -> Result<HaysonRecord, TableError>
The staging half of Table::patch — see Table::stage_put for what staging does and
does not do. The record it merges over is the staged one when this key already has a write
in flight, so two patches in one window compose instead of the later one dropping the
earlier.
Only the fields changes names are claimed, not the whole merged record: a patch of age
must not refuse a patch of bio on the same key.
pub fn delete(&mut self, key: &str, force: bool) -> Result<bool, TableError>
Sourcepub fn stage_delete(
&mut self,
key: &str,
force: bool,
) -> Result<bool, TableError>
pub fn stage_delete( &mut self, key: &str, force: bool, ) -> Result<bool, TableError>
The staging half of Table::delete — see Table::stage_put. Answers whether a record
was there to remove straight away, counting one staged in this same window, so the answer
does not have to wait for the tombstone to be appended.
Sourcepub fn query(&self, spec: &QuerySpec) -> Result<QueryResult, TableError>
pub fn query(&self, spec: &QuerySpec) -> Result<QueryResult, TableError>
Runs spec against the committed log. Writes still in the staging window are not part
of the answer: flushing needs &mut self, and every read that runs inside an already
borrowed database (integrity checks, unit-of-work reads, drop_field’s residue scan) goes
through this one. Table::query_following — what the bindings call — flushes first, and
so is the one a caller staging its own writes wants.
Sourcepub fn query_with_overlay(
&self,
spec: &QuerySpec,
overlay: &dyn QueryOverlay,
delta: &CorpusDelta,
) -> Result<QueryResult, TableError>
pub fn query_with_overlay( &self, spec: &QuerySpec, overlay: &dyn QueryOverlay, delta: &CorpusDelta, ) -> Result<QueryResult, TableError>
Table::query as a unit of work will leave the table: overlay supplies the staged
records and the keys staged for deletion, and delta the same writes expressed as a corpus
change, so a search is scored over the corpus the unit will leave rather than the
committed one. The plan carries a PlanOverlay saying what the staged half contributed.
Sourcepub fn indexed_fields(&self) -> Vec<String>
pub fn indexed_fields(&self) -> Vec<String>
The single-field exact/sorted fields of this table — what a unit of work’s overlay
mirrors so an equality on one of them does not have to check every record it staged.
pub fn has_fulltext(&self) -> bool
Sourcepub fn tokens_of(&self, record: &HaysonRecord) -> Vec<String>
pub fn tokens_of(&self, record: &HaysonRecord) -> Vec<String>
The full-text tokens record would be indexed under, asked of a record the registry has not
been told about yet — a unit of work’s staged write, on its way into a CorpusDelta.
pub fn aggregate( &self, spec: &QuerySpec, aggregate: &AggregateSpec, ) -> Result<AggregateResult, TableError>
Sourcepub fn aggregate_grouped(
&self,
spec: &QuerySpec,
aggregate: &AggregateSpec,
) -> Result<GroupedAggregateResult, TableError>
pub fn aggregate_grouped( &self, spec: &QuerySpec, aggregate: &AggregateSpec, ) -> Result<GroupedAggregateResult, TableError>
Requires aggregate.group_by to be set — panics via execute_grouped_aggregate otherwise.
Sourcepub fn current_seq(&self) -> u64
pub fn current_seq(&self) -> u64
Highest _seq this table has reserved — after Table::open, this is the highest _seq
actually durable in the log; a live table also counts _seq values reserved but not yet
applied by Table::prepare_txn_ops.
Sourcepub fn prepare_txn_ops(
&mut self,
ops: &[TxnOp],
) -> Result<Vec<PreparedTxnEntry>, TableError>
pub fn prepare_txn_ops( &mut self, ops: &[TxnOp], ) -> Result<Vec<PreparedTxnEntry>, TableError>
Step 3 (“prepare”) of a multi-table unit of work: validates every op against this table’s
schema and unique constraints, reserves a _seq and serializes a log line for each — but
appends nothing. Bypasses WriteQueue/PendingMap entirely (unlike put/patch/delete):
the caller’s exclusive &mut Table for the lifetime of the unit already rules out any other
writer, so there is nothing left for a pending-claim to guard against.
A rejected op aborts the whole call with nothing appended — but _seq values already
reserved for earlier ops in this call stay burned, same as the TS reference.
Sourcepub fn apply_txn_entries(
&mut self,
entries: Vec<PreparedTxnEntry>,
) -> Result<()>
pub fn apply_txn_entries( &mut self, entries: Vec<PreparedTxnEntry>, ) -> Result<()>
Step 5 (“write”) of a multi-table unit of work: appends the lines a prior
prepare_txn_ops call already serialized, in order, in one append per partition they
touch — then fsyncs and updates the registry so the table reflects them immediately.
Sourcepub fn recover_txn_lines(
&mut self,
entries: &[(u64, String)],
) -> Result<usize, TableError>
pub fn recover_txn_lines( &mut self, entries: &[(u64, String)], ) -> Result<usize, TableError>
Finishes an unfinished journal at reopen: appends every already-serialized (seq, line)
pair whose seq is above what this table’s log already holds, in order, then fsyncs and
updates the registry — the same “seq higher than the log” rule the TS engine uses. Returns
how many lines were actually appended (0 when this table already has everything).