feat: remove typesense

This commit is contained in:
2025-01-05 23:14:19 +01:00
parent d0d49b217d
commit 709fb2d7be
21 changed files with 128 additions and 381 deletions

View File

@@ -1,17 +1,20 @@
import { resources } from "@lib/resources.ts";
import { SearchResult } from "@lib/types.ts";
import { getTypeSenseClient } from "@lib/typesense.ts";
import fuzzysort from "npm:fuzzysort";
import { GenericResource } from "@lib/types.ts";
import { extractHashTags } from "@lib/string.ts";
import { getAllMovies, Movie } from "@lib/resource/movies.ts";
import { Article, getAllArticles } from "@lib/resource/articles.ts";
import { getAllRecipes, Recipe } from "@lib/resource/recipes.ts";
import { getAllSeries, Series } from "@lib/resource/series.ts";
type ResourceType = keyof typeof resources;
type SearchParams = {
q: string;
type?: ResourceType;
types?: string[];
tags?: string[];
rating?: string;
author?: string;
query_by?: string;
rating?: number;
authors?: string[];
};
export function parseResourceUrl(_url: string | URL): SearchParams | undefined {
@@ -31,56 +34,60 @@ export function parseResourceUrl(_url: string | URL): SearchParams | undefined {
return {
q: query,
type: url.searchParams.get("type") as ResourceType || undefined,
types: url.searchParams.get("type")?.split(",") as ResourceType[] ||
undefined,
tags: hashTags,
rating: url.searchParams.get("rating") || undefined,
query_by: url.searchParams.get("query_by") || undefined,
rating: url.searchParams.has("rating")
? parseInt(url.searchParams.get("rating")!)
: undefined,
};
} catch (_err) {
return undefined;
}
}
const isResource = (
item: Movie | Series | Article | Recipe | boolean,
): item is Movie | Series | Article | Recipe => {
return !!item;
};
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");
}
{ q, tags = [], types, authors, rating }: SearchParams,
): Promise<GenericResource[]> {
console.log("searchResource", { q, tags, types, authors, rating });
const filter_by: string[] = [];
if (type) {
filter_by.push(`type:=${type}`);
}
let resources = (await Promise.all([
(!types || types.includes("movie")) && getAllMovies(),
(!types || types.includes("series")) && getAllSeries(),
(!types || types.includes("article")) && getAllArticles(),
(!types || types.includes("recipe")) && getAllRecipes(),
])).flat().filter(isResource);
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,
resources = resources.filter((r) => {
return tags?.every((t) => r.tags.includes(t));
});
}
if (authors?.length) {
resources = resources.filter((r) => {
return r?.meta?.author && authors.includes(r?.meta?.author);
});
}
if (rating) {
resources = resources.filter((r) => {
return r?.meta?.rating && r.meta.rating >= rating;
});
}
if (q.length && q !== "*") {
const results = fuzzysort.go(q, resources, {
keys: ["content", "name", "description"],
threshold: 0.3,
});
resources = results.map((r) => r.obj);
}
return resources;
}