#wasm #indexeddb #future #webassembly #idb

indexed_db_futures

Future bindings for IndexedDB via web_sys

8 releases

0.3.0 Dec 3, 2022
0.2.3 Feb 9, 2022
0.2.2 Dec 27, 2021
0.2.0 Aug 17, 2021
0.1.0 Jul 25, 2021

#102 in WebAssembly

Download history 1580/week @ 2022-12-06 1346/week @ 2022-12-13 996/week @ 2022-12-20 1291/week @ 2022-12-27 1110/week @ 2023-01-03 1313/week @ 2023-01-10 968/week @ 2023-01-17 1231/week @ 2023-01-24 739/week @ 2023-01-31 1496/week @ 2023-02-07 1164/week @ 2023-02-14 914/week @ 2023-02-21 1759/week @ 2023-02-28 3098/week @ 2023-03-07 2824/week @ 2023-03-14 2119/week @ 2023-03-21

10,060 downloads per month
Used in 8 crates (2 directly)

MIT license

110KB
2.5K SLoC

Indexed DB Futures

Wraps the web_sys Indexed DB API in a Future-based API and removes the pain of dealing with Javascript callbacks in Rust.

See root crate docs for usage instructions.


lib.rs:

Wraps the web_sys Indexed DB API in a Future-based API and removes the pain of dealing with Javascript callbacks in Rust.

Overall API design

In most cases API methods will return a [Result] containing a wrapped [IdbRequest][web_sys::IdbRequest], such as [VoidRequest][crate::request::VoidRequest], which can then be turned into a future by calling .into_future() or, when more appropriate, the [Future][std::future::Future] directly, e.g. [CountFuture][crate::request::CountFuture].

The key difference between a wrapped Request and Future is that Requests don't have any event listeners attached, which aims to make quickfire operations such as inserting several records into an [IdbObjectStore][crate::idb_object_store::IdbObjectStore] a little bit more efficient.

Features

The library can ship without cursor or index support for apps that just need a simple key-value store akin to localStorage.

  • cursors - Enable cursor support
  • indices - Enable index support
  • nightly - Use unsafe nightly features where appropriate, such as [unwrap_unchecked][Option::unwrap_unchecked].
  • default:
    • cursors
    • indices

Examples

Connecting to a DB and doing basic CRUD

Variable types included for clarity.

use indexed_db_futures::prelude::*;

pub async fn example() -> Result<(), DomException> {
    // Open my_db v1
    let mut db_req: OpenDbRequest = IdbDatabase::open_u32("my_db", 1)?;
    db_req.set_on_upgrade_needed(Some(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> {
        // Check if the object store exists; create it if it doesn't
        if let None = evt.db().object_store_names().find(|n| n == "my_store") {
            evt.db().create_object_store("my_store")?;
        }
        Ok(())
    }));

    let db: IdbDatabase = db_req.into_future().await?;

    // Insert/overwrite a record
    let tx: IdbTransaction = db
      .transaction_on_one_with_mode("my_store", IdbTransactionMode::Readwrite)?;
    let store: IdbObjectStore = tx.object_store("my_store")?;

    let value_to_put: JsValue = get_some_js_value();
    store.put_key_val_owned("my_key", &value_to_put)?;

    // IDBTransactions can have an Error or an Abort event; into_result() turns both into a
    // DOMException
    tx.await.into_result()?;

    // Delete a record
    let tx = db.transaction_on_one_with_mode("my_store", IdbTransactionMode::Readwrite)?;
    let store = tx.object_store("my_store")?;
    store.delete_owned("my_key")?;
    tx.await.into_result()?;

    // Get a record
    let tx = db.transaction_on_one("my_store")?;
    let store = tx.object_store("my_store")?;

    let value: Option<JsValue> = store.get_owned("my_key")?.await?;
    use_value(value);

    // All of the requests in the transaction have already finished so we can just drop it to
    // avoid the unused future warning, or assign it to _.
    let _ = tx;

    Ok(())
}

Dependencies

~9MB
~175K SLoC