core: fix attachments lookup not being sorted as per sort options

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
This commit is contained in:
01zulfi
2026-08-14 16:39:48 +05:00
parent df9cb7c3ff
commit 0d2502952a
4 changed files with 75 additions and 7 deletions

View File

@@ -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({

View File

@@ -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<keyof T, number>,
options
{
limit: options.limit,
prefix: options.prefix,
suffix: options.suffix,
preserveOrder: sortOptions !== undefined
}
);
}

View File

@@ -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" },

View File

@@ -29,6 +29,7 @@ export function fuzzy<T>(
limit?: number;
prefix?: string;
suffix?: string;
preserveOrder?: boolean;
} = {}
): T[] {
const results = fuzzyMatch(query, items, getIdentifier, fields, options);
@@ -57,11 +58,13 @@ export function fuzzy<T>(
}
}
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<T>(