1#![deny(missing_docs)]
15
16mod error;
17mod indexed_db;
18
19use std::io;
20
21pub use error::Error;
22use futures::prelude::*;
23pub use kvdb::KeyValueDB;
24use kvdb::{DBKeyValue, DBTransaction, DBValue};
25use kvdb_memorydb::{self as in_memory, InMemory};
26use send_wrapper::SendWrapper;
27use web_sys::IdbDatabase;
28
29pub struct Database {
31 name: String,
32 version: u32,
33 columns: u32,
34 in_memory: InMemory,
35 indexed_db: SendWrapper<IdbDatabase>,
36}
37
38parity_util_mem::malloc_size_of_is_0!(Database);
40
41impl Database {
42 pub async fn open(name: String, columns: u32) -> Result<Database, error::Error> {
45 let name_clone = name.clone();
46 let db = indexed_db::open(name.as_str(), None, columns).await?;
48
49 let db = if columns + 1 > db.columns {
55 let next_version = db.version + 1;
56 drop(db);
57 indexed_db::open(name.as_str(), Some(next_version), columns).await?
58 } else {
59 db
60 };
61 let indexed_db::IndexedDB { version, inner, .. } = db;
63 let in_memory = in_memory::create(columns);
64 for column in 0..columns {
66 let mut txn = DBTransaction::new();
67 let mut stream = indexed_db::idb_cursor(&*inner, column);
68 while let Some((key, value)) = stream.next().await {
69 txn.put_vec(column, key.as_ref(), value);
70 }
71 in_memory
73 .write(txn)
74 .expect("writing in memory always succeeds; qed");
75 }
76 Ok(Database {
77 name: name_clone,
78 version,
79 columns,
80 in_memory,
81 indexed_db: inner,
82 })
83 }
84
85 pub fn name(&self) -> &str {
87 self.name.as_str()
88 }
89
90 pub fn version(&self) -> u32 {
92 self.version
93 }
94}
95
96impl Drop for Database {
97 fn drop(&mut self) {
98 self.indexed_db.close();
99 }
100}
101
102impl KeyValueDB for Database {
103 fn get(&self, col: u32, key: &[u8]) -> io::Result<Option<DBValue>> {
104 self.in_memory.get(col, key)
105 }
106
107 fn get_by_prefix(&self, col: u32, prefix: &[u8]) -> io::Result<Option<Vec<u8>>> {
108 self.in_memory.get_by_prefix(col, prefix)
109 }
110
111 fn write(&self, transaction: DBTransaction) -> io::Result<()> {
112 let _ = indexed_db::idb_commit_transaction(&*self.indexed_db, &transaction, self.columns);
113 self.in_memory.write(transaction)
114 }
115
116 fn iter<'a>(&'a self, col: u32) -> Box<dyn Iterator<Item = io::Result<DBKeyValue>> + 'a> {
117 self.in_memory.iter(col)
118 }
119
120 fn iter_with_prefix<'a>(
121 &'a self,
122 col: u32,
123 prefix: &'a [u8],
124 ) -> Box<dyn Iterator<Item = io::Result<DBKeyValue>> + 'a> {
125 self.in_memory.iter_with_prefix(col, prefix)
126 }
127}