UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1 lines 10.9 kB
{"version":3,"file":"custom-field.mjs","names":[],"sources":["../../../../../../src/libs/collection/custom-fields/fields/relation/custom-field.ts"],"sourcesContent":["import z from \"zod\";\nimport type {\n\tLucidBricksTable,\n\tSelect,\n\tServiceResponse,\n} from \"../../../../../types.js\";\nimport { copy } from \"../../../../i18n/index.js\";\nimport buildSchemaIndex from \"../../../helpers/build-schema-index.js\";\nimport buildTableName from \"../../../helpers/build-table-name.js\";\nimport prefixGeneratedColName from \"../../../helpers/prefix-generated-column-name.js\";\nimport CustomField from \"../../custom-field.js\";\nimport type {\n\tCFConfig,\n\tCFProps,\n\tCFResponse,\n\tCustomFieldErrorItem,\n\tCustomFieldValidationError,\n\tFieldRelationRefTarget,\n\tFieldRelationValidationInput,\n\tGetIndexDefinitionProps,\n\tGetSchemaDefinitionProps,\n\tIndexDefinition,\n\tSchemaDefinition,\n} from \"../../types.js\";\nimport keyToTitle from \"../../utils/key-to-title.js\";\nimport { validateRelationItemCount } from \"../../utils/relation-item-count-validation.js\";\nimport zodSafeParse from \"../../utils/zod-safe-parse.js\";\nimport { relationFieldConfig } from \"./config.js\";\nimport type {\n\tRelationCustomFieldValue,\n\tRelationValidationData,\n} from \"./types.js\";\nimport { normalizeRelationCollections } from \"./utils/normalize-relation-collections.js\";\nimport {\n\tclampRelationFieldInput,\n\tnormalizeStoredRelationCustomFieldValues,\n} from \"./utils/relation-field-values.js\";\n\nclass RelationCustomField extends CustomField<\"relation\"> {\n\ttype = relationFieldConfig.type;\n\tconfig;\n\tkey;\n\tprops;\n\tconstructor(key: string, props: CFProps<\"relation\">) {\n\t\tsuper();\n\t\tthis.key = key;\n\t\tthis.props = props;\n\t\tthis.config = {\n\t\t\tkey: this.key,\n\t\t\ttype: this.type,\n\t\t\tcollection: normalizeRelationCollections(this.props.collection),\n\t\t\tdetails: {\n\t\t\t\tlabel:\n\t\t\t\t\tthis.props?.details?.label ??\n\t\t\t\t\tcopy(`admin:fields.${this.type}.${this.key}.label`, {\n\t\t\t\t\t\tdefaultMessage: keyToTitle(this.key),\n\t\t\t\t\t}),\n\t\t\t\tsummary: this.props?.details?.summary,\n\t\t\t},\n\t\t\tlocalized: this.props?.localized ?? false,\n\t\t\tdefault: this.props?.default ?? [],\n\t\t\tindex: this.props?.index,\n\t\t\tmultiple: this.props?.multiple,\n\t\t\tui: {\n\t\t\t\thidden: this.props?.ui?.hidden,\n\t\t\t\tdisabled: this.props?.ui?.disabled,\n\t\t\t\tcondition: this.props?.ui?.condition,\n\t\t\t\twidth: this.props?.ui?.width,\n\t\t\t},\n\t\t\tvalidation: this.props?.validation,\n\t\t} satisfies CFConfig<\"relation\">;\n\t}\n\toverride normalizeInputValue(value: unknown) {\n\t\treturn clampRelationFieldInput(value, this.config.multiple);\n\t}\n\toverride get defaultValue(): unknown {\n\t\treturn normalizeStoredRelationCustomFieldValues(\n\t\t\tthis.config.default,\n\t\t\tthis.config.multiple,\n\t\t);\n\t}\n\toverride get errors(): {\n\t\tfieldType: CustomFieldErrorItem;\n\t\trequired: CustomFieldErrorItem;\n\t\tzod: CustomFieldErrorItem;\n\t} {\n\t\treturn {\n\t\t\t...super.errors,\n\t\t\trequired: {\n\t\t\t\tcondition: (value: unknown) =>\n\t\t\t\t\tvalue === undefined ||\n\t\t\t\t\tvalue === null ||\n\t\t\t\t\t(Array.isArray(value) && value.length === 0),\n\t\t\t\tmessage: copy(\"server:core.fields.validation.required\"),\n\t\t\t},\n\t\t};\n\t}\n\tgetSchemaDefinition(\n\t\tprops: GetSchemaDefinitionProps,\n\t): Awaited<ServiceResponse<SchemaDefinition>> {\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\tcolumns: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"collection_key\",\n\t\t\t\t\t\ttype: props.db.getDataType(\"text\"),\n\t\t\t\t\t\tnullable: false,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: \"document_id\",\n\t\t\t\t\t\ttype: props.db.getDataType(\"integer\"),\n\t\t\t\t\t\tnullable: false,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\terror: undefined,\n\t\t};\n\t}\n\toverride getIndexDefinitions(\n\t\tprops: GetIndexDefinitionProps,\n\t): IndexDefinition[] {\n\t\tconst columns = [\n\t\t\tprefixGeneratedColName(\"collection_key\"),\n\t\t\tprefixGeneratedColName(\"document_id\"),\n\t\t];\n\n\t\treturn [\n\t\t\tbuildSchemaIndex({\n\t\t\t\tdb: props.db,\n\t\t\t\ttableName: props.table.name,\n\t\t\t\tcolumns,\n\t\t\t\tsource: \"field\",\n\t\t\t}),\n\t\t];\n\t}\n\tformatResponseValue(value: unknown) {\n\t\treturn normalizeStoredRelationCustomFieldValues(\n\t\t\tvalue,\n\t\t\tthis.config.multiple,\n\t\t) satisfies CFResponse<\"relation\">[\"value\"];\n\t}\n\toverride serializeRelationFieldValue(\n\t\tvalue: unknown,\n\t): Array<Record<string, unknown>> {\n\t\treturn normalizeStoredRelationCustomFieldValues(\n\t\t\tvalue,\n\t\t\tthis.config.multiple,\n\t\t).map((documentValue) => ({\n\t\t\t[prefixGeneratedColName(\"collection_key\")]: documentValue.collectionKey,\n\t\t\t[prefixGeneratedColName(\"document_id\")]: documentValue.id,\n\t\t}));\n\t}\n\toverride extractRelationFieldValue(\n\t\trow: Select<LucidBricksTable>,\n\t): RelationCustomFieldValue | null {\n\t\tconst documentId = row[prefixGeneratedColName(\"document_id\")];\n\t\tconst collectionKey = row[prefixGeneratedColName(\"collection_key\")];\n\n\t\tif (typeof documentId !== \"number\") return null;\n\t\tif (typeof collectionKey !== \"string\") return null;\n\n\t\treturn {\n\t\t\tid: documentId,\n\t\t\tcollectionKey: collectionKey,\n\t\t};\n\t}\n\toverride getRelationFieldValidationInput(\n\t\tvalue: unknown,\n\t): FieldRelationValidationInput {\n\t\treturn normalizeStoredRelationCustomFieldValues(\n\t\t\tvalue,\n\t\t\tthis.config.multiple,\n\t\t).reduce<Record<string, number[]>>((acc, item) => {\n\t\t\tif (!acc[item.collectionKey]) {\n\t\t\t\tacc[item.collectionKey] = [];\n\t\t\t}\n\n\t\t\tacc[item.collectionKey]?.push(item.id);\n\t\t\treturn acc;\n\t\t}, {});\n\t}\n\toverride getRelationFieldRefTargets(\n\t\trow: Select<LucidBricksTable>,\n\t): FieldRelationRefTarget[] {\n\t\tconst relationValue = this.extractRelationFieldValue(row);\n\t\tif (!relationValue) return [];\n\n\t\tconst tableNameRes = buildTableName(\n\t\t\t\"document\",\n\t\t\t{\n\t\t\t\tcollection: relationValue.collectionKey,\n\t\t\t},\n\t\t\tnull,\n\t\t);\n\t\tif (tableNameRes.error) return [];\n\n\t\treturn [\n\t\t\t{\n\t\t\t\ttable: tableNameRes.data.name,\n\t\t\t\tvalue: relationValue.id,\n\t\t\t},\n\t\t];\n\t}\n\tuniqueValidation(value: unknown, refData?: RelationValidationData[]) {\n\t\tconst valueSchema = z.array(\n\t\t\tz.object({\n\t\t\t\tid: z.number(),\n\t\t\t\tcollectionKey: z.string(),\n\t\t\t}),\n\t\t);\n\t\tconst candidateValue = clampRelationFieldInput(value, this.config.multiple);\n\t\tconst valueValidate = zodSafeParse(candidateValue, valueSchema);\n\t\tif (!valueValidate.valid) return valueValidate;\n\n\t\tconst normalizedValue = normalizeStoredRelationCustomFieldValues(\n\t\t\tcandidateValue,\n\t\t\tthis.config.multiple,\n\t\t);\n\t\tconst itemCountValidation = validateRelationItemCount({\n\t\t\tmultiple: this.config.multiple,\n\t\t\tlength: normalizedValue.length,\n\t\t\tvalidation: this.config.validation,\n\t\t});\n\t\tif (!itemCountValidation.valid) return itemCountValidation;\n\t\tconst allowedCollections = normalizeRelationCollections(\n\t\t\tthis.config.collection,\n\t\t);\n\t\tconst errors: CustomFieldValidationError[] = [];\n\n\t\tfor (const [itemIndex, documentValue] of normalizedValue.entries()) {\n\t\t\tif (!allowedCollections.includes(documentValue.collectionKey)) {\n\t\t\t\terrors.push({\n\t\t\t\t\titemIndex,\n\t\t\t\t\tmessage: copy(\"server:core.fields.relation.validation.not.found\"),\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst findDocument = refData?.find(\n\t\t\t\t(d) =>\n\t\t\t\t\td.id === documentValue.id &&\n\t\t\t\t\td.collection_key === documentValue.collectionKey,\n\t\t\t);\n\n\t\t\tif (findDocument === undefined) {\n\t\t\t\terrors.push({\n\t\t\t\t\titemIndex,\n\t\t\t\t\tmessage: copy(\"server:core.fields.relation.validation.not.found\"),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (errors.length > 0) {\n\t\t\treturn {\n\t\t\t\tvalid: false,\n\t\t\t\terrors,\n\t\t\t};\n\t\t}\n\n\t\treturn { valid: true };\n\t}\n}\n\nexport default RelationCustomField;\n"],"mappings":"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"}