Skip to content

Commit

Permalink
Integrate with idb crate instead of custom handing using web-sys (#…
Browse files Browse the repository at this point in the history
…45)

* Change from web-sys to idb

* Fix bugs and bump crate version
  • Loading branch information
devashishdxt authored Jul 4, 2024
1 parent fd76da2 commit 9b683b6
Show file tree
Hide file tree
Showing 16 changed files with 303 additions and 1,105 deletions.
45 changes: 13 additions & 32 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rexie"
version = "0.5.0"
version = "0.6.0"
authors = ["Devashish Dixit <[email protected]>"]
license = "MIT/Apache-2.0"
description = "Rexie is an easy-to-use, futures based wrapper around IndexedDB that compiles to webassembly"
Expand All @@ -9,50 +9,31 @@ repository = "https://github.com/devashishdxt/rexie"
categories = ["asynchronous", "database", "wasm", "web-programming"]
keywords = ["wasm", "indexeddb", "futures", "idb", "indexed"]
readme = "README.md"
include = ["Cargo.toml", "src/**/*.rs", "tests/**/*.rs", "README.md"]
include = [
"Cargo.toml",
"src/**/*.rs",
"tests/**/*.rs",
"README.md",
"LICENSE_*",
]
edition = "2021"

[lib]
path = "src/lib.rs"
crate-type = ["cdylib", "rlib"]

[features]
default = ["js"]
js = ["wasm-bindgen-futures"]

[dependencies]
js-sys = "0.3.64"
num-traits = { version = "0.2.15", default-features = false }
thiserror = "1.0.40"
tokio = { version = "1.28.2", default-features = false, features = ["sync"] }
wasm-bindgen = "0.2.87"
wasm-bindgen-futures = { version = "0.4.37", optional = true }
web-sys = { version = "0.3.64", features = [
"DomException",
"DomStringList",
"Event",
"IdbCursorWithValue",
"IdbCursorDirection",
"IdbDatabase",
"IdbFactory",
"IdbIndex",
"IdbIndexParameters",
"IdbKeyRange",
"IdbObjectStore",
"IdbObjectStoreParameters",
"IdbOpenDbRequest",
"IdbOpenDbOptions",
"IdbRequest",
"IdbTransaction",
"IdbTransactionMode",
"StorageType",
] }
idb = { version = "0.6.2", features = ["builder"] }
thiserror = "1.0.61"
wasm-bindgen = "0.2.92"

[dev-dependencies]
serde = { version = "1.0.164", features = ["derive"] }
serde_json = "1.0.97"
serde-wasm-bindgen = "0.5.0"
wasm-bindgen-test = "0.3.37"
js-sys = "0.3.69"
num-traits = { version = "0.2.19", default-features = false }

[profile.release]
# Tell `rustc` to optimize for small code size.
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ To use Rexie, you need to add the following to your `Cargo.toml`:

```toml
[dependencies]
rexie = "0.4"
rexie = "0.6"
```

### Example

To create a new database, you can use the `Rexie::builder` method:
To create a new database, you can use the [`Rexie::builder`] method:

```rust
use rexie::*;
Expand All @@ -39,14 +39,14 @@ async fn build_database() -> Result<Rexie> {

// Check basic details of the database
assert_eq!(rexie.name(), "test");
assert_eq!(rexie.version(), 1.0);
assert_eq!(rexie.version(), Ok(1));
assert_eq!(rexie.store_names(), vec!["employees"]);

Ok(rexie)
}
```

To add an employee, you can use the `Store::add` method after creating a `Transaction`:
To add an employee, you can use the [`Store::add`] method after creating a [`Transaction`]:

```rust
use rexie::*;
Expand Down Expand Up @@ -77,7 +77,7 @@ async fn add_employee(rexie: &Rexie, name: &str, email: &str) -> Result<u32> {
}
```

To get an employee, you can use the `Store::get` method after creating a `Transaction`:
To get an employee, you can use the [`Store::get`] method after creating a [`Transaction`]:

