UNPKG

@paroicms/server

Version:
111 lines 4.33 kB
import { getNodeTypeByName } from "@paroicms/internal-anywhere-lib"; import { makeDefaultRelativeId, parseSqliteDateTime } from "@paroicms/internal-server-lib"; import { isDef, } from "@paroicms/public-anywhere-lib"; import { type } from "arktype"; const CreateNodeParentNodeAT = type({ typeName: "string", "+": "reject", }); const CreateNodeInsertedAT = type({ id: "number", publishDate: "string|number|Date", "+": "reject", }).pipe((r) => ({ id: String(r.id), publishDate: parseSqliteDateTime(r.publishDate), })); export async function createNode(siteSchema, cn, { parentId, typeName, relativeId, }) { if (typeName === "_site") { if (isDef(parentId)) throw new Error(`cannot create site node with parentId '${parentId}'`); } else { if (!isDef(parentId)) throw new Error(`cannot create node '${typeName}' without parentId`); const row = await cn("PaNode").select("typeName").where("id", parentId).first(); if (!row) throw new Error(`cannot find parent node '${parentId}'`); const parentNode = CreateNodeParentNodeAT.assert(row); if (!isTypeNameChildOf(siteSchema, { typeName, parentTypeName: parentNode.typeName })) { throw new Error(`invalid parentTypeName '${parentNode.typeName}'`); } } const newRelativeId = relativeId ?? (await findAvailableRelativeId(siteSchema, cn, { parentId, typeName })); const [inserted] = await cn("PaNode") .insert({ parentId, relativeId: newRelativeId, typeName, publishDate: cn.fn.now(), }) .returning(["id", "publishDate"]); const { id: newId, publishDate } = CreateNodeInsertedAT.assert(inserted); return { id: newId, relativeId: newRelativeId, typeName, publishDate, parentId, }; } export async function findAvailableRelativeId(siteSchema, cn, { parentId, typeName, }) { const nodeType = getNodeTypeByName(siteSchema, typeName); const documentType = nodeType.kind === "document" ? nodeType : undefined; const makeRelativeId = provideRelativeIdGenerator(documentType && documentType.documentKind === "regular" ? documentType.relativeIdGenerator : undefined); let attempt = 0; while (true) { const newRelativeId = makeRelativeId(); const existing = await cn("PaNode") .select("id") .where("relativeId", newRelativeId) .andWhere("parentId", parentId ?? null) .first(); if (isDef(existing)) { if (++attempt === 20) throw new Error(`failed to find a relativeId for node '${typeName}'`); } return newRelativeId; } } export function isTypeNameChildOf(siteSchema, { parentTypeName, typeName }) { const parentType = getNodeTypeByName(siteSchema, parentTypeName); if (parentType.kind === "site") { return typeName === "home"; } if (parentType.kind === "document") { const childType = getNodeTypeByName(siteSchema, typeName); if (childType.kind === "document") { return ((parentType.regularChildren?.includes(childType.typeName) || parentType.routingChildren?.includes(childType.typeName)) ?? false); } for (const listType of parentType.lists ?? []) { if (listType.parts.includes(typeName)) return true; } for (const field of parentType.fields ?? []) { if (field.storedAs === "partField" && field.partType === typeName) return true; } } if (parentType.kind === "part") { if (parentType.list?.parts.includes(typeName)) return true; for (const field of parentType.fields ?? []) { if (field.storedAs === "partField" && field.partType === typeName) return true; } } return false; } function provideRelativeIdGenerator(rim) { const makerName = rim?.[0] ?? "default"; if (makerName === "default") { const size = rim ? Number(rim[1]) : undefined; return () => makeDefaultRelativeId({ size }); } throw new Error(`Invalid relativeId maker name '${makerName}'`); } //# sourceMappingURL=init-node-queries.js.map