1use std::cmp::Ordering;
2use std::collections::BTreeMap;
3
4use hyper_util::rt::TokioIo;
5use tokio::sync::mpsc;
6use tokio_stream::wrappers::ReceiverStream;
7use tonic::Request;
8use tonic::codegen::async_trait;
9use tonic::metadata::MetadataValue;
10use tonic::service::Interceptor;
11use tonic::service::interceptor::InterceptedService;
12use tonic::transport::{Channel, ClientTlsConfig, Endpoint, Uri};
13use tower::service_fn;
14
15use crate::env::{
16 ENV_HOST_SERVICE_SOCKET, ENV_HOST_SERVICE_TOKEN, HOST_SERVICE_BINDING_HEADER,
17 host_service_configured,
18};
19use crate::generated::v1::{self as pb, indexed_db_client::IndexedDbClient};
20
21type IndexedDbTransport = InterceptedService<Channel, RelayTokenInterceptor>;
22
23const INDEXEDDB_RELAY_TOKEN_HEADER: &str = "x-gestalt-host-service-relay-token";
24const CURSOR_CHANNEL_BUFFER: usize = 1;
25const TRANSACTION_CHANNEL_BUFFER: usize = 1;
26
27#[derive(Debug, thiserror::Error)]
28pub enum IndexedDBError {
30 #[error("not found")]
32 NotFound,
33 #[error("already exists")]
35 AlreadyExists,
36 #[error("cursor is keys-only; value not available")]
38 KeysOnly,
39 #[error("{0}")]
41 InvalidArgument(String),
42 #[error("{0}")]
44 Transaction(String),
45 #[error("{0}")]
47 Transport(#[from] tonic::transport::Error),
48 #[error("{0}")]
50 Status(#[from] tonic::Status),
51 #[error("{0}")]
53 Env(String),
54}
55
56pub type Record = BTreeMap<String, serde_json::Value>;
58
59#[derive(Debug, Clone, PartialEq)]
61pub enum Key {
62 Int(i64),
64 Float(f64),
66 Str(String),
68 Date(std::time::SystemTime),
70 Bytes(Vec<u8>),
72 Array(Vec<Key>),
74}
75
76impl From<&str> for Key {
77 fn from(value: &str) -> Self {
78 Self::Str(value.to_string())
79 }
80}
81
82impl From<String> for Key {
83 fn from(value: String) -> Self {
84 Self::Str(value)
85 }
86}
87
88impl From<i64> for Key {
89 fn from(value: i64) -> Self {
90 Self::Int(value)
91 }
92}
93
94impl From<i32> for Key {
95 fn from(value: i32) -> Self {
96 Self::Int(i64::from(value))
97 }
98}
99
100impl From<u64> for Key {
101 fn from(value: u64) -> Self {
102 Self::Int(value as i64)
103 }
104}
105
106impl From<f64> for Key {
107 fn from(value: f64) -> Self {
108 Self::Float(value)
109 }
110}
111
112impl From<bool> for Key {
113 fn from(value: bool) -> Self {
114 Self::Int(i64::from(value))
115 }
116}
117
118impl From<std::time::SystemTime> for Key {
119 fn from(value: std::time::SystemTime) -> Self {
120 Self::Date(value)
121 }
122}
123
124impl From<Vec<u8>> for Key {
125 fn from(value: Vec<u8>) -> Self {
126 Self::Bytes(value)
127 }
128}
129
130impl From<&[u8]> for Key {
131 fn from(value: &[u8]) -> Self {
132 Self::Bytes(value.to_vec())
133 }
134}
135
136impl<T: Into<Key>> From<Vec<T>> for Key {
137 fn from(values: Vec<T>) -> Self {
138 if values.len() == 1 {
139 values.into_iter().next().expect("one value").into()
140 } else {
141 Self::Array(values.into_iter().map(Into::into).collect())
142 }
143 }
144}
145
146#[derive(Debug, Clone, PartialEq)]
148pub struct KeyRange {
149 pub lower: Option<Key>,
151 pub upper: Option<Key>,
153 pub lower_open: bool,
155 pub upper_open: bool,
157}
158
159impl KeyRange {
160 pub fn only(key: impl Into<Key>) -> Self {
162 let key = key.into();
163 Self {
164 lower: Some(key.clone()),
165 upper: Some(key),
166 lower_open: false,
167 upper_open: false,
168 }
169 }
170
171 pub fn bound(
173 lower: impl Into<Key>,
174 upper: impl Into<Key>,
175 lower_open: bool,
176 upper_open: bool,
177 ) -> Self {
178 Self {
179 lower: Some(lower.into()),
180 upper: Some(upper.into()),
181 lower_open,
182 upper_open,
183 }
184 }
185
186 pub fn lower_bound(key: impl Into<Key>, open: bool) -> Self {
188 Self {
189 lower: Some(key.into()),
190 upper: None,
191 lower_open: open,
192 upper_open: false,
193 }
194 }
195
196 pub fn upper_bound(key: impl Into<Key>, open: bool) -> Self {
198 Self {
199 lower: None,
200 upper: Some(key.into()),
201 lower_open: false,
202 upper_open: open,
203 }
204 }
205}
206
207#[derive(Debug, Clone, PartialEq)]
209pub enum Query {
210 All,
212 Key(Key),
214 Range(KeyRange),
216}
217
218impl Query {
219 pub fn all() -> Self {
221 Self::All
222 }
223
224 fn to_proto(&self) -> Option<pb::IndexedDbQuery> {
225 use crate::indexeddb_query_codec::{QueryKind, query_to_proto};
226 query_to_proto(match self {
227 Self::All => QueryKind::All,
228 Self::Key(key) => QueryKind::Key(key),
229 Self::Range(range) => QueryKind::Range {
230 lower: range.lower.as_ref(),
231 upper: range.upper.as_ref(),
232 lower_open: range.lower_open,
233 upper_open: range.upper_open,
234 },
235 })
236 }
237}
238
239impl From<KeyRange> for Query {
240 fn from(range: KeyRange) -> Self {
241 Self::Range(range)
242 }
243}
244
245impl<T: Into<Key>> From<T> for Query {
246 fn from(value: T) -> Self {
247 Self::Key(value.into())
248 }
249}
250
251impl From<Option<KeyRange>> for Query {
252 fn from(range: Option<KeyRange>) -> Self {
253 match range {
254 None => Self::All,
255 Some(range) => Self::Range(range),
256 }
257 }
258}
259
260#[derive(Debug, Clone, PartialEq)]
262pub struct IndexSchema {
263 pub name: String,
265 pub key_path: Vec<String>,
267 pub unique: bool,
269}
270
271#[derive(Debug, Clone, PartialEq)]
273pub struct ObjectStoreSchema {
274 pub indexes: Vec<IndexSchema>,
276}
277
278#[derive(Debug, Clone, Copy, PartialEq, Eq)]
279pub enum CursorDirection {
281 Next,
283 NextUnique,
285 Prev,
287 PrevUnique,
289}
290
291impl CursorDirection {
292 fn to_proto(self) -> i32 {
293 match self {
294 Self::Next => pb::CursorDirection::CursorNext as i32,
295 Self::NextUnique => pb::CursorDirection::CursorNextUnique as i32,
296 Self::Prev => pb::CursorDirection::CursorPrev as i32,
297 Self::PrevUnique => pb::CursorDirection::CursorPrevUnique as i32,
298 }
299 }
300}
301
302#[derive(Debug, Clone, Copy, PartialEq, Eq)]
303pub enum TransactionMode {
305 Readonly,
307 Readwrite,
309}
310
311impl TransactionMode {
312 fn to_proto(self) -> i32 {
313 match self {
314 Self::Readonly => pb::TransactionMode::TransactionReadonly as i32,
315 Self::Readwrite => pb::TransactionMode::TransactionReadwrite as i32,
316 }
317 }
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
321pub enum TransactionDurabilityHint {
323 #[default]
325 Default,
326 Strict,
328 Relaxed,
330}
331
332impl TransactionDurabilityHint {
333 fn to_proto(self) -> i32 {
334 match self {
335 Self::Default => pb::TransactionDurabilityHint::TransactionDurabilityDefault as i32,
336 Self::Strict => pb::TransactionDurabilityHint::TransactionDurabilityStrict as i32,
337 Self::Relaxed => pb::TransactionDurabilityHint::TransactionDurabilityRelaxed as i32,
338 }
339 }
340}
341
342#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
343pub struct TransactionOptions {
345 pub durability_hint: TransactionDurabilityHint,
347}
348
349#[async_trait]
350pub trait IndexedDBApi: Send {
352 type ObjectStore: ObjectStoreApi;
354 type Transaction: TransactionApi;
356
357 async fn create_object_store(
359 &mut self,
360 name: &str,
361 schema: ObjectStoreSchema,
362 ) -> Result<Self::ObjectStore, IndexedDBError>;
363
364 async fn delete_object_store(&mut self, name: &str) -> Result<(), IndexedDBError>;
366
367 fn object_store(&self, name: &str) -> Self::ObjectStore;
369
370 async fn transaction(
372 &self,
373 stores: &[&str],
374 mode: TransactionMode,
375 options: TransactionOptions,
376 ) -> Result<Self::Transaction, IndexedDBError>;
377}
378
379#[async_trait]
380pub trait ObjectStoreApi: Send {
382 type Index: IndexApi;
384 type Cursor: CursorApi;
386
387 async fn get(&mut self, id: &str) -> Result<Record, IndexedDBError>;
389
390 async fn get_key(&mut self, id: &str) -> Result<String, IndexedDBError>;
392
393 async fn add(&mut self, record: Record) -> Result<(), IndexedDBError>;
395
396 async fn put(&mut self, record: Record) -> Result<(), IndexedDBError>;
398
399 async fn delete(&mut self, id: &str) -> Result<(), IndexedDBError>;
401
402 async fn clear(&mut self) -> Result<(), IndexedDBError>;
404
405 async fn get_all(&mut self, query: Query) -> Result<Vec<Record>, IndexedDBError>;
407
408 async fn get_all_keys(&mut self, query: Query) -> Result<Vec<String>, IndexedDBError>;
410
411 async fn count(&mut self, query: Query) -> Result<i64, IndexedDBError>;
413
414 async fn delete_range(&mut self, query: Query) -> Result<i64, IndexedDBError>;
416
417 fn index(&self, name: &str) -> Self::Index;
419
420 async fn open_cursor(
422 &mut self,
423 query: Query,
424 direction: CursorDirection,
425 ) -> Result<Self::Cursor, IndexedDBError>;
426
427 async fn open_key_cursor(
429 &mut self,
430 query: Query,
431 direction: CursorDirection,
432 ) -> Result<Self::Cursor, IndexedDBError>;
433}
434
435#[async_trait]
436pub trait IndexApi: Send {
438 type Cursor: CursorApi;
440
441 async fn get(&mut self, query: Query) -> Result<Record, IndexedDBError>;
443
444 async fn get_key(&mut self, query: Query) -> Result<String, IndexedDBError>;
446
447 async fn get_all(&mut self, query: Query) -> Result<Vec<Record>, IndexedDBError>;
449
450 async fn get_all_keys(&mut self, query: Query) -> Result<Vec<String>, IndexedDBError>;
452
453 async fn count(&mut self, query: Query) -> Result<i64, IndexedDBError>;
455
456 async fn delete(&mut self, query: Query) -> Result<i64, IndexedDBError>;
458
459 async fn open_cursor(
461 &mut self,
462 query: Query,
463 direction: CursorDirection,
464 ) -> Result<Self::Cursor, IndexedDBError>;
465
466 async fn open_key_cursor(
468 &mut self,
469 query: Query,
470 direction: CursorDirection,
471 ) -> Result<Self::Cursor, IndexedDBError>;
472}
473
474#[async_trait]
475pub trait TransactionApi: Send {
477 type ObjectStore<'a>: TransactionObjectStoreApi + 'a
479 where
480 Self: 'a;
481
482 fn object_store<'a>(&'a mut self, name: &str) -> Self::ObjectStore<'a>;
484
485 async fn commit(&mut self) -> Result<(), IndexedDBError>;
487
488 async fn abort(&mut self, reason: &str) -> Result<(), IndexedDBError>;
490}
491
492#[async_trait]
493pub trait TransactionObjectStoreApi: Send {
495 type Index<'a>: TransactionIndexApi + 'a
497 where
498 Self: 'a;
499
500 async fn get(&mut self, id: &str) -> Result<Record, IndexedDBError>;
502
503 async fn get_key(&mut self, id: &str) -> Result<String, IndexedDBError>;
505
506 async fn add(&mut self, record: Record) -> Result<(), IndexedDBError>;
508
509 async fn put(&mut self, record: Record) -> Result<(), IndexedDBError>;
511
512 async fn delete(&mut self, id: &str) -> Result<(), IndexedDBError>;
514
515 async fn clear(&mut self) -> Result<(), IndexedDBError>;
517
518 async fn get_all(&mut self, query: Query) -> Result<Vec<Record>, IndexedDBError>;
520
521 async fn get_all_keys(&mut self, query: Query) -> Result<Vec<String>, IndexedDBError>;
523
524 async fn count(&mut self, query: Query) -> Result<i64, IndexedDBError>;
526
527 async fn delete_range(&mut self, query: Query) -> Result<i64, IndexedDBError>;
529
530 fn index<'a>(&'a mut self, name: &str) -> Self::Index<'a>;
532}
533
534#[async_trait]
535pub trait TransactionIndexApi: Send {
537 async fn get(&mut self, query: Query) -> Result<Record, IndexedDBError>;
539
540 async fn get_key(&mut self, query: Query) -> Result<String, IndexedDBError>;
542
543 async fn get_all(&mut self, query: Query) -> Result<Vec<Record>, IndexedDBError>;
545
546 async fn get_all_keys(&mut self, query: Query) -> Result<Vec<String>, IndexedDBError>;
548
549 async fn count(&mut self, query: Query) -> Result<i64, IndexedDBError>;
551
552 async fn delete(&mut self, query: Query) -> Result<i64, IndexedDBError>;
554}
555
556#[async_trait]
557pub trait CursorApi: Send {
559 fn key(&self) -> Option<Key>;
561
562 fn primary_key(&self) -> &str;
564
565 fn value(&self) -> Result<Record, IndexedDBError>;
567
568 async fn continue_next(&mut self) -> Result<bool, IndexedDBError>;
570
571 async fn continue_to_key(&mut self, key: impl Into<Key> + Send)
573 -> Result<bool, IndexedDBError>;
574
575 async fn advance(&mut self, count: i32) -> Result<bool, IndexedDBError>;
577
578 async fn delete(&mut self) -> Result<(), IndexedDBError>;
580
581 async fn update(&mut self, value: Record) -> Result<(), IndexedDBError>;
583
584 async fn close(self) -> Result<(), IndexedDBError>
586 where
587 Self: Sized;
588}
589
590#[derive(Debug, Clone)]
592pub struct IndexedDBOpenCursorRequest {
593 pub store: String,
595 pub range: Option<KeyRange>,
597 pub direction: CursorDirection,
599 pub keys_only: bool,
601 pub index: String,
603 pub values: Vec<serde_json::Value>,
605}
606
607impl Default for IndexedDBOpenCursorRequest {
608 fn default() -> Self {
609 Self {
610 store: String::new(),
611 range: None,
612 direction: CursorDirection::Next,
613 keys_only: false,
614 index: String::new(),
615 values: Vec::new(),
616 }
617 }
618}
619
620#[derive(Debug, Clone, PartialEq)]
622pub struct IndexedDBCursorSnapshotEntry {
623 pub key: Key,
625 pub primary_key: String,
627 pub primary_key_value: Key,
629 pub record: Record,
631}
632
633#[derive(Debug, Clone)]
639pub struct IndexedDBCursorSnapshot {
640 pub index_cursor: bool,
642 pub keys_only: bool,
644 pub reverse: bool,
646 pub unique: bool,
648 pub entries: Vec<IndexedDBCursorSnapshotEntry>,
650 pub pos: isize,
652}
653
654impl IndexedDBCursorSnapshot {
655 pub fn new(req: &IndexedDBOpenCursorRequest) -> Self {
657 Self {
658 index_cursor: !req.index.is_empty(),
659 keys_only: req.keys_only,
660 reverse: matches!(
661 req.direction,
662 CursorDirection::Prev | CursorDirection::PrevUnique
663 ),
664 unique: matches!(
665 req.direction,
666 CursorDirection::NextUnique | CursorDirection::PrevUnique
667 ),
668 entries: Vec::new(),
669 pos: -1,
670 }
671 }
672
673 pub fn load(
675 &mut self,
676 mut entries: Vec<IndexedDBCursorSnapshotEntry>,
677 range: Option<&KeyRange>,
678 ) -> Result<(), IndexedDBError> {
679 entries.sort_by(|left, right| {
680 let mut cmp = compare_indexeddb_values(&left.key, &right.key);
681 if cmp == Ordering::Equal {
682 cmp = compare_indexeddb_values(&left.primary_key_value, &right.primary_key_value);
683 }
684 if self.reverse { cmp.reverse() } else { cmp }
685 });
686 self.entries = self.apply_range(entries, range)?;
687 self.pos = -1;
688 Ok(())
689 }
690
691 pub fn apply_range(
693 &self,
694 entries: Vec<IndexedDBCursorSnapshotEntry>,
695 range: Option<&KeyRange>,
696 ) -> Result<Vec<IndexedDBCursorSnapshotEntry>, IndexedDBError> {
697 let Some(range) = range else {
698 return Ok(entries);
699 };
700 let (lower, upper) = indexeddb_range_bounds(Some(range), self.index_cursor);
701 let mut filtered = Vec::with_capacity(entries.len());
702 for entry in entries {
703 let key = normalize_indexeddb_bound(&entry.key, self.index_cursor);
704 if let Some(lower) = &lower {
705 let cmp = compare_indexeddb_values(&key, lower);
706 if range.lower_open && cmp != Ordering::Greater {
707 continue;
708 }
709 if !range.lower_open && cmp == Ordering::Less {
710 continue;
711 }
712 }
713 if let Some(upper) = &upper {
714 let cmp = compare_indexeddb_values(&key, upper);
715 if range.upper_open && cmp != Ordering::Less {
716 continue;
717 }
718 if !range.upper_open && cmp == Ordering::Greater {
719 continue;
720 }
721 }
722 filtered.push(entry);
723 }
724 Ok(filtered)
725 }
726
727 #[allow(clippy::should_implement_trait)]
729 pub fn next(&mut self) -> Result<Option<&IndexedDBCursorSnapshotEntry>, IndexedDBError> {
730 if self.unique
731 && self.index_cursor
732 && self.pos >= 0
733 && (self.pos as usize) < self.entries.len()
734 {
735 let previous = self.entries[self.pos as usize].key.clone();
736 self.pos += 1;
737 while (self.pos as usize) < self.entries.len() {
738 if compare_indexeddb_values(&self.entries[self.pos as usize].key, &previous)
739 != Ordering::Equal
740 {
741 return Ok(Some(self.current()?));
742 }
743 self.pos += 1;
744 }
745 return Ok(None);
746 }
747
748 self.pos += 1;
749 if (self.pos as usize) >= self.entries.len() {
750 return Ok(None);
751 }
752 Ok(Some(self.current()?))
753 }
754
755 pub fn continue_to_key(
757 &mut self,
758 target: &Key,
759 ) -> Result<Option<&IndexedDBCursorSnapshotEntry>, IndexedDBError> {
760 let previous = if self.unique
761 && self.index_cursor
762 && self.pos >= 0
763 && (self.pos as usize) < self.entries.len()
764 {
765 Some(self.entries[self.pos as usize].key.clone())
766 } else {
767 None
768 };
769 self.pos += 1;
770 while (self.pos as usize) < self.entries.len() {
771 let current = &self.entries[self.pos as usize].key;
772 if let Some(previous) = &previous {
773 if self.unique
774 && self.index_cursor
775 && compare_indexeddb_values(current, previous) == Ordering::Equal
776 {
777 self.pos += 1;
778 continue;
779 }
780 }
781 let cmp = compare_indexeddb_values(current, target);
782 if self.reverse {
783 if cmp != Ordering::Greater {
784 return Ok(Some(self.current()?));
785 }
786 } else if cmp != Ordering::Less {
787 return Ok(Some(self.current()?));
788 }
789 self.pos += 1;
790 }
791 Ok(None)
792 }
793
794 pub fn advance(
796 &mut self,
797 count: i32,
798 ) -> Result<Option<&IndexedDBCursorSnapshotEntry>, IndexedDBError> {
799 if count <= 0 {
800 return Err(IndexedDBError::InvalidArgument(
801 "advance count must be positive".to_string(),
802 ));
803 }
804 for i in 0..count {
805 if self.next()?.is_none() {
806 return Ok(None);
807 }
808 if i == count - 1 {
809 return Ok(Some(self.current()?));
810 }
811 }
812 Ok(None)
813 }
814
815 pub fn current(&self) -> Result<&IndexedDBCursorSnapshotEntry, IndexedDBError> {
817 if self.pos < 0 || (self.pos as usize) >= self.entries.len() {
818 return Err(IndexedDBError::NotFound);
819 }
820 Ok(&self.entries[self.pos as usize])
821 }
822}
823
824pub fn new_indexeddb_cursor_snapshot(req: &IndexedDBOpenCursorRequest) -> IndexedDBCursorSnapshot {
826 IndexedDBCursorSnapshot::new(req)
827}
828
829pub fn indexeddb_range_bounds(
834 range: Option<&KeyRange>,
835 index_cursor: bool,
836) -> (Option<Key>, Option<Key>) {
837 let Some(range) = range else {
838 return (None, None);
839 };
840 let lower = range
841 .lower
842 .as_ref()
843 .map(|value| normalize_indexeddb_bound(value, index_cursor));
844 let upper = range
845 .upper
846 .as_ref()
847 .map(|value| normalize_indexeddb_bound(value, index_cursor));
848 (lower, upper)
849}
850
851pub fn compare_indexeddb_values(left: &Key, right: &Key) -> Ordering {
853 compare_keys(left, right)
854}
855
856#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
857enum KeyKind {
858 Number,
859 Date,
860 String,
861 Binary,
862 Array,
863}
864
865fn key_kind(key: &Key) -> KeyKind {
866 match key {
867 Key::Int(_) | Key::Float(_) => KeyKind::Number,
868 Key::Date(_) => KeyKind::Date,
869 Key::Str(_) => KeyKind::String,
870 Key::Bytes(_) => KeyKind::Binary,
871 Key::Array(_) => KeyKind::Array,
872 }
873}
874
875pub fn compare_keys(left: &Key, right: &Key) -> Ordering {
877 let left_kind = key_kind(left);
878 let right_kind = key_kind(right);
879 if left_kind != right_kind {
880 return left_kind.cmp(&right_kind);
881 }
882 match (left, right) {
883 (Key::Int(left), Key::Int(right)) => left.cmp(right),
884 (Key::Float(left), Key::Float(right)) => compare_float_keys(*left, *right),
885 (Key::Int(left), Key::Float(right)) => compare_int_float_keys(*left, *right),
886 (Key::Float(left), Key::Int(right)) => compare_int_float_keys(*right, *left).reverse(),
887 (Key::Date(left), Key::Date(right)) => left.cmp(right),
888 (Key::Str(left), Key::Str(right)) => compare_utf16_strings(left, right),
889 (Key::Bytes(left), Key::Bytes(right)) => left.cmp(right),
890 (Key::Array(left), Key::Array(right)) => {
891 for (left_value, right_value) in left.iter().zip(right.iter()) {
892 let cmp = compare_keys(left_value, right_value);
893 if cmp != Ordering::Equal {
894 return cmp;
895 }
896 }
897 left.len().cmp(&right.len())
898 }
899 _ => Ordering::Equal,
900 }
901}
902
903pub fn key_in_range(key: &Key, range: &KeyRange) -> bool {
905 if let Some(lower) = &range.lower {
906 let cmp = compare_keys(key, lower);
907 if range.lower_open {
908 if cmp != Ordering::Greater {
909 return false;
910 }
911 } else if cmp == Ordering::Less {
912 return false;
913 }
914 }
915 if let Some(upper) = &range.upper {
916 let cmp = compare_keys(key, upper);
917 if range.upper_open {
918 if cmp != Ordering::Less {
919 return false;
920 }
921 } else if cmp == Ordering::Greater {
922 return false;
923 }
924 }
925 true
926}
927
928pub fn match_query(key: &Key, query: &Query) -> bool {
930 match query {
931 Query::All => true,
932 Query::Key(target) => compare_keys(key, target) == Ordering::Equal,
933 Query::Range(range) => key_in_range(key, range),
934 }
935}
936
937fn normalize_indexeddb_bound(value: &Key, index_cursor: bool) -> Key {
938 if !index_cursor {
939 return value.clone();
940 }
941 if matches!(value, Key::Array(_)) {
942 return value.clone();
943 }
944 Key::Array(vec![value.clone()])
945}
946
947fn compare_utf16_strings(left: &str, right: &str) -> Ordering {
948 let left: Vec<u16> = left.encode_utf16().collect();
949 let right: Vec<u16> = right.encode_utf16().collect();
950 for (left_unit, right_unit) in left.iter().zip(right.iter()) {
951 match left_unit.cmp(right_unit) {
952 Ordering::Equal => {}
953 other => return other,
954 }
955 }
956 left.len().cmp(&right.len())
957}
958
959fn compare_int_float_keys(left: i64, right: f64) -> Ordering {
960 if right.is_nan() {
961 return Ordering::Equal;
962 }
963 match (left as f64).partial_cmp(&right) {
964 Some(ordering) => ordering,
965 None => left.cmp(&(right as i64)),
966 }
967}
968
969fn compare_float_keys(left: f64, right: f64) -> Ordering {
970 left.partial_cmp(&right).unwrap_or(Ordering::Equal)
971}
972
973#[cfg(test)]
974mod tests {
975 use super::*;
976 use std::time::{Duration, UNIX_EPOCH};
977
978 fn entry(key: Key, primary_key: &str, primary_key_value: Key) -> IndexedDBCursorSnapshotEntry {
979 IndexedDBCursorSnapshotEntry {
980 key,
981 primary_key: primary_key.to_string(),
982 primary_key_value,
983 record: Record::new(),
984 }
985 }
986
987 #[test]
988 fn cursor_snapshot_sorts_ranges_and_skips_duplicate_unique_index_keys() {
989 let mut snapshot = new_indexeddb_cursor_snapshot(&IndexedDBOpenCursorRequest {
990 direction: CursorDirection::NextUnique,
991 index: "by_status".to_string(),
992 ..Default::default()
993 });
994
995 snapshot
996 .load(
997 vec![
998 entry(
999 Key::Array(vec![Key::from("todo")]),
1000 "issue-2",
1001 Key::from("issue-2"),
1002 ),
1003 entry(
1004 Key::Array(vec![Key::from("done")]),
1005 "issue-3",
1006 Key::from("issue-3"),
1007 ),
1008 entry(
1009 Key::Array(vec![Key::from("todo")]),
1010 "issue-1",
1011 Key::from("issue-1"),
1012 ),
1013 ],
1014 Some(&KeyRange {
1015 lower: Some(Key::Array(vec![Key::from("done")])),
1016 upper: Some(Key::Array(vec![Key::from("todo")])),
1017 lower_open: false,
1018 upper_open: false,
1019 }),
1020 )
1021 .expect("load");
1022
1023 assert_eq!(
1024 snapshot.next().expect("first").unwrap().primary_key,
1025 "issue-3"
1026 );
1027 assert_eq!(
1028 snapshot.next().expect("second").unwrap().primary_key,
1029 "issue-1"
1030 );
1031 assert!(snapshot.next().expect("exhausted").is_none());
1032 }
1033
1034 #[test]
1035 fn cursor_snapshot_advance_moves_exactly_count_entries_from_current_position() {
1036 let mut snapshot = new_indexeddb_cursor_snapshot(&IndexedDBOpenCursorRequest::default());
1037 snapshot
1038 .load(
1039 vec![
1040 entry(Key::from("a"), "a", Key::from("a")),
1041 entry(Key::from("b"), "b", Key::from("b")),
1042 entry(Key::from("c"), "c", Key::from("c")),
1043 ],
1044 None,
1045 )
1046 .expect("load");
1047
1048 assert_eq!(snapshot.next().expect("first").unwrap().primary_key, "a");
1049 assert_eq!(
1050 snapshot.advance(1).expect("second").unwrap().primary_key,
1051 "b"
1052 );
1053 assert_eq!(
1054 snapshot.advance(1).expect("third").unwrap().primary_key,
1055 "c"
1056 );
1057 }
1058
1059 #[test]
1060 fn cursor_snapshot_index_range_accepts_scalar_entry_keys() {
1061 let mut snapshot = new_indexeddb_cursor_snapshot(&IndexedDBOpenCursorRequest {
1062 index: "by_status".to_string(),
1063 ..Default::default()
1064 });
1065 snapshot
1066 .load(
1067 vec![
1068 entry(Key::from("done"), "issue-2", Key::from("issue-2")),
1069 entry(Key::from("active"), "issue-1", Key::from("issue-1")),
1070 ],
1071 Some(&KeyRange {
1072 lower: Some(Key::from("active")),
1073 upper: Some(Key::from("active")),
1074 lower_open: false,
1075 upper_open: false,
1076 }),
1077 )
1078 .expect("load");
1079
1080 let first = snapshot.next().expect("first").unwrap();
1081 assert_eq!(first.primary_key, "issue-1");
1082 assert_eq!(first.key, Key::from("active"));
1083 assert!(snapshot.next().expect("exhausted").is_none());
1084 }
1085
1086 #[test]
1087 fn range_bounds_normalize_scalar_index_bounds() {
1088 let (lower, upper) = indexeddb_range_bounds(
1089 Some(&KeyRange {
1090 lower: Some(Key::from("active")),
1091 upper: Some(Key::Array(vec![Key::from("done")])),
1092 lower_open: false,
1093 upper_open: false,
1094 }),
1095 true,
1096 );
1097
1098 assert_eq!(lower, Some(Key::Array(vec![Key::from("active")])));
1099 assert_eq!(upper, Some(Key::Array(vec![Key::from("done")])));
1100 }
1101
1102 #[test]
1103 fn compare_values_orders_composite_keys() {
1104 assert_eq!(
1105 compare_indexeddb_values(
1106 &Key::Array(vec![Key::from("active"), Key::Int(1)]),
1107 &Key::Array(vec![Key::from("active"), Key::Int(2)])
1108 ),
1109 Ordering::Less
1110 );
1111 assert_eq!(
1112 compare_indexeddb_values(
1113 &Key::Array(vec![Key::from("active"), Key::Int(2)]),
1114 &Key::Array(vec![Key::from("active"), Key::Int(2)])
1115 ),
1116 Ordering::Equal
1117 );
1118 assert_eq!(
1119 compare_indexeddb_values(
1120 &Key::Array(vec![Key::from("active"), Key::Int(3)]),
1121 &Key::Array(vec![Key::from("active"), Key::Int(2)])
1122 ),
1123 Ordering::Greater
1124 );
1125 }
1126
1127 #[test]
1128 fn compare_values_orders_large_integer_keys_exactly() {
1129 assert_eq!(
1130 compare_indexeddb_values(
1131 &Key::Int(9_007_199_254_740_993),
1132 &Key::Int(9_007_199_254_740_992)
1133 ),
1134 Ordering::Greater
1135 );
1136 assert_eq!(
1137 compare_indexeddb_values(&Key::Int(i64::MAX), &Key::Float(u64::MAX as f64)),
1138 Ordering::Less
1139 );
1140 }
1141
1142 #[test]
1143 fn compare_keys_orders_date_before_string_and_bytes_after_string() {
1144 let date = Key::Date(UNIX_EPOCH + Duration::from_secs(1_700_000_000));
1145 assert_eq!(compare_keys(&Key::Int(1), &date), Ordering::Less);
1146 assert_eq!(compare_keys(&date, &Key::from("a")), Ordering::Less);
1147 assert_eq!(
1148 compare_keys(&Key::from("a"), &Key::Bytes(vec![0x00])),
1149 Ordering::Less
1150 );
1151 }
1152
1153 #[test]
1154 fn date_and_bytes_keys_match_exact_queries() {
1155 let date = Key::Date(UNIX_EPOCH + Duration::from_secs(1_700_000_000));
1156 let bytes = Key::Bytes(vec![0x01, 0x02]);
1157 assert!(match_query(&date, &Query::Key(date.clone())));
1158 assert!(match_query(&bytes, &Query::Key(bytes.clone())));
1159 assert!(key_in_range(
1160 &date,
1161 &KeyRange {
1162 lower: Some(date.clone()),
1163 upper: Some(date.clone()),
1164 lower_open: false,
1165 upper_open: false,
1166 }
1167 ));
1168 }
1169}
1170
1171pub struct Cursor {
1173 tx: mpsc::Sender<pb::CursorClientMessage>,
1174 stream: tonic::Streaming<pb::CursorResponse>,
1175 keys_only: bool,
1176 entry: Option<pb::CursorEntry>,
1177 done: bool,
1178}
1179
1180impl Cursor {
1181 pub fn key(&self) -> Option<Key> {
1183 let entry = self.entry.as_ref()?;
1184 entry
1185 .key
1186 .as_ref()
1187 .map(crate::indexeddb_query_codec::key_from_wire_key_value)
1188 }
1189
1190 pub fn primary_key(&self) -> &str {
1192 self.entry
1193 .as_ref()
1194 .map(|e| e.primary_key.as_str())
1195 .unwrap_or("")
1196 }
1197
1198 pub fn value(&self) -> Result<Record, IndexedDBError> {
1200 if self.keys_only {
1201 return Err(IndexedDBError::KeysOnly);
1202 }
1203 let entry = self.entry.as_ref().ok_or(IndexedDBError::NotFound)?;
1204 Ok(entry
1205 .record
1206 .as_ref()
1207 .map(pb_record_to_record)
1208 .unwrap_or_default())
1209 }
1210
1211 pub async fn continue_next(&mut self) -> Result<bool, IndexedDBError> {
1213 let cmd = pb::cursor_command::Command::Next(true);
1214 self.send_and_recv(cmd).await
1215 }
1216
1217 pub async fn continue_to_key(&mut self, key: impl Into<Key>) -> Result<bool, IndexedDBError> {
1219 let key = key.into();
1220 let cmd = pb::cursor_command::Command::ContinueToKey(pb::CursorKeyTarget {
1221 key: Some(crate::indexeddb_query_codec::cursor_key_to_proto(&key)),
1222 });
1223 self.send_and_recv(cmd).await
1224 }
1225
1226 pub async fn advance(&mut self, count: i32) -> Result<bool, IndexedDBError> {
1228 let cmd = pb::cursor_command::Command::Advance(count);
1229 self.send_and_recv(cmd).await
1230 }
1231
1232 pub async fn delete(&mut self) -> Result<(), IndexedDBError> {
1234 if self.done {
1235 return Err(IndexedDBError::NotFound);
1236 }
1237 let cmd = pb::cursor_command::Command::Delete(true);
1238 self.send_mutation(cmd).await
1239 }
1240
1241 pub async fn update(&mut self, value: Record) -> Result<(), IndexedDBError> {
1243 if self.done {
1244 return Err(IndexedDBError::NotFound);
1245 }
1246 let cmd = pb::cursor_command::Command::Update(record_to_pb_record(value));
1247 self.send_mutation(cmd).await
1248 }
1249
1250 pub async fn close(self) -> Result<(), IndexedDBError> {
1252 let msg = pb::CursorClientMessage {
1253 msg: Some(pb::cursor_client_message::Msg::Command(pb::CursorCommand {
1254 command: Some(pb::cursor_command::Command::Close(true)),
1255 })),
1256 };
1257 self.tx
1258 .send(msg)
1259 .await
1260 .map_err(|e| IndexedDBError::Status(tonic::Status::internal(e.to_string())))?;
1261 Ok(())
1262 }
1263
1264 async fn send_mutation(
1265 &mut self,
1266 cmd: pb::cursor_command::Command,
1267 ) -> Result<(), IndexedDBError> {
1268 let msg = pb::CursorClientMessage {
1269 msg: Some(pb::cursor_client_message::Msg::Command(pb::CursorCommand {
1270 command: Some(cmd),
1271 })),
1272 };
1273 self.tx
1274 .send(msg)
1275 .await
1276 .map_err(|e| IndexedDBError::Status(tonic::Status::internal(e.to_string())))?;
1277 let resp = self
1279 .stream
1280 .message()
1281 .await
1282 .map_err(map_status)?
1283 .ok_or_else(|| {
1284 IndexedDBError::Status(tonic::Status::internal(
1285 "cursor stream ended during mutation",
1286 ))
1287 })?;
1288 match resp.result {
1289 Some(pb::cursor_response::Result::Entry(entry)) => {
1290 self.entry = Some(entry);
1291 }
1292 Some(pb::cursor_response::Result::Done(_)) => {}
1293 None => {
1294 return Err(IndexedDBError::Status(tonic::Status::internal(
1295 "unexpected cursor mutation ack",
1296 )));
1297 }
1298 }
1299 Ok(())
1300 }
1301
1302 async fn send_and_recv(
1303 &mut self,
1304 cmd: pb::cursor_command::Command,
1305 ) -> Result<bool, IndexedDBError> {
1306 if self.done {
1307 return Ok(false);
1308 }
1309 let msg = pb::CursorClientMessage {
1310 msg: Some(pb::cursor_client_message::Msg::Command(pb::CursorCommand {
1311 command: Some(cmd),
1312 })),
1313 };
1314 self.tx
1315 .send(msg)
1316 .await
1317 .map_err(|e| IndexedDBError::Status(tonic::Status::internal(e.to_string())))?;
1318
1319 let resp = self
1320 .stream
1321 .message()
1322 .await
1323 .map_err(map_status)?
1324 .ok_or_else(|| {
1325 IndexedDBError::Status(tonic::Status::internal("cursor stream ended"))
1326 })?;
1327
1328 match resp.result {
1329 Some(pb::cursor_response::Result::Entry(entry)) => {
1330 self.entry = Some(entry);
1331 self.done = false;
1332 Ok(true)
1333 }
1334 Some(pb::cursor_response::Result::Done(exhausted)) => {
1335 if exhausted {
1336 self.done = true;
1337 }
1338 self.entry = None;
1339 Ok(false)
1340 }
1341 None => {
1342 self.entry = None;
1343 self.done = true;
1344 Ok(false)
1345 }
1346 }
1347 }
1348}
1349
1350async fn open_cursor_inner(
1351 client: &mut IndexedDbClient<IndexedDbTransport>,
1352 req: pb::OpenCursorRequest,
1353) -> Result<Cursor, IndexedDBError> {
1354 let keys_only = req.keys_only;
1355 let (tx, rx) = mpsc::channel::<pb::CursorClientMessage>(CURSOR_CHANNEL_BUFFER);
1356
1357 let open_msg = pb::CursorClientMessage {
1358 msg: Some(pb::cursor_client_message::Msg::Open(req)),
1359 };
1360 tx.send(open_msg)
1361 .await
1362 .map_err(|e| IndexedDBError::Status(tonic::Status::internal(e.to_string())))?;
1363
1364 let receiver_stream = ReceiverStream::new(rx);
1365 let mut stream = client
1366 .open_cursor(receiver_stream)
1367 .await
1368 .map_err(map_status)?
1369 .into_inner();
1370
1371 let ack = stream.message().await.map_err(map_status)?.ok_or_else(|| {
1373 IndexedDBError::Status(tonic::Status::internal("cursor stream ended during open"))
1374 })?;
1375 match ack.result {
1376 Some(pb::cursor_response::Result::Done(false)) => {}
1377 Some(pb::cursor_response::Result::Done(true)) => {
1378 return Err(IndexedDBError::Status(tonic::Status::internal(
1379 "unexpected exhausted cursor open ack",
1380 )));
1381 }
1382 _ => {
1383 return Err(IndexedDBError::Status(tonic::Status::internal(
1384 "unexpected cursor open ack",
1385 )));
1386 }
1387 }
1388
1389 Ok(Cursor {
1390 tx,
1391 stream,
1392 keys_only,
1393 entry: None,
1394 done: false,
1395 })
1396}
1397
1398pub struct IndexedDB {
1400 client: IndexedDbClient<IndexedDbTransport>,
1401}
1402
1403impl IndexedDB {
1404 pub async fn connect() -> Result<Self, IndexedDBError> {
1406 Self::connect_named("").await
1407 }
1408
1409 pub async fn connect_named(name: &str) -> Result<Self, IndexedDBError> {
1411 host_service_configured("indexeddb").map_err(IndexedDBError::Env)?;
1412 let target = std::env::var(ENV_HOST_SERVICE_SOCKET)
1413 .map_err(|_| IndexedDBError::Env(format!("{ENV_HOST_SERVICE_SOCKET} is not set")))?;
1414 let token = std::env::var(ENV_HOST_SERVICE_TOKEN).unwrap_or_default();
1415 let channel = match parse_indexeddb_target(&target)? {
1416 IndexedDBTarget::Unix(path) => {
1417 Endpoint::try_from("http://[::]:50051")?
1418 .connect_with_connector(service_fn(move |_: Uri| {
1419 let path = path.clone();
1420 async move {
1421 tokio::net::UnixStream::connect(path)
1422 .await
1423 .map(TokioIo::new)
1424 }
1425 }))
1426 .await?
1427 }
1428 IndexedDBTarget::Tcp(address) => {
1429 Endpoint::from_shared(format!("http://{address}"))?
1430 .connect()
1431 .await?
1432 }
1433 IndexedDBTarget::Tls(address) => {
1434 Endpoint::from_shared(format!("https://{address}"))?
1435 .tls_config(ClientTlsConfig::new().with_native_roots())?
1436 .connect()
1437 .await?
1438 }
1439 };
1440
1441 let client = IndexedDbClient::with_interceptor(
1442 channel,
1443 relay_token_interceptor(token.trim(), name)?,
1444 );
1445
1446 Ok(Self { client })
1447 }
1448
1449 pub async fn create_object_store(
1451 &mut self,
1452 name: &str,
1453 schema: ObjectStoreSchema,
1454 ) -> Result<ObjectStore, IndexedDBError> {
1455 let indexes = schema
1456 .indexes
1457 .into_iter()
1458 .map(|idx| pb::IndexSchema {
1459 name: idx.name,
1460 key_path: idx.key_path,
1461 unique: idx.unique,
1462 })
1463 .collect();
1464 self.client
1465 .create_object_store(pb::CreateObjectStoreRequest {
1466 name: name.to_string(),
1467 schema: Some(pb::ObjectStoreSchema {
1468 indexes,
1469 columns: vec![],
1470 }),
1471 })
1472 .await
1473 .map_err(map_status)?;
1474 Ok(self.object_store(name))
1475 }
1476
1477 pub async fn delete_object_store(&mut self, name: &str) -> Result<(), IndexedDBError> {
1479 self.client
1480 .delete_object_store(pb::DeleteObjectStoreRequest {
1481 name: name.to_string(),
1482 })
1483 .await
1484 .map_err(map_status)?;
1485 Ok(())
1486 }
1487
1488 pub fn object_store(&self, name: &str) -> ObjectStore {
1490 ObjectStore {
1491 client: self.client.clone(),
1492 store: name.to_string(),
1493 }
1494 }
1495
1496 pub async fn transaction(
1498 &self,
1499 stores: &[&str],
1500 mode: TransactionMode,
1501 options: TransactionOptions,
1502 ) -> Result<Transaction, IndexedDBError> {
1503 let (tx, rx) = mpsc::channel::<pb::TransactionClientMessage>(TRANSACTION_CHANNEL_BUFFER);
1504 tx.send(pb::TransactionClientMessage {
1505 msg: Some(pb::transaction_client_message::Msg::Begin(
1506 pb::BeginTransactionRequest {
1507 stores: stores.iter().map(|store| store.to_string()).collect(),
1508 mode: mode.to_proto(),
1509 durability_hint: options.durability_hint.to_proto(),
1510 },
1511 )),
1512 })
1513 .await
1514 .map_err(|e| IndexedDBError::Status(tonic::Status::internal(e.to_string())))?;
1515
1516 let receiver_stream = ReceiverStream::new(rx);
1517 let mut client = self.client.clone();
1518 let mut stream = client
1519 .transaction(receiver_stream)
1520 .await
1521 .map_err(map_status)?
1522 .into_inner();
1523
1524 let ack = stream.message().await.map_err(map_status)?.ok_or_else(|| {
1525 IndexedDBError::Transaction("transaction stream ended during begin".to_string())
1526 })?;
1527 match ack.msg {
1528 Some(pb::transaction_server_message::Msg::Begin(_)) => {}
1529 _ => {
1530 return Err(IndexedDBError::Transaction(
1531 "expected transaction begin response".to_string(),
1532 ));
1533 }
1534 }
1535
1536 Ok(Transaction {
1537 tx: Some(tx),
1538 stream,
1539 request_id: 0,
1540 closed: false,
1541 })
1542 }
1543}
1544
1545pub struct Transaction {
1547 tx: Option<mpsc::Sender<pb::TransactionClientMessage>>,
1548 stream: tonic::Streaming<pb::TransactionServerMessage>,
1549 request_id: u64,
1550 closed: bool,
1551}
1552
1553impl Transaction {
1554 pub fn object_store<'a>(&'a mut self, name: &str) -> TransactionObjectStore<'a> {
1556 TransactionObjectStore {
1557 tx: self,
1558 store: name.to_string(),
1559 }
1560 }
1561
1562 pub async fn commit(&mut self) -> Result<(), IndexedDBError> {
1564 self.ensure_open()?;
1565 let tx = self.tx.as_ref().ok_or_else(|| {
1566 IndexedDBError::Transaction("transaction is already finished".to_string())
1567 })?;
1568 tx.send(pb::TransactionClientMessage {
1569 msg: Some(pb::transaction_client_message::Msg::Commit(
1570 pb::TransactionCommitRequest {},
1571 )),
1572 })
1573 .await
1574 .map_err(|e| IndexedDBError::Status(tonic::Status::internal(e.to_string())))?;
1575 self.closed = true;
1576 self.tx.take();
1577
1578 let resp = self
1579 .stream
1580 .message()
1581 .await
1582 .map_err(map_status)?
1583 .ok_or_else(|| {
1584 IndexedDBError::Transaction("transaction stream ended during commit".to_string())
1585 })?;
1586 match resp.msg {
1587 Some(pb::transaction_server_message::Msg::Commit(commit)) => {
1588 map_rpc_status(commit.error)
1589 }
1590 _ => Err(IndexedDBError::Transaction(
1591 "expected transaction commit response".to_string(),
1592 )),
1593 }
1594 }
1595
1596 pub async fn abort(&mut self, reason: &str) -> Result<(), IndexedDBError> {
1598 if self.closed {
1599 return Ok(());
1600 }
1601 let tx = self.tx.as_ref().ok_or_else(|| {
1602 IndexedDBError::Transaction("transaction is already finished".to_string())
1603 })?;
1604 tx.send(pb::TransactionClientMessage {
1605 msg: Some(pb::transaction_client_message::Msg::Abort(
1606 pb::TransactionAbortRequest {
1607 reason: reason.to_string(),
1608 },
1609 )),
1610 })
1611 .await
1612 .map_err(|e| IndexedDBError::Status(tonic::Status::internal(e.to_string())))?;
1613 self.closed = true;
1614 self.tx.take();
1615
1616 let resp = self
1617 .stream
1618 .message()
1619 .await
1620 .map_err(map_status)?
1621 .ok_or_else(|| {
1622 IndexedDBError::Transaction("transaction stream ended during abort".to_string())
1623 })?;
1624 match resp.msg {
1625 Some(pb::transaction_server_message::Msg::Abort(abort)) => map_rpc_status(abort.error),
1626 _ => Err(IndexedDBError::Transaction(
1627 "expected transaction abort response".to_string(),
1628 )),
1629 }
1630 }
1631
1632 async fn send_operation(
1633 &mut self,
1634 operation: pb::transaction_operation::Operation,
1635 ) -> Result<pb::TransactionOperationResponse, IndexedDBError> {
1636 self.ensure_open()?;
1637 self.request_id += 1;
1638 let request_id = self.request_id;
1639 let tx = self.tx.as_ref().ok_or_else(|| {
1640 IndexedDBError::Transaction("transaction is already finished".to_string())
1641 })?;
1642 tx.send(pb::TransactionClientMessage {
1643 msg: Some(pb::transaction_client_message::Msg::Operation(
1644 pb::TransactionOperation {
1645 request_id,
1646 operation: Some(operation),
1647 },
1648 )),
1649 })
1650 .await
1651 .map_err(|e| IndexedDBError::Status(tonic::Status::internal(e.to_string())))?;
1652
1653 let resp = self
1654 .stream
1655 .message()
1656 .await
1657 .map_err(map_status)?
1658 .ok_or_else(|| {
1659 IndexedDBError::Transaction("transaction stream ended during operation".to_string())
1660 })?;
1661 let op = match resp.msg {
1662 Some(pb::transaction_server_message::Msg::Operation(op)) => op,
1663 _ => {
1664 self.close_locally();
1665 return Err(IndexedDBError::Transaction(
1666 "expected transaction operation response".to_string(),
1667 ));
1668 }
1669 };
1670 if op.request_id != request_id {
1671 self.close_locally();
1672 return Err(IndexedDBError::Transaction(
1673 "transaction response request id mismatch".to_string(),
1674 ));
1675 }
1676 if let Err(err) = map_rpc_status(op.error.clone()) {
1677 self.close_locally();
1678 return Err(err);
1679 }
1680 Ok(op)
1681 }
1682
1683 fn ensure_open(&self) -> Result<(), IndexedDBError> {
1684 if self.closed {
1685 return Err(IndexedDBError::Transaction(
1686 "transaction is already finished".to_string(),
1687 ));
1688 }
1689 Ok(())
1690 }
1691
1692 fn close_locally(&mut self) {
1693 self.closed = true;
1694 self.tx.take();
1695 }
1696}
1697
1698pub struct TransactionObjectStore<'a> {
1700 tx: &'a mut Transaction,
1701 store: String,
1702}
1703
1704impl TransactionObjectStore<'_> {
1705 pub async fn get(&mut self, id: &str) -> Result<Record, IndexedDBError> {
1707 let resp = self
1708 .tx
1709 .send_operation(pb::transaction_operation::Operation::Get(
1710 pb::ObjectStoreRequest {
1711 store: self.store.clone(),
1712 id: id.to_string(),
1713 },
1714 ))
1715 .await?;
1716 match resp.result {
1717 Some(pb::transaction_operation_response::Result::Record(record)) => Ok(record
1718 .record
1719 .as_ref()
1720 .map(pb_record_to_record)
1721 .unwrap_or_default()),
1722 _ => Err(unexpected_transaction_result()),
1723 }
1724 }
1725
1726 pub async fn get_key(&mut self, id: &str) -> Result<String, IndexedDBError> {
1728 let resp = self
1729 .tx
1730 .send_operation(pb::transaction_operation::Operation::GetKey(
1731 pb::ObjectStoreRequest {
1732 store: self.store.clone(),
1733 id: id.to_string(),
1734 },
1735 ))
1736 .await?;
1737 match resp.result {
1738 Some(pb::transaction_operation_response::Result::Key(key)) => Ok(key.key),
1739 _ => Err(unexpected_transaction_result()),
1740 }
1741 }
1742
1743 pub async fn add(&mut self, record: Record) -> Result<(), IndexedDBError> {
1745 self.tx
1746 .send_operation(pb::transaction_operation::Operation::Add(
1747 pb::RecordRequest {
1748 store: self.store.clone(),
1749 record: Some(record_to_pb_record(record)),
1750 },
1751 ))
1752 .await?;
1753 Ok(())
1754 }
1755
1756 pub async fn put(&mut self, record: Record) -> Result<(), IndexedDBError> {
1758 self.tx
1759 .send_operation(pb::transaction_operation::Operation::Put(
1760 pb::RecordRequest {
1761 store: self.store.clone(),
1762 record: Some(record_to_pb_record(record)),
1763 },
1764 ))
1765 .await?;
1766 Ok(())
1767 }
1768
1769 pub async fn delete(&mut self, id: &str) -> Result<(), IndexedDBError> {
1771 self.tx
1772 .send_operation(pb::transaction_operation::Operation::Delete(
1773 pb::ObjectStoreRequest {
1774 store: self.store.clone(),
1775 id: id.to_string(),
1776 },
1777 ))
1778 .await?;
1779 Ok(())
1780 }
1781
1782 pub async fn clear(&mut self) -> Result<(), IndexedDBError> {
1784 self.tx
1785 .send_operation(pb::transaction_operation::Operation::Clear(
1786 pb::ObjectStoreNameRequest {
1787 store: self.store.clone(),
1788 },
1789 ))
1790 .await?;
1791 Ok(())
1792 }
1793
1794 pub async fn get_all(
1796 &mut self,
1797 query: impl Into<Query>,
1798 count: Option<u32>,
1799 ) -> Result<Vec<Record>, IndexedDBError> {
1800 let query = query.into();
1801 let resp = self
1802 .tx
1803 .send_operation(pb::transaction_operation::Operation::GetAll(
1804 pb::ObjectStoreRangeRequest {
1805 store: self.store.clone(),
1806 query: query.to_proto(),
1807 count,
1808 },
1809 ))
1810 .await?;
1811 match resp.result {
1812 Some(pb::transaction_operation_response::Result::Records(records)) => {
1813 Ok(records.records.iter().map(pb_record_to_record).collect())
1814 }
1815 _ => Err(unexpected_transaction_result()),
1816 }
1817 }
1818
1819 pub async fn get_all_keys(
1821 &mut self,
1822 query: impl Into<Query>,
1823 count: Option<u32>,
1824 ) -> Result<Vec<String>, IndexedDBError> {
1825 let query = query.into();
1826 let resp = self
1827 .tx
1828 .send_operation(pb::transaction_operation::Operation::GetAllKeys(
1829 pb::ObjectStoreRangeRequest {
1830 store: self.store.clone(),
1831 query: query.to_proto(),
1832 count,
1833 },
1834 ))
1835 .await?;
1836 match resp.result {
1837 Some(pb::transaction_operation_response::Result::Keys(keys)) => Ok(keys.keys),
1838 _ => Err(unexpected_transaction_result()),
1839 }
1840 }
1841
1842 pub async fn count(&mut self, query: impl Into<Query>) -> Result<i64, IndexedDBError> {
1844 let query = query.into();
1845 let resp = self
1846 .tx
1847 .send_operation(pb::transaction_operation::Operation::Count(
1848 pb::ObjectStoreRangeRequest {
1849 store: self.store.clone(),
1850 query: query.to_proto(),
1851 count: None,
1852 },
1853 ))
1854 .await?;
1855 match resp.result {
1856 Some(pb::transaction_operation_response::Result::Count(count)) => Ok(count.count),
1857 _ => Err(unexpected_transaction_result()),
1858 }
1859 }
1860
1861 pub async fn delete_range(&mut self, query: impl Into<Query>) -> Result<i64, IndexedDBError> {
1863 let query = query.into();
1864 let resp = self
1865 .tx
1866 .send_operation(pb::transaction_operation::Operation::DeleteRange(
1867 pb::ObjectStoreRangeRequest {
1868 store: self.store.clone(),
1869 query: query.to_proto(),
1870 count: None,
1871 },
1872 ))
1873 .await?;
1874 match resp.result {
1875 Some(pb::transaction_operation_response::Result::Delete(deleted)) => {
1876 Ok(deleted.deleted)
1877 }
1878 _ => Err(unexpected_transaction_result()),
1879 }
1880 }
1881
1882 pub fn index<'a>(&'a mut self, name: &str) -> TransactionIndex<'a> {
1884 TransactionIndex {
1885 tx: &mut *self.tx,
1886 store: self.store.clone(),
1887 index: name.to_string(),
1888 }
1889 }
1890}
1891
1892pub struct TransactionIndex<'a> {
1894 tx: &'a mut Transaction,
1895 store: String,
1896 index: String,
1897}
1898
1899impl TransactionIndex<'_> {
1900 pub async fn get(&mut self, query: impl Into<Query>) -> Result<Record, IndexedDBError> {
1902 let resp = self
1903 .tx
1904 .send_operation(pb::transaction_operation::Operation::IndexGet(
1905 self.index_request(query.into(), None),
1906 ))
1907 .await?;
1908 match resp.result {
1909 Some(pb::transaction_operation_response::Result::Record(record)) => Ok(record
1910 .record
1911 .as_ref()
1912 .map(pb_record_to_record)
1913 .unwrap_or_default()),
1914 _ => Err(unexpected_transaction_result()),
1915 }
1916 }
1917
1918 pub async fn get_key(&mut self, query: impl Into<Query>) -> Result<String, IndexedDBError> {
1920 let resp = self
1921 .tx
1922 .send_operation(pb::transaction_operation::Operation::IndexGetKey(
1923 self.index_request(query.into(), None),
1924 ))
1925 .await?;
1926 match resp.result {
1927 Some(pb::transaction_operation_response::Result::Key(key)) => Ok(key.key),
1928 _ => Err(unexpected_transaction_result()),
1929 }
1930 }
1931
1932 pub async fn get_all(
1934 &mut self,
1935 query: impl Into<Query>,
1936 count: Option<u32>,
1937 ) -> Result<Vec<Record>, IndexedDBError> {
1938 let resp = self
1939 .tx
1940 .send_operation(pb::transaction_operation::Operation::IndexGetAll(
1941 self.index_request(query.into(), count),
1942 ))
1943 .await?;
1944 match resp.result {
1945 Some(pb::transaction_operation_response::Result::Records(records)) => {
1946 Ok(records.records.iter().map(pb_record_to_record).collect())
1947 }
1948 _ => Err(unexpected_transaction_result()),
1949 }
1950 }
1951
1952 pub async fn get_all_keys(
1954 &mut self,
1955 query: impl Into<Query>,
1956 count: Option<u32>,
1957 ) -> Result<Vec<String>, IndexedDBError> {
1958 let resp = self
1959 .tx
1960 .send_operation(pb::transaction_operation::Operation::IndexGetAllKeys(
1961 self.index_request(query.into(), count),
1962 ))
1963 .await?;
1964 match resp.result {
1965 Some(pb::transaction_operation_response::Result::Keys(keys)) => Ok(keys.keys),
1966 _ => Err(unexpected_transaction_result()),
1967 }
1968 }
1969
1970 pub async fn count(&mut self, query: impl Into<Query>) -> Result<i64, IndexedDBError> {
1972 let resp = self
1973 .tx
1974 .send_operation(pb::transaction_operation::Operation::IndexCount(
1975 self.index_request(query.into(), None),
1976 ))
1977 .await?;
1978 match resp.result {
1979 Some(pb::transaction_operation_response::Result::Count(count)) => Ok(count.count),
1980 _ => Err(unexpected_transaction_result()),
1981 }
1982 }
1983
1984 pub async fn delete(&mut self, query: impl Into<Query>) -> Result<i64, IndexedDBError> {
1986 let resp = self
1987 .tx
1988 .send_operation(pb::transaction_operation::Operation::IndexDelete(
1989 self.index_request(query.into(), None),
1990 ))
1991 .await?;
1992 match resp.result {
1993 Some(pb::transaction_operation_response::Result::Delete(deleted)) => {
1994 Ok(deleted.deleted)
1995 }
1996 _ => Err(unexpected_transaction_result()),
1997 }
1998 }
1999
2000 fn index_request(&self, query: Query, count: Option<u32>) -> pb::IndexQueryRequest {
2001 pb::IndexQueryRequest {
2002 store: self.store.clone(),
2003 index: self.index.clone(),
2004 query: query.to_proto(),
2005 count,
2006 }
2007 }
2008}
2009
2010enum IndexedDBTarget {
2011 Unix(String),
2012 Tcp(String),
2013 Tls(String),
2014}
2015
2016fn parse_indexeddb_target(raw_target: &str) -> Result<IndexedDBTarget, IndexedDBError> {
2017 let target = raw_target.trim();
2018 if target.is_empty() {
2019 return Err(IndexedDBError::Env(
2020 "IndexedDB transport target is required".to_string(),
2021 ));
2022 }
2023 if let Some(address) = target.strip_prefix("tcp://") {
2024 let address = address.trim();
2025 if address.is_empty() {
2026 return Err(IndexedDBError::Env(format!(
2027 "IndexedDB tcp target {raw_target:?} is missing host:port"
2028 )));
2029 }
2030 return Ok(IndexedDBTarget::Tcp(address.to_string()));
2031 }
2032 if let Some(address) = target.strip_prefix("tls://") {
2033 let address = address.trim();
2034 if address.is_empty() {
2035 return Err(IndexedDBError::Env(format!(
2036 "IndexedDB tls target {raw_target:?} is missing host:port"
2037 )));
2038 }
2039 return Ok(IndexedDBTarget::Tls(address.to_string()));
2040 }
2041 if let Some(path) = target.strip_prefix("unix://") {
2042 let path = path.trim();
2043 if path.is_empty() {
2044 return Err(IndexedDBError::Env(format!(
2045 "IndexedDB unix target {raw_target:?} is missing a socket path"
2046 )));
2047 }
2048 return Ok(IndexedDBTarget::Unix(path.to_string()));
2049 }
2050 if target.contains("://") {
2051 let scheme = target.split("://").next().unwrap_or_default();
2052 return Err(IndexedDBError::Env(format!(
2053 "unsupported IndexedDB target scheme {scheme:?}"
2054 )));
2055 }
2056 Ok(IndexedDBTarget::Unix(target.to_string()))
2057}
2058
2059pub struct ObjectStore {
2061 client: IndexedDbClient<IndexedDbTransport>,
2062 store: String,
2063}
2064
2065impl ObjectStore {
2066 pub async fn get(&mut self, id: &str) -> Result<Record, IndexedDBError> {
2068 let resp = self
2069 .client
2070 .get(pb::ObjectStoreRequest {
2071 store: self.store.clone(),
2072 id: id.to_string(),
2073 })
2074 .await
2075 .map_err(map_status)?;
2076 Ok(resp
2077 .into_inner()
2078 .record
2079 .as_ref()
2080 .map(pb_record_to_record)
2081 .unwrap_or_default())
2082 }
2083
2084 pub async fn get_key(&mut self, id: &str) -> Result<String, IndexedDBError> {
2086 let resp = self
2087 .client
2088 .get_key(pb::ObjectStoreRequest {
2089 store: self.store.clone(),
2090 id: id.to_string(),
2091 })
2092 .await
2093 .map_err(map_status)?;
2094 Ok(resp.into_inner().key)
2095 }
2096
2097 pub async fn add(&mut self, record: Record) -> Result<(), IndexedDBError> {
2099 self.client
2100 .add(pb::RecordRequest {
2101 store: self.store.clone(),
2102 record: Some(record_to_pb_record(record)),
2103 })
2104 .await
2105 .map_err(map_status)?;
2106 Ok(())
2107 }
2108
2109 pub async fn put(&mut self, record: Record) -> Result<(), IndexedDBError> {
2111 self.client
2112 .put(pb::RecordRequest {
2113 store: self.store.clone(),
2114 record: Some(record_to_pb_record(record)),
2115 })
2116 .await
2117 .map_err(map_status)?;
2118 Ok(())
2119 }
2120
2121 pub async fn delete(&mut self, id: &str) -> Result<(), IndexedDBError> {
2123 self.client
2124 .delete(pb::ObjectStoreRequest {
2125 store: self.store.clone(),
2126 id: id.to_string(),
2127 })
2128 .await
2129 .map_err(map_status)?;
2130 Ok(())
2131 }
2132
2133 pub async fn clear(&mut self) -> Result<(), IndexedDBError> {
2135 self.client
2136 .clear(pb::ObjectStoreNameRequest {
2137 store: self.store.clone(),
2138 })
2139 .await
2140 .map_err(map_status)?;
2141 Ok(())
2142 }
2143
2144 pub async fn get_all(
2146 &mut self,
2147 query: impl Into<Query>,
2148 count: Option<u32>,
2149 ) -> Result<Vec<Record>, IndexedDBError> {
2150 let query = query.into();
2151 let resp = self
2152 .client
2153 .get_all(pb::ObjectStoreRangeRequest {
2154 store: self.store.clone(),
2155 query: query.to_proto(),
2156 count,
2157 })
2158 .await
2159 .map_err(map_status)?;
2160 Ok(resp
2161 .into_inner()
2162 .records
2163 .iter()
2164 .map(pb_record_to_record)
2165 .collect())
2166 }
2167
2168 pub async fn get_all_keys(
2170 &mut self,
2171 query: impl Into<Query>,
2172 count: Option<u32>,
2173 ) -> Result<Vec<String>, IndexedDBError> {
2174 let query = query.into();
2175 let resp = self
2176 .client
2177 .get_all_keys(pb::ObjectStoreRangeRequest {
2178 store: self.store.clone(),
2179 query: query.to_proto(),
2180 count,
2181 })
2182 .await
2183 .map_err(map_status)?;
2184 Ok(resp.into_inner().keys)
2185 }
2186
2187 pub async fn count(&mut self, query: impl Into<Query>) -> Result<i64, IndexedDBError> {
2189 let query = query.into();
2190 let resp = self
2191 .client
2192 .count(pb::ObjectStoreRangeRequest {
2193 store: self.store.clone(),
2194 query: query.to_proto(),
2195 count: None,
2196 })
2197 .await
2198 .map_err(map_status)?;
2199 Ok(resp.into_inner().count)
2200 }
2201
2202 pub async fn delete_range(&mut self, query: impl Into<Query>) -> Result<i64, IndexedDBError> {
2204 let query = query.into();
2205 let resp = self
2206 .client
2207 .delete_range(pb::ObjectStoreRangeRequest {
2208 store: self.store.clone(),
2209 query: query.to_proto(),
2210 count: None,
2211 })
2212 .await
2213 .map_err(map_status)?;
2214 Ok(resp.into_inner().deleted)
2215 }
2216
2217 pub fn index(&self, name: &str) -> Index {
2219 Index {
2220 client: self.client.clone(),
2221 store: self.store.clone(),
2222 index: name.to_string(),
2223 }
2224 }
2225
2226 pub async fn open_cursor(
2228 &mut self,
2229 query: impl Into<Query>,
2230 direction: CursorDirection,
2231 ) -> Result<Cursor, IndexedDBError> {
2232 let query = query.into();
2233 let req = pb::OpenCursorRequest {
2234 store: self.store.clone(),
2235 index: String::new(),
2236 query: query.to_proto(),
2237 direction: direction.to_proto(),
2238 keys_only: false,
2239 };
2240 open_cursor_inner(&mut self.client, req).await
2241 }
2242
2243 pub async fn open_key_cursor(
2245 &mut self,
2246 query: impl Into<Query>,
2247 direction: CursorDirection,
2248 ) -> Result<Cursor, IndexedDBError> {
2249 let query = query.into();
2250 let req = pb::OpenCursorRequest {
2251 store: self.store.clone(),
2252 index: String::new(),
2253 query: query.to_proto(),
2254 direction: direction.to_proto(),
2255 keys_only: true,
2256 };
2257 open_cursor_inner(&mut self.client, req).await
2258 }
2259}
2260
2261pub struct Index {
2263 client: IndexedDbClient<IndexedDbTransport>,
2264 store: String,
2265 index: String,
2266}
2267
2268impl Index {
2269 fn index_request(&self, query: Query, count: Option<u32>) -> pb::IndexQueryRequest {
2270 pb::IndexQueryRequest {
2271 store: self.store.clone(),
2272 index: self.index.clone(),
2273 query: query.to_proto(),
2274 count,
2275 }
2276 }
2277
2278 pub async fn get(&mut self, query: impl Into<Query>) -> Result<Record, IndexedDBError> {
2280 let resp = self
2281 .client
2282 .index_get(self.index_request(query.into(), None))
2283 .await
2284 .map_err(map_status)?;
2285 Ok(resp
2286 .into_inner()
2287 .record
2288 .as_ref()
2289 .map(pb_record_to_record)
2290 .unwrap_or_default())
2291 }
2292
2293 pub async fn get_key(&mut self, query: impl Into<Query>) -> Result<String, IndexedDBError> {
2295 let resp = self
2296 .client
2297 .index_get_key(self.index_request(query.into(), None))
2298 .await
2299 .map_err(map_status)?;
2300 Ok(resp.into_inner().key)
2301 }
2302
2303 pub async fn get_all(
2305 &mut self,
2306 query: impl Into<Query>,
2307 count: Option<u32>,
2308 ) -> Result<Vec<Record>, IndexedDBError> {
2309 let resp = self
2310 .client
2311 .index_get_all(self.index_request(query.into(), count))
2312 .await
2313 .map_err(map_status)?;
2314 Ok(resp
2315 .into_inner()
2316 .records
2317 .iter()
2318 .map(pb_record_to_record)
2319 .collect())
2320 }
2321
2322 pub async fn get_all_keys(
2324 &mut self,
2325 query: impl Into<Query>,
2326 count: Option<u32>,
2327 ) -> Result<Vec<String>, IndexedDBError> {
2328 let resp = self
2329 .client
2330 .index_get_all_keys(self.index_request(query.into(), count))
2331 .await
2332 .map_err(map_status)?;
2333 Ok(resp.into_inner().keys)
2334 }
2335
2336 pub async fn count(&mut self, query: impl Into<Query>) -> Result<i64, IndexedDBError> {
2338 let resp = self
2339 .client
2340 .index_count(self.index_request(query.into(), None))
2341 .await
2342 .map_err(map_status)?;
2343 Ok(resp.into_inner().count)
2344 }
2345
2346 pub async fn delete(&mut self, query: impl Into<Query>) -> Result<i64, IndexedDBError> {
2348 let resp = self
2349 .client
2350 .index_delete(self.index_request(query.into(), None))
2351 .await
2352 .map_err(map_status)?;
2353 Ok(resp.into_inner().deleted)
2354 }
2355
2356 pub async fn open_cursor(
2358 &mut self,
2359 query: impl Into<Query>,
2360 direction: CursorDirection,
2361 ) -> Result<Cursor, IndexedDBError> {
2362 let query = query.into();
2363 let req = pb::OpenCursorRequest {
2364 store: self.store.clone(),
2365 index: self.index.clone(),
2366 query: query.to_proto(),
2367 direction: direction.to_proto(),
2368 keys_only: false,
2369 };
2370 open_cursor_inner(&mut self.client, req).await
2371 }
2372
2373 pub async fn open_key_cursor(
2375 &mut self,
2376 query: impl Into<Query>,
2377 direction: CursorDirection,
2378 ) -> Result<Cursor, IndexedDBError> {
2379 let query = query.into();
2380 let req = pb::OpenCursorRequest {
2381 store: self.store.clone(),
2382 index: self.index.clone(),
2383 query: query.to_proto(),
2384 direction: direction.to_proto(),
2385 keys_only: true,
2386 };
2387 open_cursor_inner(&mut self.client, req).await
2388 }
2389}
2390
2391#[async_trait]
2392impl IndexedDBApi for IndexedDB {
2393 type ObjectStore = ObjectStore;
2394 type Transaction = Transaction;
2395
2396 async fn create_object_store(
2397 &mut self,
2398 name: &str,
2399 schema: ObjectStoreSchema,
2400 ) -> Result<ObjectStore, IndexedDBError> {
2401 IndexedDB::create_object_store(self, name, schema).await
2402 }
2403
2404 async fn delete_object_store(&mut self, name: &str) -> Result<(), IndexedDBError> {
2405 IndexedDB::delete_object_store(self, name).await
2406 }
2407
2408 fn object_store(&self, name: &str) -> ObjectStore {
2409 IndexedDB::object_store(self, name)
2410 }
2411
2412 async fn transaction(
2413 &self,
2414 stores: &[&str],
2415 mode: TransactionMode,
2416 options: TransactionOptions,
2417 ) -> Result<Transaction, IndexedDBError> {
2418 IndexedDB::transaction(self, stores, mode, options).await
2419 }
2420}
2421
2422#[async_trait]
2423impl ObjectStoreApi for ObjectStore {
2424 type Index = Index;
2425 type Cursor = Cursor;
2426
2427 async fn get(&mut self, id: &str) -> Result<Record, IndexedDBError> {
2428 ObjectStore::get(self, id).await
2429 }
2430
2431 async fn get_key(&mut self, id: &str) -> Result<String, IndexedDBError> {
2432 ObjectStore::get_key(self, id).await
2433 }
2434
2435 async fn add(&mut self, record: Record) -> Result<(), IndexedDBError> {
2436 ObjectStore::add(self, record).await
2437 }
2438
2439 async fn put(&mut self, record: Record) -> Result<(), IndexedDBError> {
2440 ObjectStore::put(self, record).await
2441 }
2442
2443 async fn delete(&mut self, id: &str) -> Result<(), IndexedDBError> {
2444 ObjectStore::delete(self, id).await
2445 }
2446
2447 async fn clear(&mut self) -> Result<(), IndexedDBError> {
2448 ObjectStore::clear(self).await
2449 }
2450
2451 async fn get_all(&mut self, query: Query) -> Result<Vec<Record>, IndexedDBError> {
2452 ObjectStore::get_all(self, query, None).await
2453 }
2454
2455 async fn get_all_keys(&mut self, query: Query) -> Result<Vec<String>, IndexedDBError> {
2456 ObjectStore::get_all_keys(self, query, None).await
2457 }
2458
2459 async fn count(&mut self, query: Query) -> Result<i64, IndexedDBError> {
2460 ObjectStore::count(self, query).await
2461 }
2462
2463 async fn delete_range(&mut self, query: Query) -> Result<i64, IndexedDBError> {
2464 ObjectStore::delete_range(self, query).await
2465 }
2466
2467 fn index(&self, name: &str) -> Index {
2468 ObjectStore::index(self, name)
2469 }
2470
2471 async fn open_cursor(
2472 &mut self,
2473 query: Query,
2474 direction: CursorDirection,
2475 ) -> Result<Cursor, IndexedDBError> {
2476 ObjectStore::open_cursor(self, query, direction).await
2477 }
2478
2479 async fn open_key_cursor(
2480 &mut self,
2481 query: Query,
2482 direction: CursorDirection,
2483 ) -> Result<Cursor, IndexedDBError> {
2484 ObjectStore::open_key_cursor(self, query, direction).await
2485 }
2486}
2487
2488#[async_trait]
2489impl IndexApi for Index {
2490 type Cursor = Cursor;
2491
2492 async fn get(&mut self, query: Query) -> Result<Record, IndexedDBError> {
2493 Index::get(self, query).await
2494 }
2495
2496 async fn get_key(&mut self, query: Query) -> Result<String, IndexedDBError> {
2497 Index::get_key(self, query).await
2498 }
2499
2500 async fn get_all(&mut self, query: Query) -> Result<Vec<Record>, IndexedDBError> {
2501 Index::get_all(self, query, None).await
2502 }
2503
2504 async fn get_all_keys(&mut self, query: Query) -> Result<Vec<String>, IndexedDBError> {
2505 Index::get_all_keys(self, query, None).await
2506 }
2507
2508 async fn count(&mut self, query: Query) -> Result<i64, IndexedDBError> {
2509 Index::count(self, query).await
2510 }
2511
2512 async fn delete(&mut self, query: Query) -> Result<i64, IndexedDBError> {
2513 Index::delete(self, query).await
2514 }
2515
2516 async fn open_cursor(
2517 &mut self,
2518 query: Query,
2519 direction: CursorDirection,
2520 ) -> Result<Cursor, IndexedDBError> {
2521 Index::open_cursor(self, query, direction).await
2522 }
2523
2524 async fn open_key_cursor(
2525 &mut self,
2526 query: Query,
2527 direction: CursorDirection,
2528 ) -> Result<Cursor, IndexedDBError> {
2529 Index::open_key_cursor(self, query, direction).await
2530 }
2531}
2532
2533#[async_trait]
2534impl TransactionApi for Transaction {
2535 type ObjectStore<'a> = TransactionObjectStore<'a>;
2536
2537 fn object_store<'a>(&'a mut self, name: &str) -> TransactionObjectStore<'a> {
2538 Transaction::object_store(self, name)
2539 }
2540
2541 async fn commit(&mut self) -> Result<(), IndexedDBError> {
2542 Transaction::commit(self).await
2543 }
2544
2545 async fn abort(&mut self, reason: &str) -> Result<(), IndexedDBError> {
2546 Transaction::abort(self, reason).await
2547 }
2548}
2549
2550#[async_trait]
2551impl<'tx> TransactionObjectStoreApi for TransactionObjectStore<'tx> {
2552 type Index<'a>
2553 = TransactionIndex<'a>
2554 where
2555 Self: 'a;
2556
2557 async fn get(&mut self, id: &str) -> Result<Record, IndexedDBError> {
2558 TransactionObjectStore::get(self, id).await
2559 }
2560
2561 async fn get_key(&mut self, id: &str) -> Result<String, IndexedDBError> {
2562 TransactionObjectStore::get_key(self, id).await
2563 }
2564
2565 async fn add(&mut self, record: Record) -> Result<(), IndexedDBError> {
2566 TransactionObjectStore::add(self, record).await
2567 }
2568
2569 async fn put(&mut self, record: Record) -> Result<(), IndexedDBError> {
2570 TransactionObjectStore::put(self, record).await
2571 }
2572
2573 async fn delete(&mut self, id: &str) -> Result<(), IndexedDBError> {
2574 TransactionObjectStore::delete(self, id).await
2575 }
2576
2577 async fn clear(&mut self) -> Result<(), IndexedDBError> {
2578 TransactionObjectStore::clear(self).await
2579 }
2580
2581 async fn get_all(&mut self, query: Query) -> Result<Vec<Record>, IndexedDBError> {
2582 TransactionObjectStore::get_all(self, query, None).await
2583 }
2584
2585 async fn get_all_keys(&mut self, query: Query) -> Result<Vec<String>, IndexedDBError> {
2586 TransactionObjectStore::get_all_keys(self, query, None).await
2587 }
2588
2589 async fn count(&mut self, query: Query) -> Result<i64, IndexedDBError> {
2590 TransactionObjectStore::count(self, query).await
2591 }
2592
2593 async fn delete_range(&mut self, query: Query) -> Result<i64, IndexedDBError> {
2594 TransactionObjectStore::delete_range(self, query).await
2595 }
2596
2597 fn index<'a>(&'a mut self, name: &str) -> TransactionIndex<'a> {
2598 TransactionObjectStore::index(self, name)
2599 }
2600}
2601
2602#[async_trait]
2603impl TransactionIndexApi for TransactionIndex<'_> {
2604 async fn get(&mut self, query: Query) -> Result<Record, IndexedDBError> {
2605 TransactionIndex::get(self, query).await
2606 }
2607
2608 async fn get_key(&mut self, query: Query) -> Result<String, IndexedDBError> {
2609 TransactionIndex::get_key(self, query).await
2610 }
2611
2612 async fn get_all(&mut self, query: Query) -> Result<Vec<Record>, IndexedDBError> {
2613 TransactionIndex::get_all(self, query, None).await
2614 }
2615
2616 async fn get_all_keys(&mut self, query: Query) -> Result<Vec<String>, IndexedDBError> {
2617 TransactionIndex::get_all_keys(self, query, None).await
2618 }
2619
2620 async fn count(&mut self, query: Query) -> Result<i64, IndexedDBError> {
2621 TransactionIndex::count(self, query).await
2622 }
2623
2624 async fn delete(&mut self, query: Query) -> Result<i64, IndexedDBError> {
2625 TransactionIndex::delete(self, query).await
2626 }
2627}
2628
2629#[async_trait]
2630impl CursorApi for Cursor {
2631 fn key(&self) -> Option<Key> {
2632 Cursor::key(self)
2633 }
2634
2635 fn primary_key(&self) -> &str {
2636 Cursor::primary_key(self)
2637 }
2638
2639 fn value(&self) -> Result<Record, IndexedDBError> {
2640 Cursor::value(self)
2641 }
2642
2643 async fn continue_next(&mut self) -> Result<bool, IndexedDBError> {
2644 Cursor::continue_next(self).await
2645 }
2646
2647 async fn continue_to_key(
2648 &mut self,
2649 key: impl Into<Key> + Send,
2650 ) -> Result<bool, IndexedDBError> {
2651 Cursor::continue_to_key(self, key).await
2652 }
2653
2654 async fn advance(&mut self, count: i32) -> Result<bool, IndexedDBError> {
2655 Cursor::advance(self, count).await
2656 }
2657
2658 async fn delete(&mut self) -> Result<(), IndexedDBError> {
2659 Cursor::delete(self).await
2660 }
2661
2662 async fn update(&mut self, value: Record) -> Result<(), IndexedDBError> {
2663 Cursor::update(self, value).await
2664 }
2665
2666 async fn close(self) -> Result<(), IndexedDBError> {
2667 Cursor::close(self).await
2668 }
2669}
2670
2671fn map_status(err: tonic::Status) -> IndexedDBError {
2672 match err.code() {
2673 tonic::Code::NotFound => IndexedDBError::NotFound,
2674 tonic::Code::AlreadyExists => IndexedDBError::AlreadyExists,
2675 tonic::Code::InvalidArgument => IndexedDBError::InvalidArgument(err.message().to_string()),
2676 tonic::Code::FailedPrecondition => IndexedDBError::Transaction(err.message().to_string()),
2677 _ => IndexedDBError::Status(err),
2678 }
2679}
2680
2681fn map_rpc_status(
2682 status: Option<crate::generated::google::rpc::Status>,
2683) -> Result<(), IndexedDBError> {
2684 let Some(status) = status else {
2685 return Ok(());
2686 };
2687 match status.code {
2688 0 => Ok(()),
2689 5 => Err(IndexedDBError::NotFound),
2690 6 => Err(IndexedDBError::AlreadyExists),
2691 3 => Err(IndexedDBError::InvalidArgument(status.message)),
2692 9 => Err(IndexedDBError::Transaction(status.message)),
2693 _ => Err(IndexedDBError::Transaction(status.message)),
2694 }
2695}
2696
2697fn unexpected_transaction_result() -> IndexedDBError {
2698 IndexedDBError::Transaction("unexpected transaction operation result".to_string())
2699}
2700
2701fn record_to_pb_record(record: Record) -> pb::Record {
2702 pb::Record {
2703 fields: record
2704 .into_iter()
2705 .map(|(k, v)| (k, json_to_typed_value(&v)))
2706 .collect(),
2707 }
2708}
2709
2710fn pb_record_to_record(r: &pb::Record) -> Record {
2711 r.fields
2712 .iter()
2713 .map(|(k, v)| (k.clone(), typed_value_to_json(v)))
2714 .collect()
2715}
2716
2717fn json_to_typed_value(v: &serde_json::Value) -> pb::TypedValue {
2718 use pb::typed_value::Kind;
2719 let kind = match v {
2720 serde_json::Value::Null => Kind::NullValue(0),
2721 serde_json::Value::Bool(b) => Kind::BoolValue(*b),
2722 serde_json::Value::Number(n) => {
2723 if let Some(i) = n.as_i64() {
2724 Kind::IntValue(i)
2725 } else {
2726 Kind::FloatValue(n.as_f64().unwrap_or(0.0))
2727 }
2728 }
2729 serde_json::Value::String(s) => Kind::StringValue(s.clone()),
2730 serde_json::Value::Array(arr) => {
2731 let values = arr.iter().map(json_to_prost_value).collect();
2732 Kind::JsonValue(prost_types::Value {
2733 kind: Some(prost_types::value::Kind::ListValue(
2734 prost_types::ListValue { values },
2735 )),
2736 })
2737 }
2738 serde_json::Value::Object(obj) => {
2739 let fields = obj
2740 .iter()
2741 .map(|(k, v)| (k.clone(), json_to_prost_value(v)))
2742 .collect();
2743 Kind::JsonValue(prost_types::Value {
2744 kind: Some(prost_types::value::Kind::StructValue(prost_types::Struct {
2745 fields,
2746 })),
2747 })
2748 }
2749 };
2750 pb::TypedValue { kind: Some(kind) }
2751}
2752
2753fn prost_value_to_json(v: &prost_types::Value) -> serde_json::Value {
2754 use prost_types::value::Kind;
2755 match &v.kind {
2756 Some(Kind::NullValue(_)) => serde_json::Value::Null,
2757 Some(Kind::BoolValue(b)) => serde_json::Value::Bool(*b),
2758 Some(Kind::NumberValue(n)) => serde_json::json!(*n),
2759 Some(Kind::StringValue(s)) => serde_json::Value::String(s.clone()),
2760 Some(Kind::ListValue(list)) => {
2761 serde_json::Value::Array(list.values.iter().map(prost_value_to_json).collect())
2762 }
2763 Some(Kind::StructValue(st)) => {
2764 let obj: serde_json::Map<String, serde_json::Value> = st
2765 .fields
2766 .iter()
2767 .map(|(k, v)| (k.clone(), prost_value_to_json(v)))
2768 .collect();
2769 serde_json::Value::Object(obj)
2770 }
2771 None => serde_json::Value::Null,
2772 }
2773}
2774
2775fn json_to_prost_value(v: &serde_json::Value) -> prost_types::Value {
2776 use prost_types::value::Kind;
2777 let kind = match v {
2778 serde_json::Value::Null => Kind::NullValue(0),
2779 serde_json::Value::Bool(b) => Kind::BoolValue(*b),
2780 serde_json::Value::Number(n) => Kind::NumberValue(n.as_f64().unwrap_or(0.0)),
2781 serde_json::Value::String(s) => Kind::StringValue(s.clone()),
2782 serde_json::Value::Array(arr) => {
2783 let values = arr.iter().map(json_to_prost_value).collect();
2784 Kind::ListValue(prost_types::ListValue { values })
2785 }
2786 serde_json::Value::Object(obj) => {
2787 let fields = obj
2788 .iter()
2789 .map(|(k, v)| (k.clone(), json_to_prost_value(v)))
2790 .collect();
2791 Kind::StructValue(prost_types::Struct { fields })
2792 }
2793 };
2794 prost_types::Value { kind: Some(kind) }
2795}
2796
2797fn typed_value_to_json(v: &pb::TypedValue) -> serde_json::Value {
2798 use pb::typed_value::Kind;
2799 match &v.kind {
2800 Some(Kind::NullValue(_)) => serde_json::Value::Null,
2801 Some(Kind::BoolValue(b)) => serde_json::Value::Bool(*b),
2802 Some(Kind::IntValue(i)) => serde_json::json!(*i),
2803 Some(Kind::FloatValue(f)) => serde_json::json!(*f),
2804 Some(Kind::StringValue(s)) => serde_json::Value::String(s.clone()),
2805 Some(Kind::BytesValue(b)) => serde_json::json!(b),
2806 Some(Kind::JsonValue(pv)) => prost_value_to_json(pv),
2807 Some(Kind::TimeValue(ts)) => {
2808 serde_json::Value::String(format!("{}.{}", ts.seconds, ts.nanos))
2809 }
2810 None => serde_json::Value::Null,
2811 }
2812}
2813
2814fn relay_token_interceptor(
2815 token: &str,
2816 binding: &str,
2817) -> Result<RelayTokenInterceptor, IndexedDBError> {
2818 let relay_token = if token.trim().is_empty() {
2819 None
2820 } else {
2821 Some(MetadataValue::try_from(token.to_string()).map_err(|err| {
2822 IndexedDBError::Env(format!("invalid IndexedDB relay token metadata: {err}"))
2823 })?)
2824 };
2825 let binding = if binding.trim().is_empty() {
2826 None
2827 } else {
2828 Some(
2829 MetadataValue::try_from(binding.trim().to_string()).map_err(|err| {
2830 IndexedDBError::Env(format!("invalid IndexedDB binding metadata: {err}"))
2831 })?,
2832 )
2833 };
2834 Ok(RelayTokenInterceptor {
2835 relay_token,
2836 binding,
2837 })
2838}
2839
2840#[derive(Clone)]
2841struct RelayTokenInterceptor {
2842 relay_token: Option<MetadataValue<tonic::metadata::Ascii>>,
2843 binding: Option<MetadataValue<tonic::metadata::Ascii>>,
2844}
2845
2846impl Interceptor for RelayTokenInterceptor {
2847 fn call(&mut self, mut request: Request<()>) -> Result<Request<()>, tonic::Status> {
2848 if let Some(header) = self.relay_token.clone() {
2849 request
2850 .metadata_mut()
2851 .insert(INDEXEDDB_RELAY_TOKEN_HEADER, header);
2852 }
2853 if let Some(header) = self.binding.clone() {
2854 request
2855 .metadata_mut()
2856 .insert(HOST_SERVICE_BINDING_HEADER, header);
2857 }
2858 Ok(request)
2859 }
2860}