UNPKG

@paroicms/server

Version:
180 lines 6.71 kB
import { getNodeTypeByName } from "@paroicms/internal-anywhere-lib"; import { parseSqliteDateTime, sqliteDateTime } from "@paroicms/internal-server-lib"; import { ApiError } from "@paroicms/public-server-lib"; import { type } from "arktype"; import { depKeysOfNodeRelationCache, invalidateMultipleDocumentsInCache, invalidateNodeInCache, makeCacheDependencyKey, makeDependencyKeysForDocuments, } from "../../common/text-cache.js"; import { getDocumentNodeIdOfPart } from "../part/part.queries.js"; const TypeNameRowAT = type({ typeName: "string", "+": "reject", }); export async function getTypeNameOf(siteContext, nodeId) { const row = await siteContext .cn("PaNode as n") .select("n.typeName") .where("n.id", nodeId) .first(); if (!row) throw new ApiError(`cannot find node '${nodeId}'`, 404); const validated = TypeNameRowAT.assert(row); return validated.typeName; } export async function getDocumentSchemaOf(siteContext, nodeId) { const typeName = await getTypeNameOf(siteContext, nodeId); const nodeType = getNodeTypeByName(siteContext.siteSchema, typeName); if (nodeType.kind !== "document") throw new Error(`unknown document type '${typeName}'`); return nodeType; } const NodeSeedAT = type({ id: "number", parentId: "number|null", typeName: "string", relativeId: "string", publishDate: "Date|string|number|null", "+": "reject", }).pipe((r) => ({ id: String(r.id), parentId: r.parentId === null ? undefined : String(r.parentId), typeName: r.typeName, relativeId: r.relativeId, publishDate: parseSqliteDateTime(r.publishDate), })); export async function findOneNode({ cn }, id) { const node = await cn("PaNode as n") .select("n.id", "n.parentId", "n.typeName", "n.relativeId", "n.publishDate") .where("n.id", id) .first(); if (!node) throw new ApiError(`can't find node ${id}`, 404); return NodeSeedAT.assert(node); } const LanguageRowAT = type({ language: "string", "+": "reject", }); export async function getLanguagesOfNode({ cn, siteSchema }, nodeId) { const rows = await cn("PaLNode as l") .select("l.language") .where("l.nodeId", nodeId) .whereIn("l.language", siteSchema.languages); return rows.map((row) => LanguageRowAT.assert(row).language); } const SetNodePublishDateRowAT = type({ typeName: "string", publishDate: "string|null", "+": "reject", }).pipe((data) => ({ typeName: data.typeName, publishDate: parseSqliteDateTime(data.publishDate), })); export async function setNodePublishDate(siteContext, { nodeId, publishDate }) { const { cn, siteSchema } = siteContext; const row = await siteContext .cn("PaNode as n") .select("n.typeName", "n.publishDate") .where("n.id", nodeId) .first(); if (!row) throw new ApiError(`cannot find node '${nodeId}'`, 404); const validated = SetNodePublishDateRowAT.assert(row); const typeName = validated.typeName; const prevPublishDate = validated.publishDate; const nodeType = getNodeTypeByName(siteSchema, typeName); await cn("PaNode") .where("id", nodeId) .update({ publishDate: publishDate === null ? null : sqliteDateTime(publishDate) }); if (nodeType.kind === "document") { await invalidateOrScheduleDocument(siteContext, { nodeId, publishDate: publishDate ?? undefined, prevPublishDate, }); } else { await invalidateOrSchedulePart(siteContext, { nodeId, publishDate: publishDate ?? undefined, prevPublishDate, }); } } async function invalidateOrScheduleDocument(siteContext, options) { const { nodeId, publishDate, prevPublishDate } = options; const now = Date.now(); const wasPublished = prevPublishDate !== undefined && prevPublishDate.getTime() <= now; const eventKey = makeCacheDependencyKey({ nodeId }); if (publishDate && publishDate.getTime() <= now) { if (wasPublished) { await invalidateNodeInCache(siteContext, { nodeId }); } else { const newDocDepKeys = await depKeysOfNodeRelationCache(siteContext, { parentOfNodeId: nodeId, relation: "children", }); await siteContext.textCache.invalidate(newDocDepKeys); await siteContext.textCache.cancelScheduledInvalidation(eventKey); } } else { if (wasPublished) { await invalidateMultipleDocumentsInCache(siteContext, { nodeId, fully: true }); } if (publishDate) { const newDocDepKeys = await depKeysOfNodeRelationCache(siteContext, { parentOfNodeId: nodeId, relation: "children", }); await siteContext.textCache.scheduleInvalidation(eventKey, newDocDepKeys, publishDate); } } } async function invalidateOrSchedulePart(siteContext, options) { const { nodeId, publishDate } = options; const documentNodeId = await getDocumentNodeIdOfPart(siteContext, nodeId); const eventKey = makeCacheDependencyKey({ nodeId: documentNodeId, relation: "updated" }); if (publishDate && publishDate.getTime() <= Date.now()) { await invalidateMultipleDocumentsInCache(siteContext, { nodeId: documentNodeId, }); } else if (publishDate) { const depKeys = makeDependencyKeysForDocuments(siteContext, documentNodeId); await siteContext.textCache.scheduleInvalidation(eventKey, depKeys, publishDate); } } const NodeChildrenCountRowAT = type({ cnt: "number", "+": "reject", }); export async function countNodeChildrenOf(siteContext, parendId) { const result = await siteContext .cn("PaNode as n") .count("* as cnt") .where("n.parentId", parendId) .first(); return NodeChildrenCountRowAT.assert(result).cnt; } const ScheduledNodeRowAT = type({ id: "number", publishDate: "Date|string|number", "+": "reject", }).pipe((r) => ({ id: String(r.id), publishDate: parseSqliteDateTime(r.publishDate), })); export async function getScheduledNodes(siteContext) { const rows = await siteContext .cn("PaNode as n") .select("n.id", "n.publishDate") .whereRaw("n.publishDate > current_timestamp"); return rows.map((row) => { const validated = ScheduledNodeRowAT.assert(row); return { nodeId: validated.id, publishDate: validated.publishDate.toISOString(), }; }); } //# sourceMappingURL=node.queries.js.map