Skip to main content

WritableDataSet

Trait WritableDataSet 

Source
pub trait WritableDataSet<E>: DataSet<E>
where E: Entity<Self::Value>,
{ // 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_json serialization
  • 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 exists
  • replace: Always succeeds, overwrites existing data
  • patch: 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§

Source

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.

Source

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.

Source

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§

Source

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".

Implementors§