pub struct StorageBackend { /* private fields */ }Expand description
Concrete storage backend providing capability traits.
Capability schemas are initialized once per backend. An index removed by another process is repaired on the narrowly supported forced-index read paths. Other external schema changes may still require reopening the backend.
Implementations§
Source§impl StorageBackend
impl StorageBackend
Sourcepub fn sqlite_code_map(
path: impl AsRef<Path>,
protected_main: &[PathBuf],
protected_events: &[PathBuf],
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_code_map( path: impl AsRef<Path>, protected_main: &[PathBuf], protected_events: &[PathBuf], ) -> Result<StorageBackend, SqliteError>
Open the dedicated code-map store through the native handle-proving
VFS. protected_main and protected_events are configured production
names; the guard also samples each name’s SQLite companions. Disk policy
and the volume-lock directory come from the process environment, with the
per-user default lock directory of crate::default_volume_lock_dir;
callers with captured configuration use Self::sqlite_code_map_with_policies.
Sourcepub fn sqlite_code_map_with_policies(
path: impl AsRef<Path>,
protected_main: &[PathBuf],
protected_events: &[PathBuf],
disk_guard_config: EffectiveDiskGuardConfig,
volume_lock_dir: PathBuf,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_code_map_with_policies( path: impl AsRef<Path>, protected_main: &[PathBuf], protected_events: &[PathBuf], disk_guard_config: EffectiveDiskGuardConfig, volume_lock_dir: PathBuf, ) -> Result<StorageBackend, SqliteError>
Open a guarded code-map store using the host’s captured disk policy and absolute shared volume-lock directory. Neither value rereads environment.
Source§impl StorageBackend
impl StorageBackend
Sourcepub fn validate_memory_visibility_cutover(&self) -> Result<(), SqliteError>
pub fn validate_memory_visibility_cutover(&self) -> Result<(), SqliteError>
Validate the sealed memory-receipt cutover without a writer or migration.
Sourcepub fn schema_version(&self) -> Result<u32, SqliteError>
pub fn schema_version(&self) -> Result<u32, SqliteError>
Read the applied schema version through the pool’s ordinary reader or
writer, without running migrations. Unlike
migrations::inspect_schema_version,
this goes through the already-open pool rather than a fresh boot-time
snapshot connection, so it tolerates a WAL sidecar left by this same
backend’s own recent writes.
Source§impl StorageBackend
impl StorageBackend
Sourcepub fn sqlite_with_volume_lock_dir(
path: impl AsRef<Path>,
volume_lock_dir: PathBuf,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_with_volume_lock_dir( path: impl AsRef<Path>, volume_lock_dir: PathBuf, ) -> Result<StorageBackend, SqliteError>
File-backed SQLite database whose volume advisory lock files live in
volume_lock_dir. Every cooperating process must choose the same directory.
Sourcepub fn sqlite_with_max_readers_and_policies(
path: impl AsRef<Path>,
max_readers: Option<usize>,
wal_ceiling: WalCeilingPolicy,
disk_guard_config: EffectiveDiskGuardConfig,
volume_lock_dir: PathBuf,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_with_max_readers_and_policies( path: impl AsRef<Path>, max_readers: Option<usize>, wal_ceiling: WalCeilingPolicy, disk_guard_config: EffectiveDiskGuardConfig, volume_lock_dir: PathBuf, ) -> Result<StorageBackend, SqliteError>
The host supplies the same captured policies used for daemon identity.
Source§impl StorageBackend
impl StorageBackend
Sourcepub async fn list_namespaces(
&self,
kind: &str,
liveness: NamespaceLiveness,
) -> Result<Vec<String>, StorageError>
pub async fn list_namespaces( &self, kind: &str, liveness: NamespaceLiveness, ) -> Result<Vec<String>, StorageError>
List sorted, distinct namespaces containing an exact stored record kind.
This administrative read is unscoped: it unions existing entities, notes
and events tables, comparing kind exactly. It does not initialize absent
tables, filter schedules by due time, or interpret kind as a substrate.
Unknown kinds return an empty list. Pass NamespaceLiveness::default()
for live rows; events have no tombstone field, so both modes include them.
Source§impl StorageBackend
impl StorageBackend
Sourcepub fn sqlite_with_claimed_file_identity(
path: impl AsRef<Path>,
max_readers: Option<usize>,
wal_ceiling: WalCeilingPolicy,
read_only: bool,
expected: DatabaseFileIdentity,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_with_claimed_file_identity( path: impl AsRef<Path>, max_readers: Option<usize>, wal_ceiling: WalCeilingPolicy, read_only: bool, expected: DatabaseFileIdentity, ) -> Result<StorageBackend, SqliteError>
Refuse any database other than expected before initializing identity or WAL.
read_only retains the explicit topology mode; a writable request still
honors an existing file’s filesystem read-only mode.
On Unix, the host must initialize the claimed-file observer at process
startup before any SQLite I/O, under pool::initialize_claimed_file_observer’s
unsafe precondition. Unsupported or uninitialized Unix hosts refuse.
Native open-time I/O is outside the pre-SQL refusal guarantee.
Sourcepub fn sqlite_with_claimed_file_identity_and_policies(
path: impl AsRef<Path>,
max_readers: Option<usize>,
wal_ceiling: WalCeilingPolicy,
expected: DatabaseFileIdentity,
disk_guard_config: EffectiveDiskGuardConfig,
volume_lock_dir: PathBuf,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_with_claimed_file_identity_and_policies( path: impl AsRef<Path>, max_readers: Option<usize>, wal_ceiling: WalCeilingPolicy, expected: DatabaseFileIdentity, disk_guard_config: EffectiveDiskGuardConfig, volume_lock_dir: PathBuf, ) -> Result<StorageBackend, SqliteError>
Writable Self::sqlite_with_claimed_file_identity that carries the
host’s captured disk policy and shared volume-lock directory.
Source§impl StorageBackend
impl StorageBackend
Sourcepub fn sqlite(path: impl AsRef<Path>) -> Result<StorageBackend, SqliteError>
pub fn sqlite(path: impl AsRef<Path>) -> Result<StorageBackend, SqliteError>
File-backed SQLite database.
Opens (or creates) the database at path. An existing filesystem path
whose mode is read-only is opened with the same locked-down pool
configuration as Self::sqlite_read_only. The writable pool provides
1 writer + N readers in WAL mode for concurrent access.
No service schema is applied — call apply_schema() for each service.
The pool may create its internal _khive_database_identity singleton
table on a writable open before service migrations run.
The volume-lock directory is the per-user default of
crate::default_volume_lock_dir, shared by every process of the user;
Self::sqlite_with_volume_lock_dir names one explicitly.
Sourcepub fn sqlite_with_max_readers(
path: impl AsRef<Path>,
max_readers: Option<usize>,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_with_max_readers( path: impl AsRef<Path>, max_readers: Option<usize>, ) -> Result<StorageBackend, SqliteError>
Open SQLite with a reader count selected before any connections are opened.
None preserves the default pool size and filesystem read-only detection.
The volume-lock directory defaults as in Self::sqlite.
Sourcepub fn sqlite_with_max_readers_and_wal_ceiling(
path: impl AsRef<Path>,
max_readers: Option<usize>,
wal_ceiling: WalCeilingPolicy,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_with_max_readers_and_wal_ceiling( path: impl AsRef<Path>, max_readers: Option<usize>, wal_ceiling: WalCeilingPolicy, ) -> Result<StorageBackend, SqliteError>
Open a file-backed SQLite backend with its already-resolved WAL ceiling.
A nonzero policy fails closed until the WAL I/O limiter is installed.
The volume-lock directory defaults as in Self::sqlite.
Sourcepub fn sqlite_read_only(
path: impl AsRef<Path>,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_read_only( path: impl AsRef<Path>, ) -> Result<StorageBackend, SqliteError>
File-backed SQLite database opened read-only.
Opens the database at path and sets PRAGMA query_only = ON on the
writer connection so that any write attempt (INSERT/UPDATE/DELETE) returns
an error. Reader connections are opened with SQLITE_OPEN_READ_ONLY by the
pool; at least one remains dedicated even for a rollback-journal snapshot,
while this PRAGMA extends the protection to the otherwise-unused writer slot.
The database file must already exist — unlike sqlite() this constructor
does not create a new file.
Sourcepub fn sqlite_read_only_with_max_readers(
path: impl AsRef<Path>,
max_readers: Option<usize>,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_read_only_with_max_readers( path: impl AsRef<Path>, max_readers: Option<usize>, ) -> Result<StorageBackend, SqliteError>
Open a read-only SQLite store with a construction-time reader count.
Sourcepub fn sqlite_read_only_with_max_readers_and_wal_ceiling(
path: impl AsRef<Path>,
max_readers: Option<usize>,
wal_ceiling: WalCeilingPolicy,
) -> Result<StorageBackend, SqliteError>
pub fn sqlite_read_only_with_max_readers_and_wal_ceiling( path: impl AsRef<Path>, max_readers: Option<usize>, wal_ceiling: WalCeilingPolicy, ) -> Result<StorageBackend, SqliteError>
Open a read-only SQLite backend while retaining WAL ceiling configuration for diagnostics. No writer policy is enforced.
Sourcepub fn memory() -> Result<StorageBackend, SqliteError>
pub fn memory() -> Result<StorageBackend, SqliteError>
In-memory SQLite database (for tests).
All data is lost when the backend is dropped. The pool degrades to single-connection mode since in-memory databases cannot be shared across multiple connections.
Sourcepub fn apply_schema(&self, plan: &ServiceSchemaPlan) -> Result<(), SqliteError>
pub fn apply_schema(&self, plan: &ServiceSchemaPlan) -> Result<(), SqliteError>
Apply a service’s schema plan (run migrations).
Each migration in the plan’s sqlite list is applied idempotently,
including when another opener commits it first. Already-applied
migrations are skipped after taking the SQLite write lock. The
_schema_versions table tracks which migrations have been run.
Sourcepub fn apply_pack_ddl_statements(
&self,
statements: &[&'static str],
) -> Result<(), SqliteError>
pub fn apply_pack_ddl_statements( &self, statements: &[&'static str], ) -> Result<(), SqliteError>
Apply pack-auxiliary DDL statements.
Executes the full plan in one transaction, applying each DDL statement
idempotently via execute_batch. Each statement MUST be self-contained
and use CREATE TABLE IF NOT EXISTS (or equivalent idempotent DDL) so
that calling this method more than once does not fail.
Pack auxiliary tables are NOT tracked in _schema_versions — they are
non-versioned. Use apply_schema with a ServiceSchemaPlan when version
tracking is needed.
Plans declaring nullable-column upgrades must use
Self::apply_pack_ddl_statements_with_columns. The runtime supplies
the SQL slice and column metadata separately because its SchemaPlan
type lives above this crate in the dependency chain.
Sourcepub fn apply_pack_ddl_statements_with_columns(
&self,
statements: &[&'static str],
additions: &[PackColumnAddition],
) -> Result<(), SqliteError>
pub fn apply_pack_ddl_statements_with_columns( &self, statements: &[&'static str], additions: &[PackColumnAddition], ) -> Result<(), SqliteError>
Apply a pack’s nullable-column upgrades and idempotent SQL atomically.
Missing columns are added only to existing tables; the full SQL plan creates fresh tables. Existing columns and the final schema must match the declarations. Schema inspection, additions, and SQL all run under one writer transaction, including rollback if any later step fails.
Sourcepub fn validate_pack_schema_columns(
&self,
additions: &[PackColumnAddition],
) -> Result<(), SqliteError>
pub fn validate_pack_schema_columns( &self, additions: &[PackColumnAddition], ) -> Result<(), SqliteError>
Validate a pack’s declared columns without applying SQL or acquiring a writer. Read-only hosts use this before exposing verbs that require these columns.
Sourcepub fn prepare_core_schema(&self) -> Result<u32, SqliteError>
pub fn prepare_core_schema(&self) -> Result<u32, SqliteError>
Prepare the core schema for runtime boot.
Writable backends acquire the canonical database-GC owner before the writer, apply the ordinary versioned prefix, and may finish V21 only through its zero-legacy-reference fast path. A legacy V20 database remains at V20 for the async host’s application-assisted attachment cutover; this method alone is not a serving boot gate. Read-only backends perform a query-only compatibility check and require the snapshot to be at this build’s exact latest schema version.
Sourcepub fn attachment_cutover_status(
&self,
) -> Result<AttachmentCutoverStatus, SqliteError>
pub fn attachment_cutover_status( &self, ) -> Result<AttachmentCutoverStatus, SqliteError>
Inspect the coordinated V21 attachment cutover state.
Sourcepub fn stage_attachment_cutover(
&self,
owner: &DatabaseGcOwnerGuard,
) -> Result<(), SqliteError>
pub fn stage_attachment_cutover( &self, owner: &DatabaseGcOwnerGuard, ) -> Result<(), SqliteError>
Commit resumable V21 stage 1 while the caller owns this database’s GC protocol. The owner must remain live through verified application backfill and finalization.
Sourcepub fn apply_verified_attachments(
&self,
owner: &DatabaseGcOwnerGuard,
attachments: &[Attachment],
) -> Result<(), SqliteError>
pub fn apply_verified_attachments( &self, owner: &DatabaseGcOwnerGuard, attachments: &[Attachment], ) -> Result<(), SqliteError>
Atomically publish a verified batch of pack-owned attachment roles.
Sourcepub fn finalize_attachment_cutover(
&self,
owner: &DatabaseGcOwnerGuard,
) -> Result<(), SqliteError>
pub fn finalize_attachment_cutover( &self, owner: &DatabaseGcOwnerGuard, ) -> Result<(), SqliteError>
Atomically swap GC liveness/fences to attachments, remove the legacy entity column, and record V21 while the canonical owner is held.
Sourcepub fn entities(&self) -> Result<Arc<dyn EntityStore>, SqliteError>
pub fn entities(&self) -> Result<Arc<dyn EntityStore>, SqliteError>
Get an EntityStore. Applies the entities DDL if not already present.
Idempotent — safe to call multiple times.
Sourcepub fn entities_for_namespace(
&self,
namespace: &str,
) -> Result<Arc<dyn EntityStore>, SqliteError>
pub fn entities_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn EntityStore>, SqliteError>
Get an EntityStore. The namespace parameter is validated (non-empty) and the entities schema is applied, but the store itself is unscoped — namespace is the caller’s responsibility on each query/delete call.
Sourcepub fn attachments(&self) -> Result<Arc<dyn AttachmentStore>, SqliteError>
pub fn attachments(&self) -> Result<Arc<dyn AttachmentStore>, SqliteError>
Get the role-keyed attachment store.
Unlike the legacy capability accessors, this does not install DDL on demand. The coordinated V21 core cutover owns creation of the table, reference fences, GC liveness swap, and removal of the legacy entity column as one boot-gated operation.
Sourcepub fn graph(&self) -> Result<Arc<dyn GraphStore>, SqliteError>
pub fn graph(&self) -> Result<Arc<dyn GraphStore>, SqliteError>
Get a GraphStore for the default namespace.
Creates the graph_edges table (with indexes) if it does not already
exist. Idempotent — safe to call multiple times.
Sourcepub fn graph_for_namespace(
&self,
namespace: &str,
) -> Result<Arc<dyn GraphStore>, SqliteError>
pub fn graph_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn GraphStore>, SqliteError>
Get a GraphStore scoped to a namespace.
Sourcepub fn notes(&self) -> Result<Arc<dyn NoteStore>, SqliteError>
pub fn notes(&self) -> Result<Arc<dyn NoteStore>, SqliteError>
Get a NoteStore. Applies the notes DDL if not already present.
Idempotent — safe to call multiple times.
Sourcepub fn notes_for_namespace(
&self,
namespace: &str,
) -> Result<Arc<dyn NoteStore>, SqliteError>
pub fn notes_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn NoteStore>, SqliteError>
Get a NoteStore. The namespace parameter is validated (non-empty) and the notes schema is applied, but the store itself is unscoped — namespace is the caller’s responsibility on each query/delete call.
Sourcepub fn notes_seq_repair_run_count(&self) -> usize
pub fn notes_seq_repair_run_count(&self) -> usize
How many times the lazy notes_seq anti-join repair has actually
executed against this backend’s pool. Exposed for regression tests
asserting the repair runs at most once per backend for the process’s
lifetime, not once per notes_for_namespace call (khive #827).
Sourcepub fn events(&self) -> Result<Arc<dyn EventStore>, SqliteError>
pub fn events(&self) -> Result<Arc<dyn EventStore>, SqliteError>
Get an EventStore for the default namespace.
Creates the events table (with indexes) if it does not already exist.
Idempotent — safe to call multiple times.
Sourcepub fn events_for_namespace(
&self,
namespace: &str,
) -> Result<Arc<dyn EventStore>, SqliteError>
pub fn events_for_namespace( &self, namespace: &str, ) -> Result<Arc<dyn EventStore>, SqliteError>
Get an EventStore scoped to a namespace.
Sourcepub fn agents(&self) -> Result<Arc<dyn AgentStore>, SqliteError>
pub fn agents(&self) -> Result<Arc<dyn AgentStore>, SqliteError>
Get the agent-process store (ADR-142 §1). Applies the agents DDL if not
already present. Idempotent — safe to call multiple times. Unlike the
other stores here, agent-process records are not namespace-scoped, so
there is no _for_namespace variant.
Sourcepub fn vectors(
&self,
model_key: &str,
embedding_model: &str,
dimensions: usize,
) -> Result<Arc<dyn VectorStore>, SqliteError>
pub fn vectors( &self, model_key: &str, embedding_model: &str, dimensions: usize, ) -> Result<Arc<dyn VectorStore>, SqliteError>
Get a VectorStore for a specific embedding model, scoped to the default namespace.
Creates the vec0 virtual table if it does not already exist. The model_key
must contain only ASCII alphanumeric/underscore characters. The embedding_model
is the canonical display name stored in each vector row.
Sourcepub fn vectors_for_namespace(
&self,
model_key: &str,
embedding_model: &str,
dimensions: usize,
namespace: &str,
) -> Result<Arc<dyn VectorStore>, SqliteError>
pub fn vectors_for_namespace( &self, model_key: &str, embedding_model: &str, dimensions: usize, namespace: &str, ) -> Result<Arc<dyn VectorStore>, SqliteError>
Get a VectorStore for a specific embedding model with a default namespace.
Creates the vec0 virtual table if it does not already exist. The namespace
is a default for trait methods that lack a per-call namespace parameter
(count, delete, info). Access control is enforced at the runtime layer.
The model_key must contain only ASCII alphanumeric/underscore characters.
The embedding_model is the canonical display name stored in the embedding_model
column of each vector row (e.g. "all-minilm-l6-v2").
Sourcepub fn ensure_vector_tables(
&self,
models: &[(&str, usize)],
) -> Result<(), SqliteError>
pub fn ensure_vector_tables( &self, models: &[(&str, usize)], ) -> Result<(), SqliteError>
Ensure all requested vector tables with one schema-writer acquisition. Read-only backends inspect the same tables using one reader instead.
A writable backend prepares each model’s table once: the first call that names it validates or creates the table under the writer and records the model only after every step succeeded. Later calls for a recorded model return without taking the writer, and a failed call records nothing, so the next call repeats the check.
Sourcepub fn register_embedding_model(
&self,
engine_name: &str,
model_id: &str,
key_version: &str,
dimensions: u32,
) -> Result<(), SqliteError>
pub fn register_embedding_model( &self, engine_name: &str, model_id: &str, key_version: &str, dimensions: u32, ) -> Result<(), SqliteError>
Register an embedding model in the _embedding_models registry table.
Idempotent: if a row with the same canonical_key already exists, updates its
status back to 'active' without changing other fields.
Sourcepub fn sparse(
&self,
model_key: &str,
) -> Result<Arc<dyn SparseStore>, SqliteError>
pub fn sparse( &self, model_key: &str, ) -> Result<Arc<dyn SparseStore>, SqliteError>
Get a SparseStore for a specific model key, scoped to the default namespace.
Creates the sparse table if it does not already exist.
Sourcepub fn sparse_for_namespace(
&self,
model_key: &str,
namespace: &str,
) -> Result<Arc<dyn SparseStore>, SqliteError>
pub fn sparse_for_namespace( &self, model_key: &str, namespace: &str, ) -> Result<Arc<dyn SparseStore>, SqliteError>
Get a SparseStore for a specific model key with an explicit default namespace.
The model_key must contain only ASCII alphanumeric/underscore characters.
Sourcepub fn text(&self, table_key: &str) -> Result<Arc<dyn TextSearch>, SqliteError>
pub fn text(&self, table_key: &str) -> Result<Arc<dyn TextSearch>, SqliteError>
Get a TextSearch for a specific table key.
Creates the FTS5 virtual table if it does not already exist. Uses the
trigram tokenizer by default (CJK-safe).
The table_key must contain only ASCII alphanumeric/underscore characters.
Sourcepub fn text_with_tokenizer(
&self,
table_key: &str,
tokenizer: &str,
) -> Result<Arc<dyn TextSearch>, SqliteError>
pub fn text_with_tokenizer( &self, table_key: &str, tokenizer: &str, ) -> Result<Arc<dyn TextSearch>, SqliteError>
Get a TextSearch with an explicit FTS5 tokenizer.
Use when you need a tokenizer other than the default trigram — for
example unicode61 for Latin-only corpora.
Both table_key and tokenizer must contain only ASCII
alphanumeric/underscore characters.
Sourcepub fn blob_store(
&self,
config_root: Option<&Path>,
floor_bytes: Option<u64>,
) -> Result<Arc<dyn BlobStore>, SqliteError>
pub fn blob_store( &self, config_root: Option<&Path>, floor_bytes: Option<u64>, ) -> Result<Arc<dyn BlobStore>, SqliteError>
Get a BlobStore rooted per khive#292’s precedence chain:
KHIVE_BLOB_ROOT env var > config_root (a caller-resolved
khive.toml override — khive-db has no TOML parser of its own) >
beside this backend’s database directory. floor_bytes overrides the
default 100 GB fail-closed free-space floor (None keeps the
default). Errors if none of the three roots apply — e.g. an in-memory
backend with no override and no env var has nowhere to default to.
Sourcepub fn blob_store_read_only(
&self,
config_root: Option<&Path>,
floor_bytes: Option<u64>,
) -> Result<Arc<dyn BlobStore>, SqliteError>
pub fn blob_store_read_only( &self, config_root: Option<&Path>, floor_bytes: Option<u64>, ) -> Result<Arc<dyn BlobStore>, SqliteError>
Resolve the filesystem blob root exactly like Self::blob_store but
require it to exist instead of creating it. Snapshot runtimes wrap the
returned capability so its read methods remain available while every
mutator is refused.
Sourcepub fn is_file_backed(&self) -> bool
pub fn is_file_backed(&self) -> bool
Is this a file-backed backend?
Sourcepub fn is_read_only(&self) -> bool
pub fn is_read_only(&self) -> bool
Whether this backend was opened with SQLite’s read-only/query-only contract, explicitly or after filesystem-mode detection.
Sourcepub fn data_dir(&self) -> Option<PathBuf>
pub fn data_dir(&self) -> Option<PathBuf>
Return the directory containing the backend’s database file, or None
for an in-memory backend.
Sourcepub fn ann_root(&self) -> Option<PathBuf>
pub fn ann_root(&self) -> Option<PathBuf>
Root directory for this database’s ANN segment tree, or None for an
in-memory backend. Derived from the database file name itself
(<db-file>.ann/ beside the file), so two databases sharing a parent
directory can never adopt each other’s segments or UUID maps. The
suffix is appended at the OsString byte level — a lossy UTF-8
conversion would collapse distinct non-UTF-8 filenames into one
replacement-character root, breaking exactly that isolation.
Sourcepub fn pool(&self) -> &ConnectionPool
pub fn pool(&self) -> &ConnectionPool
Access the underlying pool (escape hatch).
Sourcepub fn database_owner_identity(
&self,
) -> Result<DatabaseOwnerIdentity, DatabaseOwnerIdentityError>
pub fn database_owner_identity( &self, ) -> Result<DatabaseOwnerIdentity, DatabaseOwnerIdentityError>
Durable owner evidence for this backend, captured at pool construction. The caller must choose the effective main backend before comparing it.
Sourcepub fn verify_database_owner(
&self,
expected: &DatabaseOwnerIdentity,
) -> Result<(), DatabaseOwnerIdentityError>
pub fn verify_database_owner( &self, expected: &DatabaseOwnerIdentity, ) -> Result<(), DatabaseOwnerIdentityError>
Refuse a secondary or copied database as the supplied database owner.
Sourcepub fn pool_arc(&self) -> Arc<ConnectionPool> ⓘ
pub fn pool_arc(&self) -> Arc<ConnectionPool> ⓘ
Clone the underlying pool Arc.
Trait Implementations§
Source§impl EntityStore for StorageBackend
impl EntityStore for StorageBackend
Source§fn upsert_entity<'life0, 'async_trait>(
&'life0 self,
entity: Entity,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_entity<'life0, 'async_trait>(
&'life0 self,
entity: Entity,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn insert_entity_if_absent<'life0, 'async_trait>(
&'life0 self,
_entity: Entity,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn insert_entity_if_absent<'life0, 'async_trait>(
&'life0 self,
_entity: Entity,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
true when this call inserted the row and false
when an existing row won the race. The existing row is never updated. Read moreSource§fn upsert_entity_with_attachments<'life0, 'async_trait>(
&'life0 self,
_entity: Entity,
_attachments: Vec<Attachment>,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_entity_with_attachments<'life0, 'async_trait>(
&'life0 self,
_entity: Entity,
_attachments: Vec<Attachment>,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn upsert_entities<'life0, 'async_trait>(
&'life0 self,
entities: Vec<Entity>,
) -> Pin<Box<dyn Future<Output = Result<BatchWriteSummary, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_entities<'life0, 'async_trait>(
&'life0 self,
entities: Vec<Entity>,
) -> Pin<Box<dyn Future<Output = Result<BatchWriteSummary, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn replace_entity_if_unchanged<'life0, 'async_trait>(
&'life0 self,
_entity: Entity,
_expected_updated_at: i64,
_expected_deleted_at: Option<i64>,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn replace_entity_if_unchanged<'life0, 'async_trait>(
&'life0 self,
_entity: Entity,
_expected_updated_at: i64,
_expected_deleted_at: Option<i64>,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn get_entity<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn get_entity<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
None if absent.Source§fn delete_entity<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
mode: DeleteMode,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn delete_entity<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
mode: DeleteMode,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_entities<'life0, 'life1, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
filter: EntityFilter,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn query_entities<'life0, 'life1, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
filter: EntityFilter,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_entities_count_free<'life0, 'life1, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filter: EntityFilter,
_page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn query_entities_count_free<'life0, 'life1, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filter: EntityFilter,
_page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn entity_sequence<'life0, 'async_trait>(
&'life0 self,
_id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<i64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn entity_sequence<'life0, 'async_trait>(
&'life0 self,
_id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<i64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_entities_after<'life0, 'life1, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filter: EntityFilter,
_after: Option<SeekCursor>,
_limit: u32,
) -> Pin<Box<dyn Future<Output = Result<SeekPage<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn query_entities_after<'life0, 'life1, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filter: EntityFilter,
_after: Option<SeekCursor>,
_limit: u32,
) -> Pin<Box<dyn Future<Output = Result<SeekPage<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_entities<'life0, 'life1, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
filter: EntityFilter,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn count_entities<'life0, 'life1, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
filter: EntityFilter,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_entities_by_type<'life0, 'life1, 'async_trait>(
&'life0 self,
_namespaces: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<(Option<String>, u64)>>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn count_entities_by_type<'life0, 'life1, 'async_trait>(
&'life0 self,
_namespaces: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<(Option<String>, u64)>>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
None, distinct from every string label. Ordering is unspecified. Read moreSource§fn get_entity_including_deleted<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn get_entity_including_deleted<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Entity>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§impl EventStore for StorageBackend
impl EventStore for StorageBackend
Source§fn append_event<'life0, 'async_trait>(
&'life0 self,
event: Event,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn append_event<'life0, 'async_trait>(
&'life0 self,
event: Event,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn append_events<'life0, 'async_trait>(
&'life0 self,
events: Vec<Event>,
) -> Pin<Box<dyn Future<Output = Result<BatchWriteSummary, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn append_events<'life0, 'async_trait>(
&'life0 self,
events: Vec<Event>,
) -> Pin<Box<dyn Future<Output = Result<BatchWriteSummary, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn get_event<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Event>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn get_event<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Event>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
None if absent.Source§fn query_events<'life0, 'async_trait>(
&'life0 self,
filter: EventFilter,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Event>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn query_events<'life0, 'async_trait>(
&'life0 self,
filter: EventFilter,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Event>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_event_page<'life0, 'async_trait>(
&'life0 self,
query: EventPageQuery,
) -> Pin<Box<dyn Future<Output = Result<EventPageWindow, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn query_event_page<'life0, 'async_trait>(
&'life0 self,
query: EventPageQuery,
) -> Pin<Box<dyn Future<Output = Result<EventPageWindow, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_events<'life0, 'async_trait>(
&'life0 self,
filter: EventFilter,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn count_events<'life0, 'async_trait>(
&'life0 self,
filter: EventFilter,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_events_grouped<'life0, 'async_trait>(
&'life0 self,
filter: EventFilter,
group_by: EventGroupBy,
) -> Pin<Box<dyn Future<Output = Result<BTreeMap<String, u64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn count_events_grouped<'life0, 'async_trait>(
&'life0 self,
filter: EventFilter,
group_by: EventGroupBy,
) -> Pin<Box<dyn Future<Output = Result<BTreeMap<String, u64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn preflight_event(&self, event: &Event) -> Result<(), StorageError>
fn preflight_event(&self, event: &Event) -> Result<(), StorageError>
event against the exact insert/observation shape the
backend would build at append time, performing no I/O. Rejects a
malformed row before it is ever enqueued for a write, so one bad
producer input cannot poison a batch shared with other callers. Read moreSource§fn append_events_idempotent<'life0, 'async_trait>(
&'life0 self,
events: Vec<Event>,
) -> Pin<Box<dyn Future<Output = Result<IdempotentEventBatchResult, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn append_events_idempotent<'life0, 'async_trait>(
&'life0 self,
events: Vec<Event>,
) -> Pin<Box<dyn Future<Output = Result<IdempotentEventBatchResult, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
EventAppendDisposition::AlreadyPresentIdentical instead of
re-inserting; any mismatch reports
EventAppendDisposition::IdentityConflict for that row alone,
while unrelated rows in the same batch still commit. Read moreSource§fn supports_idempotent_audit_batch(&self) -> bool
fn supports_idempotent_audit_batch(&self) -> bool
preflight_event and
append_events_idempotent for real, rather than inheriting their
Unsupported-returning defaults above. Read moreSource§impl GraphStore for StorageBackend
impl GraphStore for StorageBackend
Source§fn latest_annotating_note<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_node_id: Uuid,
_kind: &'life1 str,
_tag: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<(Uuid, i64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn latest_annotating_note<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_node_id: Uuid,
_kind: &'life1 str,
_tag: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<(Uuid, i64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
kind carrying the exact string tag
in its properties.tags array and connected to node_id by a live
incoming annotates edge in this store’s namespace. Returns its UUID
and creation timestamp; equal timestamps choose the smallest UUID. Read moreSource§fn latest_annotating_note_with_property<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
_node_id: Uuid,
_kind: &'life1 str,
_tag: &'life2 str,
_property_key: &'life3 str,
_property_value: &'life4 str,
) -> Pin<Box<dyn Future<Output = Result<Option<(Uuid, i64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
StorageBackend: 'async_trait,
fn latest_annotating_note_with_property<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
_node_id: Uuid,
_kind: &'life1 str,
_tag: &'life2 str,
_property_key: &'life3 str,
_property_value: &'life4 str,
) -> Pin<Box<dyn Future<Output = Result<Option<(Uuid, i64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
StorageBackend: 'async_trait,
latest_annotating_note, but also require one exact top-level
string property before selecting the newest candidate.Source§fn upsert_edge<'life0, 'async_trait>(
&'life0 self,
edge: Edge,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_edge<'life0, 'async_trait>(
&'life0 self,
edge: Edge,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn insert_edge_if_absent<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn insert_edge_if_absent<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
true when this call inserted the row and false
when an existing row won the race. The existing row is never updated. Read moreSource§fn insert_commit_annotation_if_absent<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
_guard: CommitAnnotationGuard,
) -> Pin<Box<dyn Future<Output = Result<CommitAnnotationInsertOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn insert_commit_annotation_if_absent<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
_guard: CommitAnnotationGuard,
) -> Pin<Box<dyn Future<Output = Result<CommitAnnotationInsertOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
annotates edge only while its source is a live commit
note in edge.namespace with the exact SHA, its target is the live
project for the selected source, the paired commit cursor rows still
match the preview, and no row of the edge’s natural key exists,
including a tombstone. All checks and the insert occur in one writer
transaction. Existing rows are immutable.Source§fn upsert_edges<'life0, 'async_trait>(
&'life0 self,
edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = Result<BatchWriteSummary, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_edges<'life0, 'async_trait>(
&'life0 self,
edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = Result<BatchWriteSummary, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn upsert_edge_observed<'life0, 'async_trait>(
&'life0 self,
_request: EdgeUpsertRequest,
) -> Pin<Box<dyn Future<Output = Result<EdgeUpsertResult, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_edge_observed<'life0, 'async_trait>(
&'life0 self,
_request: EdgeUpsertRequest,
) -> Pin<Box<dyn Future<Output = Result<EdgeUpsertResult, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn replace_edge_if_unchanged<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
_expected_updated_at: DateTime<Utc>,
_expected_deleted_at: Option<DateTime<Utc>>,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn replace_edge_if_unchanged<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
_expected_updated_at: DateTime<Utc>,
_expected_deleted_at: Option<DateTime<Utc>>,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn update_symmetric_edge_if_unchanged<'life0, 'async_trait>(
&'life0 self,
_request: SymmetricEdgeUpdateRequest,
) -> Pin<Box<dyn Future<Output = Result<SymmetricEdgeUpdateOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn update_symmetric_edge_if_unchanged<'life0, 'async_trait>(
&'life0 self,
_request: SymmetricEdgeUpdateRequest,
) -> Pin<Box<dyn Future<Output = Result<SymmetricEdgeUpdateOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn upsert_edge_guarded<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
) -> Pin<Box<dyn Future<Output = Result<GuardedWriteOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_edge_guarded<'life0, 'async_trait>(
&'life0 self,
_edge: Edge,
) -> Pin<Box<dyn Future<Output = Result<GuardedWriteOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn upsert_edge_guarded_observed<'life0, 'async_trait>(
&'life0 self,
_request: EdgeUpsertRequest,
) -> Pin<Box<dyn Future<Output = Result<GuardedEdgeUpsertOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_edge_guarded_observed<'life0, 'async_trait>(
&'life0 self,
_request: EdgeUpsertRequest,
) -> Pin<Box<dyn Future<Output = Result<GuardedEdgeUpsertOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
GraphStore::upsert_edge_guarded. In addition to
the endpoint guard, it distinguishes create, live replacement, and
explicit resurrection without a caller-side read/write race.Source§fn upsert_edges_guarded<'life0, 'async_trait>(
&'life0 self,
_edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = Result<GuardedBatchOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_edges_guarded<'life0, 'async_trait>(
&'life0 self,
_edges: Vec<Edge>,
) -> Pin<Box<dyn Future<Output = Result<GuardedBatchOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
GraphStore::upsert_edge_guarded. All-or-nothing:
if any edge’s endpoints are missing at write time, no edge from the
batch is persisted, BatchWriteSummary::affected is 0, and
GuardedBatchOutcome::refused names the first failing batch entry and
its missing endpoint(s) — determined by the same in-transaction
pre-check that aborted the batch, not a post-hoc re-read.
Retain the original ordered input to enumerate every aborted write via
GuardedBatchOutcome::refusal_page beyond the default bounded sample. Read moreSource§fn upsert_edges_guarded_observed<'life0, 'async_trait>(
&'life0 self,
_requests: Vec<EdgeUpsertRequest>,
) -> Pin<Box<dyn Future<Output = Result<GuardedEdgeBatchUpsertOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_edges_guarded_observed<'life0, 'async_trait>(
&'life0 self,
_requests: Vec<EdgeUpsertRequest>,
) -> Pin<Box<dyn Future<Output = Result<GuardedEdgeBatchUpsertOutcome, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn get_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = Result<Option<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn get_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = Result<Option<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
None if absent. Filters soft-deleted rows.Source§fn get_edge_including_deleted<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = Result<Option<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn get_edge_including_deleted<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
) -> Pin<Box<dyn Future<Output = Result<Option<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn get_edge_by_natural_key_including_deleted<'life0, 'life1, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
source_id: Uuid,
target_id: Uuid,
relation: EdgeRelation,
) -> Pin<Box<dyn Future<Output = Result<Option<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn get_edge_by_natural_key_including_deleted<'life0, 'life1, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
source_id: Uuid,
target_id: Uuid,
relation: EdgeRelation,
) -> Pin<Box<dyn Future<Output = Result<Option<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
query_edges/list_edges path filters deleted_at IS NULL and would report
“not found” for exactly that row. Read moreSource§fn delete_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
mode: DeleteMode,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn delete_edge<'life0, 'async_trait>(
&'life0 self,
id: LinkId,
mode: DeleteMode,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
sort: Vec<SortOrder<EdgeSortField>>,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn query_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
sort: Vec<SortOrder<EdgeSortField>>,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
total: None; callers that
need a count use Self::count_edges explicitly.Source§fn query_edges_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
filter: EdgeFilter,
sort: Vec<SortOrder<EdgeSortField>>,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn query_edges_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
filter: EdgeFilter,
sort: Vec<SortOrder<EdgeSortField>>,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Self::query_edges: a single statement with namespace IN (...)
keeps offset continuation coherent, where fetching per-namespace
prefixes and slicing a client-side merge floats the window between
calls (silent duplicate/skip enumeration). Backends without batched
namespace support retain the single-namespace path and reject
multi-namespace requests explicitly. Implementations should return
total: None; callers that need a count use
Self::count_edges_in_namespaces explicitly.Source§fn count_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn count_edges<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_edges_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
filter: EdgeFilter,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn count_edges_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
filter: EdgeFilter,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_edges_by_relation<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<(EdgeRelation, u64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn count_edges_by_relation<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<(EdgeRelation, u64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
GROUP BY relation) used to report the true per-relation
population for full-graph audits (#702.3).Source§fn count_edges_by_relation_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<Vec<(EdgeRelation, u64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn count_edges_by_relation_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<Vec<(EdgeRelation, u64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_edges_by_endpoint_base<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<EdgeEndpointBaseCounts, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn count_edges_by_endpoint_base<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<EdgeEndpointBaseCounts, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_edges_by_endpoint_base_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<EdgeEndpointBaseCounts, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn count_edges_by_endpoint_base_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<EdgeEndpointBaseCounts, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_edges_by_relation_and_endpoint_base_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<Vec<(EdgeRelation, EdgeEndpointBaseCounts)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn count_edges_by_relation_and_endpoint_base_in_namespaces<'life0, 'life1, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
) -> Pin<Box<dyn Future<Output = Result<Vec<(EdgeRelation, EdgeEndpointBaseCounts)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_edges_after<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
after: Option<Uuid>,
limit: u32,
) -> Pin<Box<dyn Future<Output = Result<EdgeSeekPage, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn query_edges_after<'life0, 'async_trait>(
&'life0 self,
filter: EdgeFilter,
after: Option<Uuid>,
limit: u32,
) -> Pin<Box<dyn Future<Output = Result<EdgeSeekPage, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
id ascending, using an
indexed range scan (id > after) against the (namespace, id)
primary key instead of OFFSET. after is exclusive; None starts
from the beginning of the set. This remains an efficient compatibility
path for a fixed edge set, but random UUIDs inserted concurrently may
sort behind an issued boundary. Public concurrent walks use
Self::query_edges_sequence_after instead (#1424).Source§fn edge_sequence<'life0, 'async_trait>(
&'life0 self,
_id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<i64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn edge_sequence<'life0, 'async_trait>(
&'life0 self,
_id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<i64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn edge_sequences<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<Vec<(Uuid, i64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn edge_sequences<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<Vec<(Uuid, i64)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_edges_sequence_after<'life0, 'async_trait>(
&'life0 self,
_filter: EdgeFilter,
_after: Option<SeekCursor>,
_limit: u32,
) -> Pin<Box<dyn Future<Output = Result<SeekPage<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn query_edges_sequence_after<'life0, 'async_trait>(
&'life0 self,
_filter: EdgeFilter,
_after: Option<SeekCursor>,
_limit: u32,
) -> Pin<Box<dyn Future<Output = Result<SeekPage<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn neighbors<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<NeighborHit>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn neighbors<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<NeighborHit>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn neighbors_page<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
after: Option<NeighborCursor>,
neighbor_kinds: Option<Vec<String>>,
) -> Pin<Box<dyn Future<Output = Result<Vec<NeighborHit>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn neighbors_page<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
after: Option<NeighborCursor>,
neighbor_kinds: Option<Vec<String>>,
) -> Pin<Box<dyn Future<Output = Result<Vec<NeighborHit>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
after is exclusive and
neighbor_kinds, when present, filters entity and note kinds before
the limit is applied. Backends that do not implement kind-aware paging
retain an explicit unsupported result rather than silently returning a
misleading page.Source§fn neighbors_both_directions<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<DirectedNeighborHit>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn neighbors_both_directions<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<DirectedNeighborHit>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Out/In) it was found in. query.direction is
ignored — this always fetches both directions. Read moreSource§fn get_edges<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [LinkId],
) -> Pin<Box<dyn Future<Output = Result<Vec<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn get_edges<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [LinkId],
) -> Pin<Box<dyn Future<Output = Result<Vec<Edge>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn get_edge_read_outcomes<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [LinkId],
) -> Pin<Box<dyn Future<Output = Result<Vec<Result<Option<Edge>, StorageError>>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn get_edge_read_outcomes<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [LinkId],
) -> Pin<Box<dyn Future<Output = Result<Vec<Result<Option<Edge>, StorageError>>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn batch_neighbors<'life0, 'life1, 'async_trait>(
&'life0 self,
sources: &'life1 [Uuid],
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<(Uuid, NeighborHit)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn batch_neighbors<'life0, 'life1, 'async_trait>(
&'life0 self,
sources: &'life1 [Uuid],
query: NeighborQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<(Uuid, NeighborHit)>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
(source_id, hit) pairs. Read moreSource§fn traverse<'life0, 'async_trait>(
&'life0 self,
request: TraversalRequest,
) -> Pin<Box<dyn Future<Output = Result<Vec<GraphPath>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn traverse<'life0, 'async_trait>(
&'life0 self,
request: TraversalRequest,
) -> Pin<Box<dyn Future<Output = Result<Vec<GraphPath>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn purge_incident_edges<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn purge_incident_edges<'life0, 'async_trait>(
&'life0 self,
node_id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
node_id, regardless of soft-delete
state. Used during endpoint hard-delete to prevent dangling graph_edges rows (ADR-002
no-dangling-references contract).Source§impl NoteStore for StorageBackend
impl NoteStore for StorageBackend
fn get_live_notes_by_key<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_key: &'life2 str,
_kind: Option<&'life3 str>,
) -> Pin<Box<dyn Future<Output = Result<Vec<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
StorageBackend: 'async_trait,
fn query_keyed_notes<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filter: &'life2 NoteFilter,
_prefix: &'life3 str,
_after: Option<&'life4 NoteKeyCursor>,
_page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<(Vec<Note>, Option<NoteKeyCursor>), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
StorageBackend: 'async_trait,
Source§fn upsert_note<'life0, 'async_trait>(
&'life0 self,
note: Note,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_note<'life0, 'async_trait>(
&'life0 self,
note: Note,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn replace_note_if_unchanged<'life0, 'async_trait>(
&'life0 self,
_note: Note,
_expected_updated_at: i64,
_expected_deleted_at: Option<i64>,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn replace_note_if_unchanged<'life0, 'async_trait>(
&'life0 self,
_note: Note,
_expected_updated_at: i64,
_expected_deleted_at: Option<i64>,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn insert_note_if_absent<'life0, 'async_trait>(
&'life0 self,
_note: Note,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn insert_note_if_absent<'life0, 'async_trait>(
&'life0 self,
_note: Note,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn upsert_notes<'life0, 'async_trait>(
&'life0 self,
notes: Vec<Note>,
) -> Pin<Box<dyn Future<Output = Result<BatchWriteSummary, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn upsert_notes<'life0, 'async_trait>(
&'life0 self,
notes: Vec<Note>,
) -> Pin<Box<dyn Future<Output = Result<BatchWriteSummary, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn get_note<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn get_note<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
None if absent.Source§fn get_note_including_deleted<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn get_note_including_deleted<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn delete_note<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
mode: DeleteMode,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn delete_note<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
mode: DeleteMode,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn update_note_properties<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
properties: Option<Value>,
updated_at: i64,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn update_note_properties<'life0, 'async_trait>(
&'life0 self,
id: Uuid,
properties: Option<Value>,
updated_at: i64,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
properties/updated_at on an existing note in place via a real
UPDATE, leaving every other column (including the row’s rowid)
untouched. Read moreSource§fn set_note_property<'life0, 'life1, 'async_trait>(
&'life0 self,
id: Uuid,
key: &'life1 str,
value: Value,
updated_at: i64,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn set_note_property<'life0, 'life1, 'async_trait>(
&'life0 self,
id: Uuid,
key: &'life1 str,
value: Value,
updated_at: i64,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
properties object. Read moreSource§fn try_patch_note_property<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
id: Uuid,
namespace: &'life1 str,
filter: &'life2 NoteFilter,
json_path: &'life3 str,
value: Value,
updated_at: i64,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
StorageBackend: 'async_trait,
fn try_patch_note_property<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
id: Uuid,
namespace: &'life1 str,
filter: &'life2 NoteFilter,
json_path: &'life3 str,
value: Value,
updated_at: i64,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
StorageBackend: 'async_trait,
properties JSON key on a note, but only
when the row’s current state (re-evaluated inside this same
statement, not a snapshot the caller fetched earlier) still satisfies
filter’s namespace/kind/property_filters. Read moreSource§fn patch_note_property_atomic<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_ids: Vec<Uuid>,
_namespace: &'life1 str,
_filter: &'life2 NoteFilter,
_json_path: &'life3 str,
_value: Value,
_updated_at: i64,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
StorageBackend: 'async_trait,
fn patch_note_property_atomic<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_ids: Vec<Uuid>,
_namespace: &'life1 str,
_filter: &'life2 NoteFilter,
_json_path: &'life3 str,
_value: Value,
_updated_at: i64,
) -> Pin<Box<dyn Future<Output = Result<(), StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_notes<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
kind: Option<&'life2 str>,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn query_notes<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
kind: Option<&'life2 str>,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_notes_count_free<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_kind: Option<&'life2 str>,
_page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn query_notes_count_free<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_kind: Option<&'life2 str>,
_page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_notes_filtered<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
filter: &'life2 NoteFilter,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn query_notes_filtered<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
filter: &'life2 NoteFilter,
page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_notes_filtered_count_free<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filter: &'life2 NoteFilter,
_page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn query_notes_filtered_count_free<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filter: &'life2 NoteFilter,
_page: PageRequest,
) -> Pin<Box<dyn Future<Output = Result<Page<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_notes_filtered_in_snapshot<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filters: &'life2 [NoteFilter],
) -> Pin<Box<dyn Future<Output = Result<Vec<u64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn count_notes_filtered_in_snapshot<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filters: &'life2 [NoteFilter],
) -> Pin<Box<dyn Future<Output = Result<Vec<u64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
crate::StorageError::Unsupported rather than composing independent
queries or treating an absent page total as zero. SQL backends should
override this operation so callers can retain separate index-friendly
predicates without racing between their counts.Source§fn count_notes_filtered_bounded_in_snapshot<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filters: &'life2 [NoteFilter],
_cap: u32,
) -> Pin<Box<dyn Future<Output = Result<Vec<BoundedCount>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn count_notes_filtered_bounded_in_snapshot<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filters: &'life2 [NoteFilter],
_cap: u32,
) -> Pin<Box<dyn Future<Output = Result<Vec<BoundedCount>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
cap. Read moreSource§fn note_sequence<'life0, 'async_trait>(
&'life0 self,
_id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<i64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn note_sequence<'life0, 'async_trait>(
&'life0 self,
_id: Uuid,
) -> Pin<Box<dyn Future<Output = Result<Option<i64>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn query_notes_filtered_after<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filter: &'life2 NoteFilter,
_after: Option<SeekCursor>,
_limit: u32,
) -> Pin<Box<dyn Future<Output = Result<SeekPage<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn query_notes_filtered_after<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_namespace: &'life1 str,
_filter: &'life2 NoteFilter,
_after: Option<SeekCursor>,
_limit: u32,
) -> Pin<Box<dyn Future<Output = Result<SeekPage<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
Self::query_notes_filtered.Source§fn query_notes_filtered_bounded<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
filter: &'life2 NoteFilter,
max_rows: u32,
) -> Pin<Box<dyn Future<Output = Result<Vec<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn query_notes_filtered_bounded<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
filter: &'life2 NoteFilter,
max_rows: u32,
) -> Pin<Box<dyn Future<Output = Result<Vec<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
max_rows + 1 notes matching filter in a single
deterministically-ordered SQL statement, with no separate COUNT(*)
and no pagination loop. Read moreSource§fn count_notes<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
kind: Option<&'life2 str>,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn count_notes<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespace: &'life1 str,
kind: Option<&'life2 str>,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
Source§fn count_notes_in_namespaces<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
kind: Option<&'life2 str>,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
fn count_notes_in_namespaces<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
namespaces: &'life1 [String],
kind: Option<&'life2 str>,
) -> Pin<Box<dyn Future<Output = Result<u64, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
StorageBackend: 'async_trait,
IN aggregate.Source§fn try_insert_note<'life0, 'async_trait>(
&'life0 self,
note: Note,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn try_insert_note<'life0, 'async_trait>(
&'life0 self,
note: Note,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn try_insert_note_with_attachments<'life0, 'async_trait>(
&'life0 self,
_note: Note,
_attachments: Vec<Attachment>,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn try_insert_note_with_attachments<'life0, 'async_trait>(
&'life0 self,
_note: Note,
_attachments: Vec<Attachment>,
) -> Pin<Box<dyn Future<Output = Result<bool, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn get_notes_batch<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<Vec<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn get_notes_batch<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<Vec<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn get_notes_batch_including_deleted<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<Vec<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn get_notes_batch_including_deleted<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<Vec<Note>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§fn get_note_visibility_batch<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<Vec<NoteVisibility>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
fn get_note_visibility_batch<'life0, 'life1, 'async_trait>(
&'life0 self,
ids: &'life1 [Uuid],
) -> Pin<Box<dyn Future<Output = Result<Vec<NoteVisibility>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
StorageBackend: 'async_trait,
Source§impl SparseStoreFactory for StorageBackend
impl SparseStoreFactory for StorageBackend
fn open( &self, model_key: &str, namespace: &str, ) -> Result<Arc<dyn SparseStore>, StorageError>
Source§impl SqlAccess for StorageBackend
impl SqlAccess for StorageBackend
Source§fn database_path(&self) -> Option<PathBuf>
fn database_path(&self) -> Option<PathBuf>
Source§fn reader<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlReader>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn reader<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlReader>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn writer<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlWriter>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn writer<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn SqlWriter>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
Source§fn atomic_unit<'life0, 'async_trait>(
&'life0 self,
op: Box<dyn for<'w> FnOnce(&'w mut (dyn SqlWriter + 'static)) -> Pin<Box<dyn Future<Output = Result<Box<dyn Any + Send>, StorageError>> + Send + 'w>> + Send>,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn Any + Send>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
fn atomic_unit<'life0, 'async_trait>(
&'life0 self,
op: Box<dyn for<'w> FnOnce(&'w mut (dyn SqlWriter + 'static)) -> Pin<Box<dyn Future<Output = Result<Box<dyn Any + Send>, StorageError>> + Send + 'w>> + Send>,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn Any + Send>, StorageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
StorageBackend: 'async_trait,
op as ONE atomic unit of work (ADR-067 Component A, Fork C
slice 2). Read moreSource§impl TextSearchFactory for StorageBackend
impl TextSearchFactory for StorageBackend
fn open( &self, table_key: &str, tokenizer: &str, ) -> Result<Arc<dyn TextSearch>, StorageError>
Source§impl VectorStoreFactory for StorageBackend
impl VectorStoreFactory for StorageBackend
Auto Trait Implementations§
impl !Freeze for StorageBackend
impl !RefUnwindSafe for StorageBackend
impl !UnwindSafe for StorageBackend
impl Send for StorageBackend
impl Sync for StorageBackend
impl Unpin for StorageBackend
impl UnsafeUnpin for StorageBackend
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more