Expand description

The Ditto custom types.

These types have a dedicated CRDT logic. Each type has two variants: a Mutable and a non Mutable one. The non Mutable version correspond to a readonly value. The Mutable version allows the developer to read and update its content and is returned by the DittoMutDocument::get_mut method.

Counter

The DittoCounter and DittoMutableCounter represent counter which can be updated simultaneously on several peers at once without fearing to lose concurrent increments.

use serde_json::json;
let store = ditto.store();
let collection = store.collection("foo").unwrap();

//                  👇 insert a new `Counter`at path "counter" with default value `0`
let id = collection.upsert(json!({ "counter": DittoCounter::new() }))?;
let doc = collection.find_by_id(&id).exec()?;
let counter: DittoCounter = doc.get("counter")?;
assert_eq!(counter.value(), 0.0);

collection.find_by_id(&id).update(|mut_doc| {
    let mut_doc = mut_doc.unwrap();
    // 👇 increment counter by `5.0`
    mut_doc
        .get_mut::<DittoMutableCounter>("counter")
        .unwrap()
        .increment(5.0)
        .unwrap();
})?;

let counter: DittoCounter = doc.get("counter")?;
assert_eq!(counter.value(), 5.0);

Register

The DittoRegister and DittoMutableRegister are containers for a single value following the concept of LWW : “Last Write Win”. Primitive types such as String, u32, bool, etc…, are implicitly wrapped to and unwrapped from registers.

let id = collection.upsert(json!({ "register": DittoRegister::new(42)?, "string":"SomeString"}))?;
let doc = collection.find_by_id(&id).exec()?;

let register: DittoRegister = doc.get("register")?;
assert_eq!(register.value::<u32>()?, 42);
// 👇 you can access a primitive type inside a Register
let register: DittoRegister = doc.get("string")?;
assert_eq!(register.value::<String>()?, "SomeString");

collection
    .find_by_id(&id)
    .update(|mut_doc| {
        let mut_doc = mut_doc.unwrap();
        // 👇 set register value to `5.0`
        mut_doc
            .get_mut::<DittoMutableRegister>("register")
            .unwrap()
            .set(5.0)
            .unwrap();
    })
    .unwrap();

// Value changed!
let register: DittoRegister = doc.get("register")?;
assert_eq!(register.value::<f32>()?, 5.0);
let direct_access: f32 = doc.get("register")?;
assert_eq!(direct_access, 5.0);

The main purpose of the DittoRegister type is to treat structs as a single CRDT value.

Without Register, fields can be mixed up, for instance:

use serde::{Deserialize, Serialize};
use serde_json::json;
#[derive(Serialize, Deserialize)]
struct Car {
    color: String,
    price: u32,
}
#[derive(Serialize, Deserialize)]
struct Boat {
    length: f32,
    name: String,
}

let car = Car {
    color: String::from("red"),
    price: 42_000,
};
let id = collection.upsert(json!({ "vehicle": car }))?;
collection
    .find_by_id(&id)
    .update(|mut_doc| {
        let boat = Boat {
            length: 248.0,
            name: String::from("Richelieu"),
        };
        let mut_doc = mut_doc.unwrap();
        // 👇 update value to boat
        mut_doc.set("vehicle", boat).unwrap();
    })
    .unwrap();
let document = collection.find_by_id(&id).exec().unwrap();
// document == {
//  "vehicle": {
//    "color": "red",
//    "length": 248,
//    "name" : "Richelieu",
//    "price": 42_000,
//  }
//}

whereas with Register, content is kept clean, but the initial value is lost:

use serde_json::json;
let car = Car{color: String::from("red"), price:42_000};
let id = collection.upsert(json!({"vehicle": DittoRegister::new(car)?}))?;

collection
.find_by_id(&id)
.update(move |mut_doc| {
    let boat = Boat{length:248.0, name:String::from("Richelieu")};
    let mut_doc = mut_doc.unwrap();
    // 👇 set register value to `boat`
    mut_doc
        .get_mut::<DittoMutableRegister>("vehicle")
        .unwrap()
        .set(boat)
        .unwrap();
})?;

let document = collection.find_by_id(&id).exec()?;
// document == {
//   "vehicle": {
//     "length": 248,
//     "name" : "Richelieu",
//  }
//}

Structs

Represents a CRDT counter that can be upserted as part of a document or assigned to a property during an update of a document.
Represents a mutable CRDT counter that can be incremented while updating a document.
Represents a mutable CRDT register that can be updated while updating a document.
Represents a CRDT register that can be upserted as part of a document or assigned to a property during an update of a document.