pub trait MemoryStore {
Show 21 methods
// Required methods
fn store(
&self,
id: u64,
content: &str,
embedding: &[f32],
) -> Result<(), MemoryError>;
fn store_with_metadata(
&self,
id: u64,
content: &str,
embedding: &[f32],
metadata: &Metadata,
) -> Result<(), MemoryError>;
fn store_with_ttl(
&self,
id: u64,
content: &str,
embedding: &[f32],
ttl_seconds: u64,
) -> Result<(), MemoryError>;
fn update_metadata(
&self,
id: u64,
metadata: &Metadata,
) -> Result<(), MemoryError>;
fn get(&self, id: u64) -> Result<Option<(String, Vec<f32>)>, MemoryError>;
fn get_metadata(&self, id: u64) -> Result<Option<Metadata>, MemoryError>;
fn get_metadata_batch(
&self,
ids: &[u64],
) -> Result<Vec<Option<Metadata>>, MemoryError>;
fn delete(&self, id: u64) -> Result<(), MemoryError>;
fn query_filtered(
&self,
embedding: &[f32],
k: usize,
filter: &Metadata,
offset: usize,
) -> Result<Vec<(u64, f32, String)>, MemoryError>;
fn query_excluding(
&self,
embedding: &[f32],
k: usize,
exclude: &Metadata,
) -> Result<Vec<(u64, f32, String)>, MemoryError>;
fn query_columnar(
&self,
embedding: &[f32],
k: usize,
filters: &[ColumnFilter],
) -> Result<Vec<Recollection>, MemoryError>;
fn relate(
&self,
from: u64,
to: u64,
relation: &str,
) -> Result<u64, MemoryError>;
fn relations(&self, id: u64) -> Result<Vec<MemoryEdge>, MemoryError>;
fn incoming_relations(
&self,
id: u64,
) -> Result<Vec<MemoryEdge>, MemoryError>;
fn relations_bounded(
&self,
id: u64,
cap: usize,
) -> Result<BoundedMemoryEdges, MemoryError>;
fn incoming_relations_bounded(
&self,
id: u64,
cap: usize,
) -> Result<BoundedMemoryEdges, MemoryError>;
fn unrelate(&self, edge_id: u64) -> Result<bool, MemoryError>;
fn count(&self) -> usize;
// Provided methods
fn store_with_metadata_and_ttl(
&self,
id: u64,
content: &str,
embedding: &[f32],
metadata: &Metadata,
ttl_seconds: u64,
) -> Result<(), MemoryError> { ... }
fn edge_count(&self) -> Option<usize> { ... }
fn list(
&self,
cursor: Option<u64>,
limit: usize,
) -> Result<(Vec<RawListedFact>, Option<u64>), MemoryError> { ... }
}Expand description
The storage primitives crate::service::MemoryService needs: write,
vector search, graph edges, and by-id lookup. A backend that implements
this trait can run the full wedge (remember/recall/recall_fused/
relate/forget/why/remember_extracted) with no orchestration code
duplicated.
Required Methods§
Sourcefn store_with_metadata(
&self,
id: u64,
content: &str,
embedding: &[f32],
metadata: &Metadata,
) -> Result<(), MemoryError>
fn store_with_metadata( &self, id: u64, content: &str, embedding: &[f32], metadata: &Metadata, ) -> Result<(), MemoryError>
Sourcefn store_with_ttl(
&self,
id: u64,
content: &str,
embedding: &[f32],
ttl_seconds: u64,
) -> Result<(), MemoryError>
fn store_with_ttl( &self, id: u64, content: &str, embedding: &[f32], ttl_seconds: u64, ) -> Result<(), MemoryError>
Store a fact that expires after ttl_seconds, no metadata.
§Errors
Returns MemoryError if persistence fails.
Sourcefn update_metadata(
&self,
id: u64,
metadata: &Metadata,
) -> Result<(), MemoryError>
fn update_metadata( &self, id: u64, metadata: &Metadata, ) -> Result<(), MemoryError>
Merge metadata into an already-stored fact’s payload, preserving any
durable TTL. Used to combine metadata with an expiry (store both in
two calls rather than needing every metadata×TTL combination as a
separate primitive).
§Errors
Returns MemoryError if id is unknown or persistence fails.
Sourcefn get(&self, id: u64) -> Result<Option<(String, Vec<f32>)>, MemoryError>
fn get(&self, id: u64) -> Result<Option<(String, Vec<f32>)>, MemoryError>
A fact’s content and embedding, or None if unknown/expired.
§Errors
Returns MemoryError if storage access fails.
Sourcefn get_metadata(&self, id: u64) -> Result<Option<Metadata>, MemoryError>
fn get_metadata(&self, id: u64) -> Result<Option<Metadata>, MemoryError>
A fact’s raw stored payload — reserved system keys (_veles_*)
included, so the service layer can check the hub flag before
stripping them for the caller — or None when the fact is
unknown/expired.
§Errors
Returns MemoryError if storage access fails.
Sourcefn get_metadata_batch(
&self,
ids: &[u64],
) -> Result<Vec<Option<Metadata>>, MemoryError>
fn get_metadata_batch( &self, ids: &[u64], ) -> Result<Vec<Option<Metadata>>, MemoryError>
Batched Self::get_metadata: one storage round trip for every id
in ids, results in the same order and length (an unknown or expired
id maps to None). Same raw-payload semantics as the single-id form.
§Errors
Returns MemoryError if storage access fails.
Sourcefn query_filtered(
&self,
embedding: &[f32],
k: usize,
filter: &Metadata,
offset: usize,
) -> Result<Vec<(u64, f32, String)>, MemoryError>
fn query_filtered( &self, embedding: &[f32], k: usize, filter: &Metadata, offset: usize, ) -> Result<Vec<(u64, f32, String)>, MemoryError>
Vector search for up to k ids, narrowed to facts whose metadata
exactly matches every key in filter.
§Errors
Returns MemoryError if the query fails.
Sourcefn query_excluding(
&self,
embedding: &[f32],
k: usize,
exclude: &Metadata,
) -> Result<Vec<(u64, f32, String)>, MemoryError>
fn query_excluding( &self, embedding: &[f32], k: usize, exclude: &Metadata, ) -> Result<Vec<(u64, f32, String)>, MemoryError>
Vector search for up to k ids, dropping facts whose metadata matches
every key in exclude.
§Errors
Returns MemoryError if the query fails.
Sourcefn query_columnar(
&self,
embedding: &[f32],
k: usize,
filters: &[ColumnFilter],
) -> Result<Vec<Recollection>, MemoryError>
fn query_columnar( &self, embedding: &[f32], k: usize, filters: &[ColumnFilter], ) -> Result<Vec<Recollection>, MemoryError>
Vector search fused with structured ColumnStore predicates (ranges
and comparisons, not just equality) — the engine behind
crate::service::MemoryService::recall_where.
§Absent and null fields
A filter is satisfied only by a fact that HAS the field with a
non-null value. A fact missing the field, or storing null in it, is
never returned — and ne is no exception, exactly as a SQL comparison
against NULL is never true.
| field state | field != target | field == target | < <= > >= |
|---|---|---|---|
| absent | no match | no match | no match |
present, null | no match | no match | no match |
| present, equal | no match | match | per the comparison |
| present, different | match | no match | per the comparison |
This is stated because it did not hold: ne on an absent field matched
on the native backend and never matched on WASM, for the API’s whole
life, because nothing compared them (#1759). Every backend is now held
to one shared table —
crate::column_filter_conformance — run against both.
Null-ness is not expressible through ColumnFilter; querying for it
is what IsNull/IsNotNull are for at the VelesQL layer.
§Errors
Returns MemoryError::InvalidFilter if a filter field is not a
plain identifier or a filter value is non-scalar, or MemoryError
if the query fails.
Sourcefn relate(&self, from: u64, to: u64, relation: &str) -> Result<u64, MemoryError>
fn relate(&self, from: u64, to: u64, relation: &str) -> Result<u64, MemoryError>
Create a typed edge from -> to. Returns the edge id.
§Errors
Returns MemoryError if either endpoint is missing or persistence fails.
Sourcefn relations(&self, id: u64) -> Result<Vec<MemoryEdge>, MemoryError>
fn relations(&self, id: u64) -> Result<Vec<MemoryEdge>, MemoryError>
Sourcefn incoming_relations(&self, id: u64) -> Result<Vec<MemoryEdge>, MemoryError>
fn incoming_relations(&self, id: u64) -> Result<Vec<MemoryEdge>, MemoryError>
The incoming edges of id — the mirror of Self::relations, with
the same liveness rule applied to the far end (here the source).
§Errors
Returns MemoryError if storage access fails.
Sourcefn relations_bounded(
&self,
id: u64,
cap: usize,
) -> Result<BoundedMemoryEdges, MemoryError>
fn relations_bounded( &self, id: u64, cap: usize, ) -> Result<BoundedMemoryEdges, MemoryError>
At most cap outgoing edges of id, plus whether its total degree
exceeded the scan — the bounded twin of Self::relations (#1820).
The contract is on COST, not just shape: an implementation must keep
work and transient allocation O(cap), never O(degree) — a super-node
(an entity hub mentioned by thousands of facts) is exactly where this
accessor is reached for. truncated is a separate signal because
edges.len() == cap cannot carry it: a node with exactly cap edges
is indistinguishable from a truncated one.
§Errors
Returns MemoryError if storage access fails.
Sourcefn incoming_relations_bounded(
&self,
id: u64,
cap: usize,
) -> Result<BoundedMemoryEdges, MemoryError>
fn incoming_relations_bounded( &self, id: u64, cap: usize, ) -> Result<BoundedMemoryEdges, MemoryError>
At most cap incoming edges of id, plus whether its total incoming
degree exceeded the scan — the mirror of Self::relations_bounded,
same O(cap) cost contract.
§Errors
Returns MemoryError if storage access fails.
Sourcefn unrelate(&self, edge_id: u64) -> Result<bool, MemoryError>
fn unrelate(&self, edge_id: u64) -> Result<bool, MemoryError>
Remove the edge with edge_id. Returns true when it existed —
idempotent: removing an absent edge is Ok(false), never an error.
§Errors
Returns MemoryError if storage access fails.
Provided Methods§
Sourcefn store_with_metadata_and_ttl(
&self,
id: u64,
content: &str,
embedding: &[f32],
metadata: &Metadata,
ttl_seconds: u64,
) -> Result<(), MemoryError>
fn store_with_metadata_and_ttl( &self, id: u64, content: &str, embedding: &[f32], metadata: &Metadata, ttl_seconds: u64, ) -> Result<(), MemoryError>
Store a fact with BOTH metadata and a durable TTL, in ONE write.
Default: the historical two-call sequence, so a backend written before this method keeps compiling and behaving as it did. Backends that can write both at once should override it — the two-call form leaves the fact live and expiring between the calls, so a short TTL can lapse in the gap and the metadata write then fails on a fact that was perfectly valid when the caller asked for it.
§Errors
Returns MemoryError if persistence fails.
Sourcefn edge_count(&self) -> Option<usize>
fn edge_count(&self) -> Option<usize>
The total number of graph edges, when the backend can answer without
materializing them — the observable difference between a store whose
why() can walk somewhere and one where it degrades to plain
similarity search.
Defaulted to None (“cannot say”) rather than required, deliberately:
a backend outside this crate (velesdb-wasm’s in-memory store) must
keep compiling when this surface grows, and a wrong-but-cheap answer
here would flag healthy graphs as flat. memory_status reports the
distinction to the caller instead of papering over it.
Sourcefn list(
&self,
cursor: Option<u64>,
limit: usize,
) -> Result<(Vec<RawListedFact>, Option<u64>), MemoryError>
fn list( &self, cursor: Option<u64>, limit: usize, ) -> Result<(Vec<RawListedFact>, Option<u64>), MemoryError>
One cursor page of the store’s live facts, ids ascending: up to
limit entries strictly after cursor (None starts the walk),
plus the cursor for the next page (None ends it). Payloads come
back RAW — reserved keys and scaffolding markers included — because
the policy of what a caller may see (hub filtering, key stripping)
belongs to the service layer, in one place, for every backend.
TTL-expired facts are skipped, not listed: an audit must show what the store will still serve, and a fact past its expiry is not it.
Defaulted to a refusal rather than required, same reasoning as
Self::edge_count: an out-of-crate backend keeps compiling, and
its list_memories answers with this error instead of a wrong walk.
§Errors
Returns MemoryError if the backend cannot enumerate at all, or if
the walk fails.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementors§
impl MemoryStore for NativeStore
persistence only.