88 lines
2.1 KiB
TypeScript
88 lines
2.1 KiB
TypeScript
import { BadRequestError } from "@lib/errors.ts";
|
|
import { resources } from "@lib/resources.ts";
|
|
import { SearchResult } from "@lib/types.ts";
|
|
import { getTypeSenseClient } from "@lib/typesense.ts";
|
|
import { extractHashTags } from "@lib/string.ts";
|
|
|
|
type ResourceType = keyof typeof resources;
|
|
|
|
type SearchParams = {
|
|
q: string;
|
|
type?: ResourceType;
|
|
tags?: string[];
|
|
rating?: string;
|
|
author?: string;
|
|
query_by?: string;
|
|
};
|
|
|
|
export function parseResourceUrl(_url: string): SearchParams | undefined {
|
|
try {
|
|
const url = new URL(_url);
|
|
let query = url.searchParams.get("q") || "*";
|
|
if (!query) {
|
|
return undefined;
|
|
}
|
|
query = decodeURIComponent(query);
|
|
|
|
const hashTags = extractHashTags(query);
|
|
|
|
for (const tag of hashTags) {
|
|
query = query.replace("#" + tag, "");
|
|
}
|
|
|
|
return {
|
|
q: query,
|
|
type: url.searchParams.get("type") as ResourceType || undefined,
|
|
tags: hashTags,
|
|
rating: url.searchParams.get("rating") || undefined,
|
|
query_by: url.searchParams.get("query_by") || undefined,
|
|
};
|
|
} catch (_err) {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
export async function searchResource(
|
|
{ q, query_by = "name,description,author,tags", tags = [], type, rating }:
|
|
SearchParams,
|
|
): Promise<SearchResult> {
|
|
const typesenseClient = await getTypeSenseClient();
|
|
if (!typesenseClient) {
|
|
throw new Error("Query not available");
|
|
}
|
|
|
|
const filter_by: string[] = [];
|
|
|
|
if (type) {
|
|
filter_by.push(`type:=${type}`);
|
|
}
|
|
|
|
if (tags?.length) {
|
|
filter_by.push(`tags:[${tags.map((t) => `\`${t}\``).join(",")}]`);
|
|
for (const tag of tags) {
|
|
q = q.replaceAll(`#${tag}`, "");
|
|
}
|
|
if (!q.trim().length) {
|
|
q = "*";
|
|
}
|
|
}
|
|
|
|
if (typeof rating !== "undefined") {
|
|
if (rating === "null") {
|
|
filter_by.push(`rating: null`);
|
|
} else {
|
|
filter_by.push(`rating: ${rating}`);
|
|
}
|
|
}
|
|
|
|
return await typesenseClient.collections("resources")
|
|
.documents().search({
|
|
q,
|
|
query_by,
|
|
facet_by: "rating,author,tags",
|
|
max_facet_values: 10,
|
|
filter_by: filter_by.join(" && "),
|
|
per_page: 50,
|
|
});
|
|
}
|