Wraps the web_sys Indexed DB API in a Future-based API and
removes the pain of dealing with JS callbacks or JSValue
in Rust.
Goals & features:
-
Shield you from having to interact with
web_sys
orjs_sys
APIs - this should feel like a native Rust API. -
Integrate with
serde
, but don't require it - as a rule of thumb, you'll useserde
-serialisable types when working with JS objects & bypassserde
for Javascript primitives. -
Implement
Stream
where applicable - cursors and key cursors have this at the time of writing. -
Implement a more Rust-oriented API - for example, transactions will roll back by default unless explicitly
committed to allow you to use
?
s.
use indexed_db_futures::database::Database;
use indexed_db_futures::prelude::*;
use indexed_db_futures::transaction::TransactionMode;
#[derive(serde::Serialize, serde::Deserialize)]
struct MySerdeType(u8, String);
async fn main() -> indexed_db_futures::OpenDbResult<()> {
let db = Database::open("my_db")
.with_version(2u8)
.with_on_upgrade_needed(|event, db| {
match (event.old_version(), event.new_version()) {
(0.0, Some(1.0)) => {
db.create_object_store("my_store")
.with_auto_increment(true)
.build()?;
}
(prev, Some(2.0)) => {
if prev == 1.0 {
let _ = db.delete_object_store("my_store");
}
db.create_object_store("my_other_store").build()?;
}
_ => {}
}
Ok(())
})
.await?;
// Populate some data
let transaction = db
.transaction("my_other_store")
.with_mode(TransactionMode::Readwrite)
.build()?;
let store = transaction.object_store("my_other_store")?;
store
.put("a primitive value that doesn't need serde")
.await?;
// awaiting individual requests is optional - they still go out
store.put(MySerdeType(10, "foos".into())).serde()?;
// Unlike JS, transactions ROLL BACK INSTEAD OF COMMITTING BY DEFAULT
transaction.commit().await?;
// Read some data
let transaction = db.transaction("my_other_store").build()?;
let store = transaction.object_store("my_other_store")?;
let Some(mut cursor) = store.open_cursor().await? else {
// `None` is returned if the cursor is empty
return Ok(());
};
loop {
match cursor.next_record_ser::<MySerdeType>().await {
Ok(Some(record)) => handle_record(record),
Ok(None) => break,
Err(e) => handle_error(e),
}
}
Ok(())
}
Head over to the docs for a proper introduction!