-
Notifications
You must be signed in to change notification settings - Fork 161
Description
- I've validated the bug against the latest version of DB packages
Describe the bug
When a collection contains items where an indexed field (used in orderBy) evaluates to undefined, and the query uses both .orderBy() and .limit(), the BTreeIndex.takeInternal method enters an infinite loop. This happens because nextPair(undefined) returns [undefined, undefined] (an array) instead of undefined, so the while loop condition pair !== undefined is always true.
To Reproduce
https://stackblitz.com/edit/vitejs-vite-xcu9tcef?file=src%2FApp.vue
<script setup lang="ts">
import {
createCollection,
eq,
useLiveQuery,
localStorageCollectionOptions,
} from '@tanstack/vue-db';
const collection = createCollection<{
id: number;
assignedTo?: { id: number };
}>(
localStorageCollectionOptions({
id: 'tasks',
storageKey: 'app-tasks',
getKey: (item) => item.id,
})
);
// Add an item with undefined assignedTo
collection.insert({ id: 1, assignedTo: undefined });
// Query with a filter on assignedTo.id
const { data } = useLiveQuery((q) =>
q
.from({ item: collection })
.where(({ item }) => eq(item.assignedTo.id, 35))
.orderBy(({ item }) => item.taskDate, 'desc')
.limit(1)
);
// Insert another item - this triggers the infinite loop
collection.insert({ id: 2, assignedTo: { id: 35 } });
</script>
<template>
<div>
{{ data }}
</div>
</template>
Debug information:
When pausing in the debugger, execution is stuck in btree-index.ts at takeInternal:
Variables at freeze:
pair = [undefined, undefined]
key = undefined
keys = Set with one empty string
result = []
n = 1
Expected behavior
The takeInternal method should handle undefined keys gracefully.