UNPKG

@paroicms/server

Version:
192 lines 7.04 kB
import { getPartTypeByName, sortParts } from "@paroicms/internal-anywhere-lib"; import { parseSqliteDateTime } from "@paroicms/internal-server-lib"; import { encodeLNodeId, } from "@paroicms/public-anywhere-lib"; import { type } from "arktype"; import { mainDbSchemaName } from "../connector/db-init/db-constants.js"; const LoadPartsRowAT = type({ nodeId: "number", relativeId: "string", typeName: "string", parentId: "number", orderNum: "number|null", listName: "string", publishDate: "string|number|Date", tNodeId: "number|null", "+": "reject", }).pipe((r) => ({ nodeId: String(r.nodeId), relativeId: r.relativeId, typeName: r.typeName, parentNodeId: String(r.parentId), orderNum: r.orderNum ?? undefined, listName: r.listName, publishDate: parseSqliteDateTime(r.publishDate), inRightLanguage: r.tNodeId !== null, })); export async function loadPartsOf(siteContext, tracker, documentId, listType) { const { siteSchema, cn } = siteContext; const listNames = [...getRecursiveListNames(siteSchema, listType)]; const rows = await cn("PaNode as n") .select([ "n.id as nodeId", "n.relativeId", "n.publishDate", "n.typeName", "n.parentId", "p.listName", "o.orderNum", "l.nodeId as tNodeId", ]) .innerJoin("PaPartNode as p", "p.nodeId", "n.id") .leftJoin("PaLNode as l", { "l.nodeId": "n.id", "l.language": cn.raw("?", [documentId.language]), "l.ready": cn.raw("?", [1]), }) .leftJoin("PaOrderedNode as o", "o.nodeId", "n.id") .where("p.documentNodeId", documentId.nodeId) .whereIn("p.listName", listNames) .whereRaw("n.publishDate <= current_timestamp"); tracker.trackAccess(mainDbSchemaName, "PaPartNode", "read"); const oneLanguageItems = rows.map((row) => { const validated = LoadPartsRowAT.assert(row); const inRightLanguage = validated.inRightLanguage; const commonValues = { nodeId: validated.nodeId, relativeId: validated.relativeId, typeName: validated.typeName, parentNodeId: validated.parentNodeId, orderNum: validated.orderNum, listName: validated.listName, publishDate: validated.publishDate.toISOString(), }; return inRightLanguage ? { ...commonValues, inRightLanguage, language: documentId.language, } : { ...commonValues, inRightLanguage, language: undefined, }; }); const completed = await completeMissingTranslations(siteContext, tracker, oneLanguageItems); const byParent = new Map(); for (const item of completed) { const key = keyOfParentPartData(item); let list = byParent.get(key); if (!list) { list = []; byParent.set(key, list); } list.push(item); } return byParent; } export function keyOfParentPartData(item) { return `${item.listName}:${item.parentNodeId}`; } export function formatListOfPartValues(siteContext, list, listType) { sortParts(listType, list); const numberOfTypes = new Map(); const rawItems = list.map((item, index) => { const numberOfType = (numberOfTypes.get(item.typeName) ?? 0) + 1; numberOfTypes.set(item.typeName, numberOfType); return formatPartValues(siteContext, { item, index, numberOfType }); }); return rawItems; } function formatPartValues(siteContext, { item, index, numberOfType }) { return { type: item.typeName, nodeId: item.nodeId, language: item.language, relativeId: item.relativeId, number: index + 1, numberOfType, inRightLanguage: item.inRightLanguage, publishDate: item.publishDate, languageLabel: siteContext.siteSchema.languageLabels[item.language], }; } const MissingTranslationsRowAT = type({ typeName: "string", nodeId: "number", language: "string", "+": "reject", }).pipe((r) => ({ typeName: r.typeName, nodeId: String(r.nodeId), language: r.language, })); async function completeMissingTranslations(siteContext, tracker, list) { const missingNodeIds = list.filter((item) => !item.inRightLanguage).map((item) => item.nodeId); let otherLanguageItems; if (missingNodeIds.length > 0) { const rows = await siteContext .cn("PaLNode as l") .select(["l.nodeId", "l.language", "n.typeName"]) .innerJoin("PaNode as n", "n.id", "l.nodeId") .whereIn("l.nodeId", missingNodeIds); tracker.trackAccess(mainDbSchemaName, "PaLNode", "read"); const formatted = rows.map((row) => MissingTranslationsRowAT.assert(row)); otherLanguageItems = new Map(formatted.map((item) => [encodeLNodeId(item), item])); } return list.map((item) => { if (item.inRightLanguage) return item; for (const language of siteContext.siteSchema.languages) { const found = otherLanguageItems?.get(encodeLNodeId({ nodeId: item.nodeId, language })); if (found) { return { typeName: item.typeName, nodeId: item.nodeId, relativeId: item.relativeId, parentNodeId: item.parentNodeId, language, orderNum: item.orderNum, listName: item.listName, inRightLanguage: false, publishDate: item.publishDate, }; } } throw new Error(`missing part for item '${item.nodeId}'`); }); } const CountPartsRowAT = type({ cnt: "number|null", "+": "reject", }).pipe((data) => ({ cnt: data.cnt ?? undefined, })); export async function countPartsOf(siteContext, tracker, parentId, listType) { const { listName } = listType; const result = await siteContext .cn("PaNode as l") .count("* as cnt") .innerJoin("PaPartNode as p", "p.nodeId", "l.id") .where("l.parentId", parentId.nodeId) .where("p.listName", listName) .first(); tracker.trackAccess(mainDbSchemaName, "PaPartNode", "read"); return CountPartsRowAT.assert(result).cnt ?? 0; } function getRecursiveListNames(siteSchema, list) { const listNames = new Set([list.listName]); const remainingPartNames = [...list.parts]; while (true) { const childTypeName = remainingPartNames.shift(); if (!childTypeName) break; const child = getPartTypeByName(siteSchema, childTypeName); if (child.list && !listNames.has(child.list.listName)) { listNames.add(child.list.listName); remainingPartNames.push(...child.list.parts); } } return listNames; } //# sourceMappingURL=parts.queries.js.map