mirror of
https://github.com/servo/servo.git
synced 2025-07-21 14:23:41 +01:00
[IndexedDB] Adhere better to the specification for idb object store related operations (#37682)
Many object store related operations require the transaction to be checked: to ensure it is still active, and, if the operation is a write, that the transaction is not read-only. I've added the `check_transaction` method to perform these checks. Additionally `Clear` was still half-implemented, so I went ahead and implemented that. --------- Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
This commit is contained in:
parent
2e3c280f46
commit
71e7019d45
3 changed files with 94 additions and 35 deletions
|
@ -262,6 +262,16 @@ impl KvsEngine for HeedEngine {
|
||||||
.expect("Could not get store");
|
.expect("Could not get store");
|
||||||
// FIXME:(arihant2math) Return count with sender
|
// FIXME:(arihant2math) Return count with sender
|
||||||
},
|
},
|
||||||
|
AsyncOperation::ReadWrite(AsyncReadWriteOperation::Clear) => {
|
||||||
|
let stores = stores
|
||||||
|
.write()
|
||||||
|
.expect("Could not acquire write lock on stores");
|
||||||
|
let store = stores
|
||||||
|
.get(&request.store_name)
|
||||||
|
.expect("Could not get store");
|
||||||
|
// FIXME:(arihant2math) Error handling
|
||||||
|
let _ = store.inner.clear(&mut wtxn);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -386,6 +386,36 @@ impl IDBObjectStore {
|
||||||
self.key_path.is_some()
|
self.key_path.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the transation is active, throwing a "TransactionInactiveError" DOMException if not.
|
||||||
|
fn check_transaction_active(&self) -> Fallible<()> {
|
||||||
|
// Let transaction be this object store handle's transaction.
|
||||||
|
let transaction = self.transaction.get().ok_or(Error::TransactionInactive)?;
|
||||||
|
|
||||||
|
// If transaction is not active, throw a "TransactionInactiveError" DOMException.
|
||||||
|
if !transaction.is_active() {
|
||||||
|
return Err(Error::TransactionInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the transation is active, throwing a "TransactionInactiveError" DOMException if not.
|
||||||
|
/// it then checks if the transaction is a read-only transaction, throwing a "ReadOnlyError" DOMException if so.
|
||||||
|
fn check_readwrite_transaction_active(&self) -> Fallible<()> {
|
||||||
|
// Let transaction be this object store handle's transaction.
|
||||||
|
let transaction = self.transaction.get().ok_or(Error::TransactionInactive)?;
|
||||||
|
|
||||||
|
// If transaction is not active, throw a "TransactionInactiveError" DOMException.
|
||||||
|
if !transaction.is_active() {
|
||||||
|
return Err(Error::TransactionInactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let IDBTransactionMode::Readonly = transaction.get_mode() {
|
||||||
|
return Err(Error::ReadOnly);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-put
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-put
|
||||||
fn put(
|
fn put(
|
||||||
&self,
|
&self,
|
||||||
|
@ -395,27 +425,15 @@ impl IDBObjectStore {
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> Fallible<DomRoot<IDBRequest>> {
|
) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
// Step 1: Let transaction be this object store handle's transaction.
|
// Step 1: Unneeded, handled by self.check_readwrite_transaction_active()
|
||||||
let transaction = self
|
|
||||||
.transaction
|
|
||||||
.get()
|
|
||||||
.expect("No transaction in Object Store");
|
|
||||||
|
|
||||||
// Step 2: Let store be this object store handle's object store.
|
// Step 2: Let store be this object store handle's object store.
|
||||||
// This is resolved in the `execute_async` function.
|
// This is resolved in the `execute_async` function.
|
||||||
|
|
||||||
// Step 3: If store has been deleted, throw an "InvalidStateError" DOMException.
|
// Step 3: If store has been deleted, throw an "InvalidStateError" DOMException.
|
||||||
// FIXME:(rasviitanen)
|
// FIXME:(rasviitanen)
|
||||||
|
|
||||||
// Step 4-5: If transaction is not active, throw a "TransactionInactiveError" DOMException.
|
// Steps 4-5
|
||||||
if !transaction.is_active() {
|
self.check_readwrite_transaction_active()?;
|
||||||
return Err(Error::TransactionInactive);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 5: If transaction is a read-only transaction, throw a "ReadOnlyError" DOMException.
|
|
||||||
if let IDBTransactionMode::Readonly = transaction.get_mode() {
|
|
||||||
return Err(Error::ReadOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 6: If store uses in-line keys and key was given, throw a "DataError" DOMException.
|
// Step 6: If store uses in-line keys and key was given, throw a "DataError" DOMException.
|
||||||
if !key.is_undefined() && self.uses_inline_keys() {
|
if !key.is_undefined() && self.uses_inline_keys() {
|
||||||
|
@ -489,7 +507,15 @@ impl IDBObjectStoreMethods<crate::DomTypeHolder> for IDBObjectStore {
|
||||||
|
|
||||||
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-delete
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-delete
|
||||||
fn Delete(&self, cx: SafeJSContext, query: HandleValue) -> Fallible<DomRoot<IDBRequest>> {
|
fn Delete(&self, cx: SafeJSContext, query: HandleValue) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
// Step 1: Unneeded, handled by self.check_readwrite_transaction_active()
|
||||||
|
// TODO: Step 2
|
||||||
|
// TODO: Step 3
|
||||||
|
// Steps 4-5
|
||||||
|
self.check_readwrite_transaction_active()?;
|
||||||
|
// Step 6
|
||||||
|
// TODO: Convert to key range instead
|
||||||
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
||||||
|
// Step 7
|
||||||
serialized_query.and_then(|q| {
|
serialized_query.and_then(|q| {
|
||||||
IDBRequest::execute_async(
|
IDBRequest::execute_async(
|
||||||
self,
|
self,
|
||||||
|
@ -502,12 +528,30 @@ impl IDBObjectStoreMethods<crate::DomTypeHolder> for IDBObjectStore {
|
||||||
|
|
||||||
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-clear
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-clear
|
||||||
fn Clear(&self) -> Fallible<DomRoot<IDBRequest>> {
|
fn Clear(&self) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
unimplemented!();
|
// Step 1: Unneeded, handled by self.check_readwrite_transaction_active()
|
||||||
|
// TODO: Step 2
|
||||||
|
// TODO: Step 3
|
||||||
|
// Steps 4-5
|
||||||
|
self.check_readwrite_transaction_active()?;
|
||||||
|
IDBRequest::execute_async(
|
||||||
|
self,
|
||||||
|
AsyncOperation::ReadWrite(AsyncReadWriteOperation::Clear),
|
||||||
|
None,
|
||||||
|
CanGc::note(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-get
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-get
|
||||||
fn Get(&self, cx: SafeJSContext, query: HandleValue) -> Fallible<DomRoot<IDBRequest>> {
|
fn Get(&self, cx: SafeJSContext, query: HandleValue) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
|
// Step 1: Unneeded, handled by self.check_transaction_active()
|
||||||
|
// TODO: Step 2
|
||||||
|
// TODO: Step 3
|
||||||
|
// Step 4
|
||||||
|
self.check_transaction_active()?;
|
||||||
|
// Step 5
|
||||||
|
// TODO: Convert to key range instead
|
||||||
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
||||||
|
// Step 6
|
||||||
serialized_query.and_then(|q| {
|
serialized_query.and_then(|q| {
|
||||||
IDBRequest::execute_async(
|
IDBRequest::execute_async(
|
||||||
self,
|
self,
|
||||||
|
@ -520,6 +564,14 @@ impl IDBObjectStoreMethods<crate::DomTypeHolder> for IDBObjectStore {
|
||||||
|
|
||||||
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-getkey
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-getkey
|
||||||
// fn GetKey(&self, _cx: SafeJSContext, _query: HandleValue) -> DomRoot<IDBRequest> {
|
// fn GetKey(&self, _cx: SafeJSContext, _query: HandleValue) -> DomRoot<IDBRequest> {
|
||||||
|
// // Step 1: Unneeded, handled by self.check_transaction_active()
|
||||||
|
// // TODO: Step 2
|
||||||
|
// // TODO: Step 3
|
||||||
|
// // Step 4
|
||||||
|
// self.check_transaction_active()?;
|
||||||
|
// // Step 5
|
||||||
|
// // TODO: Convert to key range instead
|
||||||
|
// let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
||||||
// unimplemented!();
|
// unimplemented!();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@ -545,29 +597,24 @@ impl IDBObjectStoreMethods<crate::DomTypeHolder> for IDBObjectStore {
|
||||||
|
|
||||||
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-count
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-count
|
||||||
fn Count(&self, cx: SafeJSContext, query: HandleValue) -> Fallible<DomRoot<IDBRequest>> {
|
fn Count(&self, cx: SafeJSContext, query: HandleValue) -> Fallible<DomRoot<IDBRequest>> {
|
||||||
// Step 1
|
// Step 1: Unneeded, handled by self.check_transaction_active()
|
||||||
let transaction = self.transaction.get().expect("Could not get transaction");
|
// TODO: Step 2
|
||||||
|
// TODO: Step 3
|
||||||
// Step 2
|
// Steps 4
|
||||||
// FIXME(arihant2math): investigate further
|
self.check_transaction_active()?;
|
||||||
|
|
||||||
// Step 3
|
|
||||||
// FIXME(arihant2math): Cannot tell if store has been deleted
|
|
||||||
|
|
||||||
// Step 4
|
|
||||||
if !transaction.is_active() {
|
|
||||||
return Err(Error::TransactionInactive);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 5
|
// Step 5
|
||||||
let _serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
|
||||||
|
|
||||||
// Step 6
|
// Step 6
|
||||||
// match serialized_query {
|
serialized_query.and_then(|q| {
|
||||||
// Ok(q) => IDBRequest::execute_async(&*self, AsyncOperation::Count(q), None),
|
IDBRequest::execute_async(
|
||||||
// Err(e) => Err(e),
|
self,
|
||||||
// }
|
AsyncOperation::ReadOnly(AsyncReadOnlyOperation::Count(q)),
|
||||||
Err(Error::NotSupported)
|
None,
|
||||||
|
CanGc::note(),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-name
|
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-name
|
||||||
|
|
|
@ -92,6 +92,8 @@ pub enum AsyncReadWriteOperation {
|
||||||
RemoveItem(
|
RemoveItem(
|
||||||
IndexedDBKeyType, // Key
|
IndexedDBKeyType, // Key
|
||||||
),
|
),
|
||||||
|
/// Clears all key/value pairs in the associated idb data
|
||||||
|
Clear,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Operations that are not executed instantly, but rather added to a
|
/// Operations that are not executed instantly, but rather added to a
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue