memorium/lib/crud.ts

103 lines
2.4 KiB
TypeScript
Raw Normal View History

2023-08-01 17:50:00 +02:00
import {
createDocument,
getDocument,
getDocuments,
transformDocument,
} from "@lib/documents.ts";
import { Root } from "https://esm.sh/remark-frontmatter@4.0.1";
import { getThumbhash } from "@lib/cache/image.ts";
type Resource = {
name: string;
id: string;
meta: {
image?: string;
author?: string;
thumbnail?: string;
};
};
export async function addThumbnailToResource<T = Resource>(
res: T,
): Promise<T> {
const imageUrl = res?.meta?.image;
if (!imageUrl) return res;
const thumbhash = await getThumbhash({ url: imageUrl });
if (!thumbhash) return res;
const base64String = btoa(String.fromCharCode(...thumbhash));
return {
...res,
meta: {
...res?.meta,
thumbnail: base64String,
},
};
}
2023-08-01 17:50:00 +02:00
export function createCrud<T>(
{ prefix, parse, render, hasThumbnails = false }: {
2023-08-01 17:50:00 +02:00
prefix: string;
hasThumbnails?: boolean;
render?: (doc: T) => string;
2023-08-01 17:50:00 +02:00
parse: (doc: string, id: string) => T;
},
) {
function pathFromId(id: string) {
2023-08-04 22:35:25 +02:00
return `${prefix}${id.replaceAll(":", "")}.md`;
2023-08-01 17:50:00 +02:00
}
async function read(id: string) {
const path = pathFromId(id);
const content = await getDocument(path);
const res = parse(content, id);
if (hasThumbnails) {
return addThumbnailToResource(res);
}
return res;
2023-08-01 17:50:00 +02:00
}
function create(id: string, content: string | ArrayBuffer | T) {
2023-08-01 17:50:00 +02:00
const path = pathFromId(id);
if (
typeof content === "string" || content instanceof ArrayBuffer
) {
return createDocument(path, content);
}
if (render) {
return createDocument(path, render(content));
}
throw new Error("No renderer defined for " + prefix + " CRUD");
2023-08-01 17:50:00 +02:00
}
async function update(id: string, updater: (r: Root) => Root) {
const path = pathFromId(id);
const content = await getDocument(path);
const newDoc = transformDocument(content, updater);
await createDocument(path, newDoc);
}
async function readAll() {
const allDocuments = await getDocuments();
return Promise.all(
allDocuments.filter((d) => {
return d.name.startsWith(prefix) &&
d.contentType === "text/markdown" &&
!d.name.endsWith("index.md");
}).map((doc) => {
const id = doc.name.replace(prefix, "").replace(/\.md$/, "");
return read(id);
}),
);
}
return {
read,
readAll,
create,
update,
};
}