Skip to content

Commit 3f64917

Browse files
committed
fix: MaterializedExecutor sort used string comparison for bigint values
The inline sort comparator checked `typeof av === 'number'` and fell through to `String(av).localeCompare()` for bigint, causing 10n to sort before 9n (lexicographic). Replace with shared rowComparator() which uses < / > operators that work correctly for all types.
1 parent 541e7ef commit 3f64917

File tree

2 files changed

+13
-10
lines changed

2 files changed

+13
-10
lines changed

src/client.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type {
1515
VectorSearchParams,
1616
WindowSpec,
1717
} from "./types.js";
18-
import { NULL_SENTINEL } from "./types.js";
18+
import { NULL_SENTINEL, rowComparator } from "./types.js";
1919
import type { Operator, RowBatch } from "./operators.js";
2020
import { rowPassesFilters } from "./decode.js";
2121
import { computePartialAgg, finalizePartialAgg } from "./partial-agg.js";
@@ -963,15 +963,7 @@ export class MaterializedExecutor implements QueryExecutor {
963963

964964
// Apply sort
965965
if (query.sortColumn) {
966-
const col = query.sortColumn;
967-
const desc = query.sortDirection === "desc";
968-
rows.sort((a, b) => {
969-
const av = a[col], bv = b[col];
970-
if (av === null || av === undefined) return 1;
971-
if (bv === null || bv === undefined) return -1;
972-
if (typeof av === "number" && typeof bv === "number") return desc ? bv - av : av - bv;
973-
return desc ? String(bv).localeCompare(String(av)) : String(av).localeCompare(String(bv));
974-
});
966+
rows.sort(rowComparator(query.sortColumn, query.sortDirection === "desc"));
975967
}
976968

977969
// Apply offset + limit

src/materialized-executor.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,17 @@ describe("MaterializedExecutor", () => {
129129
expect(result.rows[4].name).toBe("Eve");
130130
});
131131

132+
it("sorts bigint values numerically (not lexicographically)", async () => {
133+
const bigData = [
134+
{ id: 1n, val: 9n },
135+
{ id: 2n, val: 10n },
136+
{ id: 3n, val: 2n },
137+
{ id: 4n, val: 100n },
138+
];
139+
const result = await createFromJSON(bigData).sort("val", "asc").collect();
140+
expect(result.rows.map(r => r.val)).toEqual([2n, 9n, 10n, 100n]);
141+
});
142+
132143
it("pushes nulls to end", async () => {
133144
const dataWithNull = [
134145
{ id: 1, val: null },

0 commit comments

Comments
 (0)