diff --git a/moli-indexeddb/src/cursor.rs b/moli-indexeddb/src/cursor.rs index 2c86689066..a834a0d843 100644 --- a/moli-indexeddb/src/cursor.rs +++ b/moli-indexeddb/src/cursor.rs @@ -38,12 +38,14 @@ pub fn apply_cursor_direction_by_key( direction: CursorDirection, mut key_for: impl FnMut(&T) -> &Key, ) -> Vec { - if direction.is_reverse() { - entries.reverse(); - } + // Unique index cursors select the lowest primary key for each index key, + // including when the distinct index keys are visited in reverse order. if direction.is_unique() { entries.dedup_by(|right, left| key_for(left) == key_for(right)); } + if direction.is_reverse() { + entries.reverse(); + } entries } diff --git a/moli-indexeddb/src/tests.rs b/moli-indexeddb/src/tests.rs index a52ab65143..d8bda54a64 100644 --- a/moli-indexeddb/src/tests.rs +++ b/moli-indexeddb/src/tests.rs @@ -60,7 +60,7 @@ fn cursor_direction_helpers_reverse_and_deduplicate_by_key() { ); assert_eq!( apply_cursor_direction_by_key(entries, CursorDirection::PrevUnique, |entry| &entry.0), - vec![(Key::from("b"), 3), (Key::from("a"), 2)] + vec![(Key::from("b"), 3), (Key::from("a"), 1)] ); } @@ -1661,3 +1661,25 @@ fn auto_increment_rejects_exhausted_safe_integer_range() { .expect_err("generate_key should fail once the safe integer range is exhausted"); assert!(matches!(error, IndexedDbError::Constraint(_))); } + +#[test] +fn reverse_unique_index_cursor_keeps_first_primary_key_for_each_index_key() { + let entries = vec![ + (Key::from("a"), 1), + (Key::from("a"), 2), + (Key::from("b"), 3), + (Key::from("b"), 4), + (Key::from("c"), 5), + (Key::from("c"), 6), + ]; + let actual = + apply_cursor_direction_by_key(entries, CursorDirection::PrevUnique, |entry| &entry.0); + assert_eq!( + actual, + vec![ + (Key::from("c"), 5), + (Key::from("b"), 3), + (Key::from("a"), 1) + ] + ); +} diff --git a/moli-renderer-v8/src/script_vm/tests/indexed_db.rs b/moli-renderer-v8/src/script_vm/tests/indexed_db.rs index fe0d497978..a5a1ca517b 100644 --- a/moli-renderer-v8/src/script_vm/tests/indexed_db.rs +++ b/moli-renderer-v8/src/script_vm/tests/indexed_db.rs @@ -4888,7 +4888,7 @@ fn indexed_db_cursors_support_prev_directions() { .eval_after_selected_page_tasks("String(globalThis.__indexedDbCursorPrevResult)") .expect("indexeddb cursor prev result should be readable"); - assert_eq!(result, "c,b,a|tech:c,news:b"); + assert_eq!(result, "c,b,a|tech:c,news:a"); } #[test] diff --git a/moli-wpt-compat/fixtures/wpt/ported/indexeddb/idb-collection-query-conversion-basic.html b/moli-wpt-compat/fixtures/wpt/ported/indexeddb/idb-collection-query-conversion-basic.html index aae3509fa9..d0f87012fe 100644 --- a/moli-wpt-compat/fixtures/wpt/ported/indexeddb/idb-collection-query-conversion-basic.html +++ b/moli-wpt-compat/fixtures/wpt/ported/indexeddb/idb-collection-query-conversion-basic.html @@ -121,7 +121,7 @@ promise_test(async () => { ); assert_array_equals( await wait_request(index.getAllKeys({ direction: "prevunique" })), - [3, 2], + [3, 1], "index.getAllKeys() applies options prevunique direction" );