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