@paroicms/server
Version:
The ParoiCMS server
111 lines • 4.33 kB
JavaScript
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