UNPKG

@paroicms/server

Version:
285 lines 11.3 kB
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