dittolive_ditto::store

Struct Store

Source
pub struct Store { /* private fields */ }
Expand description

Use ditto.store() to access the Store API to read, write, and remove documents.

See the store module for guide-level docs and examples.

Implementations§

Source§

impl Store

Source

pub async fn transaction<T, E>( &self, scope: impl AsyncFnOnce(&Transaction) -> Result<T, E>, ) -> Result<T, E>
where T: Any, E: From<DittoError>,

Executes multiple DQL queries within a single atomic transaction.

ditto.store().transaction(async |txn| {
  txn.execute((
    "INSERT INTO users DOCUMENTS (:doc)",
    json!({"name": "alice"}),
  )).await?;

  txn.execute((
    "INSERT INTO users DOCUMENTS (:doc)",
    json!({"name": "bob"}),
  )).await?;

  Ok::<_, DittoError>(TransactionCompletionAction::Commit)
}).await.unwrap();

The closure returns a Result<T, E>, and in the success case, this value will be returned from the call to ditto.store().transaction(). However, if the value is a TransactionCompletionAction (i.e. if T = TransactionCompletionAction), then this value is used to determine the behaviour of the transaction:

See the “errors” section below for more information on the error case.

This ensures that either all statements are executed successfully, or none are executed at all, providing strong consistency guarantees. Certain mesh configurations may impose limitations on these guarantees. For more details, refer to the Ditto documentation. Transactions are initiated as read-write transactions by default, and only a single read-write transaction is being executed at any given time. Any other read-write transaction started concurrently will wait until the current transaction has been committed or rolled back. Therefore, it is crucial to make sure a transaction finishes as early as possible so other read-write transactions aren’t blocked for a long time.

A transaction can also be configured to be read-only, or given an option debugging hint via ditto.store.transaction_with_options. See the docs for more information.

§Errors

See the module-level docs for more details on error types in transactions.

If errors occur in an execute() call within a transaction block, this error can be handled like a normal Result, and the transaction will continue without being rolled back. If the transaction callback itself returns an Err, the transaction is implicitly rolled back and the error is propagated to the called.

For a complete guide on transactions, please refer to the Ditto documentation.

See also - Transaction

Source

pub async fn transaction_with_options<T, E>( &self, options: CreateTransactionOptions<'_>, scope: impl AsyncFnOnce(&Transaction) -> Result<T, E>, ) -> Result<T, E>
where T: Any, E: From<DittoError>,

Create a transaction with the provided options.

let mut opts = CreateTransactionOptions::new();
opts.hint = Some("debug transaction name");
opts.is_read_only = false;

ditto.store().transaction_with_options(opts, async |txn| {
  txn.execute((
    "INSERT INTO users DOCUMENTS (:doc)",
    json!({"name": "alice"}),
  )).await?;

  txn.execute((
    "INSERT INTO users DOCUMENTS (:doc)",
    json!({"name": "bob"}),
  )).await?;

  Ok::<_, DittoError>(TransactionCompletionAction::Commit)
}).await.unwrap();

If is_read_only is true, mutating DQL queries will error, even if no actual mutation would have occurred.

See ditto.store().transaction() for more documentation on the behaviour of transactions in general.

Source§

impl Store

Source

pub fn collection( &self, collection_name: &str, ) -> Result<Collection, DittoError>

Returns a Collection with the provided name. A collection name is valid if :

  • its length is less than 100
  • it is not empty
  • it does not contain the char ‘\0’
  • it does not begin with “$TS_”
Source

pub fn collections(&self) -> PendingCollectionsOperation<'_>

Returns an object that lets you fetch or observe the collections in the store.

Source

pub fn with_batched_write<F>( &self, f: F, ) -> Result<Vec<WriteTransactionResult>, DittoError>
where for<'batch> F: FnOnce(ScopedStore<'batch>) -> Action<'batch>,

Allows you to group multiple operations together that affect multiple documents, potentially across multiple collections, without auto-committing on each operation.

At the end of the batch of operations, either batch.commit_changes or batch.revert_changes must be called.

