pub trait DatabaseBackend:
Send
+ Sync
+ Debug
+ 'static {
Show 17 methods
// Required methods
fn engine_id(&self) -> &'static str;
fn capabilities(&self) -> BackendCapabilities;
fn execute_compiled_query<'life0, 'life1, 'async_trait>(
&'life0 self,
compiled: &'life1 CompiledQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<Value>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn get_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Value>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
fn create_record<'life0, 'life1, 'async_trait>(
&'life0 self,
table: &'life1 str,
content: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn update_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
content: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
fn upsert_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
content: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
fn delete_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
fn relate_edge<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
from: &'life1 RecordId,
edge_table: &'life2 str,
to: &'life3 RecordId,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait;
fn unrelate_edge<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
from: &'life1 RecordId,
edge_table: &'life2 str,
to: &'life3 RecordId,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait;
fn get_edge_targets<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
from: &'life1 RecordId,
edge_table: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<RecordId>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
// Provided methods
fn use_namespace<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ns: &'life1 str,
db_name: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
fn ensure_schemaless_table<'life0, 'life1, 'async_trait>(
&'life0 self,
table: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn merge_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
patch: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
fn define_unique_index<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
field: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
fn ttl_capability(&self) -> BackendTtlCapability { ... }
fn apply_ttl_policy<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_table: &'life1 str,
_policy: &'life2 SchemaTtlPolicy,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
}Expand description
Storage engine behind Valence: CRUD, compiled queries, and graph edges.
valence-core defines this trait only — no engine SDKs. Third-party adapters
implement it in separate crates and register instances on crate::ValenceBuilder.
| Concern | Contract |
|---|---|
engine_id | Open slug (not a closed enum) |
capabilities | Merge/graph support + telemetry label |
| CRUD / queries / edges / TTL | Per-method contracts below |
Router keys combine a logical name with engine_id via
crate::router_key().
§Implementing a published adapter
- Depend on
valence-coreonly (+async-trait, etc.). impl DatabaseBackendand exportpub const ENGINE_ID: &str.- Export a schema evaluator, e.g.
pub const PRIMARY: DatabaseFromEngine = Database::from_engine("primary", ENGINE_ID). - Optional:
XBackend::builder()with explicit setters;from_env_defaults()fills unset fields only. - Host wires with
.add_backend("primary", Arc::new(adapter))— no facade feature.
Reference: examples/acme-valence-backend-stub.
§Examples
use std::sync::Arc;
use valence_backend_mem::{InMemoryBackend, ENGINE_ID};
use valence_core::{DatabaseBackend, Valence};
let backend = Arc::new(InMemoryBackend::new());
assert_eq!(backend.engine_id(), ENGINE_ID);
let valence = Valence::builder()
.add_backend("default", backend)
.build()
.expect("build");
assert_eq!(
valence.active_backend().unwrap().engine_id(),
ENGINE_ID
);Required Methods§
Sourcefn engine_id(&self) -> &'static str
fn engine_id(&self) -> &'static str
Stable open engine slug for router keys (see crate::router_key()).
First-party constants live in crate::KnownEngines for ergonomics — that is not
a closed set; third-party crates define their own slugs.
Sourcefn capabilities(&self) -> BackendCapabilities
fn capabilities(&self) -> BackendCapabilities
Adapter capabilities for contract tests and telemetry.
Sourcefn execute_compiled_query<'life0, 'life1, 'async_trait>(
&'life0 self,
compiled: &'life1 CompiledQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<Value>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn execute_compiled_query<'life0, 'life1, 'async_trait>(
&'life0 self,
compiled: &'life1 CompiledQuery,
) -> Pin<Box<dyn Future<Output = Result<Vec<Value>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Execute a compiled admin/query statement and return JSON rows.
Contract: must honor parameter binding in compiled; empty result sets return Ok(vec![]).
Sourcefn get_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Value>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn get_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Value>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Fetch one record by primary key.
Contract: returns Ok(None) when the row does not exist.
Sourcefn create_record<'life0, 'life1, 'async_trait>(
&'life0 self,
table: &'life1 str,
content: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn create_record<'life0, 'life1, 'async_trait>(
&'life0 self,
table: &'life1 str,
content: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Insert a new record; content must include any required fields.
Contract: returns the persisted row (including server-assigned fields when applicable).
Sourcefn update_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
content: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn update_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
content: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Replace an existing record by id.
Contract: returns the updated row; errors when the id is missing unless the adapter
supports upsert semantics via Self::upsert_record.
Sourcefn upsert_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
content: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn upsert_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
content: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Create or replace a record by explicit id.
Sourcefn delete_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn delete_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Delete one record by primary key.
Contract: succeeds when the row is already absent (idempotent delete).
Sourcefn relate_edge<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
from: &'life1 RecordId,
edge_table: &'life2 str,
to: &'life3 RecordId,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
fn relate_edge<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
from: &'life1 RecordId,
edge_table: &'life2 str,
to: &'life3 RecordId,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
Create a directed graph edge from from to to through edge_table.
Sourcefn unrelate_edge<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
from: &'life1 RecordId,
edge_table: &'life2 str,
to: &'life3 RecordId,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
fn unrelate_edge<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
from: &'life1 RecordId,
edge_table: &'life2 str,
to: &'life3 RecordId,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait,
Remove a directed graph edge.
Contract: idempotent when the edge does not exist.
Sourcefn get_edge_targets<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
from: &'life1 RecordId,
edge_table: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<RecordId>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn get_edge_targets<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
from: &'life1 RecordId,
edge_table: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<RecordId>, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
List target record ids reachable via outgoing edges in edge_table.
Provided Methods§
Sourcefn use_namespace<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ns: &'life1 str,
db_name: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn use_namespace<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
ns: &'life1 str,
db_name: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Select namespace/database on engines that support multi-tenant routing.
Contract: default implementation is a no-op; remote adapters may override.
Sourcefn ensure_schemaless_table<'life0, 'life1, 'async_trait>(
&'life0 self,
table: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn ensure_schemaless_table<'life0, 'life1, 'async_trait>(
&'life0 self,
table: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Ensure a schemaless table exists before first write.
Contract: default implementation is a no-op; adapters may create tables lazily elsewhere.
Sourcefn merge_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
patch: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn merge_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
id: &'life2 str,
patch: Value,
) -> Pin<Box<dyn Future<Output = Result<Value, Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Patch an existing record with a partial JSON object.
Contract: default returns Error::Internal — override when BackendCapabilities::supports_merge
is true.
Sourcefn define_unique_index<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
field: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn define_unique_index<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: &'life1 str,
field: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Define a unique index on table.field when the engine supports DDL.
Contract: default returns Error::Internal.
Sourcefn ttl_capability(&self) -> BackendTtlCapability
fn ttl_capability(&self) -> BackendTtlCapability
Whether this adapter can apply schema TTL policies natively.
Sourcefn apply_ttl_policy<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_table: &'life1 str,
_policy: &'life2 SchemaTtlPolicy,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn apply_ttl_policy<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_table: &'life1 str,
_policy: &'life2 SchemaTtlPolicy,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Apply a schema TTL policy to table when supported.
Contract: default is a no-op.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".