aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc/lib
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2025-04-06 23:50:39 +0100
committerMohamedBassem <me@mbassem.com>2025-04-06 23:50:39 +0100
commitaf6774fab6502b3f49a71dea955357992e5edc77 (patch)
treebe63f9ebf16bdd807b5cd882265cb0c27bf1bf85 /packages/trpc/lib
parentd86628dfabe8b9c17c7dd68b3d291104c3b25704 (diff)
downloadkarakeep-af6774fab6502b3f49a71dea955357992e5edc77.tar.zst
feat: Add a search matcher for rss feed bookmarks
Diffstat (limited to 'packages/trpc/lib')
-rw-r--r--packages/trpc/lib/__tests__/search.test.ts48
-rw-r--r--packages/trpc/lib/search.ts29
2 files changed, 77 insertions, 0 deletions
diff --git a/packages/trpc/lib/__tests__/search.test.ts b/packages/trpc/lib/__tests__/search.test.ts
index 7f573b4f..9f8aac88 100644
--- a/packages/trpc/lib/__tests__/search.test.ts
+++ b/packages/trpc/lib/__tests__/search.test.ts
@@ -9,6 +9,8 @@ import {
bookmarksInLists,
bookmarkTags,
bookmarkTexts,
+ rssFeedImportsTable,
+ rssFeedsTable,
tagsOnBookmarks,
users,
} from "@hoarder/db/schema";
@@ -151,6 +153,32 @@ beforeEach(async () => {
{ bookmarkId: "b6", listId: "l1" },
]);
+ await db.insert(rssFeedsTable).values([
+ { id: "f1", userId: testUserId, name: "feed1", url: "url1" },
+ { id: "f2", userId: testUserId, name: "feed2", url: "url2" },
+ ]);
+
+ await db.insert(rssFeedImportsTable).values([
+ {
+ id: "imp1",
+ entryId: "entry1",
+ rssFeedId: "f1",
+ bookmarkId: "b1",
+ },
+ {
+ id: "imp2",
+ entryId: "entry2",
+ rssFeedId: "f2",
+ bookmarkId: "b3",
+ },
+ {
+ id: "imp3",
+ entryId: "entry3",
+ rssFeedId: "f1",
+ bookmarkId: "b5",
+ },
+ ]);
+
mockCtx = {
db,
user: {
@@ -423,6 +451,26 @@ describe("getBookmarkIdsFromMatcher", () => {
expect(result).toEqual(["b3"]);
});
+ it("should handle rssFeedName matcher", async () => {
+ const matcher: Matcher = {
+ type: "rssFeedName",
+ feedName: "feed1",
+ inverse: false,
+ };
+ const result = await getBookmarkIdsFromMatcher(mockCtx, matcher);
+ expect(result.sort()).toEqual(["b1", "b5"]);
+ });
+
+ it("should handle rssFeedName matcher with inverse=true", async () => {
+ const matcher: Matcher = {
+ type: "rssFeedName",
+ feedName: "feed1",
+ inverse: true,
+ };
+ const result = await getBookmarkIdsFromMatcher(mockCtx, matcher);
+ expect(result.sort()).toEqual(["b2", "b3", "b4", "b6"]);
+ });
+
it("should throw error for unknown matcher type", async () => {
const matcher = { type: "unknown" } as unknown as Matcher;
await expect(getBookmarkIdsFromMatcher(mockCtx, matcher)).rejects.toThrow(
diff --git a/packages/trpc/lib/search.ts b/packages/trpc/lib/search.ts
index de76748b..83dfa674 100644
--- a/packages/trpc/lib/search.ts
+++ b/packages/trpc/lib/search.ts
@@ -20,6 +20,8 @@ import {
bookmarks,
bookmarksInLists,
bookmarkTags,
+ rssFeedImportsTable,
+ rssFeedsTable,
tagsOnBookmarks,
} from "@hoarder/db/schema";
import { Matcher } from "@hoarder/shared/types/search";
@@ -177,6 +179,33 @@ async function getIds(
),
);
}
+ case "rssFeedName": {
+ const comp = matcher.inverse ? notExists : exists;
+ return db
+ .selectDistinct({ id: bookmarks.id })
+ .from(bookmarks)
+ .where(
+ and(
+ eq(bookmarks.userId, userId),
+ comp(
+ db
+ .select()
+ .from(rssFeedImportsTable)
+ .innerJoin(
+ rssFeedsTable,
+ eq(rssFeedImportsTable.rssFeedId, rssFeedsTable.id),
+ )
+ .where(
+ and(
+ eq(rssFeedImportsTable.bookmarkId, bookmarks.id),
+ eq(rssFeedsTable.userId, userId),
+ eq(rssFeedsTable.name, matcher.feedName),
+ ),
+ ),
+ ),
+ ),
+ );
+ }
case "archived": {
return db
.select({ id: bookmarks.id })