```rust
use rexie::*;
Expand All @@ -90,7 +90,7 @@ async fn get_employee(rexie: &Rexie, id: u32) -> Result<Option<serde_json::Value
let employees = transaction.store("employees")?;

// Get the employee
let employee = employees.get(&id.into()).await?;
let employee = employees.get(id.into()).await?.unwrap();

// Convert it to `serde_json::Value` from `JsValue`
let employee: Option<serde_json::Value> = serde_wasm_bindgen::from_value(employee).unwrap();
Expand Down
21 changes: 0 additions & 21 deletions src/direction.rs

This file was deleted.

123 changes: 10 additions & 113 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,122 +1,19 @@
use js_sys::Error as JsError;
use thiserror::Error;
use wasm_bindgen::prelude::*;

/// Result with `rexie::Error` as error type.
pub type Result<T> = std::result::Result<T, Error>;

/// Error type for `rexie` crate
#[derive(Debug, Error, Clone, PartialEq)]
#[derive(Debug, Error, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// Error when receiving message from async channel
#[error("error when receiving message from async channel")]
AsyncChannelError,

/// Error when fetching DOM exception
#[error("error when fetching DOM exception: {}", js_error_display(.0))]
DomExceptionError(JsValue),

/// DOM Exception is none
#[error("dom exception is none")]
DomExceptionNotFound,

/// Event target is none
#[error("event target is none")]
EventTargetNotFound,

/// Index creation failed
#[error("index creation failed: {}", js_error_display(.0))]
IndexCreationFailed(JsValue),

/// Index open failed
#[error("index open failed: {}", js_error_display(.0))]
IndexOpenFailed(JsValue),

/// Failed to delete indexed db
#[error("failed to delete indexed db: {}", js_error_display(.0))]
IndexedDbDeleteFailed(JsValue),

/// Indexed db not found
#[error("indexed db is none")]
IndexedDbNotFound(JsValue),

/// Indexed db not supported
#[error("indexed db not supported: {}", js_error_display(.0))]
IndexedDbNotSupported(JsValue),

/// Failed to open indexed db
#[error("failed to open indexed db: {}", js_error_display(.0))]
IndexedDbOpenFailed(JsValue),

/// Failed to execute indexed db request
#[error("failed to execute indexed db request: {}", js_error_display(.0))]
IndexedDbRequestError(JsValue),

/// Failed to execute indexed db upgrade
#[error("failed to execute indexed db upgrade: {}", js_error_display(.0))]
IndexedDbUpgradeFailed(JsValue),

/// Key range error
#[error("key range error: {}", js_error_display(.0))]
KeyRangeError(JsValue),

/// Object store creation failed
#[error("object store creation failed: {}", js_error_display(.0))]
ObjectStoreCreationFailed(JsValue),

/// Failed to open object store
#[error("failed to open object store: {}", js_error_display(.0))]
ObjectStoreOpenFailed(JsValue),

/// Failed to commit indexed db transaction
#[error("failed to commit indexed db transaction: {}", js_error_display(.0))]
TransactionCommitFailed(JsValue),

/// Failed to execute indexed db transaction
#[error("failed to execute db transaction: {}", js_error_display(.0))]
TransactionExecutionFailed(JsValue),

/// Transaction is none
#[error("transaction is none")]
TransactionNotFound,

/// failed to open db transaction
#[error("failed to open db transaction: {}", js_error_display(.0))]
TransactionOpenFailed(JsValue),

/// Unexpected JS type
#[error("unexpected js type")]
UnexpectedJsType,
}

fn js_error_display(option: &JsValue) -> String {
ToString::to_string(&JsError::from(option.clone()).to_string())
}

impl From<Error> for JsValue {
fn from(error: Error) -> Self {
match error {
Error::AsyncChannelError => "AsyncChannelError".into(),
Error::EventTargetNotFound => "EventTargetNotFound".into(),
Error::IndexCreationFailed(js_value) => js_value,
Error::IndexOpenFailed(js_value) => js_value,
Error::IndexedDbNotFound(js_value) => js_value,
Error::IndexedDbNotSupported(js_value) => js_value,
Error::IndexedDbOpenFailed(js_value) => js_value,
Error::IndexedDbUpgradeFailed(js_value) => js_value,
Error::KeyRangeError(js_value) => js_value,
Error::ObjectStoreCreationFailed(js_value) => js_value,
Error::ObjectStoreOpenFailed(js_value) => js_value,
Error::TransactionCommitFailed(js_value) => js_value,
Error::TransactionExecutionFailed(js_value) => js_value,
Error::TransactionOpenFailed(js_value) => js_value,
Error::DomExceptionError(js_value) => js_value,
Error::DomExceptionNotFound => "DomExceptionNotFound".into(),
Error::IndexedDbDeleteFailed(js_value) => js_value,
Error::TransactionNotFound => "TransactionNotFound".into(),
Error::IndexedDbRequestError(js_value) => js_value,
Error::UnexpectedJsType => "UnxpectedJsType".into(),
}
}
/// Indexed DB error
#[error("idb error")]
IdbError(#[from] idb::Error),
/// Couldn't abort a transaction
#[error("couldn't abort a transaction")]
TransactionAbortFailed,
/// Couldn't commit a transaction
#[error("couldn't commit a transaction")]
TransactioncommitFailed,
}
49 changes: 7 additions & 42 deletions src/index.rs
Original file line number Diff line number Diff line change
@@ -1,71 +1,36 @@
use web_sys::{IdbIndexParameters, IdbObjectStore};
use idb::builder::IndexBuilder;

use crate::{key_path::KeyPath, Error, Result};
use crate::KeyPath;

/// An index builder.
pub struct Index {
pub(crate) name: String,
pub(crate) key_path: KeyPath,
pub(crate) unique: Option<bool>,
pub(crate) multi_entry: Option<bool>,
pub(crate) builder: IndexBuilder,
}

impl Index {
/// Creates a new index with given name and key path
pub fn new(name: &str, key_path: &str) -> Self {
Self {
name: name.to_owned(),
key_path: KeyPath::new_str(key_path),
unique: None,
multi_entry: None,
builder: IndexBuilder::new(name.to_owned(), KeyPath::new_single(key_path)),
}
}

/// Creates a new index with given name and key path array
pub fn new_array<'a>(name: &str, key_path_array: impl IntoIterator<Item = &'a str>) -> Self {
Self {
name: name.to_owned(),
key_path: KeyPath::new_array(key_path_array),
unique: None,
multi_entry: None,
builder: IndexBuilder::new(name.to_owned(), KeyPath::new_array(key_path_array)),
}
}

/// Specify whether the index should be unique
pub fn unique(mut self, unique: bool) -> Self {
self.unique = Some(unique);
self.builder = self.builder.unique(unique);
self
}

/// Specify whether the index should be multi-entry, i.e., type of the value contained in key path is an array
pub fn multi_entry(mut self, multi_entry: bool) -> Self {
self.multi_entry = Some(multi_entry);
self.builder = self.builder.multi_entry(multi_entry);
self
}
}

impl Index {
pub(crate) fn create(self, object_store: &IdbObjectStore) -> Result<()> {
if !object_store.index_names().contains(&self.name) {
let mut params = IdbIndexParameters::new();

if let Some(unique) = self.unique {
params.unique(unique);
}

if let Some(multi_entry) = self.multi_entry {
params.multi_entry(multi_entry);
}

object_store
.create_index_with_str_sequence_and_optional_parameters(
&self.name,
&self.key_path.into(),
&params,
)
.map_err(Error::IndexCreationFailed)?;
}

Ok(())
}
}
32 changes: 0 additions & 32 deletions src/key_path.rs

This file was deleted.

Loading

0 comments on commit 9b683b6

Please sign in to comment.