#[cfg(feature = "futures")]
mod transaction_future;
mod transaction_mode;
#[cfg(feature = "futures")]
pub use self::transaction_future::{TransactionFuture, TransactionResult};
pub use self::transaction_mode::TransactionMode;
use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
use web_sys::{DomException, Event, EventTarget, IdbTransaction};
use crate::{utils::dom_string_list_to_vec, Database, Error, ObjectStore};
#[derive(Debug)]
pub struct Transaction {
inner: IdbTransaction,
abort_callback: Option<Closure<dyn FnMut(Event)>>,
complete_callback: Option<Closure<dyn FnMut(Event)>>,
error_callback: Option<Closure<dyn FnMut(Event)>>,
}
impl Transaction {
pub fn store_names(&self) -> Vec<String> {
dom_string_list_to_vec(&self.inner.object_store_names())
}
pub fn mode(&self) -> Result<TransactionMode, Error> {
self.inner
.mode()
.map_err(Error::TransactionModeNotFound)?
.try_into()
}
pub fn database(&self) -> Database {
self.inner.db().into()
}
pub fn error(&self) -> Option<DomException> {
self.inner.error()
}
pub fn object_store(&self, name: &str) -> Result<ObjectStore, Error> {
self.inner
.object_store(name)
.map(Into::into)
.map_err(Error::ObjectStoreNotFound)
}
pub fn commit(self) -> Result<Self, Error> {
#[allow(deprecated)]
self.inner.commit().map_err(Error::TransactionCommitError)?;
Ok(self)
}
pub fn abort(self) -> Result<Self, Error> {
self.inner.abort().map_err(Error::TransactionAbortError)?;
Ok(self)
}
pub fn on_abort<F>(&mut self, callback: F)
where
F: FnOnce(Event) + 'static,
{
let closure = Closure::once(callback);
self.inner
.set_onabort(Some(closure.as_ref().unchecked_ref()));
self.abort_callback = Some(closure);
}
pub fn on_complete<F>(&mut self, callback: F)
where
F: FnOnce(Event) + 'static,
{
let closure = Closure::once(callback);
self.inner
.set_oncomplete(Some(closure.as_ref().unchecked_ref()));
self.complete_callback = Some(closure);
}
pub fn on_error<F>(&mut self, callback: F)
where
F: FnOnce(Event) + 'static,
{
let closure = Closure::once(callback);
self.inner
.set_onerror(Some(closure.as_ref().unchecked_ref()));
self.error_callback = Some(closure);
}
pub fn forget_callbacks(&mut self) {
let abort_callback = self.abort_callback.take();
let complete_callback = self.complete_callback.take();
let error_callback = self.error_callback.take();
if let Some(callback) = abort_callback {
callback.forget();
}
if let Some(callback) = complete_callback {
callback.forget();
}
if let Some(callback) = error_callback {
callback.forget();
}
}
}
impl TryFrom<EventTarget> for Transaction {
type Error = Error;
fn try_from(target: EventTarget) -> Result<Self, Self::Error> {
let target: JsValue = target.into();
target
.dyn_into::<IdbTransaction>()
.map(Into::into)
.map_err(|value| Error::UnexpectedJsType("IdbTransaction", value))
}
}
impl From<IdbTransaction> for Transaction {
fn from(inner: IdbTransaction) -> Self {
Self {
inner,
abort_callback: None,
complete_callback: None,
error_callback: None,
}
}
}
impl From<Transaction> for IdbTransaction {
fn from(transaction: Transaction) -> Self {
transaction.inner
}
}
impl TryFrom<JsValue> for Transaction {
type Error = Error;
fn try_from(value: JsValue) -> Result<Self, Self::Error> {
value
.dyn_into::<IdbTransaction>()
.map(Into::into)
.map_err(|value| Error::UnexpectedJsType("IdbTransaction", value))
}
}
impl From<Transaction> for JsValue {
fn from(value: Transaction) -> Self {
value.inner.into()
}
}