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