UNPKG

@paroicms/server

Version:
198 lines 7.84 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, }) { 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, }); 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, }); const labelingFieldTypes = fieldTypes.filter((item) => item.storedAs === "labeling"); const labelingValues = await loadFieldLabelingValues(siteContext, { nodeId, fieldTypes: labelingFieldTypes, publishedOnly, }); 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); } else { value = lNodeTextValues.get(name); } } 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 { throw new Error(`invalid field storedAs '${fieldType.storedAs}'`); } result[name] = fieldType.withGallery ? [value ?? null, { h: getHandleOfField(siteContext, { fieldType, nodeId }) }] : value; } return result; } const FieldVarcharRowAT = type({ field: "string", dataType: "string", val: "string|null", "+": "reject", }).pipe((data) => ({ field: data.field, dataType: data.dataType, val: data.val ?? 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"]) .where("f.nodeId", nodeId) .whereIn("f.field", [...typeMap.keys()]) .where("f.language", language ?? dbAnyLanguage); for (const row of rows) { const { field: fieldName, dataType, val } = FieldVarcharRowAT.assert(row); const fieldType = typeMap.get(fieldName); if (!fieldType) throw new Error(`should have the field type of '${fieldName}'`); 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", "+": "reject", }).pipe((data) => ({ field: data.field, dataType: data.dataType, val: data.val ?? undefined, })); async function loadTextFieldValues(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("PaFieldText as f") .select(["f.field", "f.dataType", "f.val"]) .where("f.nodeId", nodeId) .whereIn("f.field", Array.from(typeMap.keys())) .where("f.language", language ?? dbAnyLanguage); for (const row of rows) { const { field: fieldName, dataType, val: rawVal } = FieldTextRowAT.assert(row); const fieldType = typeMap.get(fieldName); if (!fieldType) throw new Error(`should have the field type of '${fieldName}'`); if (dataType !== fieldType.dataType) { throw new Error(`dataType mismatch for '${fieldName}', '${language ? `${language}:` : ""}${nodeId}'`); } const val = formatStringFieldValue(rawVal, { fieldType, nodeId }); values.set(fieldName, val); } return values; } 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