aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/shared/searchQueryParser.test.ts16
-rw-r--r--packages/shared/searchQueryParser.ts5
-rw-r--r--packages/shared/types/search.ts7
-rw-r--r--packages/trpc/lib/search.ts23
4 files changed, 51 insertions, 0 deletions
diff --git a/packages/shared/searchQueryParser.test.ts b/packages/shared/searchQueryParser.test.ts
index 3fe3f388..aa11433f 100644
--- a/packages/shared/searchQueryParser.test.ts
+++ b/packages/shared/searchQueryParser.test.ts
@@ -123,6 +123,22 @@ describe("Search Query Parser", () => {
inverse: true,
},
});
+ expect(parseSearchQuery("is:broken")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "brokenLinks",
+ brokenLinks: true,
+ },
+ });
+ expect(parseSearchQuery("-is:broken")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "brokenLinks",
+ brokenLinks: false,
+ },
+ });
});
test("simple string queries", () => {
diff --git a/packages/shared/searchQueryParser.ts b/packages/shared/searchQueryParser.ts
index f919df96..7447593a 100644
--- a/packages/shared/searchQueryParser.ts
+++ b/packages/shared/searchQueryParser.ts
@@ -166,6 +166,11 @@ MATCHER.setPattern(
inverse: !!minus,
},
};
+ case "broken":
+ return {
+ text: "",
+ matcher: { type: "brokenLinks", brokenLinks: !minus },
+ };
default:
// If the token is not known, emit it as pure text
return {
diff --git a/packages/shared/types/search.ts b/packages/shared/types/search.ts
index caedcf94..c29270b8 100644
--- a/packages/shared/types/search.ts
+++ b/packages/shared/types/search.ts
@@ -83,6 +83,11 @@ const zTypeMatcher = z.object({
inverse: z.boolean(),
});
+const zBrokenLinksMatcher = z.object({
+ type: z.literal("brokenLinks"),
+ brokenLinks: z.boolean(),
+});
+
const zNonRecursiveMatcher = z.union([
zTagNameMatcher,
zListNameMatcher,
@@ -97,6 +102,7 @@ const zNonRecursiveMatcher = z.union([
zIsInListMatcher,
zTypeMatcher,
zRssFeedNameMatcher,
+ zBrokenLinksMatcher,
]);
type NonRecursiveMatcher = z.infer<typeof zNonRecursiveMatcher>;
@@ -120,6 +126,7 @@ export const zMatcherSchema: z.ZodType<Matcher> = z.lazy(() => {
zIsInListMatcher,
zTypeMatcher,
zRssFeedNameMatcher,
+ zBrokenLinksMatcher,
z.object({
type: z.literal("and"),
matchers: z.array(zMatcherSchema),
diff --git a/packages/trpc/lib/search.ts b/packages/trpc/lib/search.ts
index 67348141..88f10f22 100644
--- a/packages/trpc/lib/search.ts
+++ b/packages/trpc/lib/search.ts
@@ -350,6 +350,29 @@ async function getIds(
),
);
}
+ case "brokenLinks": {
+ // Only applies to bookmarks of type LINK
+ return db
+ .select({ id: bookmarkLinks.id })
+ .from(bookmarkLinks)
+ .leftJoin(bookmarks, eq(bookmarks.id, bookmarkLinks.id))
+ .where(
+ and(
+ eq(bookmarks.userId, userId),
+ matcher.brokenLinks
+ ? or(
+ eq(bookmarkLinks.crawlStatus, "failure"),
+ lt(bookmarkLinks.crawlStatusCode, 200),
+ gt(bookmarkLinks.crawlStatusCode, 299),
+ )
+ : and(
+ eq(bookmarkLinks.crawlStatus, "success"),
+ gte(bookmarkLinks.crawlStatusCode, 200),
+ lte(bookmarkLinks.crawlStatusCode, 299),
+ ),
+ ),
+ );
+ }
case "and": {
const vals = await Promise.all(
matcher.matchers.map((m) => getIds(db, userId, m)),