§Example
ditto.store().with_batched_write(|batch| {
    let mut foo_coll = batch.collection("foo");
    foo_coll.find...().remove();
    let mut bar_coll = batch.collection("bar");
    // Expensive multi-mutation op:
    for _ in 0 .. 10_000 {
        let doc = ...;
        bar_coll.insert(doc, None, false);
    }
    // At this point, we must say whether we commit or revert
    // these changes:
    batch.commit_changes()
})
Source

pub fn collection_names(&self) -> Result<Vec<String>, DittoError>

Returns a list of the names of collections in the local store.

Source

pub fn queries_hash( &self, live_queries: &[LiveQuery], ) -> Result<u64, DittoError>

Returns a hash representing the current version of the given queries. When a document matching such queries gets mutated, the hash will change as well.

Please note that the hash depends on how queries are constructed, so you should make sure to always compare hashes generated with the same set of queries.

Source

pub fn queries_hash_mnemonic( &self, live_queries: &[LiveQuery], ) -> Result<String, DittoError>

Returns a sequence of English words representing the current version of the given queries. When a document matching such queries gets mutated, the words will change as well.

Please note that the resulting sequence of words depends on how queries are constructed, so you should make sure to always compare hashes generated with the same set of queries.

Source

pub fn register_observer_v2<Q, F>( &self, query: Q, on_change: F, ) -> Result<Arc<StoreObserver>, DittoError>

Installs and returns a store observer for a query, configuring Ditto to trigger the passed in change handler whenever documents in the local store change such that the result of the matching query changes. The passed in query must be a SELECT query, otherwise an error will be returned.

§Example
use dittolive_ditto::prelude::*;

let store = ditto.store();
let _observer = store.register_observer_v2(
    "SELECT * FROM cars WHERE color = 'blue'",
    move |query_result| {
        for item in query_result.iter() {
            // ... handle each item
        }
    },
)?;

The first invocation of the change handler will always happen after this method has returned.

The observer will remain active until:

Observer callbacks will never be called concurrently. That is, one callback must return before the observer will call the handler again. See ditto.store().register_observer_with_signal_next(...) if you want to manually signal readiness for the next callback.

Source

pub fn register_observer_with_signal_next_v2<Q, F>( &self, query: Q, on_change: F, ) -> Result<Arc<StoreObserver>, DittoError>

Installs and returns a store observer for a query, configuring Ditto to trigger the passed in change handler whenever documents in the local store change such that the result of the matching query changes. The passed in query must be a SELECT query, otherwise an error will be returned.

Here, a function is passed as an additional argument to the change handler. This allows the change handler to control how frequently it is called. See register_observer for a convenience method that automatically signals the next invocation.

§Example
use dittolive_ditto::prelude::*;

let store = ditto.store();
let _observer = store.register_observer_with_signal_next_v2(
    "SELECT * FROM cars WHERE color = 'blue'",
    move |query_result, signal_next| {
        for item in query_result.iter() {
            // ... handle each item
        }

        // Call `signal_next` when you're ready for the next callback
        signal_next();
    },
)?;

The first invocation of the change handler will always happen after this method has returned.

The observer will remain active until:

  • the StoreObserver handle gets dropped,
  • the [observer.cancel()] method is called, or
  • the owning Ditto instance has shut down

After invoking the callback once, the observer will wait to deliver another callback until after you’ve called signal_next.

Source

pub fn observers(&self) -> impl '_ + Deref<Target = SetArc<StoreObserver>>

Gets temporary access to the set of currently registered observers.

A (read) lock is held until the return value is dropped: this means that neither Self::register_observer() nor StoreObserver::cancel() can make progress until this read lock is released.

Source

pub async fn execute_v2<Q>(&self, query: Q) -> Result<QueryResult, DittoError>
where Q: IntoQuery, Q::Args: Serialize,

Executes the given query in the local store and returns the result.

§Example
use dittolive_ditto::prelude::*;
use dittolive_ditto::dql::QueryResult;

// Query a collection
let result = ditto.store().execute_v2("SELECT * FROM cars").await?;

