idb_sys/object_store/
mod.rs

1mod key_path;
2mod object_store_params;
3
4pub use self::{key_path::KeyPath, object_store_params::ObjectStoreParams};
5
6use wasm_bindgen::{JsCast, JsValue};
7use web_sys::IdbObjectStore;
8
9use crate::{
10    utils::dom_string_list_to_vec, CursorDirection, Error, Index, IndexParams, Query, StoreRequest,
11    Transaction,
12};
13
14/// Represents an object store in a database.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct ObjectStore {
17    inner: IdbObjectStore,
18}
19
20impl ObjectStore {
21    /// Returns the name of the store.
22    pub fn name(&self) -> String {
23        self.inner.name()
24    }
25
26    /// Updates the name of the store to newName. Returns and [`Error`] if not called within an upgrade transaction.
27    pub fn set_name(&self, name: &str) {
28        self.inner.set_name(name)
29    }
30
31    /// Returns the key path of the store.
32    pub fn key_path(&self) -> Result<Option<KeyPath>, Error> {
33        let inner_key_path = self.inner.key_path().map_err(Error::KeyPathNotFound)?;
34
35        if inner_key_path.is_null() {
36            Ok(None)
37        } else {
38            Some(inner_key_path.try_into()).transpose()
39        }
40    }
41
42    /// Returns a list of the names of indexes in the store.
43    pub fn index_names(&self) -> Vec<String> {
44        dom_string_list_to_vec(&self.inner.index_names())
45    }
46
47    /// Returns the associated [`Transaction`].
48    pub fn transaction(&self) -> Transaction {
49        self.inner.transaction().into()
50    }
51
52    /// Returns `true` if the store has a key generator, and `false` otherwise.
53    pub fn auto_increment(&self) -> bool {
54        self.inner.auto_increment()
55    }
56
57    /// Adds or updates a record in store with the given value and key.
58    pub fn put(&self, value: &JsValue, key: Option<&JsValue>) -> Result<StoreRequest, Error> {
59        match key {
60            None => self.inner.put(value),
61            Some(key) => self.inner.put_with_key(value, key),
62        }
63        .map(Into::into)
64        .map_err(Error::UpdateFailed)
65    }
66
67    /// Adds a record in store with the given value and key.
68    pub fn add(&self, value: &JsValue, key: Option<&JsValue>) -> Result<StoreRequest, Error> {
69        match key {
70            None => self.inner.add(value),
71            Some(key) => self.inner.add_with_key(value, key),
72        }
73        .map(Into::into)
74        .map_err(Error::AddFailed)
75    }
76
77    /// Deletes records in store with the given key or in the given key range in query.
78    pub fn delete(&self, query: impl Into<Query>) -> Result<StoreRequest, Error> {
79        self.inner
80            .delete(&query.into().into())
81            .map(Into::into)
82            .map_err(Error::DeleteFailed)
83    }
84
85    /// Deletes all records in store.
86    pub fn clear(&self) -> Result<StoreRequest, Error> {
87        self.inner
88            .clear()
89            .map(Into::into)
90            .map_err(Error::ClearFailed)
91    }
92
93    /// Retrieves the value of the first record matching the given key or key range in query.
94    pub fn get(&self, query: impl Into<Query>) -> Result<StoreRequest, Error> {
95        self.inner
96            .get(&query.into().into())
97            .map(Into::into)
98            .map_err(Error::GetFailed)
99    }
100
101    /// Retrieves the key of the first record matching the given key or key range in query.
102    pub fn get_key(&self, query: impl Into<Query>) -> Result<StoreRequest, Error> {
103        self.inner
104            .get_key(&query.into().into())
105            .map(Into::into)
106            .map_err(Error::GetKeyFailed)
107    }
108
109    /// Retrieves the values of the records matching the given key or key range in query (up to limit if given).
110    pub fn get_all(&self, query: Option<Query>, limit: Option<u32>) -> Result<StoreRequest, Error> {
111        match (query, limit) {
112            (Some(query), Some(limit)) => self
113                .inner
114                .get_all_with_key_and_limit(&query.into(), limit)
115                .map(Into::into)
116                .map_err(Error::GetAllKeysFailed),
117            (Some(query), None) => self
118                .inner
119                .get_all_with_key(&query.into())
120                .map(Into::into)
121                .map_err(Error::GetAllKeysFailed),
122            (None, Some(limit)) => self
123                .inner
124                .get_all_with_key_and_limit(&JsValue::null(), limit)
125                .map(Into::into)
126                .map_err(Error::GetAllKeysFailed),
127            (None, None) => self
128                .inner
129                .get_all()
130                .map(Into::into)
131                .map_err(Error::GetAllKeysFailed),
132        }
133    }
134
135    /// Retrieves the keys of records matching the given key or key range in query (up to limit if given).
136    pub fn get_all_keys(
137        &self,
138        query: Option<Query>,
139        limit: Option<u32>,
140    ) -> Result<StoreRequest, Error> {
141        match (query, limit) {
142            (Some(query), Some(limit)) => self
143                .inner
144                .get_all_keys_with_key_and_limit(&query.into(), limit)
145                .map(Into::into)
146                .map_err(Error::GetAllKeysFailed),
147            (Some(query), None) => self
148                .inner
149                .get_all_keys_with_key(&query.into())
150                .map(Into::into)
151                .map_err(Error::GetAllKeysFailed),
152            (None, Some(limit)) => self
153                .inner
154                .get_all_keys_with_key_and_limit(&JsValue::null(), limit)
155                .map(Into::into)
156                .map_err(Error::GetAllKeysFailed),
157            (None, None) => self
158                .inner
159                .get_all_keys()
160                .map(Into::into)
161                .map_err(Error::GetAllKeysFailed),
162        }
163    }
164
165    /// Retrieves the number of records matching the given key or key range in query.
166    pub fn count(&self, query: Option<Query>) -> Result<StoreRequest, Error> {
167        match query {
168            None => self
169                .inner
170                .count()
171                .map(Into::into)
172                .map_err(Error::CountFailed),
173            Some(query) => self
174                .inner
175                .count_with_key(&query.into())
176                .map(Into::into)
177                .map_err(Error::CountFailed),
178        }
179    }
180
181    /// Opens a [`Cursor`](crate::Cursor) over the records matching query, ordered by direction. If query is `None`,
182    /// all records in store are matched.
183    pub fn open_cursor(
184        &self,
185        query: Option<Query>,
186        cursor_direction: Option<CursorDirection>,
187    ) -> Result<StoreRequest, Error> {
188        match (query, cursor_direction) {
189            (Some(query), Some(cursor_direction)) => self
190                .inner
191                .open_cursor_with_range_and_direction(&query.into(), cursor_direction.into())
192                .map(Into::into)
193                .map_err(Error::OpenCursorFailed),
194            (Some(query), None) => self
195                .inner
196                .open_cursor_with_range(&query.into())
197                .map(Into::into)
198                .map_err(Error::OpenCursorFailed),
199            (None, Some(cursor_direction)) => self
200                .inner
201                .open_cursor_with_range_and_direction(&JsValue::null(), cursor_direction.into())
202                .map(Into::into)
203                .map_err(Error::OpenCursorFailed),
204            (None, None) => self
205                .inner
206                .open_cursor()
207                .map(Into::into)
208                .map_err(Error::OpenCursorFailed),
209        }
210    }
211
212    /// Opens a [`KeyCursor`](crate::KeyCursor) over the records matching query, ordered by direction. If query is
213    /// `None`, all records in store are matched.
214    pub fn open_key_cursor(
215        &self,
216        query: Option<Query>,
217        cursor_direction: Option<CursorDirection>,
218    ) -> Result<StoreRequest, Error> {
219        match (query, cursor_direction) {
220            (Some(query), Some(cursor_direction)) => self
221                .inner
222                .open_key_cursor_with_range_and_direction(&query.into(), cursor_direction.into())
223                .map(Into::into)
224                .map_err(Error::OpenCursorFailed),
225            (Some(query), None) => self
226                .inner
227                .open_key_cursor_with_range(&query.into())
228                .map(Into::into)
229                .map_err(Error::OpenCursorFailed),
230            (None, Some(cursor_direction)) => self
231                .inner
232                .open_key_cursor_with_range_and_direction(&JsValue::null(), cursor_direction.into())
233                .map(Into::into)
234                .map_err(Error::OpenCursorFailed),
235            (None, None) => self
236                .inner
237                .open_key_cursor()
238                .map(Into::into)
239                .map_err(Error::OpenCursorFailed),
240        }
241    }
242
243    /// Returns an [`Index`] for the index named name in store.
244    pub fn index(&self, name: &str) -> Result<Index, Error> {
245        self.inner
246            .index(name)
247            .map(Into::into)
248            .map_err(Error::IndexNotFound)
249    }
250
251    /// Creates a new index in store with the given name, key path and options and returns a new [`Index`]. Returns an
252    /// [`Error`] if not called within an upgrade transaction.
253    pub fn create_index(
254        &self,
255        name: &str,
256        key_path: KeyPath,
257        params: Option<IndexParams>,
258    ) -> Result<Index, Error> {
259        match params {
260            None => self
261                .inner
262                .create_index_with_str_sequence(name, &key_path.into()),
263            Some(params) => self
264                .inner
265                .create_index_with_str_sequence_and_optional_parameters(
266                    name,
267                    &key_path.into(),
268                    &params.into(),
269                ),
270        }
271        .map(Into::into)
272        .map_err(Error::IndexCreateFailed)
273    }
274
275    /// Deletes the index in store with the given name. Returns an [`Error`] if not called within an upgrade
276    /// transaction.
277    pub fn delete_index(&self, name: &str) -> Result<(), Error> {
278        self.inner
279            .delete_index(name)
280            .map_err(Error::IndexDeleteFailed)
281    }
282}
283
284impl From<IdbObjectStore> for ObjectStore {
285    fn from(inner: IdbObjectStore) -> Self {
286        Self { inner }
287    }
288}
289
290impl From<ObjectStore> for IdbObjectStore {
291    fn from(object_store: ObjectStore) -> Self {
292        object_store.inner
293    }
294}
295
296impl TryFrom<JsValue> for ObjectStore {
297    type Error = Error;
298
299    fn try_from(value: JsValue) -> Result<Self, Self::Error> {
300        value
301            .dyn_into::<IdbObjectStore>()
302            .map(Into::into)
303            .map_err(|value| Error::UnexpectedJsType("IdbObjectStore", value))
304    }
305}
306
307impl From<ObjectStore> for JsValue {
308    fn from(value: ObjectStore) -> Self {
309        value.inner.into()
310    }
311}