pub trait WritableDataSet<E>: DataSet<E>{
// Required methods
fn insert<'life0, 'life1, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
entity: &'life1 E,
) -> Pin<Box<dyn Future<Output = Result<E, VantageError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn replace<'life0, 'life1, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
entity: &'life1 E,
) -> Pin<Box<dyn Future<Output = Result<E, VantageError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn patch<'life0, 'life1, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
partial: &'life1 E,
) -> Pin<Box<dyn Future<Output = Result<E, VantageError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
// Provided method
fn patch_changed<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
before: &'life1 E,
after: &'life2 E,
) -> Pin<Box<dyn Future<Output = Result<(), VantageError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: Sized + WritableValueSet + Sync + 'async_trait,
E: TryIntoRecord<Self::Value>,
<E as TryIntoRecord<Self::Value>>::Error: Debug,
Self::Value: PartialEq + Clone { ... }
}Expand description
Write operations on typed entities with automatic serialization.
This trait provides convenient write operations that automatically handle entity serialization to the storage format. All operations follow idempotent patterns safe for retry in distributed systems.
§Serialization Behavior
Entities are automatically serialized to the storage’s Value type before
persistence. The serialization format depends on your storage backend:
- JSON databases use
serde_jsonserialization - Binary stores may use CBOR or custom formats
- Document databases preserve nested structure
§Idempotency Guarantees
All write operations are designed to be safely retryable:
insert: No-op if ID already existsreplace: Always succeeds, overwrites existing datapatch: Atomic update, fails if entity doesn’t exist
§Example
use vantage_dataset::dataset::WritableDataSet;
let user = User {
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
age: 30,
};
// Idempotent insert
users.insert("user-123", user.clone()).await?;
// Update specific fields
let mut updated_user = user;
updated_user.age = 31;
users.replace("user-123", updated_user).await?;Required Methods§
Sourcefn insert<'life0, 'life1, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
entity: &'life1 E,
) -> Pin<Box<dyn Future<Output = Result<E, VantageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn insert<'life0, 'life1, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
entity: &'life1 E,
) -> Pin<Box<dyn Future<Output = Result<E, VantageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Insert entity with a specific ID (often generated) (HTTP POST with ID)
Idempotent: Succeeds if no entity exists with the given ID. If entity already exists, must return success without overwriting data, returning original data.
Returns: Entity as it was stored.
§Use Case
Generate unique ID and store centity while avoiding duplicates.
Sourcefn replace<'life0, 'life1, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
entity: &'life1 E,
) -> Pin<Box<dyn Future<Output = Result<E, VantageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn replace<'life0, 'life1, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
entity: &'life1 E,
) -> Pin<Box<dyn Future<Output = Result<E, VantageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Replace the entire entity at the specified ID (HTTP PUT)
Idempotent: Always succeeds, completely overwrites existing data
if present. If possible, will remove/recreate entity; therefore if
entity doesn’t contain certain attributes which were present in the
database, those will be removed. If entity does not exist, will
create it.
Returns: entity as it was stored.
§Use Case
Replace with a new version of a entity.
Sourcefn patch<'life0, 'life1, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
partial: &'life1 E,
) -> Pin<Box<dyn Future<Output = Result<E, VantageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn patch<'life0, 'life1, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
partial: &'life1 E,
) -> Pin<Box<dyn Future<Output = Result<E, VantageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Partially update an entity by merging with the provided data (HTTP PATCH)
Fails if entity doesn’t exist. The exact merge behavior depends on the storage implementation - typically merges object fields for JSON-like values.
Returns: entity as it was stored (not only the partial change).
§Use Case
Update only the modified fields of a entity.
Provided Methods§
Sourcefn patch_changed<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
before: &'life1 E,
after: &'life2 E,
) -> Pin<Box<dyn Future<Output = Result<(), VantageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: Sized + WritableValueSet + Sync + 'async_trait,
E: TryIntoRecord<Self::Value>,
<E as TryIntoRecord<Self::Value>>::Error: Debug,
Self::Value: PartialEq + Clone,
fn patch_changed<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: impl Into<Self::Id> + Send + 'async_trait,
before: &'life1 E,
after: &'life2 E,
) -> Pin<Box<dyn Future<Output = Result<(), VantageError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: Sized + WritableValueSet + Sync + 'async_trait,
E: TryIntoRecord<Self::Value>,
<E as TryIntoRecord<Self::Value>>::Error: Debug,
Self::Value: PartialEq + Clone,
Write only the fields that differ between before and after.
The read-modify-write most business logic wants. Read the entity, change the fields the operation owns, and call this with both — only the changed fields reach storage.
Prefer this over replace whenever the entity
came from a read. replace writes every field the caller read,
so it silently reverts a field another writer changed while the
caller was working, and it saves back values the caller never
looked at — including any the entity failed to parse and filled
with a default.
Deriving the change set from two entity values means no caller writes out field names by hand; the struct stays the one place they are declared.
Writes nothing and returns Ok(()) when the two are identical.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".