@lucidcms/core
Version:
The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.
1 lines • 8.85 kB
Source Map (JSON)
{"version":3,"file":"fetch-ref-data.mjs","names":[],"sources":["../../../../src/services/documents-bricks/helpers/fetch-ref-data.ts"],"sourcesContent":["import registeredFields, {\n\tregisteredFieldTypes,\n} from \"../../../libs/collection/custom-fields/registered-fields.js\";\nimport {\n\tcreateFieldRefFetchPlan,\n\ttype FieldRefFetchInput,\n\ttype FieldRefFetchOutput,\n\ttype FieldRefFetchPlan,\n\ttype FieldRefRelation,\n\ttype FieldRefVersionTypeResolver,\n} from \"../../../libs/collection/custom-fields/utils/ref-fetch.js\";\nimport buildTableName from \"../../../libs/collection/helpers/build-table-name.js\";\nimport type { CollectionSchemaTable } from \"../../../libs/collection/schema/types.js\";\nimport type { MediaPropsT } from \"../../../libs/formatters/media.js\";\nimport type { UserPropT } from \"../../../libs/formatters/users.js\";\nimport { copy } from \"../../../libs/i18n/index.js\";\nimport { getCollectionClientScope } from \"../../../libs/permission/client-scopes.js\";\nimport type { BrickQueryResponse } from \"../../../libs/repositories/document-bricks.js\";\nimport type {\n\tDocumentVersionType,\n\tFieldTypes,\n\tLucidBrickTableName,\n\tServiceFn,\n} from \"../../../types.js\";\nimport type { FieldRelationValues } from \"./extract-related-entity-ids.js\";\n\ntype FieldRefData = Partial<\n\tRecord<\n\t\tFieldTypes,\n\t\tArray<MediaPropsT> | Array<UserPropT> | Array<BrickQueryResponse>\n\t>\n>;\n\ntype RegisteredFieldDefinition = (typeof registeredFields)[FieldTypes];\n\nexport type FieldRefResponse = {\n\tdata: FieldRefData;\n\tmeta?: {\n\t\trelation?: {\n\t\t\t/** Document-field table schema for referenced relation collections, keyed by collection key. */\n\t\t\tfieldsSchemaByCollection: Record<\n\t\t\t\tstring,\n\t\t\t\tCollectionSchemaTable<LucidBrickTableName>\n\t\t\t>;\n\t\t};\n\t};\n};\n\ntype FetchableFieldDefinition = Extract<\n\tRegisteredFieldDefinition,\n\t{\n\t\tfetchRefs: ServiceFn<[FieldRefFetchInput], FieldRefFetchOutput>;\n\t}\n>;\n\n/**\n * Returns true when a field has a ref fetcher enabled.\n */\nconst hasRefFetcher = (\n\tfield: RegisteredFieldDefinition,\n): field is FetchableFieldDefinition => {\n\treturn field.fetchRefs !== null;\n};\n\n/**\n * Returns the field types that are present in the extracted relation values.\n */\nconst getRequestedFieldTypes = (values: FieldRelationValues): FieldTypes[] => {\n\treturn Object.keys(values).filter((key): key is FieldTypes =>\n\t\tregisteredFieldTypes.includes(key as FieldTypes),\n\t);\n};\n\n/**\n * Builds the ref fetch plan for a single field type.\n */\nconst buildFieldRefFetchPlan = (props: {\n\tfieldType: FieldTypes;\n\tfieldDefinition: FetchableFieldDefinition;\n\trelations: FieldRefRelation[];\n\tversionType: FieldRefFetchInput[\"versionType\"];\n\tresolveVersionType?: FieldRefVersionTypeResolver;\n}): FieldRefFetchPlan | null => {\n\treturn (\n\t\tprops.fieldDefinition.planFetchRefs?.({\n\t\t\tfieldType: props.fieldType,\n\t\t\trelations: props.relations,\n\t\t\tversionType: props.versionType,\n\t\t\tresolveVersionType: props.resolveVersionType,\n\t\t\tfetchRefs: props.fieldDefinition.fetchRefs,\n\t\t}) ??\n\t\tcreateFieldRefFetchPlan({\n\t\t\tfieldType: props.fieldType,\n\t\t\trelations: props.relations,\n\t\t\tversionType: props.versionType,\n\t\t\tresolveVersionType: props.resolveVersionType,\n\t\t\tfetchRefs: props.fieldDefinition.fetchRefs,\n\t\t})\n\t);\n};\n\n/**\n * Fetches reference rows for all field types present in the extracted relation values.\n */\nconst fetchRefData: ServiceFn<\n\t[\n\t\t{\n\t\t\tvalues: FieldRelationValues;\n\t\t\tversionType: Exclude<DocumentVersionType, \"revision\">;\n\t\t\tresolveVersionType?: FieldRefVersionTypeResolver;\n\t\t\tallowedDocumentCollectionKeys?: string[];\n\t\t},\n\t],\n\tFieldRefResponse\n> = async (context, data) => {\n\tif (data.allowedDocumentCollectionKeys !== undefined) {\n\t\tconst tableToCollection = new Map<string, string>();\n\t\tfor (const collection of context.config.collections) {\n\t\t\tconst tableNameRes = buildTableName(\n\t\t\t\t\"document\",\n\t\t\t\t{ collection: collection.key },\n\t\t\t\tcontext.config.db.config.tableNameByteLimit,\n\t\t\t);\n\t\t\tif (tableNameRes.error) return tableNameRes;\n\t\t\ttableToCollection.set(tableNameRes.data.name, collection.key);\n\t\t}\n\n\t\tconst allowedCollectionKeys = new Set(data.allowedDocumentCollectionKeys);\n\t\tconst missingCollectionKeys = Array.from(\n\t\t\tnew Set(\n\t\t\t\t(data.values.relation ?? []).flatMap((relation) => {\n\t\t\t\t\tconst collectionKey = tableToCollection.get(relation.table);\n\t\t\t\t\treturn collectionKey && !allowedCollectionKeys.has(collectionKey)\n\t\t\t\t\t\t? [collectionKey]\n\t\t\t\t\t\t: [];\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\tif (missingCollectionKeys.length > 0) {\n\t\t\tconst missingScopes = missingCollectionKeys.map(getCollectionClientScope);\n\t\t\treturn {\n\t\t\t\terror: {\n\t\t\t\t\ttype: \"authorisation\",\n\t\t\t\t\tname: copy(\"server:core.client.integrations.scopes.error.name\"),\n\t\t\t\t\tmessage: copy(\n\t\t\t\t\t\t\"server:core.client.integrations.scopes.missing.message\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\trequiredScopes: missingScopes.join(\", \"),\n\t\t\t\t\t\t\t\tmissingScopes: missingScopes.join(\", \"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t\tstatus: 403,\n\t\t\t\t},\n\t\t\t\tdata: undefined,\n\t\t\t};\n\t\t}\n\t}\n\n\tconst response: FieldRefResponse = {\n\t\tdata: {},\n\t};\n\n\tconst fetchPlans = getRequestedFieldTypes(data.values).flatMap(\n\t\t(fieldType) => {\n\t\t\tconst relationValues = data.values[fieldType];\n\t\t\tconst fieldDefinition = registeredFields[fieldType];\n\t\t\tif (!relationValues || relationValues.length === 0) return [];\n\t\t\tif (!hasRefFetcher(fieldDefinition)) return [];\n\n\t\t\tconst plan = buildFieldRefFetchPlan({\n\t\t\t\tfieldType,\n\t\t\t\tfieldDefinition,\n\t\t\t\trelations: relationValues,\n\t\t\t\tversionType: data.versionType,\n\t\t\t\tresolveVersionType: data.resolveVersionType,\n\t\t\t});\n\t\t\treturn plan ? [plan] : [];\n\t\t},\n\t);\n\n\tconst fetchResults = await Promise.all(\n\t\tfetchPlans.map(async (plan) => ({\n\t\t\tfieldType: plan.fieldType,\n\t\t\tres: await plan.run(context),\n\t\t})),\n\t);\n\n\tfor (const { fieldType, res } of fetchResults) {\n\t\tif (res.error) {\n\t\t\treturn {\n\t\t\t\tdata: undefined,\n\t\t\t\terror: res.error,\n\t\t\t};\n\t\t}\n\t\tif (!res.data) continue;\n\n\t\tresponse.data[fieldType] = res.data.rows;\n\t\tif (res.data.meta?.relation) {\n\t\t\tresponse.meta = {\n\t\t\t\t...response.meta,\n\t\t\t\trelation: {\n\t\t\t\t\tfieldsSchemaByCollection: {\n\t\t\t\t\t\t...(response.meta?.relation?.fieldsSchemaByCollection || {}),\n\t\t\t\t\t\t...res.data.meta.relation.fieldsSchemaByCollection,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t}\n\n\treturn {\n\t\tdata: response,\n\t\terror: undefined,\n\t};\n};\n\nexport default fetchRefData;\n"],"mappings":"0ZA0DA,MAAM,EACL,GAEO,EAAM,YAAc,KAMtB,EAA0B,GACxB,OAAO,KAAK,CAAM,CAAC,CAAC,OAAQ,GAClC,EAAqB,SAAS,CAAiB,CAChD,EAMK,EAA0B,GAQ9B,EAAM,gBAAgB,gBAAgB,CACrC,UAAW,EAAM,UACjB,UAAW,EAAM,UACjB,YAAa,EAAM,YACnB,mBAAoB,EAAM,mBAC1B,UAAW,EAAM,gBAAgB,SAClC,CAAC,GACD,EAAwB,CACvB,UAAW,EAAM,UACjB,UAAW,EAAM,UACjB,YAAa,EAAM,YACnB,mBAAoB,EAAM,mBAC1B,UAAW,EAAM,gBAAgB,SAClC,CAAC,EAOG,EAUF,MAAO,EAAS,IAAS,CAC5B,GAAI,EAAK,gCAAkC,IAAA,GAAW,CACrD,IAAM,EAAoB,IAAI,IAC9B,IAAK,IAAM,KAAc,EAAQ,OAAO,YAAa,CACpD,IAAM,EAAe,EACpB,WACA,CAAE,WAAY,EAAW,GAAI,EAC7B,EAAQ,OAAO,GAAG,OAAO,kBAC1B,EACA,GAAI,EAAa,MAAO,OAAO,EAC/B,EAAkB,IAAI,EAAa,KAAK,KAAM,EAAW,GAAG,CAC7D,CAEA,IAAM,EAAwB,IAAI,IAAI,EAAK,6BAA6B,EAClE,EAAwB,MAAM,KACnC,IAAI,KACF,EAAK,OAAO,UAAY,CAAC,EAAA,CAAG,QAAS,GAAa,CAClD,IAAM,EAAgB,EAAkB,IAAI,EAAS,KAAK,EAC1D,OAAO,GAAiB,CAAC,EAAsB,IAAI,CAAa,EAC7D,CAAC,CAAa,EACd,CAAC,CACL,CAAC,CACF,CACD,EACA,GAAI,EAAsB,OAAS,EAAG,CACrC,IAAM,EAAgB,EAAsB,IAAI,CAAwB,EACxE,MAAO,CACN,MAAO,CACN,KAAM,gBACN,KAAM,EAAK,mDAAmD,EAC9D,QAAS,EACR,yDACA,CACC,KAAM,CACL,eAAgB,EAAc,KAAK,IAAI,EACvC,cAAe,EAAc,KAAK,IAAI,CACvC,CACD,CACD,EACA,OAAQ,GACT,EACA,KAAM,IAAA,EACP,CACD,CACD,CAEA,IAAM,EAA6B,CAClC,KAAM,CAAC,CACR,EAEM,EAAa,EAAuB,EAAK,MAAM,CAAC,CAAC,QACrD,GAAc,CACd,IAAM,EAAiB,EAAK,OAAO,GAC7B,EAAkB,EAAiB,GAEzC,GADI,CAAC,GAAkB,EAAe,SAAW,GAC7C,CAAC,EAAc,CAAe,EAAG,MAAO,CAAC,EAE7C,IAAM,EAAO,EAAuB,CACnC,YACA,kBACA,UAAW,EACX,YAAa,EAAK,YAClB,mBAAoB,EAAK,kBAC1B,CAAC,EACD,OAAO,EAAO,CAAC,CAAI,EAAI,CAAC,CACzB,CACD,EAEM,EAAe,MAAM,QAAQ,IAClC,EAAW,IAAI,KAAO,KAAU,CAC/B,UAAW,EAAK,UAChB,IAAK,MAAM,EAAK,IAAI,CAAO,CAC5B,EAAE,CACH,EAEA,IAAK,GAAM,CAAE,YAAW,SAAS,EAAc,CAC9C,GAAI,EAAI,MACP,MAAO,CACN,KAAM,IAAA,GACN,MAAO,EAAI,KACZ,EAEI,EAAI,OAET,EAAS,KAAK,GAAa,EAAI,KAAK,KAChC,EAAI,KAAK,MAAM,WAClB,EAAS,KAAO,CACf,GAAG,EAAS,KACZ,SAAU,CACT,yBAA0B,CACzB,GAAI,EAAS,MAAM,UAAU,0BAA4B,CAAC,EAC1D,GAAG,EAAI,KAAK,KAAK,SAAS,wBAC3B,CACD,CACD,GAEF,CAEA,MAAO,CACN,KAAM,EACN,MAAO,IAAA,EACR,CACD"}