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