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 129 130 131 132 133 134 135 136 137 138 139 140 141
use crate::{utils::str_slice_to_array, ObjectStore, TransactionBuilder};
use std::marker::PhantomData;
use web_sys::{IdbDatabase, IdbObjectStoreParameters};
/// Wrapper for [`IDBDatabase`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase)
#[derive(Debug)]
pub struct Database<Err> {
sys: IdbDatabase,
_phantom: PhantomData<Err>,
}
impl<Err> Database<Err> {
pub(crate) fn from_sys(sys: IdbDatabase) -> Database<Err> {
Database {
sys,
_phantom: PhantomData,
}
}
/// The name of this database
///
/// Internally, this uses [`IDBDatabase::name`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/name).
pub fn name(&self) -> String {
self.sys.name()
}
/// The version of this database, clamped at `u32::MAX`
///
/// Internally, this uses [`IDBDatabase::version`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/version).
pub fn version(&self) -> u32 {
self.sys.version() as u32
}
/// The names of all [`ObjectStore`]s in this [`Database`]
///
/// Internally, this uses [`IDBDatabase::objectStoreNames`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/objectStoreNames).
pub fn object_store_names(&self) -> Vec<String> {
let names = self.sys.object_store_names();
let len = names.length();
let mut res = Vec::with_capacity(usize::try_from(len).unwrap());
for i in 0..len {
res.push(
names
.get(i)
.expect("DOMStringList did not contain as many elements as its length"),
);
}
res
}
/// Build an [`ObjectStore`]
///
/// Note that this method can only be called from within an `on_upgrade_needed` callback. It returns
/// a builder, and calling the `create` method on this builder will perform the actual creation.
///
/// Internally, this uses [`IDBDatabase::createObjectStore`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/createObjectStore).
pub fn build_object_store<'a>(&self, name: &'a str) -> ObjectStoreBuilder<'a, Err> {
ObjectStoreBuilder {
db: self.sys.clone(),
name,
options: IdbObjectStoreParameters::new(),
_phantom: PhantomData,
}
}
/// Deletes an [`ObjectStore`]
///
/// Note that this method can only be called from within an `on_upgrade_needed` callback.
///
/// Internally, this uses [`IDBDatabase::deleteObjectStore`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/deleteObjectStore).
pub fn delete_object_store(&self, name: &str) -> crate::Result<(), Err> {
self.sys.delete_object_store(name).map_err(|err| match error_name!(&err) {
Some("InvalidStateError") => crate::Error::InvalidCall,
Some("TransactionInactiveError") => panic!("Tried to create an object store with the `versionchange` transaction having already aborted"),
Some("NotFoundError") => crate::Error::DoesNotExist,
_ => crate::Error::from_js_value(err),
})
}
/// Run a transaction
///
/// This will open the object stores identified by `stores`. See the methods of [`TransactionBuilder`]
/// for more details about how transactions actually happen.
pub fn transaction(&self, stores: &[&str]) -> TransactionBuilder<Err> {
TransactionBuilder::from_names(self.sys.clone(), stores)
}
/// Closes this database connection
///
/// Note that the closing will actually happen asynchronously with no way for the client to
/// identify when the database was closed.
///
/// Internally, this uses [`IDBDatabase::close`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/close).
pub fn close(&self) {
self.sys.close();
}
}
/// Helper to build an object store
pub struct ObjectStoreBuilder<'a, Err> {
db: IdbDatabase,
name: &'a str,
options: IdbObjectStoreParameters,
_phantom: PhantomData<Err>,
}
impl<'a, Err> ObjectStoreBuilder<'a, Err> {
/// Create the object store
///
/// Internally, this uses [`IDBDatabase::createObjectStore`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/createObjectStore).
pub fn create(self) -> crate::Result<ObjectStore<Err>, Err> {
self.db
.create_object_store_with_optional_parameters(self.name, &self.options)
.map_err(
|err| match error_name!(&err) {
Some("InvalidStateError") => crate::Error::InvalidCall,
Some("TransactionInactiveError") => panic!("Tried to create an object store with the `versionchange` transaction having already aborted"),
Some("ConstraintError") => crate::Error::AlreadyExists,
Some("InvalidAccessError") => crate::Error::InvalidArgument,
_ => crate::Error::from_js_value(err),
},
)
.map(ObjectStore::from_sys)
}
/// Set the key path for out-of-line keys
///
/// Internally, this [sets this setting](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/createObjectStore#keypath).
pub fn key_path(mut self, path: &[&str]) -> Self {
self.options.key_path(Some(&str_slice_to_array(path)));
self
}
/// Enable auto-increment for the key
///
/// Internally, this [sets this setting](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/createObjectStore#autoincrement).
pub fn auto_increment(mut self) -> Self {
self.options.auto_increment(true);
self
}
}