idb_sys/cursor/
value_cursor.rs

1use js_sys::Object;
2use wasm_bindgen::{JsCast, JsValue};
3use web_sys::IdbCursorWithValue;
4
5use crate::{CursorDirection, Error, StoreRequest};
6
7/// Represents a cursor for traversing or iterating over multiple records in a database.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Cursor {
10    inner: IdbCursorWithValue,
11}
12
13impl Cursor {
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 cursor's current value. Returns an [`Error`] if the cursor is advancing or is finished.
38    pub fn value(&self) -> Result<JsValue, Error> {
39        self.inner.value().map_err(Error::CursorValueNotFound)
40    }
41
42    /// Returns the [`StoreRequest`] that was used to obtain this cursor.
43    pub fn request(&self) -> StoreRequest {
44        self.inner.request().into()
45    }
46
47    /// Advances the cursor through the next count records in range.
48    pub fn advance(&self, count: u32) -> Result<(), Error> {
49        self.inner
50            .advance(count)
51            .map_err(Error::CursorAdvanceFailed)
52    }
53
54    /// Advances the cursor to the next record in range matching or after key (if provided).
55    pub fn next(&self, key: Option<&JsValue>) -> Result<(), Error> {
56        match key {
57            None => self.inner.continue_().map_err(Error::CursorContinueFailed),
58            Some(key) => self
59                .inner
60                .continue_with_key(key)
61                .map_err(Error::CursorContinueFailed),
62        }
63    }
64
65    /// Advances the cursor to the next record in range matching or after key and primary key. Returns an [`Error`] if
66    /// the source is not an [`Index`](crate::Index).
67    pub fn next_primary_key(&self, key: &JsValue, primary_key: &JsValue) -> Result<(), Error> {
68        self.inner
69            .continue_primary_key(key, primary_key)
70            .map_err(Error::CursorContinueFailed)
71    }
72
73    /// Updated the record pointed at by the cursor with a new value.
74    pub fn update(&self, value: &JsValue) -> Result<StoreRequest, Error> {
75        self.inner
76            .update(value)
77            .map(Into::into)
78            .map_err(Error::UpdateFailed)
79    }
80
81    /// Delete the record pointed at by the cursor with a new value.
82    pub fn delete(&self) -> Result<StoreRequest, Error> {
83        self.inner
84            .delete()
85            .map(Into::into)
86            .map_err(Error::DeleteFailed)
87    }
88}
89
90impl From<IdbCursorWithValue> for Cursor {
91    fn from(inner: IdbCursorWithValue) -> Self {
92        Self { inner }
93    }
94}
95
96impl From<Cursor> for IdbCursorWithValue {
97    fn from(cursor: Cursor) -> Self {
98        cursor.inner
99    }
100}
101
102impl TryFrom<JsValue> for Cursor {
103    type Error = Error;
104
105    fn try_from(value: JsValue) -> Result<Self, Self::Error> {
106        value
107            .dyn_into::<IdbCursorWithValue>()
108            .map(Into::into)
109            .map_err(|value| Error::UnexpectedJsType("IdbCursorWithValue", value))
110    }
111}
112
113impl From<Cursor> for JsValue {
114    fn from(cursor: Cursor) -> Self {
115        cursor.inner.into()
116    }
117}