fix(indexeddb): preserve first primary keys in reverse unique cursors

Deduplicate the ascending index entries before reversing unique cursor traversal. Previously prevunique chose the last primary key in each duplicate index-key group. Preserve ordinary reverse traversal and cover multiple duplicated index keys in native cursor tests. Update the existing JavaScript cursor and collection regressions to assert the corrected primary-key choice.
This commit is contained in:
ldm0
2026-10-10 03:59:29 +08:00
committed by Donough Liu
parent 2c8f19277b
commit 579e180545
4 changed files with 30 additions and 6 deletions
+5 -3
View File
@@ -38,12 +38,14 @@ pub fn apply_cursor_direction_by_key<T>(
direction: CursorDirection,
mut key_for: impl FnMut(&T) -> &Key,
) -> Vec<T> {
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
}
+23 -1
View File
@@ -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)
]
);
}
@@ -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]
@@ -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"
);