@paroicms/server
Version:
The ParoiCMS server
285 lines • 11.3 kB
JavaScript
import { getNodeTypeByName } from "@paroicms/internal-anywhere-lib";
import { type } from "arktype";
import { getHandleOfField } from "../../common/media-handles.helpers.js";
import { dbAnyLanguage } from "../../context.js";
import { languageIfLNode } from "./_fields.helpers.js";
import { loadFieldLabelingValues } from "./labeling.queries.js";
export async function getSiteFieldValue(siteContext, options) {
const { fieldName, language, publishedOnly } = options;
const values = await loadFieldValues(siteContext, {
nodeId: siteContext.siteNodeId,
language: language ?? undefined,
fieldTypes: getFieldTypesByNames(siteContext, {
typeName: "_site",
fieldNames: [fieldName],
}),
publishedOnly,
});
return values[fieldName];
}
export function getFieldTypesByNames(siteContext, options) {
const { typeName, fieldNames, ignoreUnknownFieldNames } = options;
const fieldTypes = getNodeTypeByName(siteContext.siteSchema, typeName).fields ?? [];
if (!fieldNames)
return fieldTypes;
const names = new Set(fieldNames);
const result = fieldTypes.filter((item) => names.has(item.name));
if (names.size !== result.length && !ignoreUnknownFieldNames) {
throw new Error(`should have the field types of '${[...names].join(", ")}' for typeName '${typeName}'`);
}
return result;
}
export async function loadFieldValues(siteContext, { fieldTypes, nodeId, language, publishedOnly, preprocess, }) {
const result = {};
if (fieldTypes.length === 0)
return result;
const nodeFieldTypes = fieldTypes.filter((item) => item.storedAs === "varchar" && !item.localized);
const nodeVarcharValues = await loadVarcharFieldValues(siteContext, {
fieldTypes: nodeFieldTypes,
nodeId,
});
const lNodeFieldTypes = fieldTypes.filter((item) => item.storedAs === "varchar" && item.localized);
if (language === undefined && lNodeFieldTypes.length !== 0) {
throw new Error(`missing language for ${lNodeFieldTypes.map((item) => item.name).join(", ")}`);
}
const lNodeVarcharValues = await loadVarcharFieldValues(siteContext, {
fieldTypes: lNodeFieldTypes,
nodeId,
language,
});
const nodeTextFieldTypes = fieldTypes.filter((item) => item.storedAs === "text" && !item.localized);
const nodeTextValues = await loadTextFieldValues(siteContext, {
fieldTypes: nodeTextFieldTypes,
nodeId,
selectExcerpt: preprocess?.replaceWithExcerpt ?? false,
});
const lNodeTextFieldTypes = fieldTypes.filter((item) => item.storedAs === "text" && item.localized);
if (language === undefined && lNodeTextFieldTypes.length !== 0) {
throw new Error(`missing language for ${lNodeTextFieldTypes.map((item) => item.name).join(", ")}`);
}
const lNodeTextValues = await loadTextFieldValues(siteContext, {
fieldTypes: lNodeTextFieldTypes,
nodeId,
language,
selectExcerpt: preprocess?.replaceWithExcerpt ?? false,
});
const labelingFieldTypes = fieldTypes.filter((item) => item.storedAs === "labeling");
const labelingValues = await loadFieldLabelingValues(siteContext, {
nodeId,
fieldTypes: labelingFieldTypes,
publishedOnly,
});
const partFieldTypes = fieldTypes.filter((f) => f.storedAs === "partField");
const partFieldValues = new Map();
if (partFieldTypes.length > 0) {
const rows = await siteContext
.cn("PaPartNode as p")
.select(["p.nodeId", "p.listName"])
.innerJoin("PaNode as n", "n.id", "p.nodeId")
.where("n.parentId", nodeId);
for (const row of rows) {
const listName = String(row.listName);
if (listName.startsWith("_pf:")) {
const fieldName = listName.slice(4);
partFieldValues.set(fieldName, String(row.nodeId));
}
}
}
for (const fieldType of fieldTypes) {
const { name, storedAs, localized } = fieldType;
let value;
if (storedAs === "varchar") {
if (!localized) {
value = nodeVarcharValues.get(name);
}
else {
value = lNodeVarcharValues.get(name);
}
}
else if (storedAs === "text") {
if (!localized) {
value = nodeTextValues.get(name)?.value;
}
else {
value = lNodeTextValues.get(name)?.value;
}
}
else if (storedAs === "labeling") {
const termValue = labelingValues?.get(name);
value = termValue ? { t: termValue } : undefined;
}
else if (storedAs === "mediaHandle") {
value = {
h: getHandleOfField(siteContext, {
fieldType,
nodeId,
language: languageIfLNode(language, fieldType),
}),
};
}
else if (storedAs === "partField") {
const partNodeId = partFieldValues.get(name);
value = partNodeId ? { p: { nodeId: partNodeId } } : undefined;
}
else {
throw new Error(`invalid field storedAs '${fieldType.storedAs}'`);
}
result[name] = fieldType.withGallery
? [
value ?? null,
{
attached: "gallery",
h: getHandleOfField(siteContext, { fieldType, nodeId }),
},
]
: value;
}
if (preprocess?.replaceWithExcerpt) {
for (const fieldType of fieldTypes) {
if (fieldType.storedAs !== "text" || fieldType.renderAs !== "html")
continue;
const current = result[fieldType.name];
const excerpt = getExcerptFromLoadedValues({
localized: fieldType.localized,
name: fieldType.name,
nodeTextValues,
lNodeTextValues,
});
const hasExcerpt = excerpt !== undefined && excerpt !== "";
if (!hasExcerpt)
continue;
if (Array.isArray(current)) {
current[0] = null;
current.push({ attached: "text", excerpt });
}
else {
result[fieldType.name] = [null, { attached: "text", excerpt }];
}
}
}
return result;
}
const FieldVarcharRowAT = type({
field: "string",
dataType: "string",
val: "string|null",
plugin: "string|null",
"+": "reject",
}).pipe((data) => ({
field: data.field,
dataType: data.dataType,
val: data.val ?? undefined,
plugin: data.plugin ?? undefined,
}));
async function loadVarcharFieldValues(siteContext, options) {
const { nodeId, language, fieldTypes } = options;
const values = new Map();
if (fieldTypes.length === 0)
return values;
const typeMap = new Map(fieldTypes.map((item) => [item.name, item]));
const rows = await siteContext
.cn("PaFieldVarchar as f")
.select(["f.field", "f.dataType", "f.val", "f.plugin"])
.where("f.nodeId", nodeId)
.whereIn("f.field", [...typeMap.keys()])
.where("f.language", language ?? dbAnyLanguage);
for (const row of rows) {
const { field: fieldName, dataType, val, plugin } = FieldVarcharRowAT.assert(row);
const fieldType = typeMap.get(fieldName);
if (!fieldType)
throw new Error(`should have the field type of '${fieldName}'`);
if (plugin !== (fieldType.pluginName ?? undefined)) {
throw new Error(`Plugin mismatch for field '${fieldName}': expected '${fieldType.pluginName ?? "none"}', got '${plugin ?? "none"}'`);
}
if (dataType !== fieldType.dataType) {
throw new Error(`dataType mismatch for '${fieldName}', '${language ? `${language}:` : ""}${nodeId}'`);
}
values.set(fieldName, formatStringFieldValue(val, { fieldType, nodeId }));
}
return values;
}
const FieldTextRowAT = type({
field: "string",
dataType: "string",
val: "string|null",
plugin: "string|null",
"+": "reject",
}).pipe((data) => ({
field: data.field,
dataType: data.dataType,
val: data.val ?? undefined,
plugin: data.plugin ?? undefined,
excerpt: undefined,
}));
const FieldTextWithExcerptRowAT = type({
field: "string",
dataType: "string",
val: "string|null",
excerpt: "string|null",
plugin: "string|null",
"+": "reject",
}).pipe((data) => ({
field: data.field,
dataType: data.dataType,
val: data.val ?? undefined,
excerpt: data.excerpt ?? undefined,
plugin: data.plugin ?? undefined,
}));
async function loadTextFieldValues(siteContext, options) {
const { nodeId, language, fieldTypes, selectExcerpt } = options;
const values = new Map();
if (fieldTypes.length === 0)
return values;
const typeMap = new Map(fieldTypes.map((item) => [item.name, item]));
const selectCols = ["f.field", "f.dataType", "f.val"];
if (selectExcerpt) {
selectCols.push("f.excerpt");
}
selectCols.push("f.plugin");
const rows = await siteContext
.cn("PaFieldText as f")
.select(selectCols)
.where("f.nodeId", nodeId)
.whereIn("f.field", Array.from(typeMap.keys()))
.where("f.language", language ?? dbAnyLanguage);
const RowAT = selectExcerpt ? FieldTextWithExcerptRowAT : FieldTextRowAT;
for (const row of rows) {
const { field: fieldName, dataType, val: rawVal, excerpt, plugin } = RowAT.assert(row);
const fieldType = typeMap.get(fieldName);
if (!fieldType)
throw new Error(`should have the field type of '${fieldName}'`);
if (plugin !== (fieldType.pluginName ?? undefined)) {
throw new Error(`Plugin mismatch for field '${fieldName}': expected '${fieldType.pluginName ?? "none"}', got '${plugin ?? "none"}'`);
}
if (dataType !== fieldType.dataType) {
throw new Error(`dataType mismatch for '${fieldName}', '${language ? `${language}:` : ""}${nodeId}'`);
}
const val = formatStringFieldValue(rawVal, { fieldType, nodeId });
values.set(fieldName, { value: val, excerpt });
}
return values;
}
function getExcerptFromLoadedValues(args) {
const { name, localized, nodeTextValues, lNodeTextValues } = args;
const entry = localized ? lNodeTextValues.get(name) : nodeTextValues.get(name);
return entry?.excerpt;
}
function formatStringFieldValue(rawVal, options) {
const { fieldType } = options;
switch (fieldType.dataType) {
case "number":
return rawVal === undefined ? undefined : Number(rawVal);
case "boolean":
return rawVal === undefined ? undefined : rawVal !== "0";
case "dateTime":
case "date":
case "time":
case "string":
return rawVal;
case "json":
return rawVal === undefined ? undefined : { j: JSON.parse(rawVal) };
default:
throw new Error(`invalid dataType '${fieldType.dataType}'`);
}
}
//# sourceMappingURL=load-fields.queries.js.map