idb_sys/cursor/
key_cursor.rs

1use js_sys::Object;
2use wasm_bindgen::{JsCast, JsValue};
3use web_sys::IdbCursor;
4
5use crate::{CursorDirection, Error, StoreRequest};
6
7/// Represents a key cursor for traversing or iterating over multiple records (only keys) in a database.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct KeyCursor {
10    inner: IdbCursor,
11}
12
13impl KeyCursor {
14    /// Returns the [`ObjectStore`](crate::ObjectStore) or [`Index`](crate::Index) the cursor was opened from.
15    // TODO: make return type as enum: (IDBObjectStore or IDBIndex)
16    pub fn source(&self) -> Object {
17        self.inner.source()
18    }
19
20    /// Returns the direction of the cursor.
21    pub fn direction(&self) -> Result<CursorDirection, Error> {
22        self.inner.direction().try_into()
23    }
24
25    /// Returns the key of the cursor. Returns an [`Error`] if the cursor is advancing or is finished.
26    pub fn key(&self) -> Result<JsValue, Error> {
27        self.inner.key().map_err(Error::CursorKeyNotFound)
28    }
29
30    /// Returns the effective key of the cursor. Returns an [`Error`] if the cursor is advancing or is finished.
31    pub fn primary_key(&self) -> Result<JsValue, Error> {
32        self.inner
33            .primary_key()
34            .map_err(Error::CursorPrimaryKeyNotFound)
35    }
36
37    /// Returns the [`StoreRequest`] that was used to obtain this cursor.
38    pub fn request(&self) -> StoreRequest {
39        self.inner.request().into()
40    }
41
42    /// Advances the cursor through the next count records in range.
43    pub fn advance(&self, count: u32) -> Result<(), Error> {
44        self.inner
45            .advance(count)
46            .map_err(Error::CursorAdvanceFailed)
47    }
48
49    /// Advances the cursor to the next record in range matching or after key (if provided).
50    pub fn next(&self, key: Option<&JsValue>) -> Result<(), Error> {
51        match key {
52            None => self.inner.continue_().map_err(Error::CursorContinueFailed),
53            Some(key) => self
54                .inner
55                .continue_with_key(key)
56                .map_err(Error::CursorContinueFailed),
57        }
58    }
59
60    /// Advances the cursor to the next record in range matching or after key and primary key. Returns an [`Error`] if
61    /// the source is not an [`Index`](crate::Index).
62    pub fn next_primary_key(&self, key: &JsValue, primary_key: &JsValue) -> Result<(), Error> {
63        self.inner
64            .continue_primary_key(key, primary_key)
65            .map_err(Error::CursorContinueFailed)
66    }
67
68    /// Updated the record pointed at by the cursor with a new value.
69    pub fn update(&self, value: &JsValue) -> Result<StoreRequest, Error> {
70        self.inner
71            .update(value)
72            .map(Into::into)
73            .map_err(Error::UpdateFailed)
74    }
75
76    /// Delete the record pointed at by the cursor with a new value.
77    pub fn delete(&self) -> Result<StoreRequest, Error> {
78        self.inner
79            .delete()
80            .map(Into::into)
81            .map_err(Error::DeleteFailed)
82    }
83}
84
85impl From<IdbCursor> for KeyCursor {
86    fn from(inner: IdbCursor) -> Self {
87        Self { inner }
88    }
89}
90
91impl From<KeyCursor> for IdbCursor {
92    fn from(cursor: KeyCursor) -> Self {
93        cursor.inner
94    }
95}
96
97impl TryFrom<JsValue> for KeyCursor {
98    type Error = Error;
99
100    fn try_from(value: JsValue) -> Result<Self, Self::Error> {
101        value
102            .dyn_into::<IdbCursor>()
103            .map(Into::into)
104            .map_err(|value| Error::UnexpectedJsType("IdbCursor", value))
105    }
106}
107
108impl From<KeyCursor> for JsValue {
109    fn from(cursor: KeyCursor) -> Self {
110        cursor.inner.into()
111    }
112}