pub trait NodeDb: NodeDbMarker {
Show 24 methods
// Required methods
fn vector_search<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
query: &'life2 [f32],
k: usize,
filter: Option<&'life3 MetadataFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<SearchResult>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait;
fn vector_insert<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
embedding: &'life3 [f32],
metadata: Option<Document>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait;
fn vector_delete<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn graph_traverse<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
start: &'life2 NodeId,
depth: u8,
edge_filter: Option<&'life3 EdgeFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<SubGraph>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait;
fn graph_insert_edge<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
from: &'life2 NodeId,
to: &'life3 NodeId,
edge_type: &'life4 str,
properties: Option<Document>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<EdgeId>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait;
fn graph_delete_edge<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
edge_id: &'life2 EdgeId,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn document_get<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Option<Document>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn document_put<'life0, 'life1, 'async_trait>(
&'life0 self,
collection: &'life1 str,
doc: Document,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn document_delete<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn execute_sql<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
query: &'life1 str,
params: &'life2 [Value],
) -> Pin<Box<dyn Future<Output = NodeDbResult<QueryResult>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
// Provided methods
fn vector_insert_field<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
field_name: &'life2 str,
id: &'life3 str,
embedding: &'life4 [f32],
metadata: Option<Document>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait { ... }
fn vector_search_field<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
field_name: &'life2 str,
query: &'life3 [f32],
k: usize,
filter: Option<&'life4 MetadataFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<SearchResult>>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait { ... }
fn graph_shortest_path<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
from: &'life2 NodeId,
to: &'life3 NodeId,
max_depth: u8,
edge_filter: Option<&'life4 EdgeFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Option<Vec<NodeId>>>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait { ... }
fn text_search<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
field: &'life2 str,
query: &'life3 str,
top_k: usize,
params: TextSearchParams,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<SearchResult>>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait { ... }
fn batch_vector_insert<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
vectors: &'life2 [(&'life3 str, &'life4 [f32])],
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait { ... }
fn batch_graph_insert_edges<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>(
&'life0 self,
collection: &'life1 str,
edges: &'life2 [(&'life3 str, &'life4 str, &'life5 str)],
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
'life5: 'async_trait { ... }
fn proto_version(&self) -> u16 { ... }
fn capabilities(&self) -> u64 { ... }
fn server_version(&self) -> String { ... }
fn limits(&self) -> Limits { ... }
fn undrop_collection<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn drop_collection_purge<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn list_dropped_collections<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<DroppedCollection>>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait { ... }
fn on_collection_purged<'life0, 'async_trait>(
&'life0 self,
_handler: CollectionPurgedHandler,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>
where Self: Sync + 'async_trait,
'life0: 'async_trait { ... }
}Expand description
Unified database interface for NodeDB.
Two implementations:
NodeDbLite: executes queries against in-memory HNSW/CSR/Loro engines on the edge device. Writes produce CRDT deltas synced to Origin in background.NodeDbRemote: translates trait calls into parameterized SQL and sends them over pgwire to the Origin cluster.
The developer writes agent logic once. Switching between local and cloud is a one-line configuration change.
Required Methods§
Sourcefn vector_search<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
query: &'life2 [f32],
k: usize,
filter: Option<&'life3 MetadataFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<SearchResult>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn vector_search<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
query: &'life2 [f32],
k: usize,
filter: Option<&'life3 MetadataFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<SearchResult>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Search for the k nearest vectors to query in collection.
Returns results ordered by ascending distance. Optional metadata filter constrains which vectors are considered.
On Lite: direct in-memory HNSW search. Sub-millisecond.
On Remote: translated to SELECT ... ORDER BY embedding <-> $1 LIMIT $2.
Sourcefn vector_insert<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
embedding: &'life3 [f32],
metadata: Option<Document>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn vector_insert<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
embedding: &'life3 [f32],
metadata: Option<Document>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Insert a vector with optional metadata into collection.
On Lite: inserts into in-memory HNSW + emits CRDT delta + persists to SQLite.
On Remote: translated to INSERT INTO collection (id, embedding, metadata) VALUES (...).
Sourcefn vector_delete<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn vector_delete<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Delete a vector by ID from collection.
On Lite: marks deleted in HNSW + emits CRDT tombstone.
On Remote: DELETE FROM collection WHERE id = $1.
Sourcefn graph_traverse<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
start: &'life2 NodeId,
depth: u8,
edge_filter: Option<&'life3 EdgeFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<SubGraph>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn graph_traverse<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
start: &'life2 NodeId,
depth: u8,
edge_filter: Option<&'life3 EdgeFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<SubGraph>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Traverse the graph from start up to depth hops within
collection.
collection names the graph collection holding the adjacency
data. NodeDB’s graph overlay scopes edges per collection, so the
caller picks which graph to walk. Returns the discovered subgraph
(nodes + edges). Optional edge filter constrains which edges are
followed.
On Lite: direct CSR pointer-chasing in contiguous memory. Microseconds.
On Remote: GRAPH TRAVERSE FROM '<start>' DEPTH <n> [LABEL '<l>'].
Sourcefn graph_insert_edge<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
from: &'life2 NodeId,
to: &'life3 NodeId,
edge_type: &'life4 str,
properties: Option<Document>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<EdgeId>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn graph_insert_edge<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
from: &'life2 NodeId,
to: &'life3 NodeId,
edge_type: &'life4 str,
properties: Option<Document>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<EdgeId>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Insert a directed edge from from to to with the given label
into collection.
Returns the generated edge ID.
On Lite: appends to mutable adjacency buffer + CRDT delta + SQLite.
On Remote: GRAPH INSERT EDGE IN '<collection>' FROM '<from>' TO '<to>' TYPE '<label>'.
Sourcefn graph_delete_edge<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
edge_id: &'life2 EdgeId,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn graph_delete_edge<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
edge_id: &'life2 EdgeId,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Delete a graph edge by ID from collection.
On Lite: marks deleted + CRDT tombstone.
On Remote: GRAPH DELETE EDGE IN '<collection>' FROM '<src>' TO '<dst>' TYPE '<label>'.
Sourcefn document_get<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Option<Document>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn document_get<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Option<Document>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Get a document by ID from collection.
On Lite: direct Loro state read. Sub-millisecond.
On Remote: SELECT * FROM collection WHERE id = $1.
Sourcefn document_put<'life0, 'life1, 'async_trait>(
&'life0 self,
collection: &'life1 str,
doc: Document,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn document_put<'life0, 'life1, 'async_trait>(
&'life0 self,
collection: &'life1 str,
doc: Document,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Put (insert or update) a document into collection.
The document’s id field determines the key. If a document with that
ID already exists, it is overwritten (last-writer-wins locally; CRDT
merge on sync).
On Lite: Loro apply + CRDT delta + SQLite persist.
On Remote: INSERT ... ON CONFLICT (id) DO UPDATE SET ....
Sourcefn document_delete<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn document_delete<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
collection: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Delete a document by ID from collection.
On Lite: Loro delete + CRDT tombstone.
On Remote: DELETE FROM collection WHERE id = $1.
Sourcefn execute_sql<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
query: &'life1 str,
params: &'life2 [Value],
) -> Pin<Box<dyn Future<Output = NodeDbResult<QueryResult>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn execute_sql<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
query: &'life1 str,
params: &'life2 [Value],
) -> Pin<Box<dyn Future<Output = NodeDbResult<QueryResult>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Execute a raw SQL query with parameters.
On Lite: requires the sql feature flag (compiles in DataFusion parser).
Returns NodeDbError::SqlNotEnabled if the feature is not compiled in.
On Remote: pass-through to Origin via pgwire.
For most AI agent workloads, the typed methods above are sufficient and faster. Use this for BI tools, existing ORMs, or ad-hoc queries.
Provided Methods§
Sourcefn vector_insert_field<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
field_name: &'life2 str,
id: &'life3 str,
embedding: &'life4 [f32],
metadata: Option<Document>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn vector_insert_field<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
field_name: &'life2 str,
id: &'life3 str,
embedding: &'life4 [f32],
metadata: Option<Document>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Insert a vector into a named field within a collection.
Enables multiple embeddings per collection (e.g., “title_embedding”, “body_embedding”) with independent HNSW indexes.
Default returns Err — silently delegating to vector_insert and
dropping field_name would land the vector in the wrong field.
Implementations that route through to a server with field-aware
support must override.
Sourcefn vector_search_field<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
field_name: &'life2 str,
query: &'life3 [f32],
k: usize,
filter: Option<&'life4 MetadataFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<SearchResult>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn vector_search_field<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
field_name: &'life2 str,
query: &'life3 [f32],
k: usize,
filter: Option<&'life4 MetadataFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<SearchResult>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Search a named vector field.
Default returns Err — silently delegating to vector_search
and dropping field_name would search the wrong field.
Implementations that route through to a server with field-aware
support must override.
Sourcefn graph_shortest_path<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
from: &'life2 NodeId,
to: &'life3 NodeId,
max_depth: u8,
edge_filter: Option<&'life4 EdgeFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Option<Vec<NodeId>>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn graph_shortest_path<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
from: &'life2 NodeId,
to: &'life3 NodeId,
max_depth: u8,
edge_filter: Option<&'life4 EdgeFilter>,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Option<Vec<NodeId>>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Find the shortest path between two nodes.
Returns the path as a list of node IDs (from first, to last),
or None if no path exists within max_depth hops.
Default: forward breadth-first search built on graph_traverse.
Each frontier expansion calls graph_traverse(node, 1, edge_filter) to discover outgoing neighbors. Inherits the
underlying impl’s edge direction semantics. Implementations with
a server-side shortest-path operator (e.g. NodeDB’s
GRAPH PATH FROM <src> TO <dst> DSL) should override for
performance — round-tripping per-hop is O(path_length) wire
hops.
Sourcefn text_search<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
field: &'life2 str,
query: &'life3 str,
top_k: usize,
params: TextSearchParams,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<SearchResult>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn text_search<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
collection: &'life1 str,
field: &'life2 str,
query: &'life3 str,
top_k: usize,
params: TextSearchParams,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<SearchResult>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Full-text search with BM25 scoring against the FTS-indexed
field on collection.
NodeDB’s FTS is per-field — every BM25 index is scoped to one
declared field, so the caller names which field to search.
Returns document IDs with relevance scores, ordered by
descending score. Pass TextSearchParams::default() for
standard OR-mode non-fuzzy search.
Default returns Err — Ok(Vec::new()) is indistinguishable
from a real “no matches” answer and would silently mask the
missing implementation. Implementations must override (e.g., a
SEARCH IN '<collection>' FIELD '<field>' QUERY '<q>' round-trip
via execute_sql).
Sourcefn batch_vector_insert<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
vectors: &'life2 [(&'life3 str, &'life4 [f32])],
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn batch_vector_insert<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
collection: &'life1 str,
vectors: &'life2 [(&'life3 str, &'life4 [f32])],
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Batch insert vectors — amortizes CRDT delta export to O(1) per batch.
Sourcefn batch_graph_insert_edges<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>(
&'life0 self,
collection: &'life1 str,
edges: &'life2 [(&'life3 str, &'life4 str, &'life5 str)],
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
'life5: 'async_trait,
fn batch_graph_insert_edges<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>(
&'life0 self,
collection: &'life1 str,
edges: &'life2 [(&'life3 str, &'life4 str, &'life5 str)],
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
'life5: 'async_trait,
Batch insert graph edges into collection — amortizes CRDT
delta export to O(1) per batch.
Sourcefn proto_version(&self) -> u16
fn proto_version(&self) -> u16
The protocol version negotiated during the connection handshake.
Returns 0 for implementations that do not maintain a persistent
connection and therefore never perform a handshake.
Sourcefn capabilities(&self) -> u64
fn capabilities(&self) -> u64
The raw capability bitfield advertised by the server.
Returns 0 when no handshake was performed. Use
Capabilities::from_raw(self.capabilities()) for named predicates.
Sourcefn server_version(&self) -> String
fn server_version(&self) -> String
The server version string from HelloAckFrame (e.g. "0.1.0-dev").
Returns an empty string when no handshake was performed.
Sourcefn limits(&self) -> Limits
fn limits(&self) -> Limits
Per-operation limits announced by the server.
All fields are None when no handshake was performed — the caller
should treat None as “no server-side cap” for that dimension.
Sourcefn undrop_collection<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn undrop_collection<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Restore a soft-deleted collection within its retention window.
Equivalent to UNDROP COLLECTION <name>. Fails with 42P01 if
the retention window has elapsed and the row is gone, or with
42501 if the caller is neither preserved owner nor admin.
Default impl routes through execute_sql so any implementation
that can execute SQL inherits the correct behavior for free.
Sourcefn drop_collection_purge<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn drop_collection_purge<'life0, 'life1, 'async_trait>(
&'life0 self,
name: &'life1 str,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Hard-delete a collection, skipping soft-delete and retention.
Equivalent to DROP COLLECTION <name> PURGE. Admin-only on the
server; the server rejects non-admin callers with 42501.
Bypasses the retention safety net — data is unrecoverable.
Sourcefn list_dropped_collections<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<DroppedCollection>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
fn list_dropped_collections<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = NodeDbResult<Vec<DroppedCollection>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
List every soft-deleted collection in the current tenant that is still within its retention window.
Equivalent to SELECT tenant_id, name, owner, deactivated_at_ns, retention_expires_at_ns FROM _system.dropped_collections.
Returns Vec<DroppedCollection> — empty if no soft-deleted rows
exist for the caller’s tenant.
Sourcefn on_collection_purged<'life0, 'async_trait>(
&'life0 self,
_handler: CollectionPurgedHandler,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
fn on_collection_purged<'life0, 'async_trait>(
&'life0 self,
_handler: CollectionPurgedHandler,
) -> Pin<Box<dyn Future<Output = NodeDbResult<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
Register a handler fired when a collection the caller has synced is purged on Origin and the local copy is removed.
Default impl returns NodeDbError::storage with a
"not supported" detail — implementations that maintain a
sync client (Lite, any future push-capable remote client)
override with registration into their internal handler list.
Stateless clients (pgwire-only NodeDbRemote) have nothing
to push, so the default rejection is the correct behavior.