1
1
use crate :: store:: Store ;
2
2
use crate :: { db:: SPHERE_DB_STORE_NAMES , storage:: Storage } ;
3
3
use anyhow:: { anyhow, Error , Result } ;
4
+ use async_stream:: try_stream;
4
5
use async_trait:: async_trait;
5
- use js_sys:: Uint8Array ;
6
+ use js_sys:: { ArrayBuffer , Uint8Array } ;
6
7
use rexie:: {
7
8
KeyRange , ObjectStore , Rexie , RexieBuilder , Store as IdbStore , Transaction , TransactionMode ,
8
9
} ;
@@ -69,6 +70,11 @@ impl IndexedDbStorage {
69
70
let db = Rc :: into_inner ( self . db )
70
71
. ok_or_else ( || anyhow ! ( "Could not unwrap inner during database clear." ) ) ?;
71
72
db. close ( ) ;
73
+ Self :: delete ( & name)
74
+ }
75
+
76
+ /// Deletes database with key `db_name` from origin storage.
77
+ pub async fn delete ( db_name : & str ) -> Result < ( ) > {
72
78
Rexie :: delete ( & name)
73
79
. await
74
80
. map_err ( |error| anyhow ! ( "{:?}" , error) )
@@ -90,7 +96,21 @@ impl Storage for IndexedDbStorage {
90
96
}
91
97
}
92
98
93
- #[ derive( Clone ) ]
99
+ #[ async_trait( ?Send ) ]
100
+ impl crate :: extra:: StorageOpen for IndexedDbStorage {
101
+ async fn open < P : AsRef < Path > + ConditionalSend > ( path : P ) -> Result < Self > {
102
+ IndexedDbStorage :: new ( & key. as_ref ( ) . to_string ( ) ) . await
103
+ }
104
+ }
105
+
106
+ #[ async_trait( ?Send ) ]
107
+ impl crate :: extra:: StorageRemove for IndexedDbStorage {
108
+ async fn remove < P : AsRef < Path > + ConditionalSend > ( path : P ) -> Result < Self > {
109
+ Self :: delete ( path) . await
110
+ }
111
+ }
112
+
113
+ #[ derive( Clone , Clone ) ]
94
114
pub struct IndexedDbStore {
95
115
db : Rc < Rexie > ,
96
116
store_name : String ,
@@ -114,87 +134,104 @@ impl IndexedDbStore {
114
134
Ok ( ( ) )
115
135
}
116
136
117
- fn bytes_to_typed_array ( bytes : & [ u8 ] ) -> Result < JsValue > {
118
- let array = Uint8Array :: new_with_length ( bytes. len ( ) as u32 ) ;
119
- array. copy_from ( & bytes) ;
120
- Ok ( JsValue :: from ( array) )
121
- }
122
-
123
- async fn contains ( key : & JsValue , store : & IdbStore ) -> Result < bool > {
137
+ async fn contains ( key : & [ u8 ] , store : & IdbStore ) -> Result < bool > {
138
+ let key_js = bytes_to_typed_array ( key) ?;
124
139
let count = store
125
140
. count ( Some (
126
- & KeyRange :: only ( key ) . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?,
141
+ & KeyRange :: only ( & key_js ) . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?,
127
142
) )
128
143
. await
129
144
. map_err ( |error| anyhow ! ( "{:?}" , error) ) ?;
130
145
Ok ( count > 0 )
131
146
}
132
147
133
- async fn read ( key : & JsValue , store : & IdbStore ) -> Result < Option < Vec < u8 > > > {
148
+ async fn read ( key : & [ u8 ] , store : & IdbStore ) -> Result < Option < Vec < u8 > > > {
149
+ let key_js = bytes_to_typed_array ( key) ?;
134
150
Ok ( match IndexedDbStore :: contains ( & key, & store) . await ? {
135
- true => Some (
151
+ true => Some ( typed_array_to_bytes (
136
152
store
137
- . get ( & key )
153
+ . get ( & key_js )
138
154
. await
139
- . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?
140
- . dyn_into :: < Uint8Array > ( )
141
- . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?
142
- . to_vec ( ) ,
143
- ) ,
155
+ . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?,
156
+ ) ?) ,
144
157
false => None ,
145
158
} )
146
159
}
160
+
161
+ async fn put ( key : & [ u8 ] , value : & [ u8 ] , store : & IdbStore ) -> Result < ( ) > {
162
+ let key_js = bytes_to_typed_array ( key) ?;
163
+ let value_js = bytes_to_typed_array ( value) ?;
164
+ store
165
+ . put ( & value_js, Some ( & key_js) )
166
+ . await
167
+ . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?;
168
+ Ok ( ( ) )
169
+ }
170
+
171
+ async fn delete ( key : & [ u8 ] , store : & IdbStore ) -> Result < ( ) > {
172
+ let key_js = bytes_to_typed_array ( key) ?;
173
+ store
174
+ . delete ( & key_js)
175
+ . await
176
+ . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?;
177
+ Ok ( ( ) )
178
+ }
147
179
}
148
180
149
181
#[ async_trait( ?Send ) ]
150
182
impl Store for IndexedDbStore {
151
183
async fn read ( & self , key : & [ u8 ] ) -> Result < Option < Vec < u8 > > > {
152
184
let ( store, tx) = self . start_transaction ( TransactionMode :: ReadOnly ) ?;
153
- let key = IndexedDbStore :: bytes_to_typed_array ( key) ?;
154
-
155
- let maybe_dag = IndexedDbStore :: read ( & key, & store) . await ?;
156
-
185
+ let maybe_dag = IndexedDbStore :: read ( key, & store) . await ?;
157
186
IndexedDbStore :: finish_transaction ( tx) . await ?;
158
-
159
187
Ok ( maybe_dag)
160
188
}
161
189
162
190
async fn write ( & mut self , key : & [ u8 ] , bytes : & [ u8 ] ) -> Result < Option < Vec < u8 > > > {
163
191
let ( store, tx) = self . start_transaction ( TransactionMode :: ReadWrite ) ?;
164
-
165
- let key = IndexedDbStore :: bytes_to_typed_array ( key) ?;
166
- let value = IndexedDbStore :: bytes_to_typed_array ( bytes) ?;
167
-
168
192
let old_bytes = IndexedDbStore :: read ( & key, & store) . await ?;
169
-
170
- store
171
- . put ( & value, Some ( & key) )
172
- . await
173
- . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?;
174
-
193
+ IndexedDbStore :: put ( key, bytes, & store) . await ?;
175
194
IndexedDbStore :: finish_transaction ( tx) . await ?;
176
-
177
195
Ok ( old_bytes)
178
196
}
179
197
180
198
async fn remove ( & mut self , key : & [ u8 ] ) -> Result < Option < Vec < u8 > > > {
181
199
let ( store, tx) = self . start_transaction ( TransactionMode :: ReadWrite ) ?;
182
-
183
- let key = IndexedDbStore :: bytes_to_typed_array ( key) ?;
184
-
185
- let old_value = IndexedDbStore :: read ( & key, & store) . await ?;
186
-
187
- store
188
- . delete ( & key)
189
- . await
190
- . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?;
191
-
200
+ let old_value = IndexedDbStore :: read ( key, & store) . await ?;
201
+ IndexedDbStore :: delete ( key, & store) . await ?;
192
202
IndexedDbStore :: finish_transaction ( tx) . await ?;
193
-
194
203
Ok ( old_value)
195
204
}
196
205
}
197
206
207
+ impl crate :: IterableStore for IndexedDbStore {
208
+ fn get_all_entries ( & self ) -> crate :: IterableStoreStream < ' _ > {
209
+ Box :: pin ( try_stream ! {
210
+ let ( store, tx) = self . start_transaction( TransactionMode :: ReadWrite ) ?;
211
+ let limit = 100 ;
212
+ let mut offset = 0 ;
213
+ loop {
214
+ let results = store. get_all( None , Some ( limit) , Some ( offset) , None ) . await
215
+ . map_err( |error| anyhow!( "{:?}" , error) ) ?;
216
+ let count = results. len( ) ;
217
+ if count == 0 {
218
+ IndexedDbStore :: finish_transaction( tx) . await ?;
219
+ break ;
220
+ }
221
+
222
+ offset += count as u32 ;
223
+
224
+ for ( key_js, value_js) in results {
225
+ yield (
226
+ typed_array_to_bytes( JsValue :: from( Uint8Array :: new( & key_js) ) ) ?,
227
+ Some ( typed_array_to_bytes( value_js) ?)
228
+ ) ;
229
+ }
230
+ }
231
+ } )
232
+ }
233
+ }
234
+
198
235
#[ cfg( feature = "performance" ) ]
199
236
struct SpaceUsageError ( Error ) ;
200
237
@@ -263,3 +300,16 @@ impl crate::Space for IndexedDbStorage {
263
300
}
264
301
}
265
302
}
303
+
304
+ fn bytes_to_typed_array ( bytes : & [ u8 ] ) -> Result < JsValue > {
305
+ let array = Uint8Array :: new_with_length ( bytes. len ( ) as u32 ) ;
306
+ array. copy_from ( & bytes) ;
307
+ Ok ( JsValue :: from ( array) )
308
+ }
309
+
310
+ fn typed_array_to_bytes ( js_value : JsValue ) -> Result < Vec < u8 > > {
311
+ Ok ( js_value
312
+ . dyn_into :: < Uint8Array > ( )
313
+ . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?
314
+ . to_vec ( ) )
315
+ }
0 commit comments