Skip to content

Commit

Permalink
Serializes search props into a Solr search string
Browse files Browse the repository at this point in the history
  • Loading branch information
allanlasser committed Jan 8, 2025
1 parent 777c6ab commit 1660b09
Show file tree
Hide file tree
Showing 2 changed files with 196 additions and 0 deletions.
104 changes: 104 additions & 0 deletions src/lib/components/documents/Search.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<script lang="ts" context="module">
export function serialize({
query,
filters,
sort,
order = "asc",
}: {
query?: string;
filters?: FilterFields;
sort?: SortField;
order?: SortOrder;
}): string {
const parts: string[] = [];
// Add main query
if (query) parts.push(query);
if (filters) {
// Add access filter
if (filters.access) {
parts.push(`access:${filters.access}`);
}
// Add page count filters
if (filters.minPages && filters.maxPages) {
parts.push(`pages:[${filters.minPages} TO ${filters.maxPages}]`);
} else if (filters.minPages) {
parts.push(`pages:[${filters.minPages} TO *]`);
} else if (filters.maxPages) {
parts.push(`pages:[* TO ${filters.maxPages}]`);
}
// Add user filters
if (filters.users?.length) {
const userPart = filters.users.map((u) => `user:${u.id}`).join(" OR ");
parts.push(filters.users.length > 1 ? `(${userPart})` : userPart);
}
// Add organization filters
if (filters.orgs?.length) {
const orgPart = filters.orgs
.map((o) => `organization:${o.id}`)
.join(" OR ");
parts.push(filters.orgs.length > 1 ? `(${orgPart})` : orgPart);
}
// Add project filters
if (filters.projects?.length) {
const projectPart = filters.projects
.map((p) => `project:${p.id}`)
.join(" OR ");
parts.push(
filters.projects.length > 1 ? `(${projectPart})` : projectPart,
);
}
}
if (sort) {
if (order === "asc") {
parts.push(`sort:${sort}`);
} else {
parts.push(`sort:-${sort}`);
}
}
return parts.join(" ");
}
</script>

<script lang="ts">
import { _ } from "svelte-i18n";
import Search from "../forms/Search.svelte";
import Filter, { type FilterFields, defaultFilters } from "./Filter.svelte";
import Sort, { type SortField, type SortOrder } from "./Sort.svelte";
export let query = "";
export let filters: FilterFields = defaultFilters;
export let sort: SortField = "created_at";
export let order: SortOrder = "desc";
export let fields: SortField[] = ["created_at", "title", "page_count"];
</script>

<div class="search">
<Search bind:query name="q" />
<div class="controls">
<Filter bind:filters />
<Sort bind:order bind:sort {fields} {query} />
</div>
</div>

<style>
.search {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5rem;
}
.controls {
display: flex;
gap: 0.5rem;
align-items: center;
}
</style>
92 changes: 92 additions & 0 deletions src/lib/components/documents/tests/Search.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { describe, it, expect } from "vitest";
import { serialize } from "../Search.svelte";
import type { FilterFields } from "../Filter.svelte";
import type { SortField, SortOrder } from "../Sort.svelte";
import type { Project, User } from "@/lib/api/types";

interface SearchProps {
query?: string;
filters?: FilterFields;
sort?: SortField;
order?: SortOrder;
}

describe("Search.svelte", () => {
describe("serialize", () => {
it("should serialize a basic query", () => {
const props: SearchProps = { query: "foobar" };
expect(serialize(props)).toBe("foobar");
});

it("should serialize filters", () => {
const props: SearchProps = {
query: "document",
filters: {
users: [{ id: 12345, name: "Test User" }] as User[],
},
};
expect(serialize(props)).toBe("document user:12345");
});

it("should serialize multiple filters with OR", () => {
const props: SearchProps = {
query: "report",
filters: {
projects: [
{ id: 45678, title: "Project 1" },
{ id: 121212, title: "Project 2" },
] as Project[],
},
};
expect(serialize(props)).toBe("report (project:45678 OR project:121212)");
});

it("should serialize access filter", () => {
const props: SearchProps = {
query: "secret",
filters: { access: "private" },
};
expect(serialize(props)).toBe("secret access:private");
});

it("should serialize page count filters", () => {
// with both min and max
let props: SearchProps = {
query: "long",
filters: { minPages: 10, maxPages: 20 },
};
expect(serialize(props)).toBe("long pages:[10 TO 20]");

// with only min
props = {
query: "long",
filters: { minPages: 10 },
};
expect(serialize(props)).toBe("long pages:[10 TO *]");

// with only max
props = {
query: "long",
filters: { maxPages: 20 },
};
expect(serialize(props)).toBe("long pages:[* TO 20]");
});

it("should serialize sort and order", () => {
// in ascending order, the sort is positive
let props: SearchProps = {
query: "test",
sort: "title",
order: "asc",
};
expect(serialize(props)).toBe("test sort:title");
// in descending order, the sort is negative
props = {
query: "test",
sort: "title",
order: "desc",
};
expect(serialize(props)).toBe("test sort:-title");
});
});
});

0 comments on commit 1660b09

Please sign in to comment.