mirror of
https://github.com/servo/servo.git
synced 2025-09-30 16:49:16 +01:00
indexeddb: Implement openCursor
and openKeyCursor
for object store (#39080)
Continue on implementing indexeddb's cursor. This patch focuses on implementing the `openCursor` [1] and `openKeyCursor` [2] methods of the `IDBObjectStore` interface, which create and initialize cursors by running the iterate-a-cursor algorithm [3]. It also adds struct `IndexedDBRecord` to `components/shared/net/indexeddb_thread.rs`. This struct can later be used to implement the new `IDBRecord` interface [4]. [1] https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-opencursor [2] https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-openkeycursor [3] https://www.w3.org/TR/IndexedDB-2/#iterate-a-cursor [4] https://w3c.github.io/IndexedDB/#record-interface Testing: Pass WPT tests that were expected to fail. Fixes: Part of #38111 --------- Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
This commit is contained in:
parent
1f63116bdd
commit
250c4cda00
26 changed files with 580 additions and 279 deletions
|
@ -8,12 +8,12 @@ use std::iter::repeat_n;
|
|||
use dom_struct::dom_struct;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::jsapi::Heap;
|
||||
use js::jsval::{DoubleValue, JSVal, UndefinedValue};
|
||||
use js::jsval::{DoubleValue, JSVal, ObjectValue, UndefinedValue};
|
||||
use js::rust::HandleValue;
|
||||
use net_traits::IpcSend;
|
||||
use net_traits::indexeddb_thread::{
|
||||
AsyncOperation, BackendError, BackendResult, IndexedDBKeyType, IndexedDBThreadMsg,
|
||||
IndexedDBTxnMode, PutItemResult,
|
||||
AsyncOperation, AsyncReadOnlyOperation, BackendError, BackendResult, IndexedDBKeyType,
|
||||
IndexedDBRecord, IndexedDBThreadMsg, IndexedDBTxnMode, PutItemResult,
|
||||
};
|
||||
use profile_traits::ipc::IpcReceiver;
|
||||
use script_bindings::conversions::SafeToJSValConvertible;
|
||||
|
@ -27,13 +27,15 @@ use crate::dom::bindings::codegen::Bindings::IDBTransactionBinding::IDBTransacti
|
|||
use crate::dom::bindings::error::{Error, Fallible, create_dom_exception};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, DomObject, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use crate::dom::bindings::structuredclone;
|
||||
use crate::dom::domexception::DOMException;
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::idbcursor::{IterationParam, iterate_cursor};
|
||||
use crate::dom::idbcursorwithvalue::IDBCursorWithValue;
|
||||
use crate::dom::idbobjectstore::IDBObjectStore;
|
||||
use crate::dom::idbtransaction::IDBTransaction;
|
||||
use crate::indexed_db::key_type_to_jsval;
|
||||
|
@ -43,6 +45,7 @@ use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
|
|||
#[derive(Clone)]
|
||||
struct RequestListener {
|
||||
request: Trusted<IDBRequest>,
|
||||
iteration_param: Option<IterationParam>,
|
||||
}
|
||||
|
||||
pub enum IdbResult {
|
||||
|
@ -51,6 +54,7 @@ pub enum IdbResult {
|
|||
Value(Vec<u8>),
|
||||
Values(Vec<Vec<u8>>),
|
||||
Count(u64),
|
||||
Iterate(Vec<IndexedDBRecord>),
|
||||
Error(Error),
|
||||
None,
|
||||
}
|
||||
|
@ -88,6 +92,12 @@ impl From<PutItemResult> for IdbResult {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Vec<IndexedDBRecord>> for IdbResult {
|
||||
fn from(value: Vec<IndexedDBRecord>) -> Self {
|
||||
Self::Iterate(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for IdbResult {
|
||||
fn from(_value: ()) -> Self {
|
||||
Self::None
|
||||
|
@ -171,6 +181,33 @@ impl RequestListener {
|
|||
IdbResult::Count(count) => {
|
||||
answer.handle_mut().set(DoubleValue(count as f64));
|
||||
},
|
||||
IdbResult::Iterate(records) => {
|
||||
let param = self.iteration_param.as_ref().expect(
|
||||
"iteration_param must be provided by IDBRequest::execute_async for Iterate",
|
||||
);
|
||||
let cursor = match iterate_cursor(&global, cx, param, records) {
|
||||
Ok(cursor) => cursor,
|
||||
Err(e) => {
|
||||
warn!("Error reading structuredclone data");
|
||||
Self::handle_async_request_error(&global, cx, request, e);
|
||||
return;
|
||||
},
|
||||
};
|
||||
if let Some(cursor) = cursor {
|
||||
match cursor.downcast::<IDBCursorWithValue>() {
|
||||
Some(cursor_with_value) => {
|
||||
answer.handle_mut().set(ObjectValue(
|
||||
*cursor_with_value.reflector().get_jsobject(),
|
||||
));
|
||||
},
|
||||
None => {
|
||||
answer
|
||||
.handle_mut()
|
||||
.set(ObjectValue(*cursor.reflector().get_jsobject()));
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
IdbResult::None => {
|
||||
// no-op
|
||||
},
|
||||
|
@ -313,6 +350,7 @@ impl IDBRequest {
|
|||
operation: AsyncOperation,
|
||||
receiver: IpcReceiver<BackendResult<T>>,
|
||||
request: Option<DomRoot<IDBRequest>>,
|
||||
iteration_param: Option<IterationParam>,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<DomRoot<IDBRequest>>
|
||||
where
|
||||
|
@ -346,8 +384,24 @@ impl IDBRequest {
|
|||
IDBTransactionMode::Versionchange => IndexedDBTxnMode::Versionchange,
|
||||
};
|
||||
|
||||
if matches!(
|
||||
operation,
|
||||
AsyncOperation::ReadOnly(AsyncReadOnlyOperation::Iterate { .. })
|
||||
) {
|
||||
assert!(
|
||||
iteration_param.is_some(),
|
||||
"iteration_param must be provided for Iterate"
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
iteration_param.is_none(),
|
||||
"iteration_param should not be provided for operation other than Iterate"
|
||||
);
|
||||
}
|
||||
|
||||
let response_listener = RequestListener {
|
||||
request: Trusted::new(&request),
|
||||
iteration_param,
|
||||
};
|
||||
|
||||
let task_source = global
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue