# What is Ditto?

Ditto is a cross-platform, peer-to-peer database that allows apps
to sync **with and without** internet connectivity.

Install Ditto into your application, then use the APIs to read and write data
into its storage system, and it will then automatically sync any changes to other devices.

Unlike other synchronization solutions, Ditto is designed for "peer-to-peer" scenarios
where it can directly communicate with other devices even without an Internet connection.

Additionally, Ditto automatically manages the complexity of using multiple network transports,
like Bluetooth, P2P Wi-Fi, and Local Area Network,
to find and connect to other devices and then synchronize any changes.

# Ditto Platform Docs

Visit <https://ditto.com/link/docs> to learn about the full Ditto platform,
including multi-language SDKs, the Ditto Cloud offering, and more.

Rust developers should be sure to check out these essential topics:

- [Ditto Edge Sync Platform Basics][000]
- [Mesh Networking 101][001]
- [Data-Handling Essentials][002]
- [Ditto Query Language (DQL)][003]

[000]: https://ditto.com/link/basic-about
[001]: https://ditto.com/link/basic-mesh-networking-101
[002]: https://ditto.com/link/basic-data-handling-essentials
[003]: https://ditto.com/link/dql

# Playground Quickstart

Ditto offers a "playground" mode that lets you start playing and developing
with Ditto without any authentication hassle.

- [Visit our credentials docs to learn how to get your Ditto AppID and Playground Token][100]

[100]: https://ditto.com/link/get-started-sync-credentials

```rust ,no_run
use dittolive_ditto::prelude::*;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let database_id = std::env::var("DITTO_DB_ID")?; // Use an ENV of your choice

    // Use one of the following connect configurations:

    // Production using Ditto Big Peer
    let connect = DittoConfigConnect::Server { url: "REPLACE_ME_WITH_YOUR_SERVER_URL".parse().unwrap() };

    // Production using Small Peers only
    let connect = {
        // See the docs for how to generate a private key
        // https://docs.ditto.live/key-concepts/authentication-and-authorization#generating-a-shared-key
        let private_key = std::fs::read("path/to/private-key.der")?;
        DittoConfigConnect::SmallPeersOnly { private_key: Some(private_key) }
    };

    // Testing/Development using Small Peers only. NOT FOR PRODUCTION USE
    let connect = DittoConfigConnect::SmallPeersOnly { private_key: None };

    let config = DittoConfig::new(database_id, connect);

    // Use the async or sync constructor
    let ditto = Ditto::open_sync(config)?;
    // let ditto = Ditto::open(config).await?; // async constructor

    // Start syncing with peers
    ditto.sync().start()?;

    Ok(())
}
```

## Write data using Ditto Query Language (DQL)

The preferred method to write data to Ditto is by using DQL.
To do this, we'll first access the Ditto [`Store`][store], then
execute a DQL insert statement.

```rust,no_run
use dittolive_ditto::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct Car {
    color: String,
    make: String,
}

async fn dql_insert_car(ditto: &Ditto, car: &Car) -> anyhow::Result<()> {
    let store = ditto.store();
    let query_result = store.execute(
        // `cars` is the collection name
        "INSERT INTO cars DOCUMENTS (:newCar)",
        Some(serde_json::json!({
            "newCar": car
        }).into())
    ).await?;

    // Optional: See the count of items inserted
    let item_count = query_result.item_count();

    // Optional: Inspect each item that was inserted
    for query_item in query_result.iter() {
        println!("Inserted: {}", query_item.json_string());
    }

    Ok(())
}

// To call:
async fn call_dql_insert(ditto: Ditto) -> anyhow::Result<()> {
    let my_car = Car {
        color: "blue".to_string(),
        make: "ford".to_string(),
    };
    dql_insert_car(&ditto, &my_car).await?;
    Ok(())
}
```

- See the [DQL INSERT documentation][200] for more info on DQL inserts
- See [`QueryResult`] and [`QueryResultItem`] to learn about the returned values
- See the [Ditto Rust template repository][201] for full examples
- Tip: Make sure you have [`serde`] added to your `Cargo.toml` with the `derive` feature
- Tip: Make sure you have [`serde_json`] added to your `Cargo.toml`

```toml
# Cargo.toml
[dependencies]
serde = { version = "1.0.204", features = ["derive"] }
serde_json = "1.0.120"
```

[`QueryResult`]: crate::store::dql::QueryResult
[`QueryResultItem`]: crate::store::dql::QueryResultItem
[200]: https://ditto.com/link/dql-insert
[201]: https://github.com/getditto/template-rust/blob/25ff8da0f2eb753c20c871f01c70512c368a9235/src/bin/simple_dql.rs#L124-L142
[`serde`]: https://docs.rs/serde
[`serde_json`]: https://docs.rs/serde_json

## Read data using DQL

