11use crate :: store:: Store ;
22use crate :: { db:: SPHERE_DB_STORE_NAMES , storage:: Storage } ;
33use anyhow:: { anyhow, Error , Result } ;
4+ use async_stream:: try_stream;
45use async_trait:: async_trait;
56use js_sys:: Uint8Array ;
7+ use noosphere_common:: ConditionalSend ;
68use rexie:: {
79 KeyRange , ObjectStore , Rexie , RexieBuilder , Store as IdbStore , Transaction , TransactionMode ,
810} ;
9- use std:: { fmt:: Debug , rc:: Rc } ;
11+ use std:: { fmt:: Debug , path :: Path , rc:: Rc } ;
1012use wasm_bindgen:: { JsCast , JsValue } ;
1113
1214pub const INDEXEDDB_STORAGE_VERSION : u32 = 1 ;
@@ -69,7 +71,12 @@ impl IndexedDbStorage {
6971 let db = Rc :: into_inner ( self . db )
7072 . ok_or_else ( || anyhow ! ( "Could not unwrap inner during database clear." ) ) ?;
7173 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)
7380 . await
7481 . map_err ( |error| anyhow ! ( "{:?}" , error) )
7582 }
@@ -90,6 +97,30 @@ impl Storage for IndexedDbStorage {
9097 }
9198}
9299
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+
93124#[ derive( Clone ) ]
94125pub struct IndexedDbStore {
95126 db : Rc < Rexie > ,
@@ -114,87 +145,104 @@ impl IndexedDbStore {
114145 Ok ( ( ) )
115146 }
116147
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) ?;
124150 let count = store
125151 . count ( Some (
126- & KeyRange :: only ( key ) . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?,
152+ & KeyRange :: only ( & key_js ) . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?,
127153 ) )
128154 . await
129155 . map_err ( |error| anyhow ! ( "{:?}" , error) ) ?;
130156 Ok ( count > 0 )
131157 }
132158
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) ?;
134161 Ok ( match IndexedDbStore :: contains ( & key, & store) . await ? {
135- true => Some (
162+ true => Some ( typed_array_to_bytes (
136163 store
137- . get ( & key )
164+ . get ( & key_js )
138165 . 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+ ) ?) ,
144168 false => None ,
145169 } )
146170 }
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+ }
147190}
148191
149192#[ async_trait( ?Send ) ]
150193impl Store for IndexedDbStore {
151194 async fn read ( & self , key : & [ u8 ] ) -> Result < Option < Vec < u8 > > > {
152195 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 ?;
157197 IndexedDbStore :: finish_transaction ( tx) . await ?;
158-
159198 Ok ( maybe_dag)
160199 }
161200
162201 async fn write ( & mut self , key : & [ u8 ] , bytes : & [ u8 ] ) -> Result < Option < Vec < u8 > > > {
163202 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-
168203 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 ?;
175205 IndexedDbStore :: finish_transaction ( tx) . await ?;
176-
177206 Ok ( old_bytes)
178207 }
179208
180209 async fn remove ( & mut self , key : & [ u8 ] ) -> Result < Option < Vec < u8 > > > {
181210 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 ?;
192213 IndexedDbStore :: finish_transaction ( tx) . await ?;
193-
194214 Ok ( old_value)
195215 }
196216}
197217
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+
198246#[ cfg( feature = "performance" ) ]
199247struct SpaceUsageError ( Error ) ;
200248
@@ -263,3 +311,16 @@ impl crate::Space for IndexedDbStorage {
263311 }
264312 }
265313}
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