sourceapplibrarian.js

import Database from "better-sqlite3";
const db = new Database("./db/site.db");
db.pragma("journal_mode = DELETE");

const books = {
	carol: {
		original: "carol",
		author: "Charles Dickens",
		alexandrine: "93.15 D548",
		pageCreated: "1843",
		sequence: ["_", "1", "2", "3", "4", "5"],
		translations: {
			carol: {
				title: "A Christmas Carol",
				lang: "en",
				chapters: {
					_: {
						name: "Front page",
						short: "Front"
					},
					1: {
						number: "Stave One",
						name: "Marley’s Ghost",
						short: "1"
					},
					2: {
						number: "Stave Two",
						name: "The First of the Three Spirits",
						short: "2"
					},
					3: {
						number: "Stave Three",
						name: "The Second of the Three Spirits",
						short: "3"
					},
					4: {
						number: "Stave Four",
						name: "The Last of the Spirits",
						short: "4"
					},
					5: {
						number: "Stave Five",
						name: "The End of It",
						short: "5"
					}
				}
			}
		}
	},
	cosmou: {
		original: "cosmou",
		alexandrine: "11.15 S169",
		translations: {
			cosmou: { title: "Περὶ θεῶν καὶ κόσμου", lang: "grc" },
			"on-the-gods": { title: "On the Gods and the World", lang: "en" }
		}
	},
	end: {
		original: "end",
		alexandrine: "91.18 G692",
		translations: {
			end: { title: "The End Poem", lang: "en" },
			endgedicht: { title: "Het Endgedicht", lang: "nl" },
			chungmo: { title: "終末之詩", lang: "zh-Hant" },
			zhongmo: { title: "终末之诗", lang: "zh" }
		}
	},
	furrycode: {
		original: null,
		alexandrine: "71.59 S658",
		codexLink: "http://captainpackrat.com/furry/furcode.htm",
		codexVerb: "visit",
		translations: {
			furrycode: { title: "De Code van de Furry’s", lang: "nl" }
		}
	},
	moon: {
		original: "moon",
		alexandrine: "55.61 S128",
		translations: {
			moon: { title: "In Event of Moon Disaster", lang: "en" },
			maanramp: { title: "In geval van maanramp", lang: "nl" },
			qamar: { title: "في حال حدثت كارثة القمر", lang: "ar" },
			selini: {
				title: "Για το ενδεχόμενο καταστροφής στη Σελήνη",
				lang: "el"
			},
			lune: {
				title: "Dans L’Hypothèse d’une catastrophe sur la Lune",
				lang: "fr"
			},
			yuehchiu: { title: "月球災難", lang: "zh-Hant" },
			yueqiu: { title: "月球灾难", lang: "zh" }
		}
	},
	toolbag: {
		original: null,
		alexandrine: "42.05 (41) G659",
		codexLink:
			"https://uk.bookshop.org/books/the-walker-s-guide-to-outdoor-clues-and-signs-explore-the-great-outdoors-from-your-armchair/9781444780109?aid=7944",
		codexVerb: "buy",
		translations: {
			toolbag: { title: "Your Invisible Toolbag", lang: "en" }
		}
	},
	udhr: {
		original: "udhr",
		alexandrine: "86.81",
		translations: {
			udhr: {
				title: "The Universal Declaration of Human Rights",
				lang: "en"
			},
			rechten: {
				title: "Universele verklaring van de rechten van de mens",
				lang: "nl"
			},
			huquq: { title: "الإعلان العالمي لحقوق الإنسان", lang: "ar" },
			dikaiomata: {
				title: "Οικουμενική διακήρυξη για τα ανθρώπινα δικαιώματα",
				lang: "el"
			},
			rajtoj: {
				title: "Universala deklaracio de homaj rajtoj",
				lang: "eo"
			},
			dudh: {
				title: "Déclaration universelle des droits de l’homme",
				lang: "fr"
			},
			adhikarom: { title: "मानव अधिकारों की सार्वभौम घोषणा", lang: "hi" },
			haki: {
				title: "Taarifa ya ulimwengu juu ya haki za binadamu",
				lang: "sw"
			},
			jinken: {
				title: "世界人権宣言",
				lang: "ja"
			},
			jenchuan: { title: "世界人權宣言", lang: "zh-Hant" },
			renquan: { title: "世界人权宣言", lang: "zh" }
		}
	}
};

