Skip to content

Commit

Permalink
improvements: switch to typesense backend
Browse files Browse the repository at this point in the history
- move type-based model.ts to /lib
- add 'later' field to database
- rename pages and switch them all to the typesense backend
  • Loading branch information
kevinstadler committed Sep 13, 2024
1 parent 39d807f commit 1833e78
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 189 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# thomas-bernhard-global

bugs / open questions

- [ ] how should languages be encoded in urls (queries with special characters like `portuguese (brazil)` are currently also broken/unreliable)
File renamed without changes.
28 changes: 19 additions & 9 deletions app/publication/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { notFound } from "next/navigation";
import { useTranslations } from "next-intl";
import { getTranslations } from "next-intl/server";

import { getLaterEditions, getPublication, getSameLanguagePublications } from "@/app/data";
import { AppLink } from "@/components/app-link";
import { BernhardWorkLink } from "@/components/bernhard-links";
import { InlineList } from "@/components/inline-list";
import { MainContent } from "@/components/main-content";
import { ClickablePublicationThumbnail, PublicationCover } from "@/components/publication-cover";
import type { Publication, Translator } from "@/types/model";
import { getPublication, getSameLanguagePublications } from "@/lib/data";
import type { Publication, Translator } from "@/lib/model";

interface PublicationPageProps {
params: {
Expand All @@ -32,13 +32,22 @@ function translatorIndices(pub: Publication): Array<[Translator, Array<number>]>
}, []);
}

