diff --git a/components/script/dom/idbkeyrange.rs b/components/script/dom/idbkeyrange.rs new file mode 100644 index 00000000000..e9b951c5512 --- /dev/null +++ b/components/script/dom/idbkeyrange.rs @@ -0,0 +1,128 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use dom_struct::dom_struct; +use js::gc::MutableHandleValue; +use js::rust::HandleValue; +use net_traits::indexeddb_thread::IndexedDBKeyRange; +use script_bindings::codegen::GenericBindings::IDBKeyRangeBinding::IDBKeyRangeMethods; +use script_bindings::root::DomRoot; +use script_bindings::script_runtime::CanGc; + +use crate::dom::bindings::error::Fallible; +use crate::dom::bindings::import::module::SafeJSContext; +use crate::dom::bindings::reflector::{Reflector, reflect_dom_object}; +use crate::dom::globalscope::GlobalScope; +use crate::indexed_db::{convert_value_to_key, key_type_to_jsval}; + +#[dom_struct] +pub struct IDBKeyRange { + reflector_: Reflector, + #[no_trace] + inner: IndexedDBKeyRange, +} + +impl IDBKeyRange { + pub fn new_inherited(inner: IndexedDBKeyRange) -> Self { + IDBKeyRange { + reflector_: Reflector::new(), + inner, + } + } + + pub fn new(global: &GlobalScope, inner: IndexedDBKeyRange, can_gc: CanGc) -> DomRoot { + reflect_dom_object(Box::new(IDBKeyRange::new_inherited(inner)), global, can_gc) + } + + #[expect(unused)] + pub fn inner(&self) -> &IndexedDBKeyRange { + &self.inner + } +} + +impl IDBKeyRangeMethods for IDBKeyRange { + // https://www.w3.org/TR/IndexedDB-2/#dom-idbkeyrange-lower + fn Lower(&self, cx: SafeJSContext, answer: MutableHandleValue) { + if let Some(lower) = self.inner.lower.as_ref() { + key_type_to_jsval(cx, lower, answer); + } + } + + // https://www.w3.org/TR/IndexedDB-2/#dom-idbkeyrange-upper + fn Upper(&self, cx: SafeJSContext, answer: MutableHandleValue) { + if let Some(upper) = self.inner.upper.as_ref() { + key_type_to_jsval(cx, upper, answer); + } + } + + // https://www.w3.org/TR/IndexedDB-2/#dom-idbkeyrange-loweropen + fn LowerOpen(&self) -> bool { + self.inner.lower_open + } + + // https://www.w3.org/TR/IndexedDB-2/#dom-idbkeyrange-upperopen + fn UpperOpen(&self) -> bool { + self.inner.upper_open + } + + // https://www.w3.org/TR/IndexedDB-2/#dom-idbkeyrange-only + fn Only( + cx: SafeJSContext, + global: &GlobalScope, + value: HandleValue, + ) -> Fallible> { + let key = convert_value_to_key(cx, value, None)?; + let inner = IndexedDBKeyRange::only(key); + Ok(IDBKeyRange::new(global, inner, CanGc::note())) + } + + // https://www.w3.org/TR/IndexedDB-2/#dom-idbkeyrange-lowerbound + fn LowerBound( + cx: SafeJSContext, + global: &GlobalScope, + lower: HandleValue, + open: bool, + ) -> Fallible> { + let key = convert_value_to_key(cx, lower, None)?; + let inner = IndexedDBKeyRange::lower_bound(key, open); + Ok(IDBKeyRange::new(global, inner, CanGc::note())) + } + + // https://www.w3.org/TR/IndexedDB-2/#dom-idbkeyrange-upperbound + fn UpperBound( + cx: SafeJSContext, + global: &GlobalScope, + upper: HandleValue, + open: bool, + ) -> Fallible> { + let key = convert_value_to_key(cx, upper, None)?; + let inner = IndexedDBKeyRange::upper_bound(key, open); + Ok(IDBKeyRange::new(global, inner, CanGc::note())) + } + + // https://www.w3.org/TR/IndexedDB-2/#dom-idbkeyrange-bound + fn Bound( + cx: SafeJSContext, + global: &GlobalScope, + lower: HandleValue, + upper: HandleValue, + lower_open: bool, + upper_open: bool, + ) -> Fallible> { + let lower_key = convert_value_to_key(cx, lower, None)?; + let upper_key = convert_value_to_key(cx, upper, None)?; + let inner = + IndexedDBKeyRange::new(Some(lower_key), Some(upper_key), lower_open, upper_open); + Ok(IDBKeyRange::new(global, inner, CanGc::note())) + } + + // https://www.w3.org/TR/IndexedDB-2/#dom-idbkeyrange-_includes + fn Includes(&self, cx: SafeJSContext, value: HandleValue) -> Fallible { + let key = convert_value_to_key(cx, value, None)?; + if self.inner.contains(&key) { + return Ok(true); + } + Ok(false) + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 8190a0b1dda..80918eda497 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -422,6 +422,7 @@ pub(crate) mod htmlunknownelement; pub(crate) mod htmlvideoelement; pub(crate) mod idbdatabase; pub(crate) mod idbfactory; +pub(crate) mod idbkeyrange; pub(crate) mod idbobjectstore; pub(crate) mod idbopendbrequest; pub(crate) mod idbrequest; diff --git a/components/script_bindings/webidls/IDBKeyRange.webidl b/components/script_bindings/webidls/IDBKeyRange.webidl new file mode 100644 index 00000000000..7627f559285 --- /dev/null +++ b/components/script_bindings/webidls/IDBKeyRange.webidl @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +/* + * The origin of this IDL file is + * https://w3c.github.io/IndexedDB/#keyrange + * + */ + +// https://w3c.github.io/IndexedDB/#keyrange +[Pref="dom_indexeddb_enabled", Exposed=(Window,Worker)] +interface IDBKeyRange { + readonly attribute any lower; + readonly attribute any upper; + readonly attribute boolean lowerOpen; + readonly attribute boolean upperOpen; + + // Static construction methods: + [Throws, NewObject] static IDBKeyRange only(any value); + [Throws, NewObject] static IDBKeyRange lowerBound(any lower, optional boolean open = false); + [Throws, NewObject] static IDBKeyRange upperBound(any upper, optional boolean open = false); + [Throws, NewObject] static IDBKeyRange bound(any lower, + any upper, + optional boolean lowerOpen = false, + optional boolean upperOpen = false); + + [Throws] boolean _includes(any key); +}; diff --git a/components/shared/net/indexeddb_thread.rs b/components/shared/net/indexeddb_thread.rs index c943ea08199..77163ca53bd 100644 --- a/components/shared/net/indexeddb_thread.rs +++ b/components/shared/net/indexeddb_thread.rs @@ -5,6 +5,7 @@ use std::cmp::{PartialEq, PartialOrd}; use ipc_channel::ipc::IpcSender; +use malloc_size_of_derive::MallocSizeOf; use serde::{Deserialize, Serialize}; use servo_url::origin::ImmutableOrigin; @@ -17,7 +18,7 @@ pub enum IndexedDBTxnMode { } /// -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] pub enum IndexedDBKeyType { Number(f64), String(String), @@ -113,7 +114,7 @@ impl PartialEq for IndexedDBKeyType { } // -#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)] #[allow(unused)] pub struct IndexedDBKeyRange { pub lower: Option, @@ -133,6 +134,42 @@ impl From for IndexedDBKeyRange { } impl IndexedDBKeyRange { + pub fn only(key: IndexedDBKeyType) -> Self { + Self::from(key) + } + + pub fn new( + lower: Option, + upper: Option, + lower_open: bool, + upper_open: bool, + ) -> Self { + IndexedDBKeyRange { + lower, + upper, + lower_open, + upper_open, + } + } + + pub fn lower_bound(key: IndexedDBKeyType, open: bool) -> Self { + IndexedDBKeyRange { + lower: Some(key), + upper: None, + lower_open: open, + upper_open: false, + } + } + + pub fn upper_bound(key: IndexedDBKeyType, open: bool) -> Self { + IndexedDBKeyRange { + lower: None, + upper: Some(key), + lower_open: false, + upper_open: open, + } + } + // pub fn contains(&self, key: &IndexedDBKeyType) -> bool { // A key is in a key range if both of the following conditions are fulfilled: @@ -150,6 +187,17 @@ impl IndexedDBKeyRange { .is_none_or(|upper| key < upper || (!self.upper_open && key == upper)); lower_bound_condition && upper_bound_condition } + + pub fn is_singleton(&self) -> bool { + self.lower == self.upper && !self.lower_open && !self.upper_open + } + + pub fn as_singleton(&self) -> Option<&IndexedDBKeyType> { + if self.is_singleton() { + return Some(self.lower.as_ref().unwrap()); + } + None + } } #[derive(Debug, Deserialize, Serialize)] diff --git a/tests/wpt/meta/IndexedDB/idb-partitioned-coverage.sub.html.ini b/tests/wpt/meta/IndexedDB/idb-partitioned-coverage.sub.html.ini index 925df45ce6b..17e1d5444ac 100644 --- a/tests/wpt/meta/IndexedDB/idb-partitioned-coverage.sub.html.ini +++ b/tests/wpt/meta/IndexedDB/idb-partitioned-coverage.sub.html.ini @@ -1,5 +1,4 @@ [idb-partitioned-coverage.sub.html] - expected: ERROR [Deletes are processed in order] expected: FAIL @@ -47,3 +46,42 @@ [IDBObjectStore.openKeyCursor() - invalid inputs] 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 + + [maxCount=0] + 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 + + [Retrieve multiEntry key] + expected: FAIL + + [Retrieve one key multiple values] + expected: FAIL + + [Get all values with invalid query keys] + expected: FAIL diff --git a/tests/wpt/meta/IndexedDB/idb_binary_key_conversion.any.js.ini b/tests/wpt/meta/IndexedDB/idb_binary_key_conversion.any.js.ini index eaf7c50252f..40cb36ba77e 100644 --- a/tests/wpt/meta/IndexedDB/idb_binary_key_conversion.any.js.ini +++ b/tests/wpt/meta/IndexedDB/idb_binary_key_conversion.any.js.ini @@ -2,6 +2,7 @@ expected: ERROR [idb_binary_key_conversion.any.worker.html] + expected: CRASH [Empty ArrayBuffer] expected: FAIL @@ -19,6 +20,7 @@ [idb_binary_key_conversion.any.html] + expected: CRASH [Empty ArrayBuffer] expected: FAIL diff --git a/tests/wpt/meta/IndexedDB/idbindex-cross-realm-methods.html.ini b/tests/wpt/meta/IndexedDB/idbindex-cross-realm-methods.html.ini index e0076b52a46..dc22f9303ec 100644 --- a/tests/wpt/meta/IndexedDB/idbindex-cross-realm-methods.html.ini +++ b/tests/wpt/meta/IndexedDB/idbindex-cross-realm-methods.html.ini @@ -1,2 +1,21 @@ [idbindex-cross-realm-methods.html] - expected: ERROR + [Cross-realm IDBIndex::get() method from detached