const insertKeys = db.transaction((row, table) => {
	const rowKeys = Object.keys(row);
	db.prepare(
		`INSERT INTO ${table} (${rowKeys
			.map(x => ` ${x}`)
			.toString()
			.trim()}) VALUES (${rowKeys
			.map(x => ` @${x}`)
			.toString()
			.trim()})`
	).run(row);
});

const updateKeys = db.transaction((newRow, oldRow, table) => {
	const tableID = table.replace(/s$/, "ID");
	for (const key in newRow) {
		if (newRow[key] != oldRow[key] && newRow[key] !== undefined) {
			db.prepare(
				`UPDATE ${table} SET ${key} = ? WHERE ${tableID} = ?`
			).run(newRow[key], newRow[tableID]);
		}
	}
});

const setRecord = db.transaction((row, record) => {
	const table = "editionID" in row ? "editions" : "pagesets";

	if (record === undefined) {
		insertKeys(row, table);
	} else {
		updateKeys(row, record, table);
	}
});

for (const bookID in books) {
	const book = books[bookID];

	if ("sequence" in book) {
		for (
			let chapterIdx = 0;
			chapterIdx < book.sequence.length;
			chapterIdx++
		) {
			const chapter = book.sequence[chapterIdx];
			const subfolder = chapter == "_" ? "" : `/${chapter}`;
			const lastChapter =
				chapterIdx == 0 ? null : book.sequence[chapterIdx - 1];
			const nextChapter =
				chapterIdx == book.sequence.length - 1
					? null
					: book.sequence[chapterIdx + 1];

			const chapterData = {
				pagesetID: `codex/${bookID}${subfolder}`,
				original: `codex/${book.original ?? bookID}${subfolder}`,
				subsite: "codex",
				alexandrine: book.alexandrine ?? null,
				pageCreated: book.pageCreated ?? null,
				codexLink: book.codexLink ?? null,
				codexVerb: book.codexVerb ?? null
			};

			const chapterRecord = db
				.prepare("SELECT * FROM pagesets WHERE pagesetID = ?")
				.get(chapterData.pagesetID);

			setRecord(chapterData, chapterRecord);

			for (const translationID in book?.translations) {
				const translation = book.translations[translationID];
				const translatedChapter = translation.chapters[chapter];

				const chapterList = book.sequence.map(c => {
					const ch = translation.chapters[c];
					const chSubfolder = c == "_" ? "" : `/${c}`;
					return {
						link:
							chapter == c
								? null
								: `codex/${translationID}${chSubfolder}`,
						shortName: ch.short
					};
				});

				const translationData = {
					editionID: `codex/${translationID}${subfolder}`,
					lang: translation.lang,
					translates: chapterData.pagesetID,
					title:
						chapter == "_"
							? translation.title
							: `${translatedChapter.number}: ${translatedChapter.name} | ${translation.title}`,
					codexLast:
						lastChapter === null
							? null
							: `codex/${translationID}${
									lastChapter == "_" ? "" : `/${lastChapter}`
							  }`,
					codexLastTitle:
						lastChapter === null
							? null
							: translation.chapters[lastChapter].name,
					codexNext:
						nextChapter === null
							? null
							: `codex/${translationID}${
									nextChapter == "_" ? "" : `/${nextChapter}`
							  }`,
					codexNextTitle:
						nextChapter === null
							? null
							: translation.chapters[nextChapter].name,
					codexAuthor: translation.author ?? book.author ?? null,
					codexChapters: JSON.stringify(chapterList)
				};

				const translationRecord = db
					.prepare("SELECT * FROM editions WHERE editionID = ?")
					.get(translationData.editionID);

				setRecord(translationData, translationRecord);
			}
		}
	} else {
		const bookData = {
			pagesetID: `codex/${bookID}`,
			original: `codex/${book.original ?? bookID}`,
			subsite: "codex",
			alexandrine: book.alexandrine ?? null,
			pageCreated: book.pageCreated ?? null,
			codexLink: book.codexLink ?? null,
			codexVerb: book.codexVerb ?? null
		};

		const bookRecord = db
			.prepare("SELECT * FROM pagesets WHERE pagesetID = ?")
			.get(bookData.pagesetID);

		setRecord(bookData, bookRecord);

		for (const translationID in book?.translations) {
			const translation = book.translations[translationID];
			const translationData = {
				editionID: `codex/${translationID}`,
				lang: translation.lang,
				translates: bookData.pagesetID,
				title: translation.title,
				codexAuthor: translation.author ?? book.author ?? null
			};

			const translationRecord = db
				.prepare("SELECT * FROM editions WHERE editionID = ?")
				.get(translationData.editionID);

			setRecord(translationData, translationRecord);
		}
	}
}