use wasm_bindgen::prelude::*;
use web_sys::IdbObjectStore;
use crate::{
request::{wait_cursor_request, wait_request},
Direction, Error, KeyRange, Result, StoreIndex,
};
pub struct Store {
pub(crate) idb_store: IdbObjectStore,
}
impl Store {
pub(crate) fn new(idb_store: IdbObjectStore) -> Self {
Self { idb_store }
}
pub fn auto_increment(&self) -> bool {
self.idb_store.auto_increment()
}
pub fn name(&self) -> String {
self.idb_store.name()
}
pub fn key_path(&self) -> Result<Option<String>> {
self.idb_store
.key_path()
.map(|js_value| js_value.as_string())
.map_err(Error::IndexedDbRequestError)
}
pub fn index_names(&self) -> Vec<String> {
let list = self.idb_store.index_names();
let mut result = Vec::new();
for index in 0..list.length() {
if let Some(s) = list.get(index) {
result.push(s);
}
}
result
}
pub fn index(&self, name: &str) -> Result<StoreIndex> {
let idb_index = self.idb_store.index(name).map_err(Error::IndexOpenFailed)?;
Ok(StoreIndex::new(idb_index))
}
pub async fn get(&self, key: &JsValue) -> Result<JsValue> {
let request = self
.idb_store
.get(key)
.map_err(Error::IndexedDbRequestError)?;
wait_request(request, Error::IndexedDbRequestError).await
}
pub async fn get_all(
&self,
key_range: Option<&KeyRange>,
limit: Option<u32>,
offset: Option<u32>,
direction: Option<Direction>,
) -> Result<Vec<(JsValue, JsValue)>> {
let request = match (key_range, direction) {
(Some(key_range), Some(direction)) => self
.idb_store
.open_cursor_with_range_and_direction(key_range.as_ref(), direction.into()),
(Some(key_range), None) => self.idb_store.open_cursor_with_range(key_range.as_ref()),
(None, Some(direction)) => self
.idb_store
.open_cursor_with_range_and_direction(&JsValue::null(), direction.into()),
_ => self.idb_store.open_cursor(),
}
.map_err(Error::IndexedDbRequestError)?;
wait_cursor_request(request, limit, offset, Error::IndexedDbRequestError).await
}
pub async fn add(&self, value: &JsValue, key: Option<&JsValue>) -> Result<JsValue> {
let request = match key {
Some(key) => self.idb_store.add_with_key(value, key),
None => self.idb_store.add(value),
}
.map_err(Error::IndexedDbRequestError)?;
wait_request(request, Error::IndexedDbRequestError).await
}
pub async fn put(&self, value: &JsValue, key: Option<&JsValue>) -> Result<JsValue> {
let request = match key {
Some(key) => self.idb_store.put_with_key(value, key),
None => self.idb_store.put(value),
}
.map_err(Error::IndexedDbRequestError)?;
wait_request(request, Error::IndexedDbRequestError).await
}
pub async fn delete(&self, key: &JsValue) -> Result<()> {
let request = self
.idb_store
.delete(key)
.map_err(Error::IndexedDbRequestError)?;
wait_request(request, Error::IndexedDbRequestError).await?;
Ok(())
}
pub async fn count(&self, key_range: Option<&KeyRange>) -> Result<u32> {
let request = match key_range {
Some(key_range) => self.idb_store.count_with_key(key_range.as_ref()),
None => self.idb_store.count(),
}
.map_err(Error::IndexedDbRequestError)?;
let result = wait_request(request, Error::IndexedDbRequestError).await?;
result
.as_f64()
.and_then(num_traits::cast)
.ok_or(Error::UnexpectedJsType)
}
pub async fn clear(&self) -> Result<()> {
let request = self
.idb_store
.clear()
.map_err(Error::IndexedDbRequestError)?;
wait_request(request, Error::IndexedDbRequestError)
.await
.map(|_| ())
}
}