export default function PublicationPage(props: PublicationPageProps) {
const t = useTranslations("PublicationPage");
const pub = getPublication(props.params.id);
export default async function PublicationPage(props: PublicationPageProps) {
const t = await getTranslations("PublicationPage");
const pub = await getPublication(props.params.id);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!pub) {
return notFound();
}
const later = getLaterEditions(pub);

const later =
// TODO database should just return null instead of empty arrays wherever possible
pub.later?.length === 0
? undefined
: pub.later?.map((id) => {
return getPublication(id);
});

const translatorInfo = translatorIndices(pub);
// don't show translator/translation indices when all translations are authored by all translators
const showIndices = translatorInfo.some(([_t, is]) => {
Expand Down Expand Up @@ -104,7 +113,8 @@ export default function PublicationPage(props: PublicationPageProps) {
<>
<p className="font-bold">{t("later_editions")}</p>
<div className="flex">
{later.map((p) => {
{later.map(async (pp) => {
const p = await pp;
return (
<div key={p.id}>
<ClickablePublicationThumbnail publication={p} />
Expand All @@ -120,7 +130,7 @@ export default function PublicationPage(props: PublicationPageProps) {
{t("more_in")} {pub.language}
</h2>
<div className="flex">
{getSameLanguagePublications(pub).map((p) => {
{(await getSameLanguagePublications(pub)).map((p) => {
return <ClickablePublicationThumbnail key={p.id} className="size-44" publication={p} />;
})}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import TypesenseInstantSearchAdapter, { type SearchClient } from "typesense-inst

import { ClickablePublicationThumbnail } from "@/components/publication-cover";
import { collectionName } from "@/lib/data";
import type { Publication } from "@/types/model";
import type { Publication } from "@/lib/model";

const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
server: {
Expand Down
File renamed without changes.
File renamed without changes.
58 changes: 12 additions & 46 deletions app/works/[...args]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,79 +1,45 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
"use client";
import { useTranslations } from "next-intl";

// import { useEffect, useState } from "react";
import { getPublications, getWorks } from "@/app/data";
import { AppNavLink } from "@/components/app-nav-link";
import { MainContent } from "@/components/main-content";
import { ClickablePublicationThumbnail } from "@/components/publication-cover";
import { PublicationGrid } from "@/components/publication-grid";
import { Category } from "@/types/model";
import { getPublications } from "@/lib/data";
import { type Category, otherCategories } from "@/lib/model";

interface WorkPageProps {
params: {
args: [Category?, string?];
};
}

export default function WorkPage(props: WorkPageProps) {
// eslint-disable-next-line @next/next/no-async-client-component
export default async function WorkPage(props: WorkPageProps) {
const catt = useTranslations("BernhardCategories");
const _t = useTranslations("WorkPage");

const category = props.params.args[0];
// const [category, _setCategory] = useState<Category | undefined>(props.params.args[0]);
// const [workId, setWorkId] = useState<string | undefined>(props.params.args[1]);

// query result based on category
// const [works, _setWorks] = useState<Array<BernhardWork>>(getWorks(category));
const works = getWorks(category);
const publications = getPublications({ erstpublikation: true }, category, "", 0, 0);
// // query result based on id (and language?)
// const [publications, setPublications] = useState<Array<Publication>>([]);

// useEffect(() => {
// setPublications(getPublications({ erstpublikation: true }));
// }, [workId]);

//if (false) {
// //publicationTypes.includes(category)) {
// // setWorks(getWorks(category));
// if (workId) {
// const work = getWork(workId);
// if (!work) {
// return notFound();
// }
// }
// }
const publications = await getPublications({ q: "*", filter: { erstpublikation: true } });

return (
<MainContent className="">
<div className="flex flex-wrap justify-center gap-4">
{Object.keys(Category).map((c) => {
{otherCategories.map((c) => {
return (
<AppNavLink key={c} href={`/works/${c}`}>
{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
catt(c as any)
}
{catt(c)}
</AppNavLink>
);
})}
</div>

<div>
{
// category ? catt(category as any) : null
}
<ul>
{works.map((w) => {
return (
<li key={w.id}>
<AppNavLink href={`/works/${w.gnd ?? w.id}`}>
{w.title} {w.year ? `(${String(w.year)})` : null}
</AppNavLink>
</li>
);
})}
</ul>
{category}
<ul></ul>
</div>
<PublicationGrid>
{publications.map((p) => {
Expand Down
6 changes: 3 additions & 3 deletions components/app-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ export function AppHeader(): ReactNode {
label: t("links.works"),
},
languages: {
href: createHref({ pathname: "/language" }),
href: createHref({ pathname: "/languages" }),
label: t("links.languages"),
},
translators: {
href: createHref({ pathname: "/translator" }),
href: createHref({ pathname: "/translators" }),
label: t("links.translators"),
},
search: {
href: createHref({ pathname: "/instantsearch" }),
href: createHref({ pathname: "/search" }),
label: t("links.search"),
},
} satisfies Record<string, { href: LinkProps["href"]; label: string }>;
Expand Down
23 changes: 15 additions & 8 deletions lib/data.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Client } from "typesense";
import type { SearchResponse } from "typesense/lib/Typesense/Documents";

import page from "@/app/(index)/page";
import type { Publication } from "@/types/model";
import type { Publication } from "@/lib/model";

const perPage = 16;

Expand Down Expand Up @@ -59,6 +58,10 @@ export async function getFaceted(
}) as unknown as Promise<SearchResponse<Publication>>;
}

export async function getPublication(id: string) {
return collection.documents(id).retrieve() as Promise<Publication>;
}

export async function getPublications(
args: SearchArgs = searchDefaults,
): Promise<Array<Publication>> {
Expand All @@ -72,8 +75,7 @@ export async function getPublications(
per_page: args.per_page,
})
.then((r) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return r.hits!.map((h) => {
return r.hits?.map((h) => {
return h.document;
}) as unknown as Array<Publication>;
});
Expand All @@ -82,8 +84,13 @@ export async function getPublications(
// get 4 publications, ideally in the same language but excluding the publication itself *and* its
// children (because they will already be listed separately anyway)
export async function getSameLanguagePublications(pub: Publication) {
return collection.documents().search({
q: "*",
filter_by: `language: ${pub.language} && id :!= [ ${[pub.id, ...(pub.later ?? [])].join()} ]`,
}) as unknown as Promise<Array<Publication>>;
return (
await collection.documents().search({
q: "*",
per_page: 4,
filter_by: `language: ${pub.language} && id :!= [ ${[pub.id, ...(pub.later ?? [])].join()} ]`,
})
).hits?.map((r) => {
return r.document;
}) as unknown as Array<Publication>;
}
25 changes: 9 additions & 16 deletions types/model.ts → lib/model.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
// these end up in public URLs as slugs, so come up with good names!
export enum Category {
novels = "novels",
novellas = "novellas & short prose",
autobiography = "autobiography",
fragments = "fragments",
export const otherCategories = [
"prose",
"drama",
"poetry",
"letterspeechinterview",
"adaptations",
] as const;
export const proseCategories = ["novels", "novellas", "autobiography", "fragments"] as const;

drama = "drama & libretti",
poetry = "poetry",
letterspeechinterview = "letters, speeches, interviews",
adaptations = "adaptations",
}

export type Prose =
| Category.autobiography
| Category.fragments
| Category.novellas
| Category.novels;
export type Category = (typeof otherCategories)[number] | (typeof proseCategories)[number];

/** Publication contains one or more translated works. */
export interface Publication {
Expand Down
102 changes: 0 additions & 102 deletions readme.md

This file was deleted.

7 changes: 3 additions & 4 deletions scripts/tsv-to-json.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def workkey(pub, i):
logger.error(f"{pub['Signatur']} does not have a numeric year ('{pub['year']}')")
year = None

assets = [ { 'id': pub['Signatur']} ] if os.path.isfile(f'../public/covers/{pub["Signatur"]}.jpg') else None
assets = [ { 'id': pub['Signatur']} ] if os.path.isfile(f'../public/covers/{pub["Signatur"]}.jpg') else []
if len(pub['more']):
assets += [ { 'id': name } for name in pub['more'].split(', ') ]

Expand All @@ -228,10 +228,9 @@ def workkey(pub, i):
if pub['parents']:
for par in pub['parents']:
try:
publications[par]['children'].append(pub['signatur'])
publications[par]['later'].append(pub['id'])
except KeyError:
continue

logger.warning(f"{pub['id']} was previously published in {par} but couldn't find a record for {par}")


print(f"extracted {len(publications)} of {len(data)} publications")
Expand Down

0 comments on commit 1833e78

Please sign in to comment.