From 0d2502952a1747a72a72ba867dd6119bb97abcba Mon Sep 17 00:00:00 2001 From: 01zulfi <85733202+01zulfi@users.noreply.github.com> Date: Fri, 14 Aug 2026 16:39:48 +0500 Subject: [PATCH] core: fix attachments lookup not being sorted as per sort options Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com> --- packages/core/__tests__/lookup.test.js | 34 ++++++++++++++++++- packages/core/src/api/lookup.ts | 14 ++++++-- .../core/src/utils/__tests__/fuzzy.test.ts | 23 +++++++++++++ packages/core/src/utils/fuzzy.ts | 11 +++--- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/packages/core/__tests__/lookup.test.js b/packages/core/__tests__/lookup.test.js index 0c646d8be..ca4a55559 100644 --- a/packages/core/__tests__/lookup.test.js +++ b/packages/core/__tests__/lookup.test.js @@ -22,7 +22,8 @@ import { TEST_NOTE, notebookTest, TEST_NOTEBOOK2, - databaseTest + databaseTest, + loginFakeUser } from "./utils/index.ts"; import { test, expect, describe } from "vitest"; @@ -140,6 +141,37 @@ test("search reminders", () => expect(descriptionSearch).toHaveLength(1); })); +test("search attachments sorted by dateUploaded should be sorted across batches, not just within each batch", () => + databaseTest().then(async (db) => { + await loginFakeUser(db); + // force multiple batches (2 items per batch) + db.options.batchSize = 2; + + const dateUploaded = [3000, 1000, 4000, 2000]; + for (let i = 0; i < dateUploaded.length; i++) { + const hash = await db.attachments.save( + Buffer.from(`attachment-data-${i}`).toString("base64"), + "image/png", + "photo.png" + ); + await db.attachments.add({ hash, dateUploaded: dateUploaded[i] }); + } + + const searched = await db.lookup.attachments("photo").sorted({ + sortBy: "dateUploaded", + sortDirection: "desc" + }); + + const results = []; + for (let i = 0; i < searched.length; i++) { + const { item } = await searched.item(i); + results.push(item.dateUploaded); + } + + const expected = [...dateUploaded].sort((a, b) => b - a); + expect(results).toEqual(expected); + })); + describe("notesWithHighlighting", () => { test("search notes with nbsp in should decode html entities", () => noteTest({ diff --git a/packages/core/src/api/lookup.ts b/packages/core/src/api/lookup.ts index 2096d10b8..f059d5444 100644 --- a/packages/core/src/api/lookup.ts +++ b/packages/core/src/api/lookup.ts @@ -656,8 +656,13 @@ export default class Lookup { } = {} ) { const columns = fields.map((f) => f.column); - const items = await selector.fields(columns).items(); + const sortOptions = + options.sortOptions?.sortBy !== "relevance" + ? options.sortOptions + : undefined; + const items = await selector.fields(columns).items(undefined, sortOptions); selector.fields([]); + return fuzzy( query, items, @@ -665,7 +670,12 @@ export default class Lookup { Object.fromEntries( fields.filter((f) => !f.ignore).map((f) => [f.name, f.weight || 1]) ) as Record, - options + { + limit: options.limit, + prefix: options.prefix, + suffix: options.suffix, + preserveOrder: sortOptions !== undefined + } ); } diff --git a/packages/core/src/utils/__tests__/fuzzy.test.ts b/packages/core/src/utils/__tests__/fuzzy.test.ts index 5b576ffe3..35dd63fc3 100644 --- a/packages/core/src/utils/__tests__/fuzzy.test.ts +++ b/packages/core/src/utils/__tests__/fuzzy.test.ts @@ -41,6 +41,7 @@ describe("lookup.fuzzy", () => { items[2] ]); }); + describe("opts.prefix", () => { test("should prefix matched field with provided value when given", () => { const items = [ @@ -67,6 +68,7 @@ describe("lookup.fuzzy", () => { ).toStrictEqual([{ id: "2", title: "worlprefix-d" }]); }); }); + describe("opt.suffix", () => { test("should suffix matched field with provided value when given", () => { const items = [ @@ -94,6 +96,27 @@ describe("lookup.fuzzy", () => { }); }); + describe("opt.preserveOrder", () => { + test("should preserve input order when requested", () => { + const items = [ + { id: "1", title: "alpha" }, + { id: "2", title: "a" } + ]; + + const result = fuzzy( + "a", + items, + (i) => i.id, + { title: 1 }, + { + preserveOrder: true + } + ); + + expect(result).toStrictEqual(items); + }); + }); + describe("separator normalization", () => { const items = [ { id: "1", title: "file search.jpg" }, diff --git a/packages/core/src/utils/fuzzy.ts b/packages/core/src/utils/fuzzy.ts index d51b25c24..3a58ec34a 100644 --- a/packages/core/src/utils/fuzzy.ts +++ b/packages/core/src/utils/fuzzy.ts @@ -29,6 +29,7 @@ export function fuzzy( limit?: number; prefix?: string; suffix?: string; + preserveOrder?: boolean; } = {} ): T[] { const results = fuzzyMatch(query, items, getIdentifier, fields, options); @@ -57,11 +58,13 @@ export function fuzzy( } } - const matches = Array.from(results.entries()) - .sort((a, b) => b[1].score - a[1].score) - .map((item) => item[1].item); + const matches = Array.from(results.entries()); - return matches; + if (!options.preserveOrder) { + matches.sort((a, b) => b[1].score - a[1].score); + } + + return matches.map((item) => item[1].item); } function fuzzyMatch(