aboutsummaryrefslogtreecommitdiffstats
path: root/packages/shared/searchQueryParser.test.ts
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2024-12-31 13:17:56 +0200
committerGitHub <noreply@github.com>2024-12-31 13:17:56 +0200
commitcbaf9e6034aa09911fca967b7af6cad11f154b3e (patch)
tree6995d9d60d9ae5181af78e6577f8d7b724d7a971 /packages/shared/searchQueryParser.test.ts
parentf476fca758bb039f9605488b61ba35fc097d6cfc (diff)
downloadkarakeep-cbaf9e6034aa09911fca967b7af6cad11f154b3e.tar.zst
feat: Introduce advanced search capabilities (#753)
* feat: Implement search filtering in the backend * feat: Implement search language parser * rename matcher name * Add ability to interleve text * More fixes * be more tolerable to parsing errors * Add a search query explainer widget * Handle date parsing gracefully * Fix the lockfile * Encode query search param * Fix table body error * Fix error when writing quotes
Diffstat (limited to 'packages/shared/searchQueryParser.test.ts')
-rw-r--r--packages/shared/searchQueryParser.test.ts275
1 files changed, 275 insertions, 0 deletions
diff --git a/packages/shared/searchQueryParser.test.ts b/packages/shared/searchQueryParser.test.ts
new file mode 100644
index 00000000..428d5929
--- /dev/null
+++ b/packages/shared/searchQueryParser.test.ts
@@ -0,0 +1,275 @@
+import { describe, expect, test } from "vitest";
+
+import { parseSearchQuery } from "./searchQueryParser";
+
+describe("Search Query Parser", () => {
+ test("simple is queries", () => {
+ expect(parseSearchQuery("is:archived")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "archived",
+ archived: true,
+ },
+ });
+ expect(parseSearchQuery("is:not_archived")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "archived",
+ archived: false,
+ },
+ });
+ expect(parseSearchQuery("is:fav")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "favourited",
+ favourited: true,
+ },
+ });
+ expect(parseSearchQuery("is:not_fav")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "favourited",
+ favourited: false,
+ },
+ });
+ });
+
+ test("simple string queries", () => {
+ expect(parseSearchQuery("url:https://example.com")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "url",
+ url: "https://example.com",
+ },
+ });
+ expect(parseSearchQuery('url:"https://example.com"')).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "url",
+ url: "https://example.com",
+ },
+ });
+ expect(parseSearchQuery("#my-tag")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "tagName",
+ tagName: "my-tag",
+ },
+ });
+ expect(parseSearchQuery('#"my tag"')).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "tagName",
+ tagName: "my tag",
+ },
+ });
+ expect(parseSearchQuery("list:my-list")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "listName",
+ listName: "my-list",
+ },
+ });
+ expect(parseSearchQuery('list:"my list"')).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "listName",
+ listName: "my list",
+ },
+ });
+ });
+ test("date queries", () => {
+ expect(parseSearchQuery("after:2023-10-12")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "dateAfter",
+ dateAfter: new Date("2023-10-12"),
+ },
+ });
+ expect(parseSearchQuery("before:2023-10-12")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "dateBefore",
+ dateBefore: new Date("2023-10-12"),
+ },
+ });
+ });
+
+ test("complex queries", () => {
+ expect(parseSearchQuery("is:fav is:archived")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "and",
+ matchers: [
+ {
+ type: "favourited",
+ favourited: true,
+ },
+ {
+ type: "archived",
+ archived: true,
+ },
+ ],
+ },
+ });
+
+ expect(parseSearchQuery("(is:fav is:archived) #my-tag")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "and",
+ matchers: [
+ {
+ type: "favourited",
+ favourited: true,
+ },
+ {
+ type: "archived",
+ archived: true,
+ },
+ {
+ type: "tagName",
+ tagName: "my-tag",
+ },
+ ],
+ },
+ });
+
+ expect(parseSearchQuery("(is:fav is:archived) or (#my-tag)")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "or",
+ matchers: [
+ {
+ type: "and",
+ matchers: [
+ {
+ type: "favourited",
+ favourited: true,
+ },
+ {
+ type: "archived",
+ archived: true,
+ },
+ ],
+ },
+ {
+ type: "tagName",
+ tagName: "my-tag",
+ },
+ ],
+ },
+ });
+
+ expect(parseSearchQuery("(is:fav or is:archived) and #my-tag")).toEqual({
+ result: "full",
+ text: "",
+ matcher: {
+ type: "and",
+ matchers: [
+ {
+ type: "or",
+ matchers: [
+ {
+ type: "favourited",
+ favourited: true,
+ },
+ {
+ type: "archived",
+ archived: true,
+ },
+ ],
+ },
+ {
+ type: "tagName",
+ tagName: "my-tag",
+ },
+ ],
+ },
+ });
+ });
+ test("pure text", () => {
+ expect(parseSearchQuery("hello")).toEqual({
+ result: "full",
+ text: "hello",
+ matcher: undefined,
+ });
+ expect(parseSearchQuery("hello world")).toEqual({
+ result: "full",
+ text: "hello world",
+ matcher: undefined,
+ });
+ });
+
+ test("text interlived with matchers", () => {
+ expect(
+ parseSearchQuery(
+ "hello is:fav world is:archived mixed world #my-tag test",
+ ),
+ ).toEqual({
+ result: "full",
+ text: "hello world mixed world test",
+ matcher: {
+ type: "and",
+ matchers: [
+ {
+ type: "favourited",
+ favourited: true,
+ },
+ {
+ type: "archived",
+ archived: true,
+ },
+ {
+ type: "tagName",
+ tagName: "my-tag",
+ },
+ ],
+ },
+ });
+ });
+
+ test("unknown qualifiers are emitted as pure text", () => {
+ expect(parseSearchQuery("is:fav is:helloworld")).toEqual({
+ result: "full",
+ text: "is:helloworld",
+ matcher: {
+ type: "favourited",
+ favourited: true,
+ },
+ });
+ });
+
+ test("partial results", () => {
+ expect(parseSearchQuery("(is:archived) or ")).toEqual({
+ result: "partial",
+ text: "or",
+ matcher: {
+ type: "archived",
+ archived: true,
+ },
+ });
+ expect(parseSearchQuery("is:fav is: ( random")).toEqual({
+ result: "partial",
+ text: "is: ( random",
+ matcher: {
+ type: "favourited",
+ favourited: true,
+ },
+ });
+ });
+});