script: Ensure autoincrement and keypath are passed in correctly from IDBTransaction (#38738)

Previously, the correct autoincremented and keypath parameters were only
being passed if the object store is being created. This PR queries this
info from the backend and passes it onto the constructor in
IDBTransaction. Furthermore it exposes keypath and index_names from
IDBObjectStore, mainly for WPT.

Testing: WPT
Fixes: None

---------

Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
This commit is contained in:
Ashwin Naren 2025-09-11 02:13:15 -07:00 committed by GitHub
parent 722b0de8d8
commit 97690b1cba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 84 additions and 170 deletions

View file

@ -3,6 +3,8 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
use js::gc::MutableHandleValue;
use js::jsval::NullValue;
use js::rust::HandleValue;
use net_traits::IpcSend;
use net_traits::indexeddb_thread::{
@ -10,6 +12,7 @@ use net_traits::indexeddb_thread::{
IndexedDBThreadMsg, SyncOperation,
};
use profile_traits::ipc;
use script_bindings::conversions::SafeToJSValConvertible;
use script_bindings::error::ErrorResult;
use crate::dom::bindings::cell::DomRefCell;
@ -34,7 +37,7 @@ use crate::indexed_db::{
};
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
#[derive(JSTraceable, MallocSizeOf)]
#[derive(Clone, JSTraceable, MallocSizeOf)]
pub enum KeyPath {
String(DOMString),
StringSequence(Vec<DOMString>),
@ -133,38 +136,6 @@ impl IDBObjectStore {
receiver.recv().unwrap().unwrap()
}
// fn get_stored_key_path(&mut self) -> Option<KeyPath> {
// let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
//
// let operation = SyncOperation::KeyPath(
// sender,
// self.global().origin().immutable().clone(),
// self.db_name.to_string(),
// self.name.borrow().to_string(),
// );
//
// self.global()
// .resource_threads()
// .sender()
// .send(IndexedDBThreadMsg::Sync(operation))
// .unwrap();
//
// // First unwrap for ipc
// // Second unwrap will never happen unless this db gets manually deleted somehow
// let key_path = receiver.recv().unwrap().unwrap();
// key_path.map(|p| {
// // TODO: have separate storage for string sequence of len 1 and signle string
// if p.len() == 1 {
// KeyPath::String(DOMString::from_string(p[0].clone()))
// } else {
// let strings: Vec<_> = p.into_iter().map(|s| {
// DOMString::from_string(s)
// }).collect();
// KeyPath::StringSequence(strings)
// }
// })
// }
// https://www.w3.org/TR/IndexedDB-2/#object-store-in-line-keys
fn uses_inline_keys(&self) -> bool {
self.key_path.is_some()
@ -546,14 +517,18 @@ impl IDBObjectStoreMethods<crate::DomTypeHolder> for IDBObjectStore {
}
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-keypath
// fn KeyPath(&self, _cx: SafeJSContext, _val: MutableHandleValue) {
// unimplemented!();
// }
fn KeyPath(&self, cx: SafeJSContext, mut ret_val: MutableHandleValue) {
match &self.key_path {
Some(KeyPath::String(path)) => path.safe_to_jsval(cx, ret_val),
Some(KeyPath::StringSequence(paths)) => paths.safe_to_jsval(cx, ret_val),
None => ret_val.set(NullValue()),
}
}
// https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-indexnames
// fn IndexNames(&self) -> DomRoot<DOMStringList> {
// unimplemented!();
// }
fn IndexNames(&self) -> DomRoot<DOMStringList> {
self.index_names.clone()
}
/// <https://www.w3.org/TR/IndexedDB-2/#dom-idbobjectstore-transaction>
fn Transaction(&self) -> DomRoot<IDBTransaction> {

View file

@ -8,12 +8,14 @@ use std::collections::HashMap;
use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender;
use net_traits::IpcSend;
use net_traits::indexeddb_thread::{IndexedDBThreadMsg, SyncOperation};
use net_traits::indexeddb_thread::{IndexedDBThreadMsg, KeyPath, SyncOperation};
use profile_traits::ipc;
use script_bindings::codegen::GenericUnionTypes::StringOrStringSequence;
use stylo_atoms::Atom;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::DOMStringListBinding::DOMStringListMethods;
use crate::dom::bindings::codegen::Bindings::IDBDatabaseBinding::IDBObjectStoreParameters;
use crate::dom::bindings::codegen::Bindings::IDBTransactionBinding::{
IDBTransactionMethods, IDBTransactionMode,
};
@ -203,6 +205,52 @@ impl IDBTransaction {
fn get_idb_thread(&self) -> IpcSender<IndexedDBThreadMsg> {
self.global().resource_threads().sender()
}
fn object_store_parameters(
&self,
object_store_name: &DOMString,
) -> Option<IDBObjectStoreParameters> {
let global = self.global();
let idb_sender = global.resource_threads().sender();
let (sender, receiver) =
ipc::channel(global.time_profiler_chan().clone()).expect("failed to create channel");
let origin = global.origin().immutable().clone();
let db_name = self.db.get_name().to_string();
let object_store_name = object_store_name.to_string();
let operation = SyncOperation::HasKeyGenerator(
sender,
origin.clone(),
db_name.clone(),
object_store_name.clone(),
);
let _ = idb_sender.send(IndexedDBThreadMsg::Sync(operation));
// First unwrap for ipc
// Second unwrap will never happen unless this db gets manually deleted somehow
let auto_increment = receiver.recv().ok()?.ok()?;
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).ok()?;
let operation = SyncOperation::KeyPath(sender, origin, db_name, object_store_name);
let _ = idb_sender.send(IndexedDBThreadMsg::Sync(operation));
// First unwrap for ipc
// Second unwrap will never happen unless this db gets manually deleted somehow
let key_path = receiver.recv().unwrap().ok()?;
let key_path = key_path.map(|key_path| match key_path {
KeyPath::String(s) => StringOrStringSequence::String(DOMString::from_string(s)),
KeyPath::Sequence(seq) => StringOrStringSequence::StringSequence(
seq.into_iter().map(DOMString::from_string).collect(),
),
});
Some(IDBObjectStoreParameters {
autoIncrement: auto_increment,
keyPath: key_path,
})
}
}
impl IDBTransactionMethods<crate::DomTypeHolder> for IDBTransaction {
@ -213,7 +261,7 @@ impl IDBTransactionMethods<crate::DomTypeHolder> for IDBTransaction {
// https://www.w3.org/TR/IndexedDB-2/#dom-idbtransaction-objectstore
fn ObjectStore(&self, name: DOMString) -> Fallible<DomRoot<IDBObjectStore>> {
// Step 1: Handle the case where transaction has finised
// Step 1: If transaction has finished, throw an "InvalidStateError" DOMException.
if self.finished.get() {
return Err(Error::InvalidState);
}
@ -228,12 +276,12 @@ impl IDBTransactionMethods<crate::DomTypeHolder> for IDBTransaction {
// returns the same IDBObjectStore instance.
let mut store_handles = self.store_handles.borrow_mut();
let store = store_handles.entry(name.to_string()).or_insert_with(|| {
// TODO: get key path from backend
let parameters = self.object_store_parameters(&name);
let store = IDBObjectStore::new(
&self.global(),
self.db.get_name(),
name,
None,
parameters.as_ref(),
CanGc::note(),
self,
);

View file

@ -11,8 +11,8 @@
[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)]
interface IDBObjectStore {
[SetterThrows] attribute DOMString name;
// readonly attribute any keyPath;
// readonly attribute DOMStringList indexNames;
readonly attribute any keyPath;
readonly attribute DOMStringList indexNames;
[SameObject] readonly attribute IDBTransaction transaction;
readonly attribute boolean autoIncrement;

View file

@ -11,6 +11,9 @@
[Index key path evaluations operate on a clone]
expected: FAIL
[Key generator and key path validity check operates on a clone]
expected: FAIL
[clone-before-keypath-eval.any.serviceworker.html]
expected: ERROR
@ -28,6 +31,9 @@
[Index key path evaluations operate on a clone]
expected: FAIL
[Key generator and key path validity check operates on a clone]
expected: FAIL
[clone-before-keypath-eval.any.sharedworker.html]
expected: ERROR

View file

@ -5,9 +5,6 @@
[Both with empty name]
expected: FAIL
[Object store 'name' and 'keyPath' properties are correctly set ]
expected: FAIL
[Attempt to create an object store outside of a version change transaction ]
expected: FAIL
@ -22,9 +19,6 @@
[Both with empty name]
expected: FAIL
[Object store 'name' and 'keyPath' properties are correctly set ]
expected: FAIL
[Attempt to create an object store outside of a version change transaction ]
expected: FAIL

View file

@ -39,6 +39,3 @@
[Calling open() with version argument 9007199254740991 should not throw.]
expected: FAIL
[Calling open() with version argument 1.5 should not throw.]
expected: FAIL

View file

@ -68,9 +68,6 @@
[Get all values with both options and count]
expected: FAIL
[Get all values with invalid query keys]
expected: FAIL
[idbobjectstore_getAll-options.tentative.any.serviceworker.html]
expected: ERROR
@ -147,6 +144,3 @@
[Get all values with both options and count]
expected: FAIL
[Get all values with invalid query keys]
expected: FAIL

View file

@ -1,7 +1,4 @@
[idbobjectstore_getAll.any.html]
[Single item get]
expected: FAIL
[Single item get (generated key)]
expected: FAIL
@ -17,12 +14,6 @@
[Test maxCount]
expected: FAIL
[Get bound range]
expected: FAIL
[Get bound range with maxCount]
expected: FAIL
[Get upper excluded]
expected: FAIL
@ -32,21 +23,12 @@
[Get bound range (generated) with maxCount]
expected: FAIL
[Non existent key]
expected: FAIL
[zero maxCount]
expected: FAIL
[Max value count]
expected: FAIL
[Query with empty range where first key < upperBound]
expected: FAIL
[Query with empty range where lowerBound < last key]
expected: FAIL
[Get all values with transaction.commit()]
expected: FAIL
@ -58,9 +40,6 @@
expected: ERROR
[idbobjectstore_getAll.any.worker.html]
[Single item get]
expected: FAIL
[Single item get (generated key)]
expected: FAIL
@ -76,12 +55,6 @@
[Test maxCount]
expected: FAIL
[Get bound range]
expected: FAIL
[Get bound range with maxCount]
expected: FAIL
[Get upper excluded]
expected: FAIL
@ -91,21 +64,12 @@
[Get bound range (generated) with maxCount]
expected: FAIL
[Non existent key]
expected: FAIL
[zero maxCount]
expected: FAIL
[Max value count]
expected: FAIL
[Query with empty range where first key < upperBound]
expected: FAIL
[Query with empty range where lowerBound < last key]
expected: FAIL
[Get all values with transaction.commit()]
expected: FAIL

View file

@ -65,9 +65,6 @@
[Get all keys with both options and count]
expected: FAIL
[Get all keys with invalid query keys]
expected: FAIL
[idbobjectstore_getAllKeys-options.tentative.any.serviceworker.html]
expected: ERROR
@ -139,9 +136,6 @@
[Get all keys with both options and count]
expected: FAIL
[Get all keys with invalid query keys]
expected: FAIL
[idbobjectstore_getAllKeys-options.tentative.any.sharedworker.html]
expected: ERROR

View file

@ -5,12 +5,6 @@
expected: ERROR
[idbobjectstore_getAllKeys.any.worker.html]
[Single item get]
expected: FAIL
[Single item get (generated key)]
expected: FAIL
[getAllKeys on empty object store]
expected: FAIL
@ -20,47 +14,23 @@
[Test maxCount]
expected: FAIL
[Get bound range]
expected: FAIL
[Get bound range with maxCount]
expected: FAIL
[Get upper excluded]
expected: FAIL
[Get lower excluded]
expected: FAIL
[Get bound range (generated) with maxCount]
expected: FAIL
[Non existent key]
expected: FAIL
[zero maxCount]
expected: FAIL
[Max value count]
expected: FAIL
[Query with empty range where first key < upperBound]
expected: FAIL
[Query with empty range where lowerBound < last key]
expected: FAIL
[Get all keys with invalid query keys]
expected: FAIL
[idbobjectstore_getAllKeys.any.html]
[Single item get]
expected: FAIL
[Single item get (generated key)]
expected: FAIL
[getAllKeys on empty object store]
expected: FAIL
@ -70,35 +40,17 @@
[Test maxCount]
expected: FAIL
[Get bound range]
expected: FAIL
[Get bound range with maxCount]
expected: FAIL
[Get upper excluded]
expected: FAIL
[Get lower excluded]
expected: FAIL
[Get bound range (generated) with maxCount]
expected: FAIL
[Non existent key]
expected: FAIL
[zero maxCount]
expected: FAIL
[Max value count]
expected: FAIL
[Query with empty range where first key < upperBound]
expected: FAIL
[Query with empty range where lowerBound < last key]
expected: FAIL
[Get all keys with invalid query keys]
expected: FAIL

View file

@ -5,12 +5,6 @@
[IDBFactory interface: operation databases()]
expected: FAIL
[IDBObjectStore interface: attribute keyPath]
expected: FAIL
[IDBObjectStore interface: attribute indexNames]
expected: FAIL
[IDBObjectStore interface: operation openCursor(optional any, optional IDBCursorDirection)]
expected: FAIL
@ -115,12 +109,6 @@
[IDBFactory interface: operation databases()]
expected: FAIL
[IDBObjectStore interface: attribute keyPath]
expected: FAIL
[IDBObjectStore interface: attribute indexNames]
expected: FAIL
[IDBObjectStore interface: operation openCursor(optional any, optional IDBCursorDirection)]
expected: FAIL

View file

@ -1,15 +1,16 @@
[keypath-special-identifiers.any.html]
expected: TIMEOUT
[Type: String, identifier: length]
expected: FAIL
expected: TIMEOUT
[Type: Array, identifier: length]
expected: FAIL
expected: TIMEOUT
[Type: Blob, identifier: size]
expected: FAIL
expected: TIMEOUT
[Type: Blob, identifier: type]
expected: FAIL
expected: TIMEOUT
[Type: File, identifier: name]
expected: FAIL
@ -25,17 +26,18 @@
expected: ERROR
[keypath-special-identifiers.any.worker.html]
expected: TIMEOUT
[Type: String, identifier: length]
expected: FAIL
expected: TIMEOUT
[Type: Array, identifier: length]
expected: FAIL
expected: TIMEOUT
[Type: Blob, identifier: size]
expected: FAIL
expected: TIMEOUT
[Type: Blob, identifier: type]
expected: FAIL
expected: TIMEOUT
[Type: File, identifier: name]
expected: FAIL