UNPKG

@lucidcms/core

Version:

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

1 lines 8.84 kB
{"version":3,"file":"extract-related-entity-ids.mjs","names":[],"sources":["../../../../src/services/documents-bricks/helpers/extract-related-entity-ids.ts"],"sourcesContent":["import type BrickBuilder from \"../../../libs/collection/builders/brick-builder/index.js\";\nimport type CollectionBuilder from \"../../../libs/collection/builders/collection-builder/index.js\";\nimport type CustomField from \"../../../libs/collection/custom-fields/custom-field.js\";\nimport {\n\tgetFieldDatabaseConfig,\n\tisStorageMode,\n} from \"../../../libs/collection/custom-fields/storage/index.js\";\nimport type {\n\tCollectionSchemaColumn,\n\tTableType,\n} from \"../../../libs/collection/schema/types.js\";\nimport type { BrickQueryResponse } from \"../../../libs/repositories/document-bricks.js\";\nimport type { DocumentQueryResponse } from \"../../../libs/repositories/documents.js\";\nimport type {\n\tFieldTypes,\n\tLucidBricksTable,\n\tLucidBrickTableName,\n\tSelect,\n\tServiceFn,\n} from \"../../../types.js\";\n\nexport type FieldRelationValues = Partial<\n\tRecord<\n\t\tFieldTypes,\n\t\tArray<{\n\t\t\ttable: string;\n\t\t\tvalues: Set<unknown>;\n\t\t}>\n\t>\n>;\n\n/**\n * Resolves the custom field instance for a schema-backed field table.\n */\nconst getSchemaFieldInstance = (\n\tcollection: CollectionBuilder,\n\tschema: {\n\t\tname: LucidBrickTableName;\n\t\tcolumns: CollectionSchemaColumn[];\n\t\tkey: {\n\t\t\tcollection: string;\n\t\t\tbrick?: string;\n\t\t\tfieldPath?: string[];\n\t\t};\n\t\ttype: TableType;\n\t},\n): CustomField<FieldTypes> | null => {\n\tconst databaseConfig = getFieldDatabaseConfig(schema.type);\n\tif (!databaseConfig || !isStorageMode(databaseConfig, \"relation-table\")) {\n\t\treturn null;\n\t}\n\n\tconst fieldKey = schema.key.fieldPath?.[schema.key.fieldPath.length - 1];\n\tif (!fieldKey) return null;\n\n\tconst owner: CollectionBuilder | BrickBuilder | undefined = schema.key.brick\n\t\t? collection.brickInstances.find((brick) => brick.key === schema.key.brick)\n\t\t: collection;\n\tif (!owner) return null;\n\n\treturn owner.fields.get(fieldKey) ?? null;\n};\n\n/**\n * Checks if the field instance has a multiple flag in the config.\n */\nconst hasMultipleFlag = (\n\tfieldInstance: CustomField<FieldTypes>,\n): fieldInstance is CustomField<FieldTypes> & {\n\tconfig: {\n\t\tmultiple?: boolean;\n\t};\n} => {\n\treturn (\n\t\ttypeof fieldInstance.config === \"object\" &&\n\t\tfieldInstance.config !== null &&\n\t\t\"multiple\" in fieldInstance.config\n\t);\n};\n\n/**\n * Prevents single-value relation fields from contributing extra persisted rows to\n * the global ref fetch.\n */\nconst shouldSkipRelationRow = (\n\tcollection: CollectionBuilder,\n\tschema: {\n\t\tname: LucidBrickTableName;\n\t\tcolumns: CollectionSchemaColumn[];\n\t\tkey: {\n\t\t\tcollection: string;\n\t\t\tbrick?: string;\n\t\t\tfieldPath?: string[];\n\t\t};\n\t\ttype: TableType;\n\t},\n\trow: Select<LucidBricksTable>,\n): boolean => {\n\tconst fieldInstance = getSchemaFieldInstance(collection, schema);\n\tif (!fieldInstance) return false;\n\n\tif (row.position === 0) return false;\n\n\tif (!hasMultipleFlag(fieldInstance)) return false;\n\n\treturn fieldInstance.config.multiple !== true;\n};\n\n/**\n * Adds a relation target to the deduped ref fetch map.\n */\nconst appendRelationTarget = (\n\trefData: FieldRelationValues,\n\tfieldType: FieldTypes,\n\ttarget: {\n\t\ttable: string;\n\t\tvalue: unknown;\n\t},\n) => {\n\tif (refData[fieldType] === undefined) {\n\t\trefData[fieldType] = [];\n\t}\n\n\tlet tableEntry = refData[fieldType]?.find(\n\t\t(entry) => entry.table === target.table,\n\t);\n\n\tif (!tableEntry) {\n\t\ttableEntry = {\n\t\t\ttable: target.table,\n\t\t\tvalues: new Set<unknown>(),\n\t\t};\n\t\trefData[fieldType]?.push(tableEntry);\n\t}\n\n\ttableEntry.values.add(target.value);\n};\n\nconst shouldIncludeFieldType = (\n\tfieldType: FieldTypes,\n\toptions: {\n\t\tincludeTypes?: FieldTypes[];\n\t\texcludeTypes?: FieldTypes[];\n\t},\n) => {\n\tif (options.includeTypes !== undefined) {\n\t\treturn options.includeTypes.includes(fieldType);\n\t}\n\n\treturn options.excludeTypes?.includes(fieldType) !== true;\n};\n\n/**\n * Extracts any custom field reference data based on the brick schema's foreign key information.\n * Works with arrays of BrickQueryResponse and/or DocumentQueryResponse types.\n * IDs can be used to fetch the data separately.\n */\nconst extractRelatedEntityIds: ServiceFn<\n\t[\n\t\t{\n\t\t\tcollection: CollectionBuilder;\n\t\t\tbrickSchema: {\n\t\t\t\tname: LucidBrickTableName;\n\t\t\t\ttype: TableType;\n\t\t\t\tkey: {\n\t\t\t\t\tcollection: string;\n\t\t\t\t\tbrick?: string;\n\t\t\t\t\tfieldPath?: string[];\n\t\t\t\t};\n\t\t\t\tcolumns: CollectionSchemaColumn[];\n\t\t\t}[];\n\t\t\tresponses: (BrickQueryResponse | DocumentQueryResponse)[];\n\t\t\t/** Pass an array of custom field types that should have relation data extracted. */\n\t\t\tincludeTypes?: FieldTypes[];\n\t\t\t/** Pass a Array of custom field types that should have relation data extracted */\n\t\t\texcludeTypes?: FieldTypes[];\n\t\t},\n\t],\n\tFieldRelationValues\n> = async (_, data) => {\n\tconst refData: FieldRelationValues = {};\n\n\tfor (const response of data.responses) {\n\t\tfor (const schema of data.brickSchema) {\n\t\t\tconst brickRows = response[schema.name];\n\t\t\tif (!brickRows || !Array.isArray(brickRows) || brickRows.length === 0)\n\t\t\t\tcontinue;\n\n\t\t\tconst fieldInstance = getSchemaFieldInstance(data.collection, schema);\n\n\t\t\tfor (const row of brickRows) {\n\t\t\t\tif (shouldSkipRelationRow(data.collection, schema, row)) continue;\n\n\t\t\t\tfor (const schemaColumn of schema.columns) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tschemaColumn.source === \"core\" ||\n\t\t\t\t\t\tschemaColumn.foreignKey === undefined ||\n\t\t\t\t\t\tschemaColumn.customField === undefined\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst targetColumn = row[schemaColumn.name as keyof LucidBricksTable];\n\t\t\t\t\tif (targetColumn === undefined || targetColumn === null) continue;\n\n\t\t\t\t\tconst fieldType = schemaColumn.customField.type;\n\t\t\t\t\tconst tableName = schemaColumn.foreignKey.table;\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t!shouldIncludeFieldType(fieldType, {\n\t\t\t\t\t\t\tincludeTypes: data.includeTypes,\n\t\t\t\t\t\t\texcludeTypes: data.excludeTypes,\n\t\t\t\t\t\t})\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tappendRelationTarget(refData, fieldType, {\n\t\t\t\t\t\ttable: tableName,\n\t\t\t\t\t\tvalue: targetColumn,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (!fieldInstance) continue;\n\t\t\t\tif (\n\t\t\t\t\t!shouldIncludeFieldType(fieldInstance.type, {\n\t\t\t\t\t\tincludeTypes: data.includeTypes,\n\t\t\t\t\t\texcludeTypes: data.excludeTypes,\n\t\t\t\t\t})\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfor (const relationTarget of fieldInstance.getRelationFieldRefTargets(\n\t\t\t\t\trow,\n\t\t\t\t)) {\n\t\t\t\t\tappendRelationTarget(refData, fieldInstance.type, relationTarget);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tdata: refData,\n\t\terror: undefined,\n\t};\n};\n\nexport default extractRelatedEntityIds;\n"],"mappings":"qHAkCA,MAAM,GACL,EACA,IAUoC,CACpC,IAAM,EAAiB,EAAuB,EAAO,IAAI,EACzD,GAAI,CAAC,GAAkB,CAAC,EAAc,EAAgB,gBAAgB,EACrE,OAAO,KAGR,IAAM,EAAW,EAAO,IAAI,YAAY,EAAO,IAAI,UAAU,OAAS,GACtE,GAAI,CAAC,EAAU,OAAO,KAEtB,IAAM,EAAsD,EAAO,IAAI,MACpE,EAAW,eAAe,KAAM,GAAU,EAAM,MAAQ,EAAO,IAAI,KAAK,EACxE,EAGH,OAFK,EAEE,EAAM,OAAO,IAAI,CAAQ,GAAK,KAFlB,IAGpB,EAKM,EACL,GAOC,OAAO,EAAc,QAAW,UAChC,EAAc,SAAW,MACzB,aAAc,EAAc,OAQxB,GACL,EACA,EAUA,IACa,CACb,IAAM,EAAgB,EAAuB,EAAY,CAAM,EAO/D,MANI,CAAC,GAED,EAAI,WAAa,GAEjB,CAAC,EAAgB,CAAa,EAAU,GAErC,EAAc,OAAO,WAAa,EAC1C,EAKM,GACL,EACA,EACA,IAII,CACA,EAAQ,KAAe,IAAA,KAC1B,EAAQ,GAAa,CAAC,GAGvB,IAAI,EAAa,EAAQ,EAAU,EAAE,KACnC,GAAU,EAAM,QAAU,EAAO,KACnC,EAEK,IACJ,EAAa,CACZ,MAAO,EAAO,MACd,OAAQ,IAAI,GACb,EACA,EAAQ,EAAU,EAAE,KAAK,CAAU,GAGpC,EAAW,OAAO,IAAI,EAAO,KAAK,CACnC,EAEM,GACL,EACA,IAKI,EAAQ,eAAiB,IAAA,GAItB,EAAQ,cAAc,SAAS,CAAS,IAAM,GAH7C,EAAQ,aAAa,SAAS,CAAS,EAW1C,EAsBF,MAAO,EAAG,IAAS,CACtB,IAAM,EAA+B,CAAC,EAEtC,IAAK,IAAM,KAAY,EAAK,UAC3B,IAAK,IAAM,KAAU,EAAK,YAAa,CACtC,IAAM,EAAY,EAAS,EAAO,MAClC,GAAI,CAAC,GAAa,CAAC,MAAM,QAAQ,CAAS,GAAK,EAAU,SAAW,EACnE,SAED,IAAM,EAAgB,EAAuB,EAAK,WAAY,CAAM,EAEpE,IAAK,IAAM,KAAO,EACb,MAAsB,EAAK,WAAY,EAAQ,CAAG,EAEtD,KAAK,IAAM,KAAgB,EAAO,QAAS,CAC1C,GACC,EAAa,SAAW,QACxB,EAAa,aAAe,IAAA,IAC5B,EAAa,cAAgB,IAAA,GAE7B,SAGD,IAAM,EAAe,EAAI,EAAa,MACtC,GAAI,GAA+C,KAAM,SAEzD,IAAM,EAAY,EAAa,YAAY,KACrC,EAAY,EAAa,WAAW,MAGxC,EAAuB,EAAW,CAClC,aAAc,EAAK,aACnB,aAAc,EAAK,YACpB,CAAC,GAKF,EAAqB,EAAS,EAAW,CACxC,MAAO,EACP,MAAO,CACR,CAAC,CACF,CAEK,MAEH,EAAuB,EAAc,KAAM,CAC3C,aAAc,EAAK,aACnB,aAAc,EAAK,YACpB,CAAC,EAKF,IAAK,IAAM,KAAkB,EAAc,2BAC1C,CACD,EACC,EAAqB,EAAS,EAAc,KAAM,CAAc,CAfjE,CAkBF,CAGD,MAAO,CACN,KAAM,EACN,MAAO,IAAA,EACR,CACD"}