aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc/models
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-11-23 10:13:28 +0000
committerGitHub <noreply@github.com>2025-11-23 10:13:28 +0000
commited6a3bfac52437c0b86767d7a17dc1ae48d8ccb2 (patch)
treea3be8e399f38705bc41b8e714ce116334e9c095a /packages/trpc/models
parent8ab5df675e98129bb57b106ee331a8d07d324a45 (diff)
downloadkarakeep-ed6a3bfac52437c0b86767d7a17dc1ae48d8ccb2.tar.zst
feat: Add search bar to highlights page (#2155)
* feat: Add search bar to All highlights page This commit adds a search bar to the "All highlights page" that allows users to search their highlights by text content or notes. Changes: - Added search method to Highlight model with SQL LIKE query on text and note fields - Added search endpoint to highlights router with pagination support - Updated AllHighlights component to include search input with debouncing - Search input includes clear button and search icon - Maintains existing infinite scroll pagination for search results Technical details: - Uses SQL ilike for case-insensitive search - 300ms debounce to reduce API calls - Conditionally uses search or getAll endpoint based on search query * fix db query * small fixes --------- Co-authored-by: Claude <noreply@anthropic.com>
Diffstat (limited to 'packages/trpc/models')
-rw-r--r--packages/trpc/models/highlights.ts48
1 files changed, 47 insertions, 1 deletions
diff --git a/packages/trpc/models/highlights.ts b/packages/trpc/models/highlights.ts
index 49791467..48f0672a 100644
--- a/packages/trpc/models/highlights.ts
+++ b/packages/trpc/models/highlights.ts
@@ -1,5 +1,5 @@
import { TRPCError } from "@trpc/server";
-import { and, desc, eq, lt, lte, or } from "drizzle-orm";
+import { and, desc, eq, like, lt, lte, or } from "drizzle-orm";
import { z } from "zod";
import { highlights } from "@karakeep/db/schema";
@@ -114,6 +114,52 @@ export class Highlight {
};
}
+ static async search(
+ ctx: AuthedContext,
+ searchText: string,
+ cursor?: z.infer<typeof zCursorV2> | null,
+ limit = 50,
+ ): Promise<{
+ highlights: Highlight[];
+ nextCursor: z.infer<typeof zCursorV2> | null;
+ }> {
+ const searchPattern = `%${searchText}%`;
+ const results = await ctx.db.query.highlights.findMany({
+ where: and(
+ eq(highlights.userId, ctx.user.id),
+ or(
+ like(highlights.text, searchPattern),
+ like(highlights.note, searchPattern),
+ ),
+ cursor
+ ? or(
+ lt(highlights.createdAt, cursor.createdAt),
+ and(
+ eq(highlights.createdAt, cursor.createdAt),
+ lte(highlights.id, cursor.id),
+ ),
+ )
+ : undefined,
+ ),
+ limit: limit + 1,
+ orderBy: [desc(highlights.createdAt), desc(highlights.id)],
+ });
+
+ let nextCursor: z.infer<typeof zCursorV2> | null = null;
+ if (results.length > limit) {
+ const nextItem = results.pop()!;
+ nextCursor = {
+ id: nextItem.id,
+ createdAt: nextItem.createdAt,
+ };
+ }
+
+ return {
+ highlights: results.map((h) => new Highlight(ctx, h)),
+ nextCursor,
+ };
+ }
+
async delete(): Promise<z.infer<typeof zHighlightSchema>> {
const result = await this.ctx.db
.delete(highlights)