From b3d3602dc5af6768e5b03613a7ca22ad3b47ec8d Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Mon, 9 Feb 2026 01:03:29 +0000 Subject: fix: Support nested smart lists with cycle detection (#2470) * fix: Support nested smart lists and prevent infinite loops --------- Co-authored-by: Claude --- packages/trpc/lib/__tests__/search.test.ts | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'packages/trpc/lib/__tests__') diff --git a/packages/trpc/lib/__tests__/search.test.ts b/packages/trpc/lib/__tests__/search.test.ts index ee8bfb60..d39e27a6 100644 --- a/packages/trpc/lib/__tests__/search.test.ts +++ b/packages/trpc/lib/__tests__/search.test.ts @@ -240,6 +240,61 @@ describe("getBookmarkIdsFromMatcher", () => { expect(result.sort()).toEqual(["b2", "b3", "b4", "b5"]); }); + it("should handle listName matcher when multiple lists share the same name", async () => { + await mockCtx.db.insert(bookmarkLists).values({ + id: "l5", + userId: testUserId, + name: "list1", + icon: "🚀", + type: "manual", + }); + await mockCtx.db.insert(bookmarksInLists).values({ + bookmarkId: "b2", + listId: "l5", + }); + + const matcher: Matcher = { + type: "listName", + listName: "list1", + inverse: false, + }; + const result = await getBookmarkIdsFromMatcher(mockCtx, matcher); + expect(result.sort()).toEqual(["b1", "b2", "b6"]); + }); + + it("should handle inverse listName matcher when multiple lists share the same name", async () => { + await mockCtx.db.insert(bookmarkLists).values({ + id: "l5", + userId: testUserId, + name: "list1", + icon: "🚀", + type: "manual", + }); + await mockCtx.db.insert(bookmarksInLists).values({ + bookmarkId: "b2", + listId: "l5", + }); + + const matcher: Matcher = { + type: "listName", + listName: "list1", + inverse: true, + }; + const result = await getBookmarkIdsFromMatcher(mockCtx, matcher); + expect(result.sort()).toEqual(["b3", "b4", "b5"]); + }); + + it("should return empty when inverse listName references a missing list", async () => { + const matcher: Matcher = { + type: "listName", + listName: "does-not-exist", + inverse: true, + }; + + const result = await getBookmarkIdsFromMatcher(mockCtx, matcher); + expect(result).toEqual([]); + }); + it("should handle archived matcher", async () => { const matcher: Matcher = { type: "archived", archived: true }; const result = await getBookmarkIdsFromMatcher(mockCtx, matcher); -- cgit v1.2.3-70-g09d2