#indexed-db #idb #macro-derive #object-store #future

deli

为在浏览器中使用derive宏在Indexed DB中轻松创建和管理对象存储,对idb创建的便利包装

1个不稳定版本

0.1.0 2022年11月23日

#1027WebAssembly

MIT/Apache

54KB
1K SLoC

deli

Deli 是对 idb 创建的便利包装,用于在浏览器中使用derive宏轻松创建和管理Indexed DB中的对象存储。

用法

要使用 deli,您需要在您的 Cargo.toml 中添加以下内容

[dependencies]
deli = "0.1"

deli 旨在在浏览器中使用WebAssembly。因此,请确保使用 --target wasm32-unknown-unknown 编译您的项目。或者,您可以在 .cargo/config.toml 中添加以下构建配置

[build]
target = "wasm32-unknown-unknown"

示例

定义一个 Model

第一步是使用 Model derive宏定义您的数据模型。您还需要为您的模型实现 serde::Serializeserde::Deserialize 特性,以便在将其保存到存储中之前将数据转换为 json

use deli::Model;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Model)]
pub struct Employee {
    #[deli(auto_increment)]
    pub id: u32,
    pub name: String,
    #[deli(unique)]
    pub email: String,
    #[deli(index)]
    pub age: u8,
}

Model derive宏自动为您的基本结构实现 Model 特性,并创建一个 Store 来访问和写入存储中的数据。

容器属性
  • #[deli(name)]:在索引数据库中,默认情况下,在创建数据库时将创建一个名为结构的对象存储(在上面的例子中,将在索引数据库中创建一个名为 Employee 的对象存储)。要更改默认的对象存储名称,请使用 #[deli(name = "your_object_store_name")]

  • #[deli(store_name)]:默认情况下,派生宏将创建一个 <ModelName>Store 结构(在上面的例子中,将创建一个 EmployeeStore 结构)。要更改默认名称,请使用 #[deli(store_name = "YourStoreName")]

字段属性
  • #[deli(key)]:定义对象存储的主键路径。
  • #[deli(auto_increment)]:定义具有 auto_increment 值的主键路径(隐含 #[deli(key)])的对象存储。
  • #[deli(index)]:为字段创建索引。
  • #[deli(unique)]:为字段创建唯一索引(隐含 #[deli(index)])。
  • #[deli(multi_entry)]:为字段创建一个多入口索引(隐含#[deli(index)])。
  • #[deli(rename)]:重命名对象存储中的字段。注意,这应与serde序列化保持一致。例如,如果您使用#[serde(rename_all = "camelCase")],则需要适当地重命名deli的字段,以与serde序列化保持同步。

创建数据库

下一步是创建一个新的Database,并将您的模型注册到其中。

use deli::{Database, Error};

async fn create_database() -> Result<Database, Error> {
    let database = Database.builder("test_db", 1).register_model::<Employee>().await?;
}

开始事务

一旦创建了Database实例,您就可以使用事务开始读取和写入数据库中的数据。

use deli::{Database, Error, Transaction};

fn create_read_transaction(database: &Database) -> Result<Transaction, Error> {
    database.transaction().with_model::<Employee>().build()
}

fn create_write_transaction(database: &Database) -> Result<Transaction, Error> {
    database.transaction().writable().with_model::<Employee>().build()
}

您可以在事务中添加多个.with_model::<Model>()调用,以添加多个模型到事务中。

读取和写入模型存储中的数据

一旦您有一个模型的事务,您就可以读取或写入该模型中的数据。

use deli::{Error, Model, Transaction};

async fn add_employee(transaction: &Transaction) -> Result<u32, Error> {
    Employee::with_transaction(transaction)?.add("Alice", "alice@example.com", &25).await
}

async fn get_employee(transaction: &Transaction, id: u32) -> Result<Option<Employee>, Error> {
    Employee::with_transaction(transaction)?.get(&id).await
}

async fn get_all_employees(transaction: &Transaction) -> Result<Vec<Employee>, Error> {
    // NOTE: Here `..` (i.e., `RangeFull`) means fetch all values from store
    Employee::with_transaction(transaction)?.get_all(.., None).await
}

async fn get_employees_with_bounds(
    transaction: &Transaction,
    from_id: u32,
    to_id: u32,
) -> Result<Vec<Employee>, Error> {
    Employee::with_transaction(transaction)?.get_all(&from_id..=&to_id, None).await
}

提交事务

完成所有写入后,您可以提交事务。

async fn commit_transaction(transaction: Transaction) -> Result<(), Error> {
    transaction.commit().await
}

请注意,通常不需要调用commit(),当所有未解决的问题都得到解决且没有新的请求时,事务将自动提交。

此外,使用长生命周期的索引数据库事务时请小心,因为行为可能会根据浏览器而有所不同。例如,在事件循环中进行IO(网络请求)时,事务可能会自动提交。

许可证

根据您的选择,许可协议为以下之一:

贡献

除非您明确声明,否则任何有意提交以包含在您的工作中的贡献,根据Apache-2.0许可证定义,应按上述方式双许可,不附加任何其他条款或条件。

依赖项

~11–14MB
~267K SLoC