UNPKG

@strapi/data-transfer

Version:

Data transfer capabilities for Strapi

1 lines • 23.7 kB
{"version":3,"file":"components.mjs","sources":["../../src/utils/components.ts"],"sourcesContent":["import _ from 'lodash';\nimport { get, has, omit, pipe, assign } from 'lodash/fp';\n\nimport { contentTypes as contentTypesUtils, async, errors } from '@strapi/utils';\nimport type { Modules, UID, Data, Utils, Schema, Core } from '@strapi/types';\n\ntype LoadedComponents<TUID extends UID.Schema> = Data.Entity<\n TUID,\n Schema.AttributeNamesByType<TUID, 'component' | 'dynamiczone'>\n>;\n\ntype ComponentValue = Schema.Attribute.Value<\n Schema.Attribute.Component<UID.Component, false> | Schema.Attribute.Component<UID.Component, true>\n>;\n\ntype ComponentBody = {\n [key: string]: Schema.Attribute.Value<\n | Schema.Attribute.Component<UID.Component, false>\n | Schema.Attribute.Component<UID.Component, true>\n | Schema.Attribute.DynamicZone\n >;\n};\n\nconst isDialectMySQL = () => strapi.db?.dialect.client === 'mysql';\n\nfunction omitComponentData(\n contentType: Schema.ContentType,\n data: Modules.EntityService.Params.Data.Input<Schema.ContentType['uid']>\n): Partial<Modules.EntityService.Params.Data.Input<Schema.ContentType['uid']>>;\nfunction omitComponentData(\n contentType: Schema.Component,\n data: Modules.EntityService.Params.Data.Input<Schema.Component['uid']>\n): Partial<Modules.EntityService.Params.Data.Input<Schema.Component['uid']>>;\nfunction omitComponentData(\n contentType: Schema.ContentType | Schema.Component,\n data: Modules.EntityService.Params.Data.Input<Schema.ContentType['uid'] | Schema.Component['uid']>\n): Partial<\n Modules.EntityService.Params.Data.Input<Schema.ContentType['uid'] | Schema.Component['uid']>\n> {\n const { attributes } = contentType;\n const componentAttributes = Object.keys(attributes).filter((attributeName) =>\n contentTypesUtils.isComponentAttribute(attributes[attributeName])\n );\n\n return omit(componentAttributes, data);\n}\n\n// NOTE: we could generalize the logic to allow CRUD of relation directly in the DB layer\nconst createComponents = async <\n TUID extends UID.Schema,\n TData extends Modules.EntityService.Params.Data.Input<TUID>,\n>(\n uid: TUID,\n data: TData\n) => {\n const { attributes = {} } = strapi.getModel(uid);\n\n const componentBody: ComponentBody = {};\n\n const attributeNames = Object.keys(attributes);\n\n for (const attributeName of attributeNames) {\n const attribute = attributes[attributeName];\n\n if (!has(attributeName, data) || !contentTypesUtils.isComponentAttribute(attribute)) {\n continue;\n }\n\n if (attribute.type === 'component') {\n const { component: componentUID, repeatable = false } = attribute;\n\n const componentValue = data[attributeName as keyof TData];\n\n if (componentValue === null) {\n continue;\n }\n\n if (repeatable === true) {\n if (!Array.isArray(componentValue)) {\n throw new Error('Expected an array to create repeatable component');\n }\n\n // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1\n const components = (await async.map(\n componentValue,\n (value: any) => createComponent(componentUID, value),\n { concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }\n )) as Schema.Attribute.Value<Schema.Attribute.Component<UID.Component, true>>;\n\n componentBody[attributeName] = components.map(({ id }) => {\n return {\n id,\n __pivot: {\n field: attributeName,\n component_type: componentUID,\n },\n };\n });\n } else {\n const component = await createComponent(\n componentUID,\n componentValue as Modules.EntityService.Params.Data.Input<UID.Component>\n );\n componentBody[attributeName] = {\n id: component.id,\n __pivot: {\n field: attributeName,\n component_type: componentUID,\n },\n };\n }\n\n continue;\n }\n\n if (attribute.type === 'dynamiczone') {\n const dynamiczoneValues = data[\n attributeName as keyof TData\n ] as Modules.EntityService.Params.Attribute.GetValue<Schema.Attribute.DynamicZone>;\n\n if (!Array.isArray(dynamiczoneValues)) {\n throw new Error('Expected an array to create repeatable component');\n }\n\n const createDynamicZoneComponents = async (\n value: Utils.Array.Values<typeof dynamiczoneValues>\n ) => {\n const { id } = await createComponent(value.__component, value);\n return {\n id,\n __component: value.__component,\n __pivot: {\n field: attributeName,\n },\n };\n };\n\n // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1\n componentBody[attributeName] = await async.map(\n dynamiczoneValues,\n createDynamicZoneComponents,\n { concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }\n );\n\n continue;\n }\n }\n\n return componentBody;\n};\n\nconst getComponents = async <TUID extends UID.Schema>(\n uid: TUID,\n entity: { id: Modules.EntityService.Params.Attribute.ID }\n): Promise<LoadedComponents<TUID>> => {\n const componentAttributes = contentTypesUtils.getComponentAttributes(strapi.getModel(uid));\n\n if (_.isEmpty(componentAttributes)) {\n return {} as LoadedComponents<TUID>;\n }\n\n return strapi.db.query(uid).load(entity, componentAttributes) as Promise<LoadedComponents<TUID>>;\n};\n\n/*\n delete old components\n create or update\n*/\nconst updateComponents = async <\n TUID extends UID.Schema,\n TData extends Partial<Modules.EntityService.Params.Data.Input<TUID>>,\n>(\n uid: TUID,\n entityToUpdate: { id: Modules.EntityService.Params.Attribute.ID },\n data: TData\n) => {\n const { attributes = {} } = strapi.getModel(uid);\n\n const componentBody: ComponentBody = {};\n\n for (const attributeName of Object.keys(attributes)) {\n const attribute = attributes[attributeName];\n\n if (!has(attributeName, data)) {\n continue;\n }\n\n if (attribute.type === 'component') {\n const { component: componentUID, repeatable = false } = attribute;\n\n const componentValue = data[\n attributeName as keyof TData\n ] as Schema.Attribute.Value<Schema.Attribute.Component>;\n\n await deleteOldComponents(uid, componentUID, entityToUpdate, attributeName, componentValue);\n\n if (repeatable === true) {\n if (!Array.isArray(componentValue)) {\n throw new Error('Expected an array to create repeatable component');\n }\n\n // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1\n const components = (await async.map(\n componentValue,\n (value: any) => updateOrCreateComponent(componentUID, value),\n { concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }\n )) as Schema.Attribute.Value<Schema.Attribute.Component<UID.Component, true>>;\n\n componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {\n return {\n id,\n __pivot: {\n field: attributeName,\n component_type: componentUID,\n },\n };\n });\n } else {\n const component = await updateOrCreateComponent(componentUID, componentValue);\n componentBody[attributeName] = component && {\n id: component.id,\n __pivot: {\n field: attributeName,\n component_type: componentUID,\n },\n };\n }\n\n continue;\n }\n\n if (attribute.type === 'dynamiczone') {\n const dynamiczoneValues = data[\n attributeName as keyof TData\n ] as Schema.Attribute.Value<Schema.Attribute.DynamicZone>;\n\n await deleteOldDZComponents(uid, entityToUpdate, attributeName, dynamiczoneValues);\n\n if (!Array.isArray(dynamiczoneValues)) {\n throw new Error('Expected an array to create repeatable component');\n }\n\n // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1\n componentBody[attributeName] = await async.map(\n dynamiczoneValues,\n async (value: any) => {\n const { id } = await updateOrCreateComponent(value.__component, value);\n\n return {\n id,\n __component: value.__component,\n __pivot: {\n field: attributeName,\n },\n };\n },\n { concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }\n );\n\n continue;\n }\n }\n\n return componentBody;\n};\n\nconst pickStringifiedId = ({\n id,\n}: {\n id: Modules.EntityService.Params.Attribute.ID;\n}): Modules.EntityService.Params.Attribute.ID & string => {\n if (typeof id === 'string') {\n return id;\n }\n\n return `${id}`;\n};\n\nconst deleteOldComponents = async <TUID extends UID.Schema>(\n uid: TUID,\n componentUID: UID.Component,\n entityToUpdate: { id: Modules.EntityService.Params.Attribute.ID },\n attributeName: string,\n componentValue: Schema.Attribute.Value<Schema.Attribute.Component>\n) => {\n const previousValue = (await strapi.db\n .query(uid)\n .load(entityToUpdate, attributeName)) as ComponentValue;\n\n const idsToKeep = _.castArray(componentValue).filter(has('id')).map(pickStringifiedId);\n const allIds = _.castArray(previousValue).filter(has('id')).map(pickStringifiedId);\n\n idsToKeep.forEach((id) => {\n if (!allIds.includes(id)) {\n throw new errors.ApplicationError(\n `Some of the provided components in ${attributeName} are not related to the entity`\n );\n }\n });\n\n const idsToDelete = _.difference(allIds, idsToKeep);\n\n if (idsToDelete.length > 0) {\n for (const idToDelete of idsToDelete) {\n await deleteComponent(componentUID, { id: idToDelete });\n }\n }\n};\n\nconst deleteOldDZComponents = async <TUID extends UID.Schema>(\n uid: TUID,\n entityToUpdate: { id: Modules.EntityService.Params.Attribute.ID },\n attributeName: string,\n dynamiczoneValues: Schema.Attribute.Value<Schema.Attribute.DynamicZone>\n) => {\n const previousValue = (await strapi.db\n .query(uid)\n .load(entityToUpdate, attributeName)) as Schema.Attribute.Value<Schema.Attribute.DynamicZone>;\n\n const idsToKeep = _.castArray(dynamiczoneValues)\n .filter(has('id'))\n .map((v) => ({\n id: pickStringifiedId(v),\n __component: v.__component,\n }));\n\n const allIds = _.castArray(previousValue)\n .filter(has('id'))\n .map((v) => ({\n id: pickStringifiedId(v),\n __component: v.__component,\n }));\n\n idsToKeep.forEach(({ id, __component }) => {\n if (!allIds.find((el) => el.id === id && el.__component === __component)) {\n const err = new Error(\n `Some of the provided components in ${attributeName} are not related to the entity`\n );\n\n Object.assign(err, { status: 400 });\n throw err;\n }\n });\n\n type IdsToDelete = Schema.Attribute.Value<Schema.Attribute.DynamicZone>;\n\n const idsToDelete = allIds.reduce((acc, { id, __component }) => {\n if (!idsToKeep.find((el) => el.id === id && el.__component === __component)) {\n acc.push({ id, __component });\n }\n\n return acc;\n }, [] as IdsToDelete);\n\n if (idsToDelete.length > 0) {\n for (const idToDelete of idsToDelete) {\n const { id, __component } = idToDelete;\n await deleteComponent(__component, { id });\n }\n }\n};\n\nconst deleteComponents = async <TUID extends UID.Schema, TEntity extends Data.Entity<TUID>>(\n uid: TUID,\n entityToDelete: TEntity,\n { loadComponents = true } = {}\n) => {\n const { attributes = {} } = strapi.getModel(uid);\n\n const attributeNames = Object.keys(attributes);\n\n for (const attributeName of attributeNames) {\n const attribute = attributes[attributeName];\n\n if (attribute.type === 'component' || attribute.type === 'dynamiczone') {\n let value;\n if (loadComponents) {\n value = await strapi.db.query(uid).load(entityToDelete, attributeName);\n } else {\n value = entityToDelete[attributeName as keyof TEntity];\n }\n\n if (!value) {\n continue;\n }\n\n if (attribute.type === 'component') {\n const { component: componentUID } = attribute;\n // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1\n await async.map(\n _.castArray(value),\n (subValue: any) => deleteComponent(componentUID, subValue),\n {\n concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity,\n }\n );\n } else {\n // delete dynamic zone components\n // MySQL/MariaDB can cause deadlocks here if concurrency higher than 1\n await async.map(\n _.castArray(value),\n (subValue: any) => deleteComponent(subValue.__component, subValue),\n { concurrency: isDialectMySQL() && !strapi.db?.inTransaction() ? 1 : Infinity }\n );\n }\n\n continue;\n }\n }\n};\n\n/** *************************\n Component queries\n************************** */\n\n// components can have nested compos so this must be recursive\nconst createComponent = async <TUID extends UID.Component = UID.Component>(\n uid: TUID,\n data: Modules.EntityService.Params.Data.Input<TUID>\n) => {\n const model = strapi.getModel(uid) as Schema.Component;\n\n const componentData = await createComponents(uid, data);\n const transform = pipe(\n // Make sure we don't save the component with a pre-defined ID\n omit('id'),\n // Remove the component data from the original data object ...\n (payload) => omitComponentData(model, payload),\n // ... and assign the newly created component instead\n assign(componentData)\n );\n\n return strapi.db.query(uid).create({ data: transform(data) });\n};\n\n// components can have nested compos so this must be recursive\nconst updateComponent = async <TUID extends UID.Component>(\n uid: TUID,\n componentToUpdate: { id: Modules.EntityService.Params.Attribute.ID },\n data: Modules.EntityService.Params.Data.Input<TUID>\n) => {\n const model = strapi.getModel(uid) as Schema.Component;\n\n const componentData = await updateComponents(uid, componentToUpdate, data);\n\n return strapi.db.query(uid).update({\n where: {\n id: componentToUpdate.id,\n },\n data: Object.assign(omitComponentData(model, data), componentData),\n });\n};\n\nconst updateOrCreateComponent = <TUID extends UID.Component>(\n componentUID: TUID,\n value: Modules.EntityService.Params.Data.Input<TUID>\n) => {\n if (value === null) {\n return null;\n }\n\n // update\n if ('id' in value && typeof value.id !== 'undefined') {\n // TODO: verify the compo is associated with the entity\n return updateComponent(componentUID, { id: value.id }, value);\n }\n\n // create\n return createComponent(componentUID, value);\n};\n\nconst deleteComponent = async <TUID extends UID.Component>(\n uid: TUID,\n componentToDelete: Data.Component<TUID>\n) => {\n await deleteComponents(uid, componentToDelete);\n await strapi.db.query(uid).delete({ where: { id: componentToDelete.id } });\n};\n\n/**\n * Resolve the component UID of an entity's attribute based\n * on a given path (components & dynamic zones only)\n */\nconst resolveComponentUID = ({\n paths,\n strapi,\n data,\n contentType,\n}: {\n paths: string[];\n strapi: Core.Strapi;\n data: any;\n contentType: Schema.ContentType;\n}): UID.Schema | undefined => {\n let value: unknown = data;\n let cType:\n | Schema.ContentType\n | Schema.Component\n | ((...opts: any[]) => Schema.ContentType | Schema.Component) = contentType;\n for (const path of paths) {\n value = get(path, value);\n\n // Needed when the value of cType should be computed\n // based on the next value (eg: dynamic zones)\n if (typeof cType === 'function') {\n cType = cType(value);\n }\n\n if (path in cType.attributes) {\n const attribute: Schema.Attribute.AnyAttribute = cType.attributes[path];\n\n if (attribute.type === 'component') {\n cType = strapi.getModel(attribute.component);\n }\n\n if (attribute.type === 'dynamiczone') {\n cType = ({ __component }: { __component: UID.Component }) => strapi.getModel(__component);\n }\n }\n }\n\n if ('uid' in cType) {\n return cType.uid;\n }\n\n return undefined;\n};\n\nexport {\n omitComponentData,\n getComponents,\n createComponents,\n updateComponents,\n deleteComponents,\n deleteComponent,\n resolveComponentUID,\n};\n"],"names":["isDialectMySQL","strapi","db","dialect","client","omitComponentData","contentType","data","attributes","componentAttributes","Object","keys","filter","attributeName","contentTypesUtils","isComponentAttribute","omit","createComponents","uid","getModel","componentBody","attributeNames","attribute","has","type","component","componentUID","repeatable","componentValue","Array","isArray","Error","components","async","map","value","createComponent","concurrency","inTransaction","Infinity","id","__pivot","field","component_type","dynamiczoneValues","createDynamicZoneComponents","__component","getComponents","entity","getComponentAttributes","_","isEmpty","query","load","deleteComponents","entityToDelete","loadComponents","castArray","subValue","deleteComponent","model","componentData","transform","pipe","payload","assign","create","componentToDelete","delete","where","resolveComponentUID","paths","cType","path","get","undefined"],"mappings":"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"}