@strapi/core 5.56.0 → 5.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Strapi.d.ts +1 -0
- package/dist/Strapi.d.ts.map +1 -1
- package/dist/Strapi.js +6 -3
- package/dist/Strapi.js.map +1 -1
- package/dist/Strapi.mjs +6 -3
- package/dist/Strapi.mjs.map +1 -1
- package/dist/configuration/get-dirs.js +2 -2
- package/dist/configuration/get-dirs.js.map +1 -1
- package/dist/configuration/get-dirs.mjs +2 -2
- package/dist/configuration/get-dirs.mjs.map +1 -1
- package/dist/configuration/index.d.ts +1 -2
- package/dist/configuration/index.d.ts.map +1 -1
- package/dist/configuration/index.js +1 -2
- package/dist/configuration/index.js.map +1 -1
- package/dist/configuration/index.mjs +2 -3
- package/dist/configuration/index.mjs.map +1 -1
- package/dist/core-api/controller/collection-type.js +3 -3
- package/dist/core-api/controller/collection-type.js.map +1 -1
- package/dist/core-api/controller/collection-type.mjs +1 -1
- package/dist/core-api/controller/collection-type.mjs.map +1 -1
- package/dist/core-api/controller/index.js +2 -2
- package/dist/core-api/controller/index.js.map +1 -1
- package/dist/core-api/controller/index.mjs +2 -2
- package/dist/core-api/controller/index.mjs.map +1 -1
- package/dist/core-api/controller/single-type.js +2 -2
- package/dist/core-api/controller/single-type.js.map +1 -1
- package/dist/core-api/controller/single-type.mjs +1 -1
- package/dist/core-api/controller/single-type.mjs.map +1 -1
- package/dist/core-api/controller/transform.d.ts +1 -4
- package/dist/core-api/controller/transform.d.ts.map +1 -1
- package/dist/core-api/controller/transform.js +8 -8
- package/dist/core-api/controller/transform.js.map +1 -1
- package/dist/core-api/controller/transform.mjs +5 -5
- package/dist/core-api/controller/transform.mjs.map +1 -1
- package/dist/core-api/routes/index.js +1 -1
- package/dist/core-api/routes/index.js.map +1 -1
- package/dist/core-api/routes/index.mjs +1 -1
- package/dist/core-api/routes/index.mjs.map +1 -1
- package/dist/core-api/service/pagination.js +9 -9
- package/dist/core-api/service/pagination.js.map +1 -1
- package/dist/core-api/service/pagination.mjs +7 -7
- package/dist/core-api/service/pagination.mjs.map +1 -1
- package/dist/domain/content-type/index.d.ts.map +1 -1
- package/dist/domain/content-type/index.js +1 -2
- package/dist/domain/content-type/index.js.map +1 -1
- package/dist/domain/content-type/index.mjs +1 -2
- package/dist/domain/content-type/index.mjs.map +1 -1
- package/dist/ee/index.js +4 -4
- package/dist/ee/index.js.map +1 -1
- package/dist/ee/index.mjs +3 -3
- package/dist/ee/index.mjs.map +1 -1
- package/dist/factories.d.ts.map +1 -1
- package/dist/factories.js +3 -2
- package/dist/factories.js.map +1 -1
- package/dist/factories.mjs +3 -2
- package/dist/factories.mjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/loaders/apis.d.ts.map +1 -1
- package/dist/loaders/apis.js +1 -2
- package/dist/loaders/apis.js.map +1 -1
- package/dist/loaders/apis.mjs +1 -2
- package/dist/loaders/apis.mjs.map +1 -1
- package/dist/loaders/plugins/get-enabled-plugins.d.ts +1 -1
- package/dist/loaders/plugins/get-enabled-plugins.d.ts.map +1 -1
- package/dist/loaders/plugins/get-enabled-plugins.js +6 -5
- package/dist/loaders/plugins/get-enabled-plugins.js.map +1 -1
- package/dist/loaders/plugins/get-enabled-plugins.mjs +6 -5
- package/dist/loaders/plugins/get-enabled-plugins.mjs.map +1 -1
- package/dist/loaders/plugins/get-user-plugins-config.js +2 -2
- package/dist/loaders/plugins/get-user-plugins-config.js.map +1 -1
- package/dist/loaders/plugins/get-user-plugins-config.mjs +2 -2
- package/dist/loaders/plugins/get-user-plugins-config.mjs.map +1 -1
- package/dist/loaders/plugins/index.js +9 -12
- package/dist/loaders/plugins/index.js.map +1 -1
- package/dist/loaders/plugins/index.mjs +9 -12
- package/dist/loaders/plugins/index.mjs.map +1 -1
- package/dist/middlewares/body.js +2 -2
- package/dist/middlewares/body.js.map +1 -1
- package/dist/middlewares/body.mjs +2 -2
- package/dist/middlewares/body.mjs.map +1 -1
- package/dist/middlewares/public.js +2 -2
- package/dist/middlewares/public.js.map +1 -1
- package/dist/middlewares/public.mjs +2 -2
- package/dist/middlewares/public.mjs.map +1 -1
- package/dist/middlewares/responses.d.ts.map +1 -1
- package/dist/middlewares/responses.js +1 -3
- package/dist/middlewares/responses.js.map +1 -1
- package/dist/middlewares/responses.mjs +1 -3
- package/dist/middlewares/responses.mjs.map +1 -1
- package/dist/middlewares/security.d.ts.map +1 -1
- package/dist/middlewares/security.js +3 -3
- package/dist/middlewares/security.js.map +1 -1
- package/dist/middlewares/security.mjs +3 -3
- package/dist/middlewares/security.mjs.map +1 -1
- package/dist/middlewares/session.js +2 -2
- package/dist/middlewares/session.js.map +1 -1
- package/dist/middlewares/session.mjs +2 -2
- package/dist/middlewares/session.mjs.map +1 -1
- package/dist/migrations/database/5.0.0-discard-drafts.d.ts.map +1 -1
- package/dist/migrations/database/5.0.0-discard-drafts.js +1 -2
- package/dist/migrations/database/5.0.0-discard-drafts.js.map +1 -1
- package/dist/migrations/database/5.0.0-discard-drafts.mjs +1 -2
- package/dist/migrations/database/5.0.0-discard-drafts.mjs.map +1 -1
- package/dist/migrations/i18n.d.ts.map +1 -1
- package/dist/migrations/i18n.js +6 -4
- package/dist/migrations/i18n.js.map +1 -1
- package/dist/migrations/i18n.mjs +6 -4
- package/dist/migrations/i18n.mjs.map +1 -1
- package/dist/package.json.js +13 -13
- package/dist/package.json.mjs +13 -13
- package/dist/registries/apis.js +2 -2
- package/dist/registries/apis.js.map +1 -1
- package/dist/registries/apis.mjs +2 -2
- package/dist/registries/apis.mjs.map +1 -1
- package/dist/registries/components.js +2 -2
- package/dist/registries/components.js.map +1 -1
- package/dist/registries/components.mjs +2 -2
- package/dist/registries/components.mjs.map +1 -1
- package/dist/registries/content-types.d.ts +1 -1
- package/dist/registries/content-types.js +3 -3
- package/dist/registries/content-types.js.map +1 -1
- package/dist/registries/content-types.mjs +3 -3
- package/dist/registries/content-types.mjs.map +1 -1
- package/dist/registries/controllers.js +3 -3
- package/dist/registries/controllers.js.map +1 -1
- package/dist/registries/controllers.mjs +3 -3
- package/dist/registries/controllers.mjs.map +1 -1
- package/dist/registries/custom-fields.js +4 -4
- package/dist/registries/custom-fields.js.map +1 -1
- package/dist/registries/custom-fields.mjs +4 -4
- package/dist/registries/custom-fields.mjs.map +1 -1
- package/dist/registries/hooks.d.ts +1 -1
- package/dist/registries/hooks.js +2 -2
- package/dist/registries/hooks.js.map +1 -1
- package/dist/registries/hooks.mjs +2 -2
- package/dist/registries/hooks.mjs.map +1 -1
- package/dist/registries/middlewares.d.ts +1 -1
- package/dist/registries/middlewares.js +3 -3
- package/dist/registries/middlewares.js.map +1 -1
- package/dist/registries/middlewares.mjs +3 -3
- package/dist/registries/middlewares.mjs.map +1 -1
- package/dist/registries/modules.d.ts +1 -4
- package/dist/registries/modules.d.ts.map +1 -1
- package/dist/registries/modules.js +3 -3
- package/dist/registries/modules.js.map +1 -1
- package/dist/registries/modules.mjs +3 -3
- package/dist/registries/modules.mjs.map +1 -1
- package/dist/registries/plugins.js +2 -2
- package/dist/registries/plugins.js.map +1 -1
- package/dist/registries/plugins.mjs +2 -2
- package/dist/registries/plugins.mjs.map +1 -1
- package/dist/registries/policies.d.ts +1 -1
- package/dist/registries/policies.js +4 -4
- package/dist/registries/policies.js.map +1 -1
- package/dist/registries/policies.mjs +3 -3
- package/dist/registries/policies.mjs.map +1 -1
- package/dist/registries/services.js +3 -3
- package/dist/registries/services.js.map +1 -1
- package/dist/registries/services.mjs +3 -3
- package/dist/registries/services.mjs.map +1 -1
- package/dist/services/auth/index.js +3 -3
- package/dist/services/auth/index.js.map +1 -1
- package/dist/services/auth/index.mjs +3 -3
- package/dist/services/auth/index.mjs.map +1 -1
- package/dist/services/core-store.js +3 -3
- package/dist/services/core-store.js.map +1 -1
- package/dist/services/core-store.mjs +1 -1
- package/dist/services/core-store.mjs.map +1 -1
- package/dist/services/cron.d.ts.map +1 -1
- package/dist/services/cron.js +2 -4
- package/dist/services/cron.js.map +1 -1
- package/dist/services/cron.mjs +2 -4
- package/dist/services/cron.mjs.map +1 -1
- package/dist/services/document-service/attributes/index.js +2 -2
- package/dist/services/document-service/attributes/index.js.map +1 -1
- package/dist/services/document-service/attributes/index.mjs +1 -1
- package/dist/services/document-service/attributes/index.mjs.map +1 -1
- package/dist/services/document-service/attributes/transforms.js +3 -3
- package/dist/services/document-service/attributes/transforms.js.map +1 -1
- package/dist/services/document-service/attributes/transforms.mjs +2 -2
- package/dist/services/document-service/attributes/transforms.mjs.map +1 -1
- package/dist/services/document-service/components.d.ts.map +1 -1
- package/dist/services/document-service/components.js +13 -14
- package/dist/services/document-service/components.js.map +1 -1
- package/dist/services/document-service/components.mjs +12 -13
- package/dist/services/document-service/components.mjs.map +1 -1
- package/dist/services/document-service/draft-and-publish.js +65 -38
- package/dist/services/document-service/draft-and-publish.js.map +1 -1
- package/dist/services/document-service/draft-and-publish.mjs +59 -32
- package/dist/services/document-service/draft-and-publish.mjs.map +1 -1
- package/dist/services/document-service/entries.d.ts +2 -2
- package/dist/services/document-service/entries.d.ts.map +1 -1
- package/dist/services/document-service/entries.js +16 -8
- package/dist/services/document-service/entries.js.map +1 -1
- package/dist/services/document-service/entries.mjs +17 -9
- package/dist/services/document-service/entries.mjs.map +1 -1
- package/dist/services/document-service/first-published-at.js +7 -5
- package/dist/services/document-service/first-published-at.js.map +1 -1
- package/dist/services/document-service/first-published-at.mjs +7 -5
- package/dist/services/document-service/first-published-at.mjs.map +1 -1
- package/dist/services/document-service/internationalization.d.ts.map +1 -1
- package/dist/services/document-service/internationalization.js +37 -28
- package/dist/services/document-service/internationalization.js.map +1 -1
- package/dist/services/document-service/internationalization.mjs +33 -24
- package/dist/services/document-service/internationalization.mjs.map +1 -1
- package/dist/services/document-service/params.d.ts +1 -0
- package/dist/services/document-service/params.d.ts.map +1 -1
- package/dist/services/document-service/params.js +6 -4
- package/dist/services/document-service/params.js.map +1 -1
- package/dist/services/document-service/params.mjs +6 -5
- package/dist/services/document-service/params.mjs.map +1 -1
- package/dist/services/document-service/repository.d.ts.map +1 -1
- package/dist/services/document-service/repository.js +84 -61
- package/dist/services/document-service/repository.js.map +1 -1
- package/dist/services/document-service/repository.mjs +47 -24
- package/dist/services/document-service/repository.mjs.map +1 -1
- package/dist/services/document-service/transform/id-map.d.ts.map +1 -1
- package/dist/services/document-service/transform/id-map.js +2 -1
- package/dist/services/document-service/transform/id-map.js.map +1 -1
- package/dist/services/document-service/transform/id-map.mjs +2 -1
- package/dist/services/document-service/transform/id-map.mjs.map +1 -1
- package/dist/services/document-service/transform/id-transform.js +2 -2
- package/dist/services/document-service/transform/id-transform.js.map +1 -1
- package/dist/services/document-service/transform/id-transform.mjs +1 -1
- package/dist/services/document-service/transform/id-transform.mjs.map +1 -1
- package/dist/services/document-service/transform/query.d.ts +3 -1
- package/dist/services/document-service/transform/query.d.ts.map +1 -1
- package/dist/services/document-service/transform/query.js +12 -6
- package/dist/services/document-service/transform/query.js.map +1 -1
- package/dist/services/document-service/transform/query.mjs +11 -5
- package/dist/services/document-service/transform/query.mjs.map +1 -1
- package/dist/services/document-service/transform/relations/extract/data-ids.js +2 -2
- package/dist/services/document-service/transform/relations/extract/data-ids.js.map +1 -1
- package/dist/services/document-service/transform/relations/extract/data-ids.mjs +1 -1
- package/dist/services/document-service/transform/relations/extract/data-ids.mjs.map +1 -1
- package/dist/services/document-service/transform/relations/transform/data-ids.js +2 -2
- package/dist/services/document-service/transform/relations/transform/data-ids.js.map +1 -1
- package/dist/services/document-service/transform/relations/transform/data-ids.mjs +1 -1
- package/dist/services/document-service/transform/relations/transform/data-ids.mjs.map +1 -1
- package/dist/services/document-service/transform/relations/transform/default-locale.js +1 -1
- package/dist/services/document-service/transform/relations/transform/default-locale.js.map +1 -1
- package/dist/services/document-service/transform/relations/transform/default-locale.mjs +1 -1
- package/dist/services/document-service/transform/relations/transform/default-locale.mjs.map +1 -1
- package/dist/services/document-service/transform/relations/utils/dp.d.ts.map +1 -1
- package/dist/services/document-service/transform/relations/utils/dp.js +1 -2
- package/dist/services/document-service/transform/relations/utils/dp.js.map +1 -1
- package/dist/services/document-service/transform/relations/utils/dp.mjs +1 -2
- package/dist/services/document-service/transform/relations/utils/dp.mjs.map +1 -1
- package/dist/services/document-service/transform/relations/utils/i18n.d.ts +2 -2
- package/dist/services/document-service/transform/relations/utils/i18n.d.ts.map +1 -1
- package/dist/services/document-service/transform/relations/utils/i18n.js +2 -2
- package/dist/services/document-service/transform/relations/utils/i18n.js.map +1 -1
- package/dist/services/document-service/transform/relations/utils/i18n.mjs +2 -2
- package/dist/services/document-service/transform/relations/utils/i18n.mjs.map +1 -1
- package/dist/services/document-service/transform/relations/utils/map-relation.js +6 -6
- package/dist/services/document-service/transform/relations/utils/map-relation.js.map +1 -1
- package/dist/services/document-service/transform/relations/utils/map-relation.mjs +3 -3
- package/dist/services/document-service/transform/relations/utils/map-relation.mjs.map +1 -1
- package/dist/services/document-service/transform/relations/utils/xto-one.js +3 -3
- package/dist/services/document-service/transform/relations/utils/xto-one.js.map +1 -1
- package/dist/services/document-service/transform/relations/utils/xto-one.mjs +2 -2
- package/dist/services/document-service/transform/relations/utils/xto-one.mjs.map +1 -1
- package/dist/services/document-service/utils/bidirectional-relations.js +3 -3
- package/dist/services/document-service/utils/bidirectional-relations.js.map +1 -1
- package/dist/services/document-service/utils/bidirectional-relations.mjs +3 -3
- package/dist/services/document-service/utils/bidirectional-relations.mjs.map +1 -1
- package/dist/services/document-service/utils/clone-relations.js +3 -3
- package/dist/services/document-service/utils/clone-relations.js.map +1 -1
- package/dist/services/document-service/utils/clone-relations.mjs +3 -3
- package/dist/services/document-service/utils/clone-relations.mjs.map +1 -1
- package/dist/services/document-service/utils/self-referential-relations.js +4 -4
- package/dist/services/document-service/utils/self-referential-relations.js.map +1 -1
- package/dist/services/document-service/utils/self-referential-relations.mjs +4 -4
- package/dist/services/document-service/utils/self-referential-relations.mjs.map +1 -1
- package/dist/services/document-service/utils/unidirectional-relations.js +3 -3
- package/dist/services/document-service/utils/unidirectional-relations.js.map +1 -1
- package/dist/services/document-service/utils/unidirectional-relations.mjs +3 -3
- package/dist/services/document-service/utils/unidirectional-relations.mjs.map +1 -1
- package/dist/services/entity-validator/index.d.ts.map +1 -1
- package/dist/services/entity-validator/index.js +9 -10
- package/dist/services/entity-validator/index.js.map +1 -1
- package/dist/services/entity-validator/index.mjs +4 -5
- package/dist/services/entity-validator/index.mjs.map +1 -1
- package/dist/services/localization.d.ts +4 -0
- package/dist/services/localization.d.ts.map +1 -0
- package/dist/services/localization.js +51 -0
- package/dist/services/localization.js.map +1 -0
- package/dist/services/localization.mjs +49 -0
- package/dist/services/localization.mjs.map +1 -0
- package/dist/services/server/compose-endpoint.js +7 -7
- package/dist/services/server/compose-endpoint.js.map +1 -1
- package/dist/services/server/compose-endpoint.mjs +3 -3
- package/dist/services/server/compose-endpoint.mjs.map +1 -1
- package/dist/services/server/koa-methods.js +2 -2
- package/dist/services/server/koa-methods.js.map +1 -1
- package/dist/services/server/koa-methods.mjs +1 -1
- package/dist/services/server/koa-methods.mjs.map +1 -1
- package/dist/services/server/koa.d.ts.map +1 -1
- package/dist/services/server/koa.js +1 -2
- package/dist/services/server/koa.js.map +1 -1
- package/dist/services/server/koa.mjs +1 -2
- package/dist/services/server/koa.mjs.map +1 -1
- package/dist/services/server/middleware.d.ts.map +1 -1
- package/dist/services/server/middleware.js +1 -2
- package/dist/services/server/middleware.js.map +1 -1
- package/dist/services/server/middleware.mjs +1 -2
- package/dist/services/server/middleware.mjs.map +1 -1
- package/dist/services/server/routing.js +2 -2
- package/dist/services/server/routing.js.map +1 -1
- package/dist/services/server/routing.mjs +2 -2
- package/dist/services/server/routing.mjs.map +1 -1
- package/dist/services/utils/conditional-fields.d.ts +1 -1
- package/dist/services/utils/conditional-fields.d.ts.map +1 -1
- package/dist/services/utils/conditional-fields.js +2 -8
- package/dist/services/utils/conditional-fields.js.map +1 -1
- package/dist/services/utils/conditional-fields.mjs +2 -8
- package/dist/services/utils/conditional-fields.mjs.map +1 -1
- package/dist/services/utils/dynamic-zones.d.ts.map +1 -1
- package/dist/services/utils/dynamic-zones.js +2 -8
- package/dist/services/utils/dynamic-zones.js.map +1 -1
- package/dist/services/utils/dynamic-zones.mjs +2 -8
- package/dist/services/utils/dynamic-zones.mjs.map +1 -1
- package/dist/utils/cron.js +2 -2
- package/dist/utils/cron.js.map +1 -1
- package/dist/utils/cron.mjs +1 -1
- package/dist/utils/cron.mjs.map +1 -1
- package/dist/utils/filepath-to-prop-path.d.ts.map +1 -1
- package/dist/utils/filepath-to-prop-path.js +5 -12
- package/dist/utils/filepath-to-prop-path.js.map +1 -1
- package/dist/utils/filepath-to-prop-path.mjs +5 -11
- package/dist/utils/filepath-to-prop-path.mjs.map +1 -1
- package/dist/utils/is-initialized.js +3 -3
- package/dist/utils/is-initialized.js.map +1 -1
- package/dist/utils/is-initialized.mjs +2 -2
- package/dist/utils/is-initialized.mjs.map +1 -1
- package/dist/utils/startup-logger.d.ts.map +1 -1
- package/dist/utils/startup-logger.js +2 -4
- package/dist/utils/startup-logger.js.map +1 -1
- package/dist/utils/startup-logger.mjs +2 -3
- package/dist/utils/startup-logger.mjs.map +1 -1
- package/dist/utils/transform-content-types-to-models.js +4 -4
- package/dist/utils/transform-content-types-to-models.js.map +1 -1
- package/dist/utils/transform-content-types-to-models.mjs +3 -3
- package/dist/utils/transform-content-types-to-models.mjs.map +1 -1
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"map-relation.mjs","sources":["../../../../../../src/services/document-service/transform/relations/utils/map-relation.ts"],"sourcesContent":["/* eslint-disable node/no-callback-literal */\nimport {
|
|
1
|
+
{"version":3,"file":"map-relation.mjs","sources":["../../../../../../src/services/document-service/transform/relations/utils/map-relation.ts"],"sourcesContent":["/* eslint-disable node/no-callback-literal */\nimport { curry, isObject } from 'lodash';\n\nimport { traverseEntity, async } from '@strapi/utils';\n\nimport { Relation } from './types';\n\nconst isNumeric = (value: any): value is number => {\n if (Array.isArray(value)) return false; // Handle [1, 'docId'] case\n const parsed = parseInt(value, 10);\n return !Number.isNaN(parsed);\n};\n\nconst toArray = (value: any) => {\n // Keep value as it is if it's a nullish value\n if (value == null) return value;\n if (Array.isArray(value)) return value;\n\n return [value];\n};\n\n/**\n * There are multiple ways to create Strapi relations.\n * This is a utility to traverse and transform relation data\n *\n *\n * For consistency and ease of use, the response will always be an object with the following shape:\n * { set: [{...}], connect: [{...}], disconnect: [{...}] }\n *\n * @example\n * transformRelationData({\n * onLongHand: (relation) => {\n * // Change the id of the relation\n * return { id: 'other' };\n * },\n * }, relation)\n */\nconst mapRelation = async (\n callback: (relation: any) => any,\n rel: Relation,\n isRecursive = false\n): Promise<Relation> => {\n let relation: Relation = rel;\n\n const wrapInSet = (value: any) => {\n // Ignore wrapping if it's a recursive call\n if (isRecursive) {\n return value;\n }\n return { set: toArray(value) };\n };\n\n // undefined | null\n if (relation == null) {\n return callback(relation);\n }\n\n // LongHand[] | ShortHand[]\n if (Array.isArray(relation)) {\n return async\n .map(relation, (r: Relation) => mapRelation(callback, r, true))\n .then((result: any) => result.flat().filter(Boolean))\n .then(wrapInSet);\n }\n\n // LongHand\n if (isObject(relation)) {\n // { id: 1 } || { documentId: 1 }\n if ('id' in relation || 'documentId' in relation) {\n const result = await callback(relation);\n return wrapInSet(result);\n }\n\n // If not connecting anything, return default visitor\n if (!relation.set && !relation.disconnect && !relation.connect) {\n return callback(relation);\n }\n\n // { set }\n if (relation.set) {\n const set: any = await mapRelation(callback, relation.set, true);\n relation = { ...relation, set: toArray(set) };\n }\n\n // { disconnect}\n if (relation.disconnect) {\n const disconnect: any = await mapRelation(callback, relation.disconnect, true);\n relation = { ...relation, disconnect: toArray(disconnect) };\n }\n\n // { connect }\n if (relation.connect) {\n // Transform the relation to connect\n const connect: any = await mapRelation(callback, relation.connect, true);\n relation = { ...relation, connect: toArray(connect) };\n }\n\n return relation;\n }\n\n // ShortHand\n if (isNumeric(relation)) {\n const result = await callback({ id: relation });\n return wrapInSet(result);\n }\n\n if (typeof relation === 'string') {\n const result = await callback({ documentId: relation });\n return wrapInSet(result);\n }\n\n // Anything else\n return callback(relation);\n};\n\ntype TraverseEntity = Parameters<typeof traverseEntity>;\ntype TraverseEntityRelationsOptions = TraverseEntity[1] & { includeMedia?: boolean };\n\n/**\n * Utility function, same as `traverseEntity` but only for relations and, when requested, media.\n */\nconst traverseEntityRelations = async (\n visitor: TraverseEntity[0],\n options: TraverseEntityRelationsOptions,\n data: TraverseEntity[2]\n) => {\n const { includeMedia = false, ...traverseOptions } = options;\n\n return traverseEntity(\n async (options, utils) => {\n const { attribute } = options;\n\n if (!attribute) {\n return;\n }\n\n if (attribute.type !== 'relation' && !(includeMedia && attribute.type === 'media')) {\n return;\n }\n\n if (attribute.type === 'relation') {\n // TODO: Handle join columns\n if (attribute.useJoinTable === false) {\n return;\n }\n\n // morphToOne uses morphColumn (inline columns on the entity), handled directly in processData\n if (attribute.relation === 'morphToOne') {\n return;\n }\n }\n\n return visitor(options, utils);\n },\n traverseOptions,\n data\n );\n};\n\nconst mapRelationCurried = curry(mapRelation);\nconst traverseEntityRelationsCurried = curry(traverseEntityRelations);\n\nexport {\n mapRelationCurried as mapRelation,\n traverseEntityRelationsCurried as traverseEntityRelations,\n};\n"],"names":["isNumeric","value","Array","isArray","parsed","parseInt","Number","isNaN","toArray","mapRelation","callback","rel","isRecursive","relation","wrapInSet","set","async","map","r","then","result","flat","filter","Boolean","isObject","disconnect","connect","id","documentId","traverseEntityRelations","visitor","options","data","includeMedia","traverseOptions","traverseEntity","utils","attribute","type","useJoinTable","mapRelationCurried","curry","traverseEntityRelationsCurried"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _ = require('lodash');
|
|
4
4
|
var strapiUtils = require('@strapi/utils');
|
|
5
5
|
|
|
6
6
|
const { isAnyToOne } = strapiUtils.relations;
|
|
@@ -12,7 +12,7 @@ const { isAnyToOne } = strapiUtils.relations;
|
|
|
12
12
|
if (!isAnyToOne(attribute)) {
|
|
13
13
|
return value;
|
|
14
14
|
}
|
|
15
|
-
if (
|
|
15
|
+
if (value == null) {
|
|
16
16
|
return value;
|
|
17
17
|
}
|
|
18
18
|
if (Array.isArray(value)) {
|
|
@@ -23,7 +23,7 @@ const { isAnyToOne } = strapiUtils.relations;
|
|
|
23
23
|
}
|
|
24
24
|
return value;
|
|
25
25
|
}
|
|
26
|
-
if (
|
|
26
|
+
if (_.isObject(value) && !Array.isArray(value)) {
|
|
27
27
|
const objValue = value;
|
|
28
28
|
if (Array.isArray(objValue.set) && objValue.set.length > 1) {
|
|
29
29
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xto-one.js","sources":["../../../../../../src/services/document-service/transform/relations/utils/xto-one.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"xto-one.js","sources":["../../../../../../src/services/document-service/transform/relations/utils/xto-one.ts"],"sourcesContent":["import { isObject } from 'lodash';\n\nimport { relations } from '@strapi/utils';\n\nimport { Relation } from './types';\n\nconst { isAnyToOne } = relations;\n\n/**\n * \"Relates to one\" fields hold a single entry. If a caller passes more\n * than one, keep the last. Runs on the user-provided payload only — never\n * on the internal draft/published expansion that happens later.\n */\nexport const normalizeXToOneRelationValue = (attribute: any, value: Relation): Relation => {\n if (!isAnyToOne(attribute)) {\n return value;\n }\n\n if (value == null) {\n return value;\n }\n\n if (Array.isArray(value)) {\n if (value.length > 1) {\n return [value[value.length - 1]] as Relation;\n }\n return value;\n }\n\n if (isObject(value) && !Array.isArray(value)) {\n const objValue = value as { set?: any; connect?: any; disconnect?: any };\n if (Array.isArray(objValue.set) && objValue.set.length > 1) {\n return {\n ...objValue,\n set: [objValue.set[objValue.set.length - 1]],\n } as Relation;\n }\n }\n\n return value;\n};\n"],"names":["isAnyToOne","relations","normalizeXToOneRelationValue","attribute","value","Array","isArray","length","isObject","objValue","set"],"mappings":";;;;;AAMA,MAAM,EAAEA,UAAU,EAAE,GAAGC,qBAAAA;AAEvB;;;;AAIC,IACM,MAAMC,4BAAAA,GAA+B,CAACC,SAAAA,EAAgBC,KAAAA,GAAAA;IAC3D,IAAI,CAACJ,WAAWG,SAAAA,CAAAA,EAAY;QAC1B,OAAOC,KAAAA;AACT,IAAA;AAEA,IAAA,IAAIA,SAAS,IAAA,EAAM;QACjB,OAAOA,KAAAA;AACT,IAAA;IAEA,IAAIC,KAAAA,CAAMC,OAAO,CAACF,KAAAA,CAAAA,EAAQ;QACxB,IAAIA,KAAAA,CAAMG,MAAM,GAAG,CAAA,EAAG;YACpB,OAAO;AAACH,gBAAAA,KAAK,CAACA,KAAAA,CAAMG,MAAM,GAAG,CAAA;AAAG,aAAA;AAClC,QAAA;QACA,OAAOH,KAAAA;AACT,IAAA;AAEA,IAAA,IAAII,WAASJ,KAAAA,CAAAA,IAAU,CAACC,KAAAA,CAAMC,OAAO,CAACF,KAAAA,CAAAA,EAAQ;AAC5C,QAAA,MAAMK,QAAAA,GAAWL,KAAAA;QACjB,IAAIC,KAAAA,CAAMC,OAAO,CAACG,QAAAA,CAASC,GAAG,CAAA,IAAKD,QAAAA,CAASC,GAAG,CAACH,MAAM,GAAG,CAAA,EAAG;YAC1D,OAAO;AACL,gBAAA,GAAGE,QAAQ;gBACXC,GAAAA,EAAK;AAACD,oBAAAA,QAAAA,CAASC,GAAG,CAACD,QAAAA,CAASC,GAAG,CAACH,MAAM,GAAG,CAAA;AAAG;AAC9C,aAAA;AACF,QAAA;AACF,IAAA;IAEA,OAAOH,KAAAA;AACT;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isObject } from 'lodash';
|
|
2
2
|
import { relations } from '@strapi/utils';
|
|
3
3
|
|
|
4
4
|
const { isAnyToOne } = relations;
|
|
@@ -10,7 +10,7 @@ const { isAnyToOne } = relations;
|
|
|
10
10
|
if (!isAnyToOne(attribute)) {
|
|
11
11
|
return value;
|
|
12
12
|
}
|
|
13
|
-
if (
|
|
13
|
+
if (value == null) {
|
|
14
14
|
return value;
|
|
15
15
|
}
|
|
16
16
|
if (Array.isArray(value)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xto-one.mjs","sources":["../../../../../../src/services/document-service/transform/relations/utils/xto-one.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"xto-one.mjs","sources":["../../../../../../src/services/document-service/transform/relations/utils/xto-one.ts"],"sourcesContent":["import { isObject } from 'lodash';\n\nimport { relations } from '@strapi/utils';\n\nimport { Relation } from './types';\n\nconst { isAnyToOne } = relations;\n\n/**\n * \"Relates to one\" fields hold a single entry. If a caller passes more\n * than one, keep the last. Runs on the user-provided payload only — never\n * on the internal draft/published expansion that happens later.\n */\nexport const normalizeXToOneRelationValue = (attribute: any, value: Relation): Relation => {\n if (!isAnyToOne(attribute)) {\n return value;\n }\n\n if (value == null) {\n return value;\n }\n\n if (Array.isArray(value)) {\n if (value.length > 1) {\n return [value[value.length - 1]] as Relation;\n }\n return value;\n }\n\n if (isObject(value) && !Array.isArray(value)) {\n const objValue = value as { set?: any; connect?: any; disconnect?: any };\n if (Array.isArray(objValue.set) && objValue.set.length > 1) {\n return {\n ...objValue,\n set: [objValue.set[objValue.set.length - 1]],\n } as Relation;\n }\n }\n\n return value;\n};\n"],"names":["isAnyToOne","relations","normalizeXToOneRelationValue","attribute","value","Array","isArray","length","isObject","objValue","set"],"mappings":";;;AAMA,MAAM,EAAEA,UAAU,EAAE,GAAGC,SAAAA;AAEvB;;;;AAIC,IACM,MAAMC,4BAAAA,GAA+B,CAACC,SAAAA,EAAgBC,KAAAA,GAAAA;IAC3D,IAAI,CAACJ,WAAWG,SAAAA,CAAAA,EAAY;QAC1B,OAAOC,KAAAA;AACT,IAAA;AAEA,IAAA,IAAIA,SAAS,IAAA,EAAM;QACjB,OAAOA,KAAAA;AACT,IAAA;IAEA,IAAIC,KAAAA,CAAMC,OAAO,CAACF,KAAAA,CAAAA,EAAQ;QACxB,IAAIA,KAAAA,CAAMG,MAAM,GAAG,CAAA,EAAG;YACpB,OAAO;AAACH,gBAAAA,KAAK,CAACA,KAAAA,CAAMG,MAAM,GAAG,CAAA;AAAG,aAAA;AAClC,QAAA;QACA,OAAOH,KAAAA;AACT,IAAA;AAEA,IAAA,IAAII,SAASJ,KAAAA,CAAAA,IAAU,CAACC,KAAAA,CAAMC,OAAO,CAACF,KAAAA,CAAAA,EAAQ;AAC5C,QAAA,MAAMK,QAAAA,GAAWL,KAAAA;QACjB,IAAIC,KAAAA,CAAMC,OAAO,CAACG,QAAAA,CAASC,GAAG,CAAA,IAAKD,QAAAA,CAASC,GAAG,CAACH,MAAM,GAAG,CAAA,EAAG;YAC1D,OAAO;AACL,gBAAA,GAAGE,QAAQ;gBACXC,GAAAA,EAAK;AAACD,oBAAAA,QAAAA,CAASC,GAAG,CAACD,QAAAA,CAASC,GAAG,CAACH,MAAM,GAAG,CAAA;AAAG;AAC9C,aAAA;AACF,QAAA;AACF,IAAA;IAEA,OAAOH,KAAAA;AACT;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _ = require('lodash');
|
|
4
4
|
|
|
5
5
|
/** Draft id → published id for rows that already have a published counterpart (same document_id + locale). */ const draftToPublishedMap = async (trx, tableName, rowIds)=>{
|
|
6
6
|
const uniqueIds = [
|
|
@@ -201,7 +201,7 @@ const remapRelatedIds = (rows, relatedCol, idMap)=>rows.map((row)=>{
|
|
|
201
201
|
* @param newEntries - Array of new entry versions with their IDs and locales
|
|
202
202
|
* @param existingRelations - Array of join table data containing the relations to be updated
|
|
203
203
|
*/ const sync = async (oldEntries, newEntries, existingRelations)=>{
|
|
204
|
-
const newEntriesByLocale =
|
|
204
|
+
const newEntriesByLocale = _.keyBy(newEntries, 'locale');
|
|
205
205
|
const entryIdMapping = oldEntries.reduce((acc, oldEntry)=>{
|
|
206
206
|
const newEntry = newEntriesByLocale[oldEntry.locale];
|
|
207
207
|
if (!newEntry) {
|
|
@@ -248,7 +248,7 @@ const remapRelatedIds = (rows, relatedCol, idMap)=>rows.map((row)=>{
|
|
|
248
248
|
const existingSet = new Set(existingRows.map((r)=>`${r[sourceColumn]}:${r[targetColumn]}`));
|
|
249
249
|
// Batch INSERT: insert cascade-deleted rows that aren't from republished sources
|
|
250
250
|
const toInsert = mappedRelations.filter(({ newSourceId, targetId })=>!existingSet.has(`${newSourceId}:${targetId}`) && !isRepublishedEntry(newSourceId)).map(({ relation, newSourceId, originalOrder })=>({
|
|
251
|
-
...
|
|
251
|
+
..._.omit(relation, strapi.db.metadata.identifiers.ID_COLUMN),
|
|
252
252
|
[sourceColumn]: newSourceId,
|
|
253
253
|
[orderColumn]: originalOrder
|
|
254
254
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bidirectional-relations.js","sources":["../../../../src/services/document-service/utils/bidirectional-relations.ts"],"sourcesContent":["import { keyBy, omit } from 'lodash/fp';\nimport type { UID, Schema } from '@strapi/types';\nimport type { JoinTable } from '@strapi/database';\n\ninterface LoadContext {\n oldVersions: { id: string; locale: string }[];\n newVersions: { id: string; locale: string }[];\n}\n\ninterface RelationEntry {\n joinTable: JoinTable;\n relations: Record<string, unknown>[];\n /** FK column for the entity being published */\n entityColumn: string;\n /** FK column for the related entity */\n relatedColumn: string;\n}\n\n/** Draft id → published id for rows that already have a published counterpart (same document_id + locale). */\nconst draftToPublishedMap = async (trx: any, tableName: string, rowIds: unknown[]) => {\n const uniqueIds = [...new Set(rowIds)];\n if (uniqueIds.length === 0) {\n return new Map<string, string>();\n }\n\n const draftEntries = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('id', uniqueIds as any)\n .transacting(trx);\n\n if (draftEntries.length === 0) {\n return new Map<string, string>();\n }\n\n const pubEntries = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereNotNull('published_at')\n .whereIn(\n 'document_id',\n draftEntries.map((e: any) => e.document_id)\n )\n .transacting(trx);\n\n const pubByDocLocale = new Map(\n pubEntries.map((e: any) => [`${e.document_id}_${e.locale}`, e.id])\n );\n\n const map = new Map<string, string>();\n for (const d of draftEntries) {\n const pubId = pubByDocLocale.get(`${d.document_id}_${d.locale}`);\n if (pubId) {\n map.set(String(d.id), String(pubId));\n }\n }\n return map;\n};\n\nconst remapRelatedIds = (rows: any[], relatedCol: string, idMap: Map<string, string>) =>\n rows.map((row) => {\n const next = idMap.get(String(row[relatedCol]));\n return next ? { ...row, [relatedCol]: next } : row;\n });\n\n/**\n * Reads join rows tied to the entry being published (`publishedCol` IN draft/old ids) and returns\n * batches for `sync()`. When the FK in `relatedCol` points at a D&P type, maps known draft ids to\n * published ids; otherwise keeps draft ids so sync can still run after both sides exist.\n */\nconst captureJoinBatches = async (\n trx: any,\n opts: {\n joinTable: any;\n /** Column holding ids of the document being published (the `uid` passed to load). */\n publishedCol: string;\n /** The other FK; may be remapped via draftToPublishedMap. */\n relatedCol: string;\n /** Content type behind `relatedCol` (used for D&P + table name). */\n relatedUid: UID.ContentType;\n relatedHasDraftAndPublish: boolean;\n /** Model that owns this attribute; draft capture is skipped for components. */\n schemaUid: UID.ContentType;\n /**\n * True when the attribute being captured is the owning side of the relation and the entity\n * being published owns it (e.g. publishing an Article for `Article.categories`). In that case\n * the owning-side order is rebuilt from the draft by `entries.publish`, so capturing the old\n * published rows would only let `sync()` overwrite the freshly published order with a stale\n * one — silently reverting a reorder made in the draft. The inverse-side order still needs the\n * old-published capture to be restored, so this only suppresses the owning-side capture.\n */\n isOwningSide: boolean;\n oldVersions: LoadContext['oldVersions'];\n newVersions: LoadContext['newVersions'];\n }\n): Promise<RelationEntry[]> => {\n const {\n joinTable,\n publishedCol,\n relatedCol,\n relatedUid,\n relatedHasDraftAndPublish,\n schemaUid,\n isOwningSide,\n oldVersions,\n newVersions,\n } = opts;\n\n const batches: RelationEntry[] = [];\n const { name: table } = joinTable;\n\n // Skip the old-published capture for the owning side: those rows are recreated in draft order\n // by `entries.publish`, so restoring their order from the old published version is at best a\n // no-op and at worst reverts a draft reorder. The draftsOnly capture below is still needed\n // (e.g. when a related entry is published after this one) and is not affected by this guard.\n const oldIds = isOwningSide ? [] : oldVersions.map((e) => e.id);\n if (oldIds.length > 0) {\n const existing = await strapi.db\n .getConnection()\n .select('*')\n .from(table)\n .whereIn(publishedCol, oldIds)\n .transacting(trx);\n if (existing.length > 0) {\n batches.push({\n joinTable,\n relations: existing,\n entityColumn: publishedCol,\n relatedColumn: relatedCol,\n });\n }\n }\n\n if (!strapi.contentTypes[schemaUid]) {\n return batches;\n }\n\n const oldLocales = new Set(oldVersions.map((e) => e.locale));\n const draftsOnly = newVersions.filter((v) => !oldLocales.has(v.locale));\n if (draftsOnly.length === 0) {\n return batches;\n }\n\n const draftIds = draftsOnly.map((e) => e.id);\n const draftRows = await strapi.db\n .getConnection()\n .select('*')\n .from(table)\n .whereIn(publishedCol, draftIds)\n .transacting(trx);\n\n if (draftRows.length === 0) {\n return batches;\n }\n\n let relations = draftRows;\n if (relatedHasDraftAndPublish) {\n const meta = strapi.db.metadata.get(relatedUid);\n const relatedIds = draftRows.map((r: any) => r[relatedCol]);\n const map = await draftToPublishedMap(trx, meta.tableName, relatedIds);\n relations = remapRelatedIds(draftRows, relatedCol, map);\n }\n\n batches.push({ joinTable, relations, entityColumn: publishedCol, relatedColumn: relatedCol });\n return batches;\n};\n\n/**\n * Loads all bidirectional relations that need to be synchronized when content entries change state\n * (e.g., during publish/unpublish operations).\n *\n * In Strapi, bidirectional relations allow maintaining order from both sides of the relation.\n * When an entry is published, the following occurs:\n *\n * 1. The old published entry is deleted\n * 2. A new entry is created with all its relations\n *\n * This process affects relation ordering in the following way:\n *\n * Initial state (Entry A related to X, Y, Z):\n * ```\n * Entry A (draft) Entry A (published)\n * │ │\n * ├──(1)→ X ├──(1)→ X\n * ├──(2)→ Y ├──(2)→ Y\n * └──(3)→ Z └──(3)→ Z\n *\n * X's perspective: Y's perspective: Z's perspective:\n * └──(2)→ Entry A └──(1)→ Entry A └──(3)→ Entry A\n * ```\n *\n * After publishing Entry A (without relation order sync):\n * ```\n * Entry A (draft) Entry A (new published)\n * │ │\n * ├──(1)→ X ├──(1)→ X\n * ├──(2)→ Y ├──(2)→ Y\n * └──(3)→ Z └──(3)→ Z\n *\n * X's perspective: Y's perspective: Z's perspective:\n * └──(3)→ Entry A └──(3)→ Entry A └──(3)→ Entry A\n * (all relations appear last in order)\n * ```\n *\n * This module preserves the original ordering from both perspectives by:\n * 1. Capturing the relation order before the entry state changes\n * 2. Restoring this order after the new relations are created\n *\n * @param uid - The unique identifier of the content type being processed\n * @param context - Object containing arrays of old and new entry versions\n * @returns Array of objects containing join table metadata and relations to be updated\n */\nconst load = async (uid: UID.ContentType, { oldVersions, newVersions }: LoadContext) => {\n const relationsToUpdate: RelationEntry[] = [];\n\n await strapi.db.transaction(async ({ trx }) => {\n const models = [\n ...(Object.values(strapi.contentTypes) as Schema.ContentType[]),\n ...Object.values(strapi.components),\n ];\n\n for (const model of models) {\n const dbModel = strapi.db.metadata.get(model.uid);\n\n for (const attribute of Object.values(dbModel.attributes) as Record<string, any>[]) {\n const joinTable = attribute.joinTable;\n\n if (attribute.type !== 'relation' || !joinTable) {\n continue;\n }\n\n if (!(attribute.inversedBy || attribute.mappedBy)) {\n continue;\n }\n\n // Owning side: e.g. Author.articles when publishing an Author.\n const isOwningSide =\n !!attribute.inversedBy &&\n model.uid === uid &&\n attribute.relation === 'manyToMany' &&\n model.uid !== attribute.target;\n\n // Inverse side: e.g. Article.authors when publishing an Article.\n const isInverseSide = attribute.target === uid && model.uid !== uid;\n\n if (!isOwningSide && !isInverseSide) {\n continue;\n }\n\n // Direction determines which join column belongs to the entity being published\n const publishedCol = isOwningSide\n ? joinTable.joinColumn.name\n : joinTable.inverseJoinColumn.name;\n const relatedCol = isOwningSide\n ? joinTable.inverseJoinColumn.name\n : joinTable.joinColumn.name;\n\n const relatedUid = (isOwningSide ? attribute.target : model.uid) as UID.ContentType;\n\n const batches = await captureJoinBatches(trx, {\n joinTable,\n publishedCol,\n relatedCol,\n relatedUid,\n relatedHasDraftAndPublish: isOwningSide\n ? !!strapi.contentTypes[relatedUid]?.options?.draftAndPublish\n : !!model.options?.draftAndPublish,\n schemaUid: model.uid as UID.ContentType,\n isOwningSide,\n oldVersions,\n newVersions,\n });\n relationsToUpdate.push(...batches);\n }\n }\n });\n\n return relationsToUpdate;\n};\n\n/**\n * Synchronizes the order of bidirectional relations after content entries have changed state.\n *\n * When entries change state (e.g., draft → published), their IDs change and all relations are recreated.\n * While the order of relations from the entry's perspective is maintained (as they're created in order),\n * the inverse relations (from related entries' perspective) would all appear last in order since they're new.\n *\n * Example:\n * ```\n * Before publish:\n * Article(id:1) →(order:1)→ Category(id:5)\n * Category(id:5) →(order:3)→ Article(id:1)\n *\n * After publish (without sync):\n * Article(id:2) →(order:1)→ Category(id:5) [order preserved]\n * Category(id:5) →(order:99)→ Article(id:2) [order lost - appears last]\n *\n * After sync:\n * Article(id:2) →(order:1)→ Category(id:5) [order preserved]\n * Category(id:5) →(order:3)→ Article(id:2) [order restored]\n * ```\n *\n * @param oldEntries - Array of previous entry versions with their IDs and locales\n * @param newEntries - Array of new entry versions with their IDs and locales\n * @param existingRelations - Array of join table data containing the relations to be updated\n */\nconst sync = async (\n oldEntries: { id: string; locale: string }[],\n newEntries: { id: string; locale: string }[],\n existingRelations: RelationEntry[]\n) => {\n const newEntriesByLocale = keyBy('locale', newEntries);\n\n const entryIdMapping = oldEntries.reduce(\n (acc, oldEntry) => {\n const newEntry = newEntriesByLocale[oldEntry.locale];\n if (!newEntry) {\n return acc;\n }\n acc[oldEntry.id] = newEntry.id;\n return acc;\n },\n {} as Record<string, string>\n );\n\n const republishedEntryIds = new Set(newEntries.map((e) => String(e.id)));\n const isRepublishedEntry = (id: string | number) => republishedEntryIds.has(String(id));\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const {\n joinTable,\n relations,\n entityColumn: sourceColumn,\n relatedColumn: targetColumn,\n } of existingRelations) {\n const orderColumn = joinTable.orderColumnName;\n\n // Failsafe in case those don't exist\n if (!sourceColumn || !targetColumn || !orderColumn) {\n continue;\n }\n\n const mappedRelations = relations\n .map((relation) => ({\n relation,\n oldSourceId: relation[sourceColumn] as string,\n targetId: relation[targetColumn] as string,\n originalOrder: relation[orderColumn],\n newSourceId: entryIdMapping[relation[sourceColumn] as string],\n }))\n .filter((r): r is typeof r & { newSourceId: string } => Boolean(r.newSourceId));\n\n if (!mappedRelations.length) continue;\n\n const newSourceIds = mappedRelations.map((r) => r.newSourceId);\n\n // Batch UPDATE: set each row's order in a single statement using CASE\n const caseFragments = mappedRelations.map(() => `WHEN ?? = ? AND ?? = ? THEN ?`);\n const caseBindings = mappedRelations.flatMap(({ newSourceId, targetId, originalOrder }) => [\n sourceColumn,\n newSourceId,\n targetColumn,\n targetId,\n originalOrder,\n ]);\n\n await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .update({\n [orderColumn]: trx.raw(`CASE ${caseFragments.join(' ')} ELSE ?? END`, [\n ...caseBindings,\n orderColumn,\n ]),\n });\n\n // Batch SELECT: find which rows exist so we know what to insert\n const existingRows = await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .select(sourceColumn, targetColumn);\n\n const existingSet = new Set(\n existingRows.map((r: Record<string, unknown>) => `${r[sourceColumn]}:${r[targetColumn]}`)\n );\n\n // Batch INSERT: insert cascade-deleted rows that aren't from republished sources\n const toInsert = mappedRelations\n .filter(\n ({ newSourceId, targetId }) =>\n !existingSet.has(`${newSourceId}:${targetId}`) && !isRepublishedEntry(newSourceId)\n )\n .map(({ relation, newSourceId, originalOrder }) => ({\n ...omit(strapi.db.metadata.identifiers.ID_COLUMN, relation),\n [sourceColumn]: newSourceId,\n [orderColumn]: originalOrder,\n }));\n\n if (toInsert.length) {\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n await trx.batchInsert(joinTable.name, toInsert, batchSize);\n }\n }\n });\n};\n\nexport { load, sync };\n"],"names":["draftToPublishedMap","trx","tableName","rowIds","uniqueIds","Set","length","Map","draftEntries","strapi","db","getConnection","select","from","whereIn","transacting","pubEntries","whereNotNull","map","e","document_id","pubByDocLocale","locale","id","d","pubId","get","set","String","remapRelatedIds","rows","relatedCol","idMap","row","next","captureJoinBatches","opts","joinTable","publishedCol","relatedUid","relatedHasDraftAndPublish","schemaUid","isOwningSide","oldVersions","newVersions","batches","name","table","oldIds","existing","push","relations","entityColumn","relatedColumn","contentTypes","oldLocales","draftsOnly","filter","v","has","draftIds","draftRows","meta","metadata","relatedIds","r","load","uid","relationsToUpdate","transaction","models","Object","values","components","model","dbModel","attribute","attributes","type","inversedBy","mappedBy","relation","target","isInverseSide","joinColumn","inverseJoinColumn","options","draftAndPublish","sync","oldEntries","newEntries","existingRelations","newEntriesByLocale","keyBy","entryIdMapping","reduce","acc","oldEntry","newEntry","republishedEntryIds","isRepublishedEntry","sourceColumn","targetColumn","orderColumn","orderColumnName","mappedRelations","oldSourceId","targetId","originalOrder","newSourceId","Boolean","newSourceIds","caseFragments","caseBindings","flatMap","update","raw","join","existingRows","existingSet","toInsert","omit","identifiers","ID_COLUMN","batchSize","dialect","getBatchInsertSize","batchInsert"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bidirectional-relations.js","sources":["../../../../src/services/document-service/utils/bidirectional-relations.ts"],"sourcesContent":["import { keyBy, omit } from 'lodash';\nimport type { UID, Schema } from '@strapi/types';\nimport type { JoinTable } from '@strapi/database';\n\ninterface LoadContext {\n oldVersions: { id: string; locale: string }[];\n newVersions: { id: string; locale: string }[];\n}\n\ninterface RelationEntry {\n joinTable: JoinTable;\n relations: Record<string, unknown>[];\n /** FK column for the entity being published */\n entityColumn: string;\n /** FK column for the related entity */\n relatedColumn: string;\n}\n\n/** Draft id → published id for rows that already have a published counterpart (same document_id + locale). */\nconst draftToPublishedMap = async (trx: any, tableName: string, rowIds: unknown[]) => {\n const uniqueIds = [...new Set(rowIds)];\n if (uniqueIds.length === 0) {\n return new Map<string, string>();\n }\n\n const draftEntries = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('id', uniqueIds as any)\n .transacting(trx);\n\n if (draftEntries.length === 0) {\n return new Map<string, string>();\n }\n\n const pubEntries = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereNotNull('published_at')\n .whereIn(\n 'document_id',\n draftEntries.map((e: any) => e.document_id)\n )\n .transacting(trx);\n\n const pubByDocLocale = new Map(\n pubEntries.map((e: any) => [`${e.document_id}_${e.locale}`, e.id])\n );\n\n const map = new Map<string, string>();\n for (const d of draftEntries) {\n const pubId = pubByDocLocale.get(`${d.document_id}_${d.locale}`);\n if (pubId) {\n map.set(String(d.id), String(pubId));\n }\n }\n return map;\n};\n\nconst remapRelatedIds = (rows: any[], relatedCol: string, idMap: Map<string, string>) =>\n rows.map((row) => {\n const next = idMap.get(String(row[relatedCol]));\n return next ? { ...row, [relatedCol]: next } : row;\n });\n\n/**\n * Reads join rows tied to the entry being published (`publishedCol` IN draft/old ids) and returns\n * batches for `sync()`. When the FK in `relatedCol` points at a D&P type, maps known draft ids to\n * published ids; otherwise keeps draft ids so sync can still run after both sides exist.\n */\nconst captureJoinBatches = async (\n trx: any,\n opts: {\n joinTable: any;\n /** Column holding ids of the document being published (the `uid` passed to load). */\n publishedCol: string;\n /** The other FK; may be remapped via draftToPublishedMap. */\n relatedCol: string;\n /** Content type behind `relatedCol` (used for D&P + table name). */\n relatedUid: UID.ContentType;\n relatedHasDraftAndPublish: boolean;\n /** Model that owns this attribute; draft capture is skipped for components. */\n schemaUid: UID.ContentType;\n /**\n * True when the attribute being captured is the owning side of the relation and the entity\n * being published owns it (e.g. publishing an Article for `Article.categories`). In that case\n * the owning-side order is rebuilt from the draft by `entries.publish`, so capturing the old\n * published rows would only let `sync()` overwrite the freshly published order with a stale\n * one — silently reverting a reorder made in the draft. The inverse-side order still needs the\n * old-published capture to be restored, so this only suppresses the owning-side capture.\n */\n isOwningSide: boolean;\n oldVersions: LoadContext['oldVersions'];\n newVersions: LoadContext['newVersions'];\n }\n): Promise<RelationEntry[]> => {\n const {\n joinTable,\n publishedCol,\n relatedCol,\n relatedUid,\n relatedHasDraftAndPublish,\n schemaUid,\n isOwningSide,\n oldVersions,\n newVersions,\n } = opts;\n\n const batches: RelationEntry[] = [];\n const { name: table } = joinTable;\n\n // Skip the old-published capture for the owning side: those rows are recreated in draft order\n // by `entries.publish`, so restoring their order from the old published version is at best a\n // no-op and at worst reverts a draft reorder. The draftsOnly capture below is still needed\n // (e.g. when a related entry is published after this one) and is not affected by this guard.\n const oldIds = isOwningSide ? [] : oldVersions.map((e) => e.id);\n if (oldIds.length > 0) {\n const existing = await strapi.db\n .getConnection()\n .select('*')\n .from(table)\n .whereIn(publishedCol, oldIds)\n .transacting(trx);\n if (existing.length > 0) {\n batches.push({\n joinTable,\n relations: existing,\n entityColumn: publishedCol,\n relatedColumn: relatedCol,\n });\n }\n }\n\n if (!strapi.contentTypes[schemaUid]) {\n return batches;\n }\n\n const oldLocales = new Set(oldVersions.map((e) => e.locale));\n const draftsOnly = newVersions.filter((v) => !oldLocales.has(v.locale));\n if (draftsOnly.length === 0) {\n return batches;\n }\n\n const draftIds = draftsOnly.map((e) => e.id);\n const draftRows = await strapi.db\n .getConnection()\n .select('*')\n .from(table)\n .whereIn(publishedCol, draftIds)\n .transacting(trx);\n\n if (draftRows.length === 0) {\n return batches;\n }\n\n let relations = draftRows;\n if (relatedHasDraftAndPublish) {\n const meta = strapi.db.metadata.get(relatedUid);\n const relatedIds = draftRows.map((r: any) => r[relatedCol]);\n const map = await draftToPublishedMap(trx, meta.tableName, relatedIds);\n relations = remapRelatedIds(draftRows, relatedCol, map);\n }\n\n batches.push({ joinTable, relations, entityColumn: publishedCol, relatedColumn: relatedCol });\n return batches;\n};\n\n/**\n * Loads all bidirectional relations that need to be synchronized when content entries change state\n * (e.g., during publish/unpublish operations).\n *\n * In Strapi, bidirectional relations allow maintaining order from both sides of the relation.\n * When an entry is published, the following occurs:\n *\n * 1. The old published entry is deleted\n * 2. A new entry is created with all its relations\n *\n * This process affects relation ordering in the following way:\n *\n * Initial state (Entry A related to X, Y, Z):\n * ```\n * Entry A (draft) Entry A (published)\n * │ │\n * ├──(1)→ X ├──(1)→ X\n * ├──(2)→ Y ├──(2)→ Y\n * └──(3)→ Z └──(3)→ Z\n *\n * X's perspective: Y's perspective: Z's perspective:\n * └──(2)→ Entry A └──(1)→ Entry A └──(3)→ Entry A\n * ```\n *\n * After publishing Entry A (without relation order sync):\n * ```\n * Entry A (draft) Entry A (new published)\n * │ │\n * ├──(1)→ X ├──(1)→ X\n * ├──(2)→ Y ├──(2)→ Y\n * └──(3)→ Z └──(3)→ Z\n *\n * X's perspective: Y's perspective: Z's perspective:\n * └──(3)→ Entry A └──(3)→ Entry A └──(3)→ Entry A\n * (all relations appear last in order)\n * ```\n *\n * This module preserves the original ordering from both perspectives by:\n * 1. Capturing the relation order before the entry state changes\n * 2. Restoring this order after the new relations are created\n *\n * @param uid - The unique identifier of the content type being processed\n * @param context - Object containing arrays of old and new entry versions\n * @returns Array of objects containing join table metadata and relations to be updated\n */\nconst load = async (uid: UID.ContentType, { oldVersions, newVersions }: LoadContext) => {\n const relationsToUpdate: RelationEntry[] = [];\n\n await strapi.db.transaction(async ({ trx }) => {\n const models = [\n ...(Object.values(strapi.contentTypes) as Schema.ContentType[]),\n ...Object.values(strapi.components),\n ];\n\n for (const model of models) {\n const dbModel = strapi.db.metadata.get(model.uid);\n\n for (const attribute of Object.values(dbModel.attributes) as Record<string, any>[]) {\n const joinTable = attribute.joinTable;\n\n if (attribute.type !== 'relation' || !joinTable) {\n continue;\n }\n\n if (!(attribute.inversedBy || attribute.mappedBy)) {\n continue;\n }\n\n // Owning side: e.g. Author.articles when publishing an Author.\n const isOwningSide =\n !!attribute.inversedBy &&\n model.uid === uid &&\n attribute.relation === 'manyToMany' &&\n model.uid !== attribute.target;\n\n // Inverse side: e.g. Article.authors when publishing an Article.\n const isInverseSide = attribute.target === uid && model.uid !== uid;\n\n if (!isOwningSide && !isInverseSide) {\n continue;\n }\n\n // Direction determines which join column belongs to the entity being published\n const publishedCol = isOwningSide\n ? joinTable.joinColumn.name\n : joinTable.inverseJoinColumn.name;\n const relatedCol = isOwningSide\n ? joinTable.inverseJoinColumn.name\n : joinTable.joinColumn.name;\n\n const relatedUid = (isOwningSide ? attribute.target : model.uid) as UID.ContentType;\n\n const batches = await captureJoinBatches(trx, {\n joinTable,\n publishedCol,\n relatedCol,\n relatedUid,\n relatedHasDraftAndPublish: isOwningSide\n ? !!strapi.contentTypes[relatedUid]?.options?.draftAndPublish\n : !!model.options?.draftAndPublish,\n schemaUid: model.uid as UID.ContentType,\n isOwningSide,\n oldVersions,\n newVersions,\n });\n relationsToUpdate.push(...batches);\n }\n }\n });\n\n return relationsToUpdate;\n};\n\n/**\n * Synchronizes the order of bidirectional relations after content entries have changed state.\n *\n * When entries change state (e.g., draft → published), their IDs change and all relations are recreated.\n * While the order of relations from the entry's perspective is maintained (as they're created in order),\n * the inverse relations (from related entries' perspective) would all appear last in order since they're new.\n *\n * Example:\n * ```\n * Before publish:\n * Article(id:1) →(order:1)→ Category(id:5)\n * Category(id:5) →(order:3)→ Article(id:1)\n *\n * After publish (without sync):\n * Article(id:2) →(order:1)→ Category(id:5) [order preserved]\n * Category(id:5) →(order:99)→ Article(id:2) [order lost - appears last]\n *\n * After sync:\n * Article(id:2) →(order:1)→ Category(id:5) [order preserved]\n * Category(id:5) →(order:3)→ Article(id:2) [order restored]\n * ```\n *\n * @param oldEntries - Array of previous entry versions with their IDs and locales\n * @param newEntries - Array of new entry versions with their IDs and locales\n * @param existingRelations - Array of join table data containing the relations to be updated\n */\nconst sync = async (\n oldEntries: { id: string; locale: string }[],\n newEntries: { id: string; locale: string }[],\n existingRelations: RelationEntry[]\n) => {\n const newEntriesByLocale = keyBy(newEntries, 'locale');\n\n const entryIdMapping = oldEntries.reduce(\n (acc, oldEntry) => {\n const newEntry = newEntriesByLocale[oldEntry.locale];\n if (!newEntry) {\n return acc;\n }\n acc[oldEntry.id] = newEntry.id;\n return acc;\n },\n {} as Record<string, string>\n );\n\n const republishedEntryIds = new Set(newEntries.map((e) => String(e.id)));\n const isRepublishedEntry = (id: string | number) => republishedEntryIds.has(String(id));\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const {\n joinTable,\n relations,\n entityColumn: sourceColumn,\n relatedColumn: targetColumn,\n } of existingRelations) {\n const orderColumn = joinTable.orderColumnName;\n\n // Failsafe in case those don't exist\n if (!sourceColumn || !targetColumn || !orderColumn) {\n continue;\n }\n\n const mappedRelations = relations\n .map((relation) => ({\n relation,\n oldSourceId: relation[sourceColumn] as string,\n targetId: relation[targetColumn] as string,\n originalOrder: relation[orderColumn],\n newSourceId: entryIdMapping[relation[sourceColumn] as string],\n }))\n .filter((r): r is typeof r & { newSourceId: string } => Boolean(r.newSourceId));\n\n if (!mappedRelations.length) continue;\n\n const newSourceIds = mappedRelations.map((r) => r.newSourceId);\n\n // Batch UPDATE: set each row's order in a single statement using CASE\n const caseFragments = mappedRelations.map(() => `WHEN ?? = ? AND ?? = ? THEN ?`);\n const caseBindings = mappedRelations.flatMap(({ newSourceId, targetId, originalOrder }) => [\n sourceColumn,\n newSourceId,\n targetColumn,\n targetId,\n originalOrder,\n ]);\n\n await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .update({\n [orderColumn]: trx.raw(`CASE ${caseFragments.join(' ')} ELSE ?? END`, [\n ...caseBindings,\n orderColumn,\n ]),\n });\n\n // Batch SELECT: find which rows exist so we know what to insert\n const existingRows = await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .select(sourceColumn, targetColumn);\n\n const existingSet = new Set(\n existingRows.map((r: Record<string, unknown>) => `${r[sourceColumn]}:${r[targetColumn]}`)\n );\n\n // Batch INSERT: insert cascade-deleted rows that aren't from republished sources\n const toInsert = mappedRelations\n .filter(\n ({ newSourceId, targetId }) =>\n !existingSet.has(`${newSourceId}:${targetId}`) && !isRepublishedEntry(newSourceId)\n )\n .map(({ relation, newSourceId, originalOrder }) => ({\n ...omit(relation, strapi.db.metadata.identifiers.ID_COLUMN),\n [sourceColumn]: newSourceId,\n [orderColumn]: originalOrder,\n }));\n\n if (toInsert.length) {\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n await trx.batchInsert(joinTable.name, toInsert, batchSize);\n }\n }\n });\n};\n\nexport { load, sync };\n"],"names":["draftToPublishedMap","trx","tableName","rowIds","uniqueIds","Set","length","Map","draftEntries","strapi","db","getConnection","select","from","whereIn","transacting","pubEntries","whereNotNull","map","e","document_id","pubByDocLocale","locale","id","d","pubId","get","set","String","remapRelatedIds","rows","relatedCol","idMap","row","next","captureJoinBatches","opts","joinTable","publishedCol","relatedUid","relatedHasDraftAndPublish","schemaUid","isOwningSide","oldVersions","newVersions","batches","name","table","oldIds","existing","push","relations","entityColumn","relatedColumn","contentTypes","oldLocales","draftsOnly","filter","v","has","draftIds","draftRows","meta","metadata","relatedIds","r","load","uid","relationsToUpdate","transaction","models","Object","values","components","model","dbModel","attribute","attributes","type","inversedBy","mappedBy","relation","target","isInverseSide","joinColumn","inverseJoinColumn","options","draftAndPublish","sync","oldEntries","newEntries","existingRelations","newEntriesByLocale","keyBy","entryIdMapping","reduce","acc","oldEntry","newEntry","republishedEntryIds","isRepublishedEntry","sourceColumn","targetColumn","orderColumn","orderColumnName","mappedRelations","oldSourceId","targetId","originalOrder","newSourceId","Boolean","newSourceIds","caseFragments","caseBindings","flatMap","update","raw","join","existingRows","existingSet","toInsert","omit","identifiers","ID_COLUMN","batchSize","dialect","getBatchInsertSize","batchInsert"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { keyBy, omit } from 'lodash
|
|
1
|
+
import { keyBy, omit } from 'lodash';
|
|
2
2
|
|
|
3
3
|
/** Draft id → published id for rows that already have a published counterpart (same document_id + locale). */ const draftToPublishedMap = async (trx, tableName, rowIds)=>{
|
|
4
4
|
const uniqueIds = [
|
|
@@ -199,7 +199,7 @@ const remapRelatedIds = (rows, relatedCol, idMap)=>rows.map((row)=>{
|
|
|
199
199
|
* @param newEntries - Array of new entry versions with their IDs and locales
|
|
200
200
|
* @param existingRelations - Array of join table data containing the relations to be updated
|
|
201
201
|
*/ const sync = async (oldEntries, newEntries, existingRelations)=>{
|
|
202
|
-
const newEntriesByLocale = keyBy('locale'
|
|
202
|
+
const newEntriesByLocale = keyBy(newEntries, 'locale');
|
|
203
203
|
const entryIdMapping = oldEntries.reduce((acc, oldEntry)=>{
|
|
204
204
|
const newEntry = newEntriesByLocale[oldEntry.locale];
|
|
205
205
|
if (!newEntry) {
|
|
@@ -246,7 +246,7 @@ const remapRelatedIds = (rows, relatedCol, idMap)=>rows.map((row)=>{
|
|
|
246
246
|
const existingSet = new Set(existingRows.map((r)=>`${r[sourceColumn]}:${r[targetColumn]}`));
|
|
247
247
|
// Batch INSERT: insert cascade-deleted rows that aren't from republished sources
|
|
248
248
|
const toInsert = mappedRelations.filter(({ newSourceId, targetId })=>!existingSet.has(`${newSourceId}:${targetId}`) && !isRepublishedEntry(newSourceId)).map(({ relation, newSourceId, originalOrder })=>({
|
|
249
|
-
...omit(strapi.db.metadata.identifiers.ID_COLUMN
|
|
249
|
+
...omit(relation, strapi.db.metadata.identifiers.ID_COLUMN),
|
|
250
250
|
[sourceColumn]: newSourceId,
|
|
251
251
|
[orderColumn]: originalOrder
|
|
252
252
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bidirectional-relations.mjs","sources":["../../../../src/services/document-service/utils/bidirectional-relations.ts"],"sourcesContent":["import { keyBy, omit } from 'lodash/fp';\nimport type { UID, Schema } from '@strapi/types';\nimport type { JoinTable } from '@strapi/database';\n\ninterface LoadContext {\n oldVersions: { id: string; locale: string }[];\n newVersions: { id: string; locale: string }[];\n}\n\ninterface RelationEntry {\n joinTable: JoinTable;\n relations: Record<string, unknown>[];\n /** FK column for the entity being published */\n entityColumn: string;\n /** FK column for the related entity */\n relatedColumn: string;\n}\n\n/** Draft id → published id for rows that already have a published counterpart (same document_id + locale). */\nconst draftToPublishedMap = async (trx: any, tableName: string, rowIds: unknown[]) => {\n const uniqueIds = [...new Set(rowIds)];\n if (uniqueIds.length === 0) {\n return new Map<string, string>();\n }\n\n const draftEntries = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('id', uniqueIds as any)\n .transacting(trx);\n\n if (draftEntries.length === 0) {\n return new Map<string, string>();\n }\n\n const pubEntries = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereNotNull('published_at')\n .whereIn(\n 'document_id',\n draftEntries.map((e: any) => e.document_id)\n )\n .transacting(trx);\n\n const pubByDocLocale = new Map(\n pubEntries.map((e: any) => [`${e.document_id}_${e.locale}`, e.id])\n );\n\n const map = new Map<string, string>();\n for (const d of draftEntries) {\n const pubId = pubByDocLocale.get(`${d.document_id}_${d.locale}`);\n if (pubId) {\n map.set(String(d.id), String(pubId));\n }\n }\n return map;\n};\n\nconst remapRelatedIds = (rows: any[], relatedCol: string, idMap: Map<string, string>) =>\n rows.map((row) => {\n const next = idMap.get(String(row[relatedCol]));\n return next ? { ...row, [relatedCol]: next } : row;\n });\n\n/**\n * Reads join rows tied to the entry being published (`publishedCol` IN draft/old ids) and returns\n * batches for `sync()`. When the FK in `relatedCol` points at a D&P type, maps known draft ids to\n * published ids; otherwise keeps draft ids so sync can still run after both sides exist.\n */\nconst captureJoinBatches = async (\n trx: any,\n opts: {\n joinTable: any;\n /** Column holding ids of the document being published (the `uid` passed to load). */\n publishedCol: string;\n /** The other FK; may be remapped via draftToPublishedMap. */\n relatedCol: string;\n /** Content type behind `relatedCol` (used for D&P + table name). */\n relatedUid: UID.ContentType;\n relatedHasDraftAndPublish: boolean;\n /** Model that owns this attribute; draft capture is skipped for components. */\n schemaUid: UID.ContentType;\n /**\n * True when the attribute being captured is the owning side of the relation and the entity\n * being published owns it (e.g. publishing an Article for `Article.categories`). In that case\n * the owning-side order is rebuilt from the draft by `entries.publish`, so capturing the old\n * published rows would only let `sync()` overwrite the freshly published order with a stale\n * one — silently reverting a reorder made in the draft. The inverse-side order still needs the\n * old-published capture to be restored, so this only suppresses the owning-side capture.\n */\n isOwningSide: boolean;\n oldVersions: LoadContext['oldVersions'];\n newVersions: LoadContext['newVersions'];\n }\n): Promise<RelationEntry[]> => {\n const {\n joinTable,\n publishedCol,\n relatedCol,\n relatedUid,\n relatedHasDraftAndPublish,\n schemaUid,\n isOwningSide,\n oldVersions,\n newVersions,\n } = opts;\n\n const batches: RelationEntry[] = [];\n const { name: table } = joinTable;\n\n // Skip the old-published capture for the owning side: those rows are recreated in draft order\n // by `entries.publish`, so restoring their order from the old published version is at best a\n // no-op and at worst reverts a draft reorder. The draftsOnly capture below is still needed\n // (e.g. when a related entry is published after this one) and is not affected by this guard.\n const oldIds = isOwningSide ? [] : oldVersions.map((e) => e.id);\n if (oldIds.length > 0) {\n const existing = await strapi.db\n .getConnection()\n .select('*')\n .from(table)\n .whereIn(publishedCol, oldIds)\n .transacting(trx);\n if (existing.length > 0) {\n batches.push({\n joinTable,\n relations: existing,\n entityColumn: publishedCol,\n relatedColumn: relatedCol,\n });\n }\n }\n\n if (!strapi.contentTypes[schemaUid]) {\n return batches;\n }\n\n const oldLocales = new Set(oldVersions.map((e) => e.locale));\n const draftsOnly = newVersions.filter((v) => !oldLocales.has(v.locale));\n if (draftsOnly.length === 0) {\n return batches;\n }\n\n const draftIds = draftsOnly.map((e) => e.id);\n const draftRows = await strapi.db\n .getConnection()\n .select('*')\n .from(table)\n .whereIn(publishedCol, draftIds)\n .transacting(trx);\n\n if (draftRows.length === 0) {\n return batches;\n }\n\n let relations = draftRows;\n if (relatedHasDraftAndPublish) {\n const meta = strapi.db.metadata.get(relatedUid);\n const relatedIds = draftRows.map((r: any) => r[relatedCol]);\n const map = await draftToPublishedMap(trx, meta.tableName, relatedIds);\n relations = remapRelatedIds(draftRows, relatedCol, map);\n }\n\n batches.push({ joinTable, relations, entityColumn: publishedCol, relatedColumn: relatedCol });\n return batches;\n};\n\n/**\n * Loads all bidirectional relations that need to be synchronized when content entries change state\n * (e.g., during publish/unpublish operations).\n *\n * In Strapi, bidirectional relations allow maintaining order from both sides of the relation.\n * When an entry is published, the following occurs:\n *\n * 1. The old published entry is deleted\n * 2. A new entry is created with all its relations\n *\n * This process affects relation ordering in the following way:\n *\n * Initial state (Entry A related to X, Y, Z):\n * ```\n * Entry A (draft) Entry A (published)\n * │ │\n * ├──(1)→ X ├──(1)→ X\n * ├──(2)→ Y ├──(2)→ Y\n * └──(3)→ Z └──(3)→ Z\n *\n * X's perspective: Y's perspective: Z's perspective:\n * └──(2)→ Entry A └──(1)→ Entry A └──(3)→ Entry A\n * ```\n *\n * After publishing Entry A (without relation order sync):\n * ```\n * Entry A (draft) Entry A (new published)\n * │ │\n * ├──(1)→ X ├──(1)→ X\n * ├──(2)→ Y ├──(2)→ Y\n * └──(3)→ Z └──(3)→ Z\n *\n * X's perspective: Y's perspective: Z's perspective:\n * └──(3)→ Entry A └──(3)→ Entry A └──(3)→ Entry A\n * (all relations appear last in order)\n * ```\n *\n * This module preserves the original ordering from both perspectives by:\n * 1. Capturing the relation order before the entry state changes\n * 2. Restoring this order after the new relations are created\n *\n * @param uid - The unique identifier of the content type being processed\n * @param context - Object containing arrays of old and new entry versions\n * @returns Array of objects containing join table metadata and relations to be updated\n */\nconst load = async (uid: UID.ContentType, { oldVersions, newVersions }: LoadContext) => {\n const relationsToUpdate: RelationEntry[] = [];\n\n await strapi.db.transaction(async ({ trx }) => {\n const models = [\n ...(Object.values(strapi.contentTypes) as Schema.ContentType[]),\n ...Object.values(strapi.components),\n ];\n\n for (const model of models) {\n const dbModel = strapi.db.metadata.get(model.uid);\n\n for (const attribute of Object.values(dbModel.attributes) as Record<string, any>[]) {\n const joinTable = attribute.joinTable;\n\n if (attribute.type !== 'relation' || !joinTable) {\n continue;\n }\n\n if (!(attribute.inversedBy || attribute.mappedBy)) {\n continue;\n }\n\n // Owning side: e.g. Author.articles when publishing an Author.\n const isOwningSide =\n !!attribute.inversedBy &&\n model.uid === uid &&\n attribute.relation === 'manyToMany' &&\n model.uid !== attribute.target;\n\n // Inverse side: e.g. Article.authors when publishing an Article.\n const isInverseSide = attribute.target === uid && model.uid !== uid;\n\n if (!isOwningSide && !isInverseSide) {\n continue;\n }\n\n // Direction determines which join column belongs to the entity being published\n const publishedCol = isOwningSide\n ? joinTable.joinColumn.name\n : joinTable.inverseJoinColumn.name;\n const relatedCol = isOwningSide\n ? joinTable.inverseJoinColumn.name\n : joinTable.joinColumn.name;\n\n const relatedUid = (isOwningSide ? attribute.target : model.uid) as UID.ContentType;\n\n const batches = await captureJoinBatches(trx, {\n joinTable,\n publishedCol,\n relatedCol,\n relatedUid,\n relatedHasDraftAndPublish: isOwningSide\n ? !!strapi.contentTypes[relatedUid]?.options?.draftAndPublish\n : !!model.options?.draftAndPublish,\n schemaUid: model.uid as UID.ContentType,\n isOwningSide,\n oldVersions,\n newVersions,\n });\n relationsToUpdate.push(...batches);\n }\n }\n });\n\n return relationsToUpdate;\n};\n\n/**\n * Synchronizes the order of bidirectional relations after content entries have changed state.\n *\n * When entries change state (e.g., draft → published), their IDs change and all relations are recreated.\n * While the order of relations from the entry's perspective is maintained (as they're created in order),\n * the inverse relations (from related entries' perspective) would all appear last in order since they're new.\n *\n * Example:\n * ```\n * Before publish:\n * Article(id:1) →(order:1)→ Category(id:5)\n * Category(id:5) →(order:3)→ Article(id:1)\n *\n * After publish (without sync):\n * Article(id:2) →(order:1)→ Category(id:5) [order preserved]\n * Category(id:5) →(order:99)→ Article(id:2) [order lost - appears last]\n *\n * After sync:\n * Article(id:2) →(order:1)→ Category(id:5) [order preserved]\n * Category(id:5) →(order:3)→ Article(id:2) [order restored]\n * ```\n *\n * @param oldEntries - Array of previous entry versions with their IDs and locales\n * @param newEntries - Array of new entry versions with their IDs and locales\n * @param existingRelations - Array of join table data containing the relations to be updated\n */\nconst sync = async (\n oldEntries: { id: string; locale: string }[],\n newEntries: { id: string; locale: string }[],\n existingRelations: RelationEntry[]\n) => {\n const newEntriesByLocale = keyBy('locale', newEntries);\n\n const entryIdMapping = oldEntries.reduce(\n (acc, oldEntry) => {\n const newEntry = newEntriesByLocale[oldEntry.locale];\n if (!newEntry) {\n return acc;\n }\n acc[oldEntry.id] = newEntry.id;\n return acc;\n },\n {} as Record<string, string>\n );\n\n const republishedEntryIds = new Set(newEntries.map((e) => String(e.id)));\n const isRepublishedEntry = (id: string | number) => republishedEntryIds.has(String(id));\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const {\n joinTable,\n relations,\n entityColumn: sourceColumn,\n relatedColumn: targetColumn,\n } of existingRelations) {\n const orderColumn = joinTable.orderColumnName;\n\n // Failsafe in case those don't exist\n if (!sourceColumn || !targetColumn || !orderColumn) {\n continue;\n }\n\n const mappedRelations = relations\n .map((relation) => ({\n relation,\n oldSourceId: relation[sourceColumn] as string,\n targetId: relation[targetColumn] as string,\n originalOrder: relation[orderColumn],\n newSourceId: entryIdMapping[relation[sourceColumn] as string],\n }))\n .filter((r): r is typeof r & { newSourceId: string } => Boolean(r.newSourceId));\n\n if (!mappedRelations.length) continue;\n\n const newSourceIds = mappedRelations.map((r) => r.newSourceId);\n\n // Batch UPDATE: set each row's order in a single statement using CASE\n const caseFragments = mappedRelations.map(() => `WHEN ?? = ? AND ?? = ? THEN ?`);\n const caseBindings = mappedRelations.flatMap(({ newSourceId, targetId, originalOrder }) => [\n sourceColumn,\n newSourceId,\n targetColumn,\n targetId,\n originalOrder,\n ]);\n\n await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .update({\n [orderColumn]: trx.raw(`CASE ${caseFragments.join(' ')} ELSE ?? END`, [\n ...caseBindings,\n orderColumn,\n ]),\n });\n\n // Batch SELECT: find which rows exist so we know what to insert\n const existingRows = await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .select(sourceColumn, targetColumn);\n\n const existingSet = new Set(\n existingRows.map((r: Record<string, unknown>) => `${r[sourceColumn]}:${r[targetColumn]}`)\n );\n\n // Batch INSERT: insert cascade-deleted rows that aren't from republished sources\n const toInsert = mappedRelations\n .filter(\n ({ newSourceId, targetId }) =>\n !existingSet.has(`${newSourceId}:${targetId}`) && !isRepublishedEntry(newSourceId)\n )\n .map(({ relation, newSourceId, originalOrder }) => ({\n ...omit(strapi.db.metadata.identifiers.ID_COLUMN, relation),\n [sourceColumn]: newSourceId,\n [orderColumn]: originalOrder,\n }));\n\n if (toInsert.length) {\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n await trx.batchInsert(joinTable.name, toInsert, batchSize);\n }\n }\n });\n};\n\nexport { load, sync };\n"],"names":["draftToPublishedMap","trx","tableName","rowIds","uniqueIds","Set","length","Map","draftEntries","strapi","db","getConnection","select","from","whereIn","transacting","pubEntries","whereNotNull","map","e","document_id","pubByDocLocale","locale","id","d","pubId","get","set","String","remapRelatedIds","rows","relatedCol","idMap","row","next","captureJoinBatches","opts","joinTable","publishedCol","relatedUid","relatedHasDraftAndPublish","schemaUid","isOwningSide","oldVersions","newVersions","batches","name","table","oldIds","existing","push","relations","entityColumn","relatedColumn","contentTypes","oldLocales","draftsOnly","filter","v","has","draftIds","draftRows","meta","metadata","relatedIds","r","load","uid","relationsToUpdate","transaction","models","Object","values","components","model","dbModel","attribute","attributes","type","inversedBy","mappedBy","relation","target","isInverseSide","joinColumn","inverseJoinColumn","options","draftAndPublish","sync","oldEntries","newEntries","existingRelations","newEntriesByLocale","keyBy","entryIdMapping","reduce","acc","oldEntry","newEntry","republishedEntryIds","isRepublishedEntry","sourceColumn","targetColumn","orderColumn","orderColumnName","mappedRelations","oldSourceId","targetId","originalOrder","newSourceId","Boolean","newSourceIds","caseFragments","caseBindings","flatMap","update","raw","join","existingRows","existingSet","toInsert","omit","identifiers","ID_COLUMN","batchSize","dialect","getBatchInsertSize","batchInsert"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bidirectional-relations.mjs","sources":["../../../../src/services/document-service/utils/bidirectional-relations.ts"],"sourcesContent":["import { keyBy, omit } from 'lodash';\nimport type { UID, Schema } from '@strapi/types';\nimport type { JoinTable } from '@strapi/database';\n\ninterface LoadContext {\n oldVersions: { id: string; locale: string }[];\n newVersions: { id: string; locale: string }[];\n}\n\ninterface RelationEntry {\n joinTable: JoinTable;\n relations: Record<string, unknown>[];\n /** FK column for the entity being published */\n entityColumn: string;\n /** FK column for the related entity */\n relatedColumn: string;\n}\n\n/** Draft id → published id for rows that already have a published counterpart (same document_id + locale). */\nconst draftToPublishedMap = async (trx: any, tableName: string, rowIds: unknown[]) => {\n const uniqueIds = [...new Set(rowIds)];\n if (uniqueIds.length === 0) {\n return new Map<string, string>();\n }\n\n const draftEntries = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('id', uniqueIds as any)\n .transacting(trx);\n\n if (draftEntries.length === 0) {\n return new Map<string, string>();\n }\n\n const pubEntries = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereNotNull('published_at')\n .whereIn(\n 'document_id',\n draftEntries.map((e: any) => e.document_id)\n )\n .transacting(trx);\n\n const pubByDocLocale = new Map(\n pubEntries.map((e: any) => [`${e.document_id}_${e.locale}`, e.id])\n );\n\n const map = new Map<string, string>();\n for (const d of draftEntries) {\n const pubId = pubByDocLocale.get(`${d.document_id}_${d.locale}`);\n if (pubId) {\n map.set(String(d.id), String(pubId));\n }\n }\n return map;\n};\n\nconst remapRelatedIds = (rows: any[], relatedCol: string, idMap: Map<string, string>) =>\n rows.map((row) => {\n const next = idMap.get(String(row[relatedCol]));\n return next ? { ...row, [relatedCol]: next } : row;\n });\n\n/**\n * Reads join rows tied to the entry being published (`publishedCol` IN draft/old ids) and returns\n * batches for `sync()`. When the FK in `relatedCol` points at a D&P type, maps known draft ids to\n * published ids; otherwise keeps draft ids so sync can still run after both sides exist.\n */\nconst captureJoinBatches = async (\n trx: any,\n opts: {\n joinTable: any;\n /** Column holding ids of the document being published (the `uid` passed to load). */\n publishedCol: string;\n /** The other FK; may be remapped via draftToPublishedMap. */\n relatedCol: string;\n /** Content type behind `relatedCol` (used for D&P + table name). */\n relatedUid: UID.ContentType;\n relatedHasDraftAndPublish: boolean;\n /** Model that owns this attribute; draft capture is skipped for components. */\n schemaUid: UID.ContentType;\n /**\n * True when the attribute being captured is the owning side of the relation and the entity\n * being published owns it (e.g. publishing an Article for `Article.categories`). In that case\n * the owning-side order is rebuilt from the draft by `entries.publish`, so capturing the old\n * published rows would only let `sync()` overwrite the freshly published order with a stale\n * one — silently reverting a reorder made in the draft. The inverse-side order still needs the\n * old-published capture to be restored, so this only suppresses the owning-side capture.\n */\n isOwningSide: boolean;\n oldVersions: LoadContext['oldVersions'];\n newVersions: LoadContext['newVersions'];\n }\n): Promise<RelationEntry[]> => {\n const {\n joinTable,\n publishedCol,\n relatedCol,\n relatedUid,\n relatedHasDraftAndPublish,\n schemaUid,\n isOwningSide,\n oldVersions,\n newVersions,\n } = opts;\n\n const batches: RelationEntry[] = [];\n const { name: table } = joinTable;\n\n // Skip the old-published capture for the owning side: those rows are recreated in draft order\n // by `entries.publish`, so restoring their order from the old published version is at best a\n // no-op and at worst reverts a draft reorder. The draftsOnly capture below is still needed\n // (e.g. when a related entry is published after this one) and is not affected by this guard.\n const oldIds = isOwningSide ? [] : oldVersions.map((e) => e.id);\n if (oldIds.length > 0) {\n const existing = await strapi.db\n .getConnection()\n .select('*')\n .from(table)\n .whereIn(publishedCol, oldIds)\n .transacting(trx);\n if (existing.length > 0) {\n batches.push({\n joinTable,\n relations: existing,\n entityColumn: publishedCol,\n relatedColumn: relatedCol,\n });\n }\n }\n\n if (!strapi.contentTypes[schemaUid]) {\n return batches;\n }\n\n const oldLocales = new Set(oldVersions.map((e) => e.locale));\n const draftsOnly = newVersions.filter((v) => !oldLocales.has(v.locale));\n if (draftsOnly.length === 0) {\n return batches;\n }\n\n const draftIds = draftsOnly.map((e) => e.id);\n const draftRows = await strapi.db\n .getConnection()\n .select('*')\n .from(table)\n .whereIn(publishedCol, draftIds)\n .transacting(trx);\n\n if (draftRows.length === 0) {\n return batches;\n }\n\n let relations = draftRows;\n if (relatedHasDraftAndPublish) {\n const meta = strapi.db.metadata.get(relatedUid);\n const relatedIds = draftRows.map((r: any) => r[relatedCol]);\n const map = await draftToPublishedMap(trx, meta.tableName, relatedIds);\n relations = remapRelatedIds(draftRows, relatedCol, map);\n }\n\n batches.push({ joinTable, relations, entityColumn: publishedCol, relatedColumn: relatedCol });\n return batches;\n};\n\n/**\n * Loads all bidirectional relations that need to be synchronized when content entries change state\n * (e.g., during publish/unpublish operations).\n *\n * In Strapi, bidirectional relations allow maintaining order from both sides of the relation.\n * When an entry is published, the following occurs:\n *\n * 1. The old published entry is deleted\n * 2. A new entry is created with all its relations\n *\n * This process affects relation ordering in the following way:\n *\n * Initial state (Entry A related to X, Y, Z):\n * ```\n * Entry A (draft) Entry A (published)\n * │ │\n * ├──(1)→ X ├──(1)→ X\n * ├──(2)→ Y ├──(2)→ Y\n * └──(3)→ Z └──(3)→ Z\n *\n * X's perspective: Y's perspective: Z's perspective:\n * └──(2)→ Entry A └──(1)→ Entry A └──(3)→ Entry A\n * ```\n *\n * After publishing Entry A (without relation order sync):\n * ```\n * Entry A (draft) Entry A (new published)\n * │ │\n * ├──(1)→ X ├──(1)→ X\n * ├──(2)→ Y ├──(2)→ Y\n * └──(3)→ Z └──(3)→ Z\n *\n * X's perspective: Y's perspective: Z's perspective:\n * └──(3)→ Entry A └──(3)→ Entry A └──(3)→ Entry A\n * (all relations appear last in order)\n * ```\n *\n * This module preserves the original ordering from both perspectives by:\n * 1. Capturing the relation order before the entry state changes\n * 2. Restoring this order after the new relations are created\n *\n * @param uid - The unique identifier of the content type being processed\n * @param context - Object containing arrays of old and new entry versions\n * @returns Array of objects containing join table metadata and relations to be updated\n */\nconst load = async (uid: UID.ContentType, { oldVersions, newVersions }: LoadContext) => {\n const relationsToUpdate: RelationEntry[] = [];\n\n await strapi.db.transaction(async ({ trx }) => {\n const models = [\n ...(Object.values(strapi.contentTypes) as Schema.ContentType[]),\n ...Object.values(strapi.components),\n ];\n\n for (const model of models) {\n const dbModel = strapi.db.metadata.get(model.uid);\n\n for (const attribute of Object.values(dbModel.attributes) as Record<string, any>[]) {\n const joinTable = attribute.joinTable;\n\n if (attribute.type !== 'relation' || !joinTable) {\n continue;\n }\n\n if (!(attribute.inversedBy || attribute.mappedBy)) {\n continue;\n }\n\n // Owning side: e.g. Author.articles when publishing an Author.\n const isOwningSide =\n !!attribute.inversedBy &&\n model.uid === uid &&\n attribute.relation === 'manyToMany' &&\n model.uid !== attribute.target;\n\n // Inverse side: e.g. Article.authors when publishing an Article.\n const isInverseSide = attribute.target === uid && model.uid !== uid;\n\n if (!isOwningSide && !isInverseSide) {\n continue;\n }\n\n // Direction determines which join column belongs to the entity being published\n const publishedCol = isOwningSide\n ? joinTable.joinColumn.name\n : joinTable.inverseJoinColumn.name;\n const relatedCol = isOwningSide\n ? joinTable.inverseJoinColumn.name\n : joinTable.joinColumn.name;\n\n const relatedUid = (isOwningSide ? attribute.target : model.uid) as UID.ContentType;\n\n const batches = await captureJoinBatches(trx, {\n joinTable,\n publishedCol,\n relatedCol,\n relatedUid,\n relatedHasDraftAndPublish: isOwningSide\n ? !!strapi.contentTypes[relatedUid]?.options?.draftAndPublish\n : !!model.options?.draftAndPublish,\n schemaUid: model.uid as UID.ContentType,\n isOwningSide,\n oldVersions,\n newVersions,\n });\n relationsToUpdate.push(...batches);\n }\n }\n });\n\n return relationsToUpdate;\n};\n\n/**\n * Synchronizes the order of bidirectional relations after content entries have changed state.\n *\n * When entries change state (e.g., draft → published), their IDs change and all relations are recreated.\n * While the order of relations from the entry's perspective is maintained (as they're created in order),\n * the inverse relations (from related entries' perspective) would all appear last in order since they're new.\n *\n * Example:\n * ```\n * Before publish:\n * Article(id:1) →(order:1)→ Category(id:5)\n * Category(id:5) →(order:3)→ Article(id:1)\n *\n * After publish (without sync):\n * Article(id:2) →(order:1)→ Category(id:5) [order preserved]\n * Category(id:5) →(order:99)→ Article(id:2) [order lost - appears last]\n *\n * After sync:\n * Article(id:2) →(order:1)→ Category(id:5) [order preserved]\n * Category(id:5) →(order:3)→ Article(id:2) [order restored]\n * ```\n *\n * @param oldEntries - Array of previous entry versions with their IDs and locales\n * @param newEntries - Array of new entry versions with their IDs and locales\n * @param existingRelations - Array of join table data containing the relations to be updated\n */\nconst sync = async (\n oldEntries: { id: string; locale: string }[],\n newEntries: { id: string; locale: string }[],\n existingRelations: RelationEntry[]\n) => {\n const newEntriesByLocale = keyBy(newEntries, 'locale');\n\n const entryIdMapping = oldEntries.reduce(\n (acc, oldEntry) => {\n const newEntry = newEntriesByLocale[oldEntry.locale];\n if (!newEntry) {\n return acc;\n }\n acc[oldEntry.id] = newEntry.id;\n return acc;\n },\n {} as Record<string, string>\n );\n\n const republishedEntryIds = new Set(newEntries.map((e) => String(e.id)));\n const isRepublishedEntry = (id: string | number) => republishedEntryIds.has(String(id));\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const {\n joinTable,\n relations,\n entityColumn: sourceColumn,\n relatedColumn: targetColumn,\n } of existingRelations) {\n const orderColumn = joinTable.orderColumnName;\n\n // Failsafe in case those don't exist\n if (!sourceColumn || !targetColumn || !orderColumn) {\n continue;\n }\n\n const mappedRelations = relations\n .map((relation) => ({\n relation,\n oldSourceId: relation[sourceColumn] as string,\n targetId: relation[targetColumn] as string,\n originalOrder: relation[orderColumn],\n newSourceId: entryIdMapping[relation[sourceColumn] as string],\n }))\n .filter((r): r is typeof r & { newSourceId: string } => Boolean(r.newSourceId));\n\n if (!mappedRelations.length) continue;\n\n const newSourceIds = mappedRelations.map((r) => r.newSourceId);\n\n // Batch UPDATE: set each row's order in a single statement using CASE\n const caseFragments = mappedRelations.map(() => `WHEN ?? = ? AND ?? = ? THEN ?`);\n const caseBindings = mappedRelations.flatMap(({ newSourceId, targetId, originalOrder }) => [\n sourceColumn,\n newSourceId,\n targetColumn,\n targetId,\n originalOrder,\n ]);\n\n await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .update({\n [orderColumn]: trx.raw(`CASE ${caseFragments.join(' ')} ELSE ?? END`, [\n ...caseBindings,\n orderColumn,\n ]),\n });\n\n // Batch SELECT: find which rows exist so we know what to insert\n const existingRows = await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .select(sourceColumn, targetColumn);\n\n const existingSet = new Set(\n existingRows.map((r: Record<string, unknown>) => `${r[sourceColumn]}:${r[targetColumn]}`)\n );\n\n // Batch INSERT: insert cascade-deleted rows that aren't from republished sources\n const toInsert = mappedRelations\n .filter(\n ({ newSourceId, targetId }) =>\n !existingSet.has(`${newSourceId}:${targetId}`) && !isRepublishedEntry(newSourceId)\n )\n .map(({ relation, newSourceId, originalOrder }) => ({\n ...omit(relation, strapi.db.metadata.identifiers.ID_COLUMN),\n [sourceColumn]: newSourceId,\n [orderColumn]: originalOrder,\n }));\n\n if (toInsert.length) {\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n await trx.batchInsert(joinTable.name, toInsert, batchSize);\n }\n }\n });\n};\n\nexport { load, sync };\n"],"names":["draftToPublishedMap","trx","tableName","rowIds","uniqueIds","Set","length","Map","draftEntries","strapi","db","getConnection","select","from","whereIn","transacting","pubEntries","whereNotNull","map","e","document_id","pubByDocLocale","locale","id","d","pubId","get","set","String","remapRelatedIds","rows","relatedCol","idMap","row","next","captureJoinBatches","opts","joinTable","publishedCol","relatedUid","relatedHasDraftAndPublish","schemaUid","isOwningSide","oldVersions","newVersions","batches","name","table","oldIds","existing","push","relations","entityColumn","relatedColumn","contentTypes","oldLocales","draftsOnly","filter","v","has","draftIds","draftRows","meta","metadata","relatedIds","r","load","uid","relationsToUpdate","transaction","models","Object","values","components","model","dbModel","attribute","attributes","type","inversedBy","mappedBy","relation","target","isInverseSide","joinColumn","inverseJoinColumn","options","draftAndPublish","sync","oldEntries","newEntries","existingRelations","newEntriesByLocale","keyBy","entryIdMapping","reduce","acc","oldEntry","newEntry","republishedEntryIds","isRepublishedEntry","sourceColumn","targetColumn","orderColumn","orderColumnName","mappedRelations","oldSourceId","targetId","originalOrder","newSourceId","Boolean","newSourceIds","caseFragments","caseBindings","flatMap","update","raw","join","existingRows","existingSet","toInsert","omit","identifiers","ID_COLUMN","batchSize","dialect","getBatchInsertSize","batchInsert"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _ = require('lodash');
|
|
4
4
|
var mapRelation = require('../transform/relations/utils/map-relation.js');
|
|
5
5
|
|
|
6
6
|
const RELATION_OPERATIONS = [
|
|
@@ -59,7 +59,7 @@ const collectRelationOperationOverrides = async (submittedData, contentType, get
|
|
|
59
59
|
const prepareCloneData = async (originalData, submittedData, contentType, getModel)=>{
|
|
60
60
|
const submitted = submittedData ?? {};
|
|
61
61
|
const relationOperationOverrides = await collectRelationOperationOverrides(submitted, contentType, getModel);
|
|
62
|
-
|
|
62
|
+
const data = _.merge({}, originalData, submitted);
|
|
63
63
|
const relationsToCopy = [];
|
|
64
64
|
for (const [attributeName, attribute] of Object.entries(contentType.attributes)){
|
|
65
65
|
if (!isRelationAttribute(attribute) || !canTransformRelationOperationPayload(attribute)) {
|
|
@@ -78,7 +78,7 @@ const prepareCloneData = async (originalData, submittedData, contentType, getMod
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
for (const [path, value] of relationOperationOverrides){
|
|
81
|
-
|
|
81
|
+
_.set(data, path, value);
|
|
82
82
|
}
|
|
83
83
|
return {
|
|
84
84
|
data,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clone-relations.js","sources":["../../../../src/services/document-service/utils/clone-relations.ts"],"sourcesContent":["import { merge, set } from 'lodash/fp';\n\nimport type { Core, Schema, UID } from '@strapi/types';\nimport type { traverseEntity } from '@strapi/utils';\nimport { traverseEntityRelations } from '../transform/relations/utils/map-relation';\n\nconst RELATION_OPERATIONS = ['connect', 'disconnect', 'set'] as const;\ntype TraversableData = Parameters<typeof traverseEntity>[2];\n\ntype CloneRelationAttribute = Schema.Attribute.Relation & {\n targetAttribute?: string;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n};\n\nconst isRelationAttribute = (attribute: unknown): attribute is CloneRelationAttribute => {\n return (\n isRecord(attribute) && attribute.type === 'relation' && typeof attribute.relation === 'string'\n );\n};\n\nconst isRelationOperationPayload = (value: unknown): value is Record<string, unknown> => {\n return (\n isRecord(value) &&\n RELATION_OPERATIONS.some((operation) => Object.prototype.hasOwnProperty.call(value, operation))\n );\n};\n\nconst hasMeaningfulRelationOperations = (value: Record<string, unknown>) => {\n if (Object.prototype.hasOwnProperty.call(value, 'set')) {\n return true;\n }\n\n return ['connect', 'disconnect'].some((operation) => {\n const operationValue = value[operation];\n return Array.isArray(operationValue) ? operationValue.length > 0 : operationValue != null;\n });\n};\n\nconst canTransformRelationOperationPayload = (attribute: Schema.Attribute.Relation) => {\n return attribute.useJoinTable !== false && attribute.relation !== 'morphToOne';\n};\n\nconst isBidirectionalOneToOne = (attribute: CloneRelationAttribute) => {\n return (\n attribute.relation === 'oneToOne' &&\n [attribute.inversedBy, attribute.mappedBy, attribute.targetAttribute].some(\n (inverseAttribute) => inverseAttribute != null\n )\n );\n};\n\nconst hasPopulatedRelation = (value: unknown) => {\n return isRecord(value) && ('id' in value || 'documentId' in value);\n};\n\nconst collectRelationOperationOverrides = async (\n submittedData: Record<string, unknown>,\n contentType: Schema.ContentType,\n getModel: (uid: string) => Schema.Schema\n) => {\n const overrides = new Map<string, Record<string, unknown>>();\n\n await traverseEntityRelations(\n ({ path, value }) => {\n if (isRelationOperationPayload(value) && hasMeaningfulRelationOperations(value)) {\n overrides.set(path.rawWithIndices!, value);\n }\n },\n { schema: contentType, getModel },\n submittedData as TraversableData\n );\n\n return [...overrides.entries()].sort(([leftPath], [rightPath]) =>\n leftPath.localeCompare(rightPath)\n );\n};\n\nexport const prepareCloneData = async (\n originalData: Record<string, unknown>,\n submittedData: Record<string, unknown> | undefined,\n contentType: Schema.ContentType,\n getModel: (uid: string) => Schema.Schema\n) => {\n const submitted = submittedData ?? {};\n const relationOperationOverrides = await collectRelationOperationOverrides(\n submitted,\n contentType,\n getModel\n );\n let data = merge(originalData, submitted) as Record<string, unknown>;\n const relationsToCopy: string[] = [];\n\n for (const [attributeName, attribute] of Object.entries(contentType.attributes)) {\n if (!isRelationAttribute(attribute) || !canTransformRelationOperationPayload(attribute)) {\n continue;\n }\n\n const relationWasSubmitted = Object.prototype.hasOwnProperty.call(submitted, attributeName);\n const submittedValue = submitted[attributeName];\n const isOperationPayload = isRelationOperationPayload(submittedValue);\n const hasMeaningfulOperations =\n isOperationPayload && hasMeaningfulRelationOperations(submittedValue);\n\n const relationIsUnchanged =\n !relationWasSubmitted || (isOperationPayload && !hasMeaningfulOperations);\n\n if (\n relationIsUnchanged &&\n isBidirectionalOneToOne(attribute) &&\n hasPopulatedRelation(originalData[attributeName])\n ) {\n // Normal relation attachment enforces oneToOne ownership by removing the source link.\n // Leave unchanged relations out of create and copy their join row after the clone exists.\n delete data[attributeName];\n relationsToCopy.push(attributeName);\n }\n }\n\n for (const [path, value] of relationOperationOverrides) {\n data = set(path, value, data) as Record<string, unknown>;\n }\n\n return { data, relationsToCopy };\n};\n\nexport const copyCloneRelationRows = async (\n strapi: Core.Strapi,\n uid: UID.ContentType,\n sourceEntryId: number,\n targetEntryId: number,\n attributeNames: string[]\n) => {\n if (attributeNames.length === 0) {\n return;\n }\n\n const { attributes } = strapi.db.metadata.get(uid);\n const idColumn = strapi.db.metadata.identifiers.ID_COLUMN;\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const attributeName of attributeNames) {\n const attribute = attributes[attributeName];\n\n if (attribute?.type !== 'relation' || !('joinTable' in attribute) || !attribute.joinTable) {\n continue;\n }\n\n const { joinTable } = attribute;\n const { joinColumn } = joinTable;\n const rows = (await strapi.db\n .connection(joinTable.name)\n .where({\n [joinColumn.name]: sourceEntryId,\n ...(('on' in joinTable && joinTable.on) || undefined),\n })\n .select('*')\n .transacting(trx)) as Record<string, unknown>[];\n\n const rowsToCopy = rows.map((row) => {\n const copiedRow = { ...row, [joinColumn.name]: targetEntryId };\n delete copiedRow[idColumn];\n return copiedRow;\n });\n\n for (let index = 0; index < rowsToCopy.length; index += batchSize) {\n await strapi.db\n .connection(joinTable.name)\n .insert(rowsToCopy.slice(index, index + batchSize))\n .transacting(trx);\n }\n }\n });\n};\n"],"names":["RELATION_OPERATIONS","isRecord","value","Array","isArray","isRelationAttribute","attribute","type","relation","isRelationOperationPayload","some","operation","Object","prototype","hasOwnProperty","call","hasMeaningfulRelationOperations","operationValue","length","canTransformRelationOperationPayload","useJoinTable","isBidirectionalOneToOne","inversedBy","mappedBy","targetAttribute","inverseAttribute","hasPopulatedRelation","collectRelationOperationOverrides","submittedData","contentType","getModel","overrides","Map","traverseEntityRelations","path","set","rawWithIndices","schema","entries","sort","leftPath","rightPath","localeCompare","prepareCloneData","originalData","submitted","relationOperationOverrides","data","merge","relationsToCopy","attributeName","attributes","relationWasSubmitted","submittedValue","isOperationPayload","hasMeaningfulOperations","relationIsUnchanged","push","copyCloneRelationRows","strapi","uid","sourceEntryId","targetEntryId","attributeNames","db","metadata","get","idColumn","identifiers","ID_COLUMN","batchSize","dialect","getBatchInsertSize","transaction","trx","joinTable","joinColumn","rows","connection","name","where","on","undefined","select","transacting","rowsToCopy","map","row","copiedRow","index","insert","slice"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"clone-relations.js","sources":["../../../../src/services/document-service/utils/clone-relations.ts"],"sourcesContent":["import { merge, set } from 'lodash';\n\nimport type { Core, Schema, UID } from '@strapi/types';\nimport type { traverseEntity } from '@strapi/utils';\nimport { traverseEntityRelations } from '../transform/relations/utils/map-relation';\n\nconst RELATION_OPERATIONS = ['connect', 'disconnect', 'set'] as const;\ntype TraversableData = Parameters<typeof traverseEntity>[2];\n\ntype CloneRelationAttribute = Schema.Attribute.Relation & {\n targetAttribute?: string;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n};\n\nconst isRelationAttribute = (attribute: unknown): attribute is CloneRelationAttribute => {\n return (\n isRecord(attribute) && attribute.type === 'relation' && typeof attribute.relation === 'string'\n );\n};\n\nconst isRelationOperationPayload = (value: unknown): value is Record<string, unknown> => {\n return (\n isRecord(value) &&\n RELATION_OPERATIONS.some((operation) => Object.prototype.hasOwnProperty.call(value, operation))\n );\n};\n\nconst hasMeaningfulRelationOperations = (value: Record<string, unknown>) => {\n if (Object.prototype.hasOwnProperty.call(value, 'set')) {\n return true;\n }\n\n return ['connect', 'disconnect'].some((operation) => {\n const operationValue = value[operation];\n return Array.isArray(operationValue) ? operationValue.length > 0 : operationValue != null;\n });\n};\n\nconst canTransformRelationOperationPayload = (attribute: Schema.Attribute.Relation) => {\n return attribute.useJoinTable !== false && attribute.relation !== 'morphToOne';\n};\n\nconst isBidirectionalOneToOne = (attribute: CloneRelationAttribute) => {\n return (\n attribute.relation === 'oneToOne' &&\n [attribute.inversedBy, attribute.mappedBy, attribute.targetAttribute].some(\n (inverseAttribute) => inverseAttribute != null\n )\n );\n};\n\nconst hasPopulatedRelation = (value: unknown) => {\n return isRecord(value) && ('id' in value || 'documentId' in value);\n};\n\nconst collectRelationOperationOverrides = async (\n submittedData: Record<string, unknown>,\n contentType: Schema.ContentType,\n getModel: (uid: string) => Schema.Schema\n) => {\n const overrides = new Map<string, Record<string, unknown>>();\n\n await traverseEntityRelations(\n ({ path, value }) => {\n if (isRelationOperationPayload(value) && hasMeaningfulRelationOperations(value)) {\n overrides.set(path.rawWithIndices!, value);\n }\n },\n { schema: contentType, getModel },\n submittedData as TraversableData\n );\n\n return [...overrides.entries()].sort(([leftPath], [rightPath]) =>\n leftPath.localeCompare(rightPath)\n );\n};\n\nexport const prepareCloneData = async (\n originalData: Record<string, unknown>,\n submittedData: Record<string, unknown> | undefined,\n contentType: Schema.ContentType,\n getModel: (uid: string) => Schema.Schema\n) => {\n const submitted = submittedData ?? {};\n const relationOperationOverrides = await collectRelationOperationOverrides(\n submitted,\n contentType,\n getModel\n );\n const data = merge({}, originalData, submitted) as Record<string, unknown>;\n const relationsToCopy: string[] = [];\n\n for (const [attributeName, attribute] of Object.entries(contentType.attributes)) {\n if (!isRelationAttribute(attribute) || !canTransformRelationOperationPayload(attribute)) {\n continue;\n }\n\n const relationWasSubmitted = Object.prototype.hasOwnProperty.call(submitted, attributeName);\n const submittedValue = submitted[attributeName];\n const isOperationPayload = isRelationOperationPayload(submittedValue);\n const hasMeaningfulOperations =\n isOperationPayload && hasMeaningfulRelationOperations(submittedValue);\n\n const relationIsUnchanged =\n !relationWasSubmitted || (isOperationPayload && !hasMeaningfulOperations);\n\n if (\n relationIsUnchanged &&\n isBidirectionalOneToOne(attribute) &&\n hasPopulatedRelation(originalData[attributeName])\n ) {\n // Normal relation attachment enforces oneToOne ownership by removing the source link.\n // Leave unchanged relations out of create and copy their join row after the clone exists.\n delete data[attributeName];\n relationsToCopy.push(attributeName);\n }\n }\n\n for (const [path, value] of relationOperationOverrides) {\n set(data, path, value);\n }\n\n return { data, relationsToCopy };\n};\n\nexport const copyCloneRelationRows = async (\n strapi: Core.Strapi,\n uid: UID.ContentType,\n sourceEntryId: number,\n targetEntryId: number,\n attributeNames: string[]\n) => {\n if (attributeNames.length === 0) {\n return;\n }\n\n const { attributes } = strapi.db.metadata.get(uid);\n const idColumn = strapi.db.metadata.identifiers.ID_COLUMN;\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const attributeName of attributeNames) {\n const attribute = attributes[attributeName];\n\n if (attribute?.type !== 'relation' || !('joinTable' in attribute) || !attribute.joinTable) {\n continue;\n }\n\n const { joinTable } = attribute;\n const { joinColumn } = joinTable;\n const rows = (await strapi.db\n .connection(joinTable.name)\n .where({\n [joinColumn.name]: sourceEntryId,\n ...(('on' in joinTable && joinTable.on) || undefined),\n })\n .select('*')\n .transacting(trx)) as Record<string, unknown>[];\n\n const rowsToCopy = rows.map((row) => {\n const copiedRow = { ...row, [joinColumn.name]: targetEntryId };\n delete copiedRow[idColumn];\n return copiedRow;\n });\n\n for (let index = 0; index < rowsToCopy.length; index += batchSize) {\n await strapi.db\n .connection(joinTable.name)\n .insert(rowsToCopy.slice(index, index + batchSize))\n .transacting(trx);\n }\n }\n });\n};\n"],"names":["RELATION_OPERATIONS","isRecord","value","Array","isArray","isRelationAttribute","attribute","type","relation","isRelationOperationPayload","some","operation","Object","prototype","hasOwnProperty","call","hasMeaningfulRelationOperations","operationValue","length","canTransformRelationOperationPayload","useJoinTable","isBidirectionalOneToOne","inversedBy","mappedBy","targetAttribute","inverseAttribute","hasPopulatedRelation","collectRelationOperationOverrides","submittedData","contentType","getModel","overrides","Map","traverseEntityRelations","path","set","rawWithIndices","schema","entries","sort","leftPath","rightPath","localeCompare","prepareCloneData","originalData","submitted","relationOperationOverrides","data","merge","relationsToCopy","attributeName","attributes","relationWasSubmitted","submittedValue","isOperationPayload","hasMeaningfulOperations","relationIsUnchanged","push","copyCloneRelationRows","strapi","uid","sourceEntryId","targetEntryId","attributeNames","db","metadata","get","idColumn","identifiers","ID_COLUMN","batchSize","dialect","getBatchInsertSize","transaction","trx","joinTable","joinColumn","rows","connection","name","where","on","undefined","select","transacting","rowsToCopy","map","row","copiedRow","index","insert","slice"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { merge, set } from 'lodash
|
|
1
|
+
import { merge, set } from 'lodash';
|
|
2
2
|
import { traverseEntityRelations as traverseEntityRelationsCurried } from '../transform/relations/utils/map-relation.mjs';
|
|
3
3
|
|
|
4
4
|
const RELATION_OPERATIONS = [
|
|
@@ -57,7 +57,7 @@ const collectRelationOperationOverrides = async (submittedData, contentType, get
|
|
|
57
57
|
const prepareCloneData = async (originalData, submittedData, contentType, getModel)=>{
|
|
58
58
|
const submitted = submittedData ?? {};
|
|
59
59
|
const relationOperationOverrides = await collectRelationOperationOverrides(submitted, contentType, getModel);
|
|
60
|
-
|
|
60
|
+
const data = merge({}, originalData, submitted);
|
|
61
61
|
const relationsToCopy = [];
|
|
62
62
|
for (const [attributeName, attribute] of Object.entries(contentType.attributes)){
|
|
63
63
|
if (!isRelationAttribute(attribute) || !canTransformRelationOperationPayload(attribute)) {
|
|
@@ -76,7 +76,7 @@ const prepareCloneData = async (originalData, submittedData, contentType, getMod
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
for (const [path, value] of relationOperationOverrides){
|
|
79
|
-
data
|
|
79
|
+
set(data, path, value);
|
|
80
80
|
}
|
|
81
81
|
return {
|
|
82
82
|
data,
|