Skip to content

Commit

Permalink
Add transaction.commit() and get rid of all unwrap_throw() in code (
Browse files Browse the repository at this point in the history
  • Loading branch information
devashishdxt authored Apr 12, 2022
1 parent f2905cb commit 5d198a6
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 49 deletions.
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ default = ["console_error_panic_hook"]

[dependencies]
console_error_panic_hook = { version = "0.1.7", optional = true }
js-sys = "0.3.56"
js-sys = "0.3.57"
num-traits = { version = "0.2.14", default-features = false }
thiserror = "1.0.30"
tokio = { version = "1.17.0", default-features = false, features = ["sync"] }
wasm-bindgen = "0.2.79"
web-sys = { version = "0.3.56", features = [
wasm-bindgen = "0.2.80"
web-sys = { version = "0.3.57", features = [
"console",
"DomException",
"DomStringList",
Expand Down Expand Up @@ -54,7 +54,7 @@ wee_alloc = { version = "0.4.5", optional = true }
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
serde-wasm-bindgen = "0.4.2"
wasm-bindgen-test = "0.3.29"
wasm-bindgen-test = "0.3.30"

[profile.release]
# Tell `rustc` to optimize for small code size.
Expand Down
11 changes: 11 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub type Result<T> = std::result::Result<T, Error>;

/// Error type for `rexie` crate
#[derive(Debug, Error, Clone, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// Error when receiving message from async channel
#[error("error when receiving message from async channel")]
Expand Down Expand Up @@ -52,6 +53,10 @@ pub enum Error {
#[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),
Expand All @@ -64,6 +69,10 @@ pub enum Error {
#[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),
Expand Down Expand Up @@ -99,9 +108,11 @@ impl From<Error> for JsValue {
Error::IndexedDbNotFound => "IndexedDbNotFound".into(),
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::WindowNotFound => "WindowNotFound".into(),
Expand Down
6 changes: 3 additions & 3 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ impl Index {
}
}

/// Creates a new index with given name and compound key path
pub fn new_compound<S: ToString>(name: &str, key_path: impl IntoIterator<Item = S>) -> Self {
/// 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: key_path.into_iter().map(|s| s.to_string()).collect(),
key_path: key_path_array.into_iter().map(ToOwned::to_owned).collect(),
unique: None,
multi_entry: None,
}
Expand Down
19 changes: 10 additions & 9 deletions src/object_store.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashSet, string::ToString};
use std::collections::HashSet;

use js_sys::Array;
use wasm_bindgen::prelude::*;
Expand Down Expand Up @@ -31,12 +31,9 @@ impl ObjectStore {
self
}

/// Specify compound key path for the object store
pub fn key_path_array<S: ToString>(
mut self,
key_path_array: impl IntoIterator<Item = S>,
) -> Self {
self.key_path = key_path_array.into_iter().map(|s| s.to_string()).collect();
/// Specify key path array for the object store
pub fn key_path_array<'a>(mut self, key_path_array: impl IntoIterator<Item = &'a str>) -> Self {
self.key_path = key_path_array.into_iter().map(ToOwned::to_owned).collect();
self
}

Expand Down Expand Up @@ -107,7 +104,9 @@ impl ObjectStore {
let mut indexes_to_remove = Vec::new();

for index in 0..db_index_names.length() {
let db_index_name = db_index_names.get(index).unwrap_throw();
let db_index_name = db_index_names.get(index).ok_or_else(|| {
Error::ObjectStoreCreationFailed("unable to get index name".into())
})?;

if index_names.contains(&db_index_name) {
index_names.remove(&db_index_name);
Expand All @@ -117,7 +116,9 @@ impl ObjectStore {
}

for index_name in indexes_to_remove {
object_store.delete_index(&index_name).unwrap_throw();
object_store
.delete_index(&index_name)
.map_err(Error::ObjectStoreCreationFailed)?;
}

Ok(())
Expand Down
52 changes: 30 additions & 22 deletions src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,8 @@ pub async fn wait_request<R: DbRequest + Unpin>(
pub async fn wait_transaction_abort(transaction: IdbTransaction) -> crate::Result<()> {
let (sender, receiver) = oneshot::channel();

let abort_closure: Closure<dyn FnMut(Event)> = Closure::once(move |_| {
sender
.send(())
.map_err(|_| Error::AsyncChannelError)
.unwrap_throw();
});
let abort_closure: Closure<dyn FnMut(Event) -> crate::Result<()>> =
Closure::once(move |_| sender.send(()).map_err(|_| Error::AsyncChannelError));

transaction.set_onabort(Some(get_callback(&abort_closure)));

Expand Down Expand Up @@ -127,14 +123,27 @@ impl DbRequest for IdbTransaction {
}
}

impl<T> DbRequest for &T
where
T: DbRequest,
{
fn on_success(&self, callback: Option<&Function>) {
(**self).on_success(callback);
}

fn on_error(&self, callback: Option<&Function>) {
(**self).on_error(callback);
}
}

#[must_use = "futures do nothing unless polled or spawned"]
pub struct RequestFuture<R>
where
R: DbRequest + Unpin,
{
_inner: R,
_success_closure: Closure<dyn FnMut(Event)>,
_error_closure: Closure<dyn FnMut(Event)>,
_success_closure: Closure<dyn FnMut(Event) -> crate::Result<()>>,
_error_closure: Closure<dyn FnMut(Event) -> crate::Result<()>>,
receiver: UnboundedReceiver<Result<JsValue, JsValue>>,
map_err: fn(JsValue) -> Error,
}
Expand Down Expand Up @@ -179,23 +188,24 @@ where

fn get_success_closure(
sender: UnboundedSender<Result<JsValue, JsValue>>,
) -> Closure<dyn FnMut(Event)> {
) -> Closure<dyn FnMut(Event) -> crate::Result<()>> {
Closure::once(move |event: Event| {
let target = event.target().unwrap_throw();
let target = event.target().ok_or(Error::EventTargetNotFound)?;
let request: &IdbRequest = AsRef::<JsValue>::as_ref(&target).unchecked_ref();

sender
.send(request.result())
.map_err(|_| Error::AsyncChannelError)
.unwrap_throw();
.map_err(|_| Error::AsyncChannelError)?;

Ok(())
})
}

fn get_error_closure(
sender: UnboundedSender<Result<JsValue, JsValue>>,
) -> Closure<dyn FnMut(Event)> {
) -> Closure<dyn FnMut(Event) -> crate::Result<()>> {
Closure::once(move |event: Event| {
let target = event.target().unwrap_throw();
let target = event.target().ok_or(Error::EventTargetNotFound)?;
let request: &IdbRequest = AsRef::<JsValue>::as_ref(&target).unchecked_ref();

let error: Result<JsValue, JsValue> = match request.error() {
Expand All @@ -204,10 +214,9 @@ fn get_error_closure(
Err(error) => Err(error),
};

sender
.send(error)
.map_err(|_| Error::AsyncChannelError)
.unwrap_throw();
sender.send(error).map_err(|_| Error::AsyncChannelError)?;

Ok(())
})
}

Expand All @@ -217,15 +226,14 @@ fn get_cursor_closure(
advancing: Arc<AtomicBool>,
limit: Option<u32>,
offset: u32,
) -> Closure<dyn FnMut(Event)> {
) -> Closure<dyn FnMut(Event) -> crate::Result<()>> {
Closure::wrap(Box::new(move |event| {
sender
.send(cursor_closure_inner(
event, &seen, &advancing, limit, offset,
))
.map_err(|_| Error::AsyncChannelError)
.unwrap_throw();
}) as Box<dyn FnMut(Event)>)
}) as Box<dyn FnMut(Event) -> crate::Result<()>>)
}

fn cursor_closure_inner(
Expand Down Expand Up @@ -281,6 +289,6 @@ fn cursor_closure_inner(
}
}

fn get_callback(closure: &Closure<dyn FnMut(Event)>) -> &Function {
fn get_callback(closure: &Closure<dyn FnMut(Event) -> crate::Result<()>>) -> &Function {
closure.as_ref().unchecked_ref()
}
14 changes: 8 additions & 6 deletions src/rexie_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,9 @@ fn get_idb_open_request(name: &str, version: Option<u32>) -> Result<IdbOpenDbReq
fn set_upgrade_handler(
idb_open_request: &IdbOpenDbRequest,
object_stores: Vec<ObjectStore>,
) -> Closure<dyn FnMut(Event)> {
let upgrade_handler = Closure::once(move |event: Event| {
upgrade_handler(event, object_stores).unwrap_throw();
});
) -> Closure<dyn FnMut(Event) -> Result<()>> {
let upgrade_handler =
Closure::once(move |event: Event| -> Result<()> { upgrade_handler(event, object_stores) });

idb_open_request.set_onupgradeneeded(Some(upgrade_handler.as_ref().unchecked_ref()));

Expand Down Expand Up @@ -117,7 +116,9 @@ fn upgrade_handler(event: Event, object_stores: Vec<ObjectStore>) -> Result<()>
let mut stores_to_remove = Vec::new();

for index in 0..db_store_names.length() {
let db_store_name = db_store_names.get(index).unwrap_throw();
let db_store_name = db_store_names
.get(index)
.ok_or_else(|| Error::IndexedDbUpgradeFailed("unable to get store name".into()))?;

if store_names.contains(&db_store_name) {
store_names.remove(&db_store_name);
Expand All @@ -127,7 +128,8 @@ fn upgrade_handler(event: Event, object_stores: Vec<ObjectStore>) -> Result<()>
}

for store_name in stores_to_remove {
idb.delete_object_store(&store_name).unwrap_throw();
idb.delete_object_store(&store_name)
.map_err(Error::IndexedDbUpgradeFailed)?;
}

Ok(())
Expand Down
23 changes: 22 additions & 1 deletion src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ pub struct Transaction {
impl Transaction {
/// Returns mode of the transaction
pub fn mode(&self) -> TransactionMode {
self.idb_transaction.mode().unwrap_throw().into()
self.idb_transaction
.mode()
.expect_throw("unable to get transaction mode")
.into()
}

/// Returns names of all stores in the transaction
Expand All @@ -77,6 +80,24 @@ impl Transaction {
wait_transaction_abort(self.idb_transaction).await
}

/// Commits a transaction
///
/// # Note
///
/// Note that `commit()` doesn't normally have to be called — a transaction will automatically commit when all
/// outstanding requests have been satisfied and no new requests have been made.
///
/// [Reference](https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction/commit)
pub async fn commit(self) -> Result<()> {
let done = wait_request(&self.idb_transaction, Error::TransactionExecutionFailed);

self.idb_transaction
.commit()
.map_err(Error::TransactionCommitFailed)?;

done.await.map(|_| ())
}

/// Waits for a transaction to complete.
pub async fn done(self) -> Result<()> {
wait_request(self.idb_transaction, Error::TransactionExecutionFailed)
Expand Down
8 changes: 4 additions & 4 deletions tests/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async fn create_db() -> Rexie {
.add_object_store(
ObjectStore::new("invoices")
.key_path_array(["id", "year"])
.add_index(Index::new_compound("agent_customer", ["agent", "customer"])),
.add_index(Index::new_array("agent_customer", ["agent", "customer"])),
)
.build()
.await;
Expand Down Expand Up @@ -100,7 +100,7 @@ async fn basic_test_db(rexie: &Rexie) {
assert!(email_index.unique());
assert!(!email_index.multi_entry());

assert!(transaction.done().await.is_ok());
assert!(transaction.commit().await.is_ok());
}

/// Closes and deletes the database
Expand All @@ -122,7 +122,7 @@ async fn add_employee(rexie: &Rexie, name: &str, email: &str) -> Result<u32> {
let employee = serde_wasm_bindgen::to_value(&employee).unwrap();
let employee_id = employees.add(&employee, None).await?;

transaction.done().await?;
transaction.commit().await?;
Ok(num_traits::cast(employee_id.as_f64().unwrap()).unwrap())
}

Expand Down Expand Up @@ -213,7 +213,7 @@ async fn add_invoice(
let invoice = serde_wasm_bindgen::to_value(&invoice).unwrap();
invoices.add(&invoice, None).await?;

transaction.done().await?;
transaction.commit().await?;
Ok(())
}

Expand Down

0 comments on commit 5d198a6

Please sign in to comment.