```rust,no_run
use dittolive_ditto::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct Car {
    color: String,
    make: String,
}

async fn dql_select_cars(ditto: &Ditto, color: &str) -> anyhow::Result<Vec<Car>> {
    let store = ditto.store();
    let query_result = store.execute(
        "SELECT * FROM cars WHERE color = :myColor",
        Some(serde_json::json!({
            "myColor": color
        }).into())
    ).await?;

    let cars = query_result.iter()
        .map(|query_item| query_item.deserialize_value::<Car>())
        .collect::<Result<Vec<Car>, _>>()?;

    Ok(cars)
}

// To call:
async fn call_dql_select(ditto: Ditto) -> anyhow::Result<()> {
    let cars: Vec<Car> = dql_select_cars(&ditto, "blue").await?;
    Ok(())
}
```

- See the [DQL SELECT documentation][300] for more info on DQL selects
- See the [Ditto Rust template repository][301] for full examples

[300]: https://ditto.com/link/dql-select
[301]: https://github.com/getditto/template-rust/blob/25ff8da0f2eb753c20c871f01c70512c368a9235/src/bin/simple_dql.rs#L144-L158

<details>
<summary><h1 id="notes-about-using-a-rust-wrapped-c-library-advanced">
Notes about using a Rust-wrapped C library (advanced)
</h1></summary>

**Please note**: this crate uses sane defaults that should "just work".
These notes should not be required to get started with Ditto, instead they're
meant for people interested in more advanced use-cases such as dynamically
linking or pre-downloading the companion C-library artifact.

Ditto's core functionality is released and packaged as a C library, which is
then imported into Rust via the `::dittolive-ditto-sys` crate.

## Downloading the companion binary artifact

This crate will, at build time, download the appropriate binary artifact from
`https://software.ditto.live/rust/Ditto/<version>/<target>/release/[lib]dittoffi.{a,so,dylib,dll,lib}`

- For example: <https://software.ditto.live/rust/Ditto/4.5.4/aarch64-apple-darwin/release/libdittoffi.dylib>

If you wish to avoid this, you will have to do it yourself:

1.  Download the proper binary artifact;

1.  Instruct `::dittolive-ditto-sys`' `build.rs` script to use it by setting the
    `DITTOFFI_SEARCH_PATH` environment variable appropriately (using an absolute
    path is recommended).

More precisely, the library search resolution order is as follows:

1.  `$DITTOFFI_SEARCH_PATH` (if set)
1.  The current working directory (`$PWD`)
1.  Best effort will be made to search `$CARGO_TARGET_DIR` and `$CARGO_TARGET_DIR/deps`, this is imprecise as it must be derived from `$OUT_DIR`.
1.  `$OUT_DIR` (e.g. `${CARGO_TARGET_DIR}/<profile>/build/dittolive-ditto-sys-.../out`)
1.  When using dynamic linking, host built-in defaults (e.g. `/usr/lib`, `/lib`, `/usr/local/lib`, `$HOME/lib`) controlled by (system) linker setup.

If the library artifact is not found at any of these locations, the build script
will attempt its own download into the `$OUT_DIR` (and use that path).

## Linking

C linkage is typically accompanied with some idiosyncrasies, such as symbol
conflicts, or path resolution errors.

The first question you should answer is whether you want your application to
use **static** or **dynamic** linking to access the Ditto library.

### Statically linking `libdittoffi` (default, recommended)

This happens whenever the `LIBDITTO_STATIC` is explicitly set to `1`, or unset.

If you have a special path to the `libdittoffi.a`/`dittoffi.lib` file (on Unix
and Windows, respectively), then you can use the `DITTOFFI_SEARCH_PATH` env var
to point to its location (using an absolute path), at linkage time (during
`cargo build` exclusively).

### Dynamically linking (advanced)

You can opt into this behavior by setting the `LIBDITTO_STATIC=0` environment variable.
When opting into this, you will have to handle library path resolution to the
`libdittoffi.so`/`libdittoffi.dylib`/`dittoffi.dll` file (on Linux, macOS, and Windows, respectively).

That is, whilst the `DITTOFFI_SEARCH_PATH` is still important to help the
`cargo build` / linkage step resolve the dynamic library, the actual usage of
this file happens at _runtime_, when the (Rust) binary using `::dittolive_ditto`
is executed.

It is thus advisable to install the C dynamic library artifact under one of the
system folders, such as `/usr/lib` or whatnot on Unix.

Otherwise, you would have to either:

- meddle with link-time flags to set OS-specific loader metadata in the binary,
  such as the `R{,UN}PATH` / `install_path`, paying special attention to the
  choice of absolute paths, binary-relative paths (such as `$ORIGIN/...` on Linux),
  or even working-directory-relative paths, or

- use env vars directives for the system dynamic loader, such as
  `DYLD_FALLBACK_LIBRARY_PATH` on macOS, or `LD_LIBRARY_PATH` on Linux.

(For the technically-savy, on macOS, the `install_path` of our `.dylib` artifact
is set to `$rpath/libdittoffi.dylib`).

</details>
