Add entry relations and tags

Show relations and tag membership sections on entry detail.

Signed-off-by: codex@lucy.xalior.com
This commit is contained in:
2026-01-10 18:23:58 +00:00
parent 06ddeba9bb
commit d9f55c3eb6
2 changed files with 206 additions and 0 deletions

View File

@@ -14,6 +14,7 @@ import {
languages,
machinetypes,
genretypes,
categories,
files,
filetypes,
releases,
@@ -33,6 +34,11 @@ import {
permissions,
permissiontypes,
origintypes,
relations,
relationtypes,
tags,
tagtypes,
members,
webrefs,
websites,
magazines,
@@ -299,6 +305,20 @@ export interface EntryDetail {
linkSite?: string | null;
comments?: string | null;
}[];
relations?: {
direction: "from" | "to";
type: { id: string; name: string | null };
entry: { id: number; title: string | null };
}[];
tags?: {
id: number;
name: string;
type: { id: string; name: string | null };
category: { id: number | null; name: string | null };
memberSeq: number | null;
link: string | null;
comments: string | null;
}[];
origins?: {
type: { id: string; name: string | null };
libraryTitle: string;
@@ -583,6 +603,30 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
dateDay: number | string | null;
publication: string | null;
}[] = [];
let relationOutRows: {
relationtypeId: string;
relationtypeName: string | null;
relatedId: number | string;
relatedTitle: string | null;
}[] = [];
let relationInRows: {
relationtypeId: string;
relationtypeName: string | null;
relationtypeReciprocal: string | null;
relatedId: number | string;
relatedTitle: string | null;
}[] = [];
let tagRows: {
id: number | string;
name: string;
tagtypeId: string;
tagtypeName: string | null;
categoryId: number | string | null;
categoryName: string | null;
memberSeq: number | string | null;
link: string | null;
comments: string | null;
}[] = [];
try {
aliasRows = await db
.select({ releaseSeq: aliases.releaseSeq, languageId: aliases.languageId, title: aliases.title })
@@ -644,6 +688,59 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
);
originRows = rows as typeof originRows;
} catch {}
try {
const rows = await db
.select({
relationtypeId: relations.relationtypeId,
relationtypeName: relationtypes.name,
relatedId: relations.originalId,
relatedTitle: entries.title,
})
.from(relations)
.innerJoin(relationtypes, eq(relationtypes.id, relations.relationtypeId))
.leftJoin(entries, eq(entries.id, relations.originalId))
.where(eq(relations.entryId, id));
relationOutRows = rows as typeof relationOutRows;
} catch {}
try {
const rows = await db
.select({
relationtypeId: relations.relationtypeId,
relationtypeName: relationtypes.name,
relationtypeReciprocal: relationtypes.reciprocal,
relatedId: relations.entryId,
relatedTitle: entries.title,
})
.from(relations)
.innerJoin(relationtypes, eq(relationtypes.id, relations.relationtypeId))
.leftJoin(entries, eq(entries.id, relations.entryId))
.where(eq(relations.originalId, id));
relationInRows = rows as typeof relationInRows;
} catch {}
try {
const rows = await db
.select({
id: tags.id,
name: tags.name,
tagtypeId: tags.tagtypeId,
tagtypeName: tagtypes.name,
categoryId: members.categoryId,
categoryName: categories.name,
memberSeq: members.memberSeq,
link: tags.link,
comments: tags.comments,
})
.from(members)
.innerJoin(tags, eq(tags.id, members.tagId))
.leftJoin(tagtypes, eq(tagtypes.id, tags.tagtypeId))
.leftJoin(categories, eq(categories.id, members.categoryId))
.where(eq(members.entryId, id))
.orderBy(
asc(tags.name),
asc(members.memberSeq)
);
tagRows = rows as typeof tagRows;
} catch {}
return {
id: base.id,
@@ -663,6 +760,27 @@ export async function getEntryById(id: number): Promise<EntryDetail | null> {
linkSite: l.linkSite ?? null,
comments: l.comments ?? null,
})),
relations: [
...relationOutRows.map((r) => ({
direction: "from" as const,
type: { id: r.relationtypeId, name: r.relationtypeName ?? null },
entry: { id: Number(r.relatedId), title: r.relatedTitle ?? null },
})),
...relationInRows.map((r) => ({
direction: "to" as const,
type: { id: r.relationtypeId, name: r.relationtypeReciprocal ?? r.relationtypeName ?? null },
entry: { id: Number(r.relatedId), title: r.relatedTitle ?? null },
})),
],
tags: tagRows.map((t) => ({
id: Number(t.id),
name: t.name,
type: { id: t.tagtypeId, name: t.tagtypeName ?? null },
category: { id: t.categoryId != null ? Number(t.categoryId) : null, name: t.categoryName ?? null },
memberSeq: t.memberSeq != null ? Number(t.memberSeq) : null,
link: t.link ?? null,
comments: t.comments ?? null,
})),
origins: originRows.map((o) => ({
type: { id: o.origintypeId, name: o.origintypeName ?? null },
libraryTitle: o.libraryTitle,