10 个不稳定版本 (3 个重大变更)
0.4.1 | 2024年2月25日 |
---|---|
0.4.0 | 2024年1月29日 |
0.3.4 | 2024年1月20日 |
0.2.2 | 2024年1月14日 |
0.1.0 | 2024年1月14日 |
在 数据库接口 中排名第 278
每月下载量 119
88KB
1.5K SLoC
indexed-db
IndexedDB 的绑定,默认事务为中止并支持多线程操作。
为什么还需要另一个 IndexedDB crate?
在我编写此 crate 的时候,其他替代方案都有默认将 IndexedDB 事务提交的行为。这是因为在 IndexedDB 事务中,提交具有奇怪的语义:一旦应用程序在没有进行任何请求的情况下返回到事件循环,它们就会立即提交。
这个 crate 强制你的事务遵守 IndexedDB 的要求,这样就可以在出现错误时中止事务,而不是自动提交。
顺便提一下,在发布 0.4.0 版本时,这个 crate 是唯一在 wasm-bindgen
的多线程执行器下运行良好的 IndexedDB crate。你可以在 这个线程 中找到所有详细信息。
错误处理
此 crate 使用 Error<Err>
类型。基本上,所有由这个 crate 提供的结构体都有 Err
泛型参数。它是 indexed-db
使用周围的代码中用户的类型,以便于使用。
特别是,如果你想要恢复一个通过 indexed-db
代码传递的自定义错误(类型为 Err
),你只需要将错误与 Error::User(_)
匹配,你将能够恢复你的自定义错误详细信息。
另一方面,当您的回调之一想要通过 indexed-db
返回您自己的类型的错误时,它可以使用 From<Err> for Error<Err>
实现。这是由 ?
运算符自动完成的,或者可以通过使用 return Err(e.into());
进行显式返回。
示例
use anyhow::Context;
use indexed_db::Factory;
use web_sys::js_sys::JsString;
async fn example() -> anyhow::Result<()> {
// Obtain the database builder
// This database builder will let us easily use custom errors of type
// `std::io::Error`.
let factory = Factory::<std::io::Error>::get().context("opening IndexedDB")?;
// Open the database, creating it if needed
let db = factory
.open("database", 1, |evt| async move {
let db = evt.database();
let store = db.build_object_store("store").auto_increment().create()?;
// You can also add objects from this callback
store.add(&JsString::from("foo")).await?;
Ok(())
})
.await
.context("creating the 'database' IndexedDB")?;
// In a transaction, add two records
db.transaction(&["store"])
.rw()
.run(|t| async move {
let store = t.object_store("store")?;
store.add(&JsString::from("bar")).await?;
store.add(&JsString::from("baz")).await?;
Ok(())
})
.await?;
// In another transaction, read the first record
db.transaction(&["store"])
.run(|t| async move {
let data = t.object_store("store")?.get_all(Some(1)).await?;
if data.len() != 1 {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Unexpected data length",
))?;
}
Ok(())
})
.await?;
// If we return `Err` (or panic) from a transaction, then it will abort
db.transaction(&["store"])
.rw()
.run(|t| async move {
let store = t.object_store("store")?;
store.add(&JsString::from("quux")).await?;
if store.count().await? > 3 {
// Oops! In this example, we have 4 items by this point
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Too many objects in store",
))?;
}
Ok(())
})
.await
.unwrap_err();
// And no write will have happened
db.transaction(&["store"])
.run(|t| async move {
let num_items = t.object_store("store")?.count().await?;
assert_eq!(num_items, 3);
Ok(())
})
.await?;
// More complex example: using cursors to iterate over a store
db.transaction(&["store"])
.run(|t| async move {
let mut all_items = Vec::new();
let mut cursor = t.object_store("store")?.cursor().open().await?;
while let Some(value) = cursor.value() {
all_items.push(value);
cursor.advance(1).await?;
}
assert_eq!(all_items.len(), 3);
assert_eq!(all_items[0], **JsString::from("foo"));
Ok(())
})
.await?;
Ok(())
}
依赖关系
~7–9.5MB
~185K SLoC