// Insert a document into a collection
let insert_result: QueryResult = ditto
    .store()
    .execute_v2((
         "INSERT INTO cars DOCUMENTS (:newCar)",
         serde_json::json!({
             "newCar": {
                 "make": "ford",
                 "color": "blue"
             }
         })
    ))
    .await?;

Use placeholders to incorporate values from the optional query_args parameter into the query. The keys of the [QueryArguments] object must match the placeholders used within the query. You can not use placeholders in the FROM clause.

This method only returns results from the local store without waiting for any SyncSubscriptions to have caught up with the latest changes. Only use this method if your program must proceed with immediate results.

Use ditto.store().register_observer(...) to receive updates to query results as soon as they have been synced to this peer.

§Query parameter

The query parameter must implement IntoQuery, which is a trait that is implemented by objects that can be turned into a query string along with the relevant query argumnents.

For queries with no arguments, a String is sufficient

Source

pub async fn new_attachment( &self, filepath: &(impl ?Sized + AsRef<Path>), user_data: HashMap<String, String>, ) -> Result<DittoAttachment, DittoError>

Creates a new attachment, which can then be inserted into a document.

The file residing at the provided path will be copied into Ditto’s store. The DittoAttachment object that is returned is what you can then use to insert an attachment into a document.

You can provide custom user data about the attachment, which will be replicated to other peers alongside the file attachment.

Source

pub async fn new_attachment_from_bytes( &self, bytes: &(impl ?Sized + AsRef<[u8]>), user_data: HashMap<String, String>, ) -> Result<DittoAttachment, DittoError>

Creates a new attachment from in-memory data

Refer to new_attachment for additional information.

Source

pub fn fetch_attachment( &self, attachment_token: impl DittoAttachmentTokenLike, on_fetch_event: impl 'static + Send + Sync + Fn(DittoAttachmentFetchEvent), ) -> Result<DittoAttachmentFetcher<'static, V2>, DittoError>

Fetches the attachment corresponding to the provided attachment token.

  • attachment_token: can be either a DittoAttachmentToken, or a &BTreeMap<CborValue, CborValue>, that is, the output of a QueryResultItem::value() once casted .as_object().

  • on_fetch_event: A closure that will be called when the status of the request to fetch the attachment has changed. If the attachment is already available then this will be called almost immediately with a completed status value.

The returned DittoAttachmentFetcher is a handle which is safe to discard, unless you wish to be able to .cancel() the fetching operation. When not explicitly cancelled, the fetching operation will remain active until it either completes, the attachment is deleted, or the owning Ditto object is dropped.

Source

pub fn attachment_fetchers(&self) -> Vec<DittoAttachmentFetcher<'static, V2>>

Gets a copy of the set of currently registered attachment fetchers.

A (read) lock is held during the copy: this contends with Self::fetch_attachment() and with DittoAttachmentFetcher::cancel().

Trait Implementations§

Source§

impl Clone for Store

Source§

fn clone(&self) -> Store

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl Freeze for Store

§

impl !RefUnwindSafe for Store

§

impl Send for Store

§

impl Sync for Store

§

impl Unpin for Store

§

impl !UnwindSafe for Store

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
§

impl<T> CompatExt for T

§

fn compat(self) -> Compat<T>

Applies the [Compat] adapter by value. Read more
§

fn compat_ref(&self) -> Compat<&T>

Applies the [Compat] adapter by shared reference. Read more
§

fn compat_mut(&mut self) -> Compat<&mut T>

Applies the [Compat] adapter by mutable reference. Read more
§

impl<T> FitForCBox for T

§

type CBoxWrapped = Box_<T>

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> ManuallyDropMut for T

§

type Ret = ManuallyDrop<T>

§

fn manually_drop_mut<'__>(&'__ mut self) -> &'__ mut ManuallyDrop<T>

§

impl<T> To for T
where T: ?Sized,

§

fn to<T>(self) -> T
where Self: Into<T>,

Converts to T by calling Into<T>::into.
§

fn try_to<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Tries to convert to T by calling TryInto<T>::try_into.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<F> ZeroSizedElseWrathOfTheGඞds for F