@strapi/core 5.56.0 → 5.58.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.
Files changed (377) hide show
  1. package/dist/Strapi.d.ts +29 -0
  2. package/dist/Strapi.d.ts.map +1 -1
  3. package/dist/Strapi.js +10 -3
  4. package/dist/Strapi.js.map +1 -1
  5. package/dist/Strapi.mjs +10 -3
  6. package/dist/Strapi.mjs.map +1 -1
  7. package/dist/configuration/get-dirs.js +2 -2
  8. package/dist/configuration/get-dirs.js.map +1 -1
  9. package/dist/configuration/get-dirs.mjs +2 -2
  10. package/dist/configuration/get-dirs.mjs.map +1 -1
  11. package/dist/configuration/index.d.ts +1 -2
  12. package/dist/configuration/index.d.ts.map +1 -1
  13. package/dist/configuration/index.js +1 -2
  14. package/dist/configuration/index.js.map +1 -1
  15. package/dist/configuration/index.mjs +2 -3
  16. package/dist/configuration/index.mjs.map +1 -1
  17. package/dist/core-api/controller/collection-type.js +3 -3
  18. package/dist/core-api/controller/collection-type.js.map +1 -1
  19. package/dist/core-api/controller/collection-type.mjs +1 -1
  20. package/dist/core-api/controller/collection-type.mjs.map +1 -1
  21. package/dist/core-api/controller/index.js +2 -2
  22. package/dist/core-api/controller/index.js.map +1 -1
  23. package/dist/core-api/controller/index.mjs +2 -2
  24. package/dist/core-api/controller/index.mjs.map +1 -1
  25. package/dist/core-api/controller/single-type.js +2 -2
  26. package/dist/core-api/controller/single-type.js.map +1 -1
  27. package/dist/core-api/controller/single-type.mjs +1 -1
  28. package/dist/core-api/controller/single-type.mjs.map +1 -1
  29. package/dist/core-api/controller/transform.d.ts +1 -4
  30. package/dist/core-api/controller/transform.d.ts.map +1 -1
  31. package/dist/core-api/controller/transform.js +8 -8
  32. package/dist/core-api/controller/transform.js.map +1 -1
  33. package/dist/core-api/controller/transform.mjs +5 -5
  34. package/dist/core-api/controller/transform.mjs.map +1 -1
  35. package/dist/core-api/routes/index.js +1 -1
  36. package/dist/core-api/routes/index.js.map +1 -1
  37. package/dist/core-api/routes/index.mjs +1 -1
  38. package/dist/core-api/routes/index.mjs.map +1 -1
  39. package/dist/core-api/service/pagination.js +9 -9
  40. package/dist/core-api/service/pagination.js.map +1 -1
  41. package/dist/core-api/service/pagination.mjs +7 -7
  42. package/dist/core-api/service/pagination.mjs.map +1 -1
  43. package/dist/domain/content-type/index.d.ts.map +1 -1
  44. package/dist/domain/content-type/index.js +1 -2
  45. package/dist/domain/content-type/index.js.map +1 -1
  46. package/dist/domain/content-type/index.mjs +1 -2
  47. package/dist/domain/content-type/index.mjs.map +1 -1
  48. package/dist/ee/entitlements.d.ts +44 -0
  49. package/dist/ee/entitlements.d.ts.map +1 -0
  50. package/dist/ee/entitlements.js +54 -0
  51. package/dist/ee/entitlements.js.map +1 -0
  52. package/dist/ee/entitlements.mjs +51 -0
  53. package/dist/ee/entitlements.mjs.map +1 -0
  54. package/dist/ee/index.d.ts +33 -0
  55. package/dist/ee/index.d.ts.map +1 -1
  56. package/dist/ee/index.js +74 -7
  57. package/dist/ee/index.js.map +1 -1
  58. package/dist/ee/index.mjs +74 -7
  59. package/dist/ee/index.mjs.map +1 -1
  60. package/dist/ee/license.d.ts +10 -0
  61. package/dist/ee/license.d.ts.map +1 -1
  62. package/dist/ee/license.js +25 -1
  63. package/dist/ee/license.js.map +1 -1
  64. package/dist/ee/license.mjs +25 -2
  65. package/dist/ee/license.mjs.map +1 -1
  66. package/dist/factories.d.ts.map +1 -1
  67. package/dist/factories.js +3 -2
  68. package/dist/factories.js.map +1 -1
  69. package/dist/factories.mjs +3 -2
  70. package/dist/factories.mjs.map +1 -1
  71. package/dist/index.js +1 -1
  72. package/dist/index.mjs +1 -1
  73. package/dist/loaders/apis.d.ts.map +1 -1
  74. package/dist/loaders/apis.js +1 -2
  75. package/dist/loaders/apis.js.map +1 -1
  76. package/dist/loaders/apis.mjs +1 -2
  77. package/dist/loaders/apis.mjs.map +1 -1
  78. package/dist/loaders/plugins/get-enabled-plugins.d.ts +1 -1
  79. package/dist/loaders/plugins/get-enabled-plugins.d.ts.map +1 -1
  80. package/dist/loaders/plugins/get-enabled-plugins.js +6 -5
  81. package/dist/loaders/plugins/get-enabled-plugins.js.map +1 -1
  82. package/dist/loaders/plugins/get-enabled-plugins.mjs +6 -5
  83. package/dist/loaders/plugins/get-enabled-plugins.mjs.map +1 -1
  84. package/dist/loaders/plugins/get-user-plugins-config.js +2 -2
  85. package/dist/loaders/plugins/get-user-plugins-config.js.map +1 -1
  86. package/dist/loaders/plugins/get-user-plugins-config.mjs +2 -2
  87. package/dist/loaders/plugins/get-user-plugins-config.mjs.map +1 -1
  88. package/dist/loaders/plugins/index.js +9 -12
  89. package/dist/loaders/plugins/index.js.map +1 -1
  90. package/dist/loaders/plugins/index.mjs +9 -12
  91. package/dist/loaders/plugins/index.mjs.map +1 -1
  92. package/dist/middlewares/body.js +2 -2
  93. package/dist/middlewares/body.js.map +1 -1
  94. package/dist/middlewares/body.mjs +2 -2
  95. package/dist/middlewares/body.mjs.map +1 -1
  96. package/dist/middlewares/public.js +2 -2
  97. package/dist/middlewares/public.js.map +1 -1
  98. package/dist/middlewares/public.mjs +2 -2
  99. package/dist/middlewares/public.mjs.map +1 -1
  100. package/dist/middlewares/responses.d.ts.map +1 -1
  101. package/dist/middlewares/responses.js +1 -3
  102. package/dist/middlewares/responses.js.map +1 -1
  103. package/dist/middlewares/responses.mjs +1 -3
  104. package/dist/middlewares/responses.mjs.map +1 -1
  105. package/dist/middlewares/security.d.ts.map +1 -1
  106. package/dist/middlewares/security.js +3 -3
  107. package/dist/middlewares/security.js.map +1 -1
  108. package/dist/middlewares/security.mjs +3 -3
  109. package/dist/middlewares/security.mjs.map +1 -1
  110. package/dist/middlewares/session.js +2 -2
  111. package/dist/middlewares/session.js.map +1 -1
  112. package/dist/middlewares/session.mjs +2 -2
  113. package/dist/middlewares/session.mjs.map +1 -1
  114. package/dist/migrations/database/5.0.0-discard-drafts.d.ts.map +1 -1
  115. package/dist/migrations/database/5.0.0-discard-drafts.js +1 -2
  116. package/dist/migrations/database/5.0.0-discard-drafts.js.map +1 -1
  117. package/dist/migrations/database/5.0.0-discard-drafts.mjs +1 -2
  118. package/dist/migrations/database/5.0.0-discard-drafts.mjs.map +1 -1
  119. package/dist/migrations/i18n.d.ts.map +1 -1
  120. package/dist/migrations/i18n.js +6 -4
  121. package/dist/migrations/i18n.js.map +1 -1
  122. package/dist/migrations/i18n.mjs +6 -4
  123. package/dist/migrations/i18n.mjs.map +1 -1
  124. package/dist/package.json.js +16 -16
  125. package/dist/package.json.mjs +16 -16
  126. package/dist/registries/apis.js +2 -2
  127. package/dist/registries/apis.js.map +1 -1
  128. package/dist/registries/apis.mjs +2 -2
  129. package/dist/registries/apis.mjs.map +1 -1
  130. package/dist/registries/components.js +2 -2
  131. package/dist/registries/components.js.map +1 -1
  132. package/dist/registries/components.mjs +2 -2
  133. package/dist/registries/components.mjs.map +1 -1
  134. package/dist/registries/content-types.d.ts +1 -1
  135. package/dist/registries/content-types.js +3 -3
  136. package/dist/registries/content-types.js.map +1 -1
  137. package/dist/registries/content-types.mjs +3 -3
  138. package/dist/registries/content-types.mjs.map +1 -1
  139. package/dist/registries/controllers.js +3 -3
  140. package/dist/registries/controllers.js.map +1 -1
  141. package/dist/registries/controllers.mjs +3 -3
  142. package/dist/registries/controllers.mjs.map +1 -1
  143. package/dist/registries/custom-fields.js +4 -4
  144. package/dist/registries/custom-fields.js.map +1 -1
  145. package/dist/registries/custom-fields.mjs +4 -4
  146. package/dist/registries/custom-fields.mjs.map +1 -1
  147. package/dist/registries/hooks.d.ts +1 -1
  148. package/dist/registries/hooks.js +2 -2
  149. package/dist/registries/hooks.js.map +1 -1
  150. package/dist/registries/hooks.mjs +2 -2
  151. package/dist/registries/hooks.mjs.map +1 -1
  152. package/dist/registries/middlewares.d.ts +1 -1
  153. package/dist/registries/middlewares.js +3 -3
  154. package/dist/registries/middlewares.js.map +1 -1
  155. package/dist/registries/middlewares.mjs +3 -3
  156. package/dist/registries/middlewares.mjs.map +1 -1
  157. package/dist/registries/modules.d.ts +1 -4
  158. package/dist/registries/modules.d.ts.map +1 -1
  159. package/dist/registries/modules.js +3 -3
  160. package/dist/registries/modules.js.map +1 -1
  161. package/dist/registries/modules.mjs +3 -3
  162. package/dist/registries/modules.mjs.map +1 -1
  163. package/dist/registries/plugins.js +2 -2
  164. package/dist/registries/plugins.js.map +1 -1
  165. package/dist/registries/plugins.mjs +2 -2
  166. package/dist/registries/plugins.mjs.map +1 -1
  167. package/dist/registries/policies.d.ts +1 -1
  168. package/dist/registries/policies.js +4 -4
  169. package/dist/registries/policies.js.map +1 -1
  170. package/dist/registries/policies.mjs +3 -3
  171. package/dist/registries/policies.mjs.map +1 -1
  172. package/dist/registries/services.js +3 -3
  173. package/dist/registries/services.js.map +1 -1
  174. package/dist/registries/services.mjs +3 -3
  175. package/dist/registries/services.mjs.map +1 -1
  176. package/dist/services/auth/index.js +3 -3
  177. package/dist/services/auth/index.js.map +1 -1
  178. package/dist/services/auth/index.mjs +3 -3
  179. package/dist/services/auth/index.mjs.map +1 -1
  180. package/dist/services/core-store.js +3 -3
  181. package/dist/services/core-store.js.map +1 -1
  182. package/dist/services/core-store.mjs +1 -1
  183. package/dist/services/core-store.mjs.map +1 -1
  184. package/dist/services/cron.d.ts.map +1 -1
  185. package/dist/services/cron.js +2 -4
  186. package/dist/services/cron.js.map +1 -1
  187. package/dist/services/cron.mjs +2 -4
  188. package/dist/services/cron.mjs.map +1 -1
  189. package/dist/services/document-service/attributes/index.js +2 -2
  190. package/dist/services/document-service/attributes/index.js.map +1 -1
  191. package/dist/services/document-service/attributes/index.mjs +1 -1
  192. package/dist/services/document-service/attributes/index.mjs.map +1 -1
  193. package/dist/services/document-service/attributes/transforms.js +3 -3
  194. package/dist/services/document-service/attributes/transforms.js.map +1 -1
  195. package/dist/services/document-service/attributes/transforms.mjs +2 -2
  196. package/dist/services/document-service/attributes/transforms.mjs.map +1 -1
  197. package/dist/services/document-service/components.d.ts.map +1 -1
  198. package/dist/services/document-service/components.js +13 -14
  199. package/dist/services/document-service/components.js.map +1 -1
  200. package/dist/services/document-service/components.mjs +12 -13
  201. package/dist/services/document-service/components.mjs.map +1 -1
  202. package/dist/services/document-service/draft-and-publish.js +65 -38
  203. package/dist/services/document-service/draft-and-publish.js.map +1 -1
  204. package/dist/services/document-service/draft-and-publish.mjs +59 -32
  205. package/dist/services/document-service/draft-and-publish.mjs.map +1 -1
  206. package/dist/services/document-service/entries.d.ts +2 -2
  207. package/dist/services/document-service/entries.d.ts.map +1 -1
  208. package/dist/services/document-service/entries.js +16 -8
  209. package/dist/services/document-service/entries.js.map +1 -1
  210. package/dist/services/document-service/entries.mjs +17 -9
  211. package/dist/services/document-service/entries.mjs.map +1 -1
  212. package/dist/services/document-service/first-published-at.js +7 -5
  213. package/dist/services/document-service/first-published-at.js.map +1 -1
  214. package/dist/services/document-service/first-published-at.mjs +7 -5
  215. package/dist/services/document-service/first-published-at.mjs.map +1 -1
  216. package/dist/services/document-service/internationalization.d.ts.map +1 -1
  217. package/dist/services/document-service/internationalization.js +37 -28
  218. package/dist/services/document-service/internationalization.js.map +1 -1
  219. package/dist/services/document-service/internationalization.mjs +33 -24
  220. package/dist/services/document-service/internationalization.mjs.map +1 -1
  221. package/dist/services/document-service/params.d.ts +1 -0
  222. package/dist/services/document-service/params.d.ts.map +1 -1
  223. package/dist/services/document-service/params.js +6 -4
  224. package/dist/services/document-service/params.js.map +1 -1
  225. package/dist/services/document-service/params.mjs +6 -5
  226. package/dist/services/document-service/params.mjs.map +1 -1
  227. package/dist/services/document-service/repository.d.ts.map +1 -1
  228. package/dist/services/document-service/repository.js +84 -61
  229. package/dist/services/document-service/repository.js.map +1 -1
  230. package/dist/services/document-service/repository.mjs +47 -24
  231. package/dist/services/document-service/repository.mjs.map +1 -1
  232. package/dist/services/document-service/transform/fields.d.ts.map +1 -1
  233. package/dist/services/document-service/transform/fields.js +7 -1
  234. package/dist/services/document-service/transform/fields.js.map +1 -1
  235. package/dist/services/document-service/transform/fields.mjs +7 -1
  236. package/dist/services/document-service/transform/fields.mjs.map +1 -1
  237. package/dist/services/document-service/transform/id-map.d.ts.map +1 -1
  238. package/dist/services/document-service/transform/id-map.js +2 -1
  239. package/dist/services/document-service/transform/id-map.js.map +1 -1
  240. package/dist/services/document-service/transform/id-map.mjs +2 -1
  241. package/dist/services/document-service/transform/id-map.mjs.map +1 -1
  242. package/dist/services/document-service/transform/id-transform.js +2 -2
  243. package/dist/services/document-service/transform/id-transform.js.map +1 -1
  244. package/dist/services/document-service/transform/id-transform.mjs +1 -1
  245. package/dist/services/document-service/transform/id-transform.mjs.map +1 -1
  246. package/dist/services/document-service/transform/populate.d.ts.map +1 -1
  247. package/dist/services/document-service/transform/populate.js +8 -1
  248. package/dist/services/document-service/transform/populate.js.map +1 -1
  249. package/dist/services/document-service/transform/populate.mjs +8 -1
  250. package/dist/services/document-service/transform/populate.mjs.map +1 -1
  251. package/dist/services/document-service/transform/query.d.ts +3 -1
  252. package/dist/services/document-service/transform/query.d.ts.map +1 -1
  253. package/dist/services/document-service/transform/query.js +12 -6
  254. package/dist/services/document-service/transform/query.js.map +1 -1
  255. package/dist/services/document-service/transform/query.mjs +11 -5
  256. package/dist/services/document-service/transform/query.mjs.map +1 -1
  257. package/dist/services/document-service/transform/relations/extract/data-ids.js +2 -2
  258. package/dist/services/document-service/transform/relations/extract/data-ids.js.map +1 -1
  259. package/dist/services/document-service/transform/relations/extract/data-ids.mjs +1 -1
  260. package/dist/services/document-service/transform/relations/extract/data-ids.mjs.map +1 -1
  261. package/dist/services/document-service/transform/relations/transform/data-ids.js +2 -2
  262. package/dist/services/document-service/transform/relations/transform/data-ids.js.map +1 -1
  263. package/dist/services/document-service/transform/relations/transform/data-ids.mjs +1 -1
  264. package/dist/services/document-service/transform/relations/transform/data-ids.mjs.map +1 -1
  265. package/dist/services/document-service/transform/relations/transform/default-locale.js +1 -1
  266. package/dist/services/document-service/transform/relations/transform/default-locale.js.map +1 -1
  267. package/dist/services/document-service/transform/relations/transform/default-locale.mjs +1 -1
  268. package/dist/services/document-service/transform/relations/transform/default-locale.mjs.map +1 -1
  269. package/dist/services/document-service/transform/relations/utils/dp.d.ts.map +1 -1
  270. package/dist/services/document-service/transform/relations/utils/dp.js +1 -2
  271. package/dist/services/document-service/transform/relations/utils/dp.js.map +1 -1
  272. package/dist/services/document-service/transform/relations/utils/dp.mjs +1 -2
  273. package/dist/services/document-service/transform/relations/utils/dp.mjs.map +1 -1
  274. package/dist/services/document-service/transform/relations/utils/i18n.d.ts +2 -2
  275. package/dist/services/document-service/transform/relations/utils/i18n.d.ts.map +1 -1
  276. package/dist/services/document-service/transform/relations/utils/i18n.js +2 -2
  277. package/dist/services/document-service/transform/relations/utils/i18n.js.map +1 -1
  278. package/dist/services/document-service/transform/relations/utils/i18n.mjs +2 -2
  279. package/dist/services/document-service/transform/relations/utils/i18n.mjs.map +1 -1
  280. package/dist/services/document-service/transform/relations/utils/map-relation.d.ts.map +1 -1
  281. package/dist/services/document-service/transform/relations/utils/map-relation.js +16 -10
  282. package/dist/services/document-service/transform/relations/utils/map-relation.js.map +1 -1
  283. package/dist/services/document-service/transform/relations/utils/map-relation.mjs +13 -7
  284. package/dist/services/document-service/transform/relations/utils/map-relation.mjs.map +1 -1
  285. package/dist/services/document-service/transform/relations/utils/xto-one.js +3 -3
  286. package/dist/services/document-service/transform/relations/utils/xto-one.js.map +1 -1
  287. package/dist/services/document-service/transform/relations/utils/xto-one.mjs +2 -2
  288. package/dist/services/document-service/transform/relations/utils/xto-one.mjs.map +1 -1
  289. package/dist/services/document-service/utils/bidirectional-relations.js +3 -3
  290. package/dist/services/document-service/utils/bidirectional-relations.js.map +1 -1
  291. package/dist/services/document-service/utils/bidirectional-relations.mjs +3 -3
  292. package/dist/services/document-service/utils/bidirectional-relations.mjs.map +1 -1
  293. package/dist/services/document-service/utils/clone-relations.js +3 -3
  294. package/dist/services/document-service/utils/clone-relations.js.map +1 -1
  295. package/dist/services/document-service/utils/clone-relations.mjs +3 -3
  296. package/dist/services/document-service/utils/clone-relations.mjs.map +1 -1
  297. package/dist/services/document-service/utils/self-referential-relations.js +4 -4
  298. package/dist/services/document-service/utils/self-referential-relations.js.map +1 -1
  299. package/dist/services/document-service/utils/self-referential-relations.mjs +4 -4
  300. package/dist/services/document-service/utils/self-referential-relations.mjs.map +1 -1
  301. package/dist/services/document-service/utils/unidirectional-relations.js +3 -3
  302. package/dist/services/document-service/utils/unidirectional-relations.js.map +1 -1
  303. package/dist/services/document-service/utils/unidirectional-relations.mjs +3 -3
  304. package/dist/services/document-service/utils/unidirectional-relations.mjs.map +1 -1
  305. package/dist/services/entity-validator/index.d.ts.map +1 -1
  306. package/dist/services/entity-validator/index.js +9 -10
  307. package/dist/services/entity-validator/index.js.map +1 -1
  308. package/dist/services/entity-validator/index.mjs +4 -5
  309. package/dist/services/entity-validator/index.mjs.map +1 -1
  310. package/dist/services/localization.d.ts +4 -0
  311. package/dist/services/localization.d.ts.map +1 -0
  312. package/dist/services/localization.js +51 -0
  313. package/dist/services/localization.js.map +1 -0
  314. package/dist/services/localization.mjs +49 -0
  315. package/dist/services/localization.mjs.map +1 -0
  316. package/dist/services/server/compose-endpoint.js +7 -7
  317. package/dist/services/server/compose-endpoint.js.map +1 -1
  318. package/dist/services/server/compose-endpoint.mjs +3 -3
  319. package/dist/services/server/compose-endpoint.mjs.map +1 -1
  320. package/dist/services/server/koa-methods.js +2 -2
  321. package/dist/services/server/koa-methods.js.map +1 -1
  322. package/dist/services/server/koa-methods.mjs +1 -1
  323. package/dist/services/server/koa-methods.mjs.map +1 -1
  324. package/dist/services/server/koa.d.ts.map +1 -1
  325. package/dist/services/server/koa.js +1 -2
  326. package/dist/services/server/koa.js.map +1 -1
  327. package/dist/services/server/koa.mjs +1 -2
  328. package/dist/services/server/koa.mjs.map +1 -1
  329. package/dist/services/server/middleware.d.ts.map +1 -1
  330. package/dist/services/server/middleware.js +1 -2
  331. package/dist/services/server/middleware.js.map +1 -1
  332. package/dist/services/server/middleware.mjs +1 -2
  333. package/dist/services/server/middleware.mjs.map +1 -1
  334. package/dist/services/server/routing.js +2 -2
  335. package/dist/services/server/routing.js.map +1 -1
  336. package/dist/services/server/routing.mjs +2 -2
  337. package/dist/services/server/routing.mjs.map +1 -1
  338. package/dist/services/utils/conditional-fields.d.ts +1 -1
  339. package/dist/services/utils/conditional-fields.d.ts.map +1 -1
  340. package/dist/services/utils/conditional-fields.js +2 -8
  341. package/dist/services/utils/conditional-fields.js.map +1 -1
  342. package/dist/services/utils/conditional-fields.mjs +2 -8
  343. package/dist/services/utils/conditional-fields.mjs.map +1 -1
  344. package/dist/services/utils/dynamic-zones.d.ts.map +1 -1
  345. package/dist/services/utils/dynamic-zones.js +2 -8
  346. package/dist/services/utils/dynamic-zones.js.map +1 -1
  347. package/dist/services/utils/dynamic-zones.mjs +2 -8
  348. package/dist/services/utils/dynamic-zones.mjs.map +1 -1
  349. package/dist/utils/cron.js +2 -2
  350. package/dist/utils/cron.js.map +1 -1
  351. package/dist/utils/cron.mjs +1 -1
  352. package/dist/utils/cron.mjs.map +1 -1
  353. package/dist/utils/detect-customizations.d.ts +31 -0
  354. package/dist/utils/detect-customizations.d.ts.map +1 -0
  355. package/dist/utils/detect-customizations.js +173 -0
  356. package/dist/utils/detect-customizations.js.map +1 -0
  357. package/dist/utils/detect-customizations.mjs +165 -0
  358. package/dist/utils/detect-customizations.mjs.map +1 -0
  359. package/dist/utils/filepath-to-prop-path.d.ts.map +1 -1
  360. package/dist/utils/filepath-to-prop-path.js +5 -12
  361. package/dist/utils/filepath-to-prop-path.js.map +1 -1
  362. package/dist/utils/filepath-to-prop-path.mjs +5 -11
  363. package/dist/utils/filepath-to-prop-path.mjs.map +1 -1
  364. package/dist/utils/is-initialized.js +3 -3
  365. package/dist/utils/is-initialized.js.map +1 -1
  366. package/dist/utils/is-initialized.mjs +2 -2
  367. package/dist/utils/is-initialized.mjs.map +1 -1
  368. package/dist/utils/startup-logger.d.ts.map +1 -1
  369. package/dist/utils/startup-logger.js +2 -4
  370. package/dist/utils/startup-logger.js.map +1 -1
  371. package/dist/utils/startup-logger.mjs +2 -3
  372. package/dist/utils/startup-logger.mjs.map +1 -1
  373. package/dist/utils/transform-content-types-to-models.js +4 -4
  374. package/dist/utils/transform-content-types-to-models.js.map +1 -1
  375. package/dist/utils/transform-content-types-to-models.mjs +3 -3
  376. package/dist/utils/transform-content-types-to-models.mjs.map +1 -1
  377. package/package.json +16 -16
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var fp = require('lodash/fp');
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
- let data = fp.merge(originalData, submitted);
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
- data = fp.set(path, value, data);
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/fp';
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
- let data = merge(originalData, submitted);
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 = set(path, value, data);
79
+ set(data, path, value);
80
80
  }
81
81
  return {
82
82
  data,
@@ -1 +1 @@
1
- {"version":3,"file":"clone-relations.mjs","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.mjs","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,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var fp = require('lodash/fp');
3
+ var _ = require('lodash');
4
4
 
5
5
  const entryKey = (entry)=>`${String(entry.document_id)}:${String(entry.locale)}`;
6
6
  const getCounterparts = async (trx, tableName, idsToResolve, status)=>{
@@ -19,7 +19,7 @@ const getCounterparts = async (trx, tableName, idsToResolve, status)=>{
19
19
  ];
20
20
  const counterpartsQuery = strapi.db.getConnection().select('id', 'document_id', 'locale').from(tableName).whereIn('document_id', documentIds).transacting(trx);
21
21
  const counterparts = status === 'published' ? await counterpartsQuery.whereNotNull('published_at') : await counterpartsQuery.whereNull('published_at');
22
- const counterpartByDocument = fp.keyBy(entryKey, counterparts);
22
+ const counterpartByDocument = _.keyBy(counterparts, entryKey);
23
23
  return drafts.reduce((acc, draft)=>{
24
24
  const counterpart = counterpartByDocument[entryKey(draft)];
25
25
  if (counterpart) {
@@ -147,7 +147,7 @@ const getCounterparts = async (trx, tableName, idsToResolve, status)=>{
147
147
  * and inserting the remapped relations into the join table.
148
148
  */ const sync = async (sourceEntries, targetEntries, relationData)=>{
149
149
  if (relationData.length === 0) return;
150
- const targetEntriesByLocale = fp.keyBy('locale', targetEntries);
150
+ const targetEntriesByLocale = _.keyBy(targetEntries, 'locale');
151
151
  // Keys stringified for object lookup; values keep the original DB type so PostgreSQL integer columns receive integers, not strings
152
152
  const idMapping = sourceEntries.reduce((acc, sourceEntry)=>{
153
153
  const targetEntry = targetEntriesByLocale[sourceEntry.locale];
@@ -171,7 +171,7 @@ const getCounterparts = async (trx, tableName, idsToResolve, status)=>{
171
171
  // Any side being remapped must resolve to a new entry.
172
172
  if (newSourceId == null || newTargetId == null) return null;
173
173
  return {
174
- ...fp.omit(strapi.db.metadata.identifiers.ID_COLUMN, relation),
174
+ ..._.omit(relation, strapi.db.metadata.identifiers.ID_COLUMN),
175
175
  [sourceColumn]: newSourceId,
176
176
  [targetColumn]: newTargetId
177
177
  };
@@ -1 +1 @@
1
- {"version":3,"file":"self-referential-relations.js","sources":["../../../../src/services/document-service/utils/self-referential-relations.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport { keyBy, omit } from 'lodash/fp';\nimport type { Data, UID } from '@strapi/types';\nimport type { Database, JoinTable } from '@strapi/database';\n\ninterface VersionEntry {\n id: Data.ID;\n locale: string;\n}\n\ninterface RelationData {\n joinTable: JoinTable;\n relations: Record<string, unknown>[];\n remap?: {\n source: boolean;\n target: boolean;\n };\n}\n\ntype TargetStatus = 'draft' | 'published';\ntype DatabaseQueryBuilder = ReturnType<Database['getConnection']>;\ntype DatabaseTransaction = Parameters<DatabaseQueryBuilder['transacting']>[0];\n\nconst entryKey = (entry: { document_id: unknown; locale: unknown }) =>\n `${String(entry.document_id)}:${String(entry.locale)}`;\n\nconst getCounterparts = async (\n trx: DatabaseTransaction,\n tableName: string,\n idsToResolve: unknown[],\n status: TargetStatus\n): Promise<Record<string, Data.ID>> => {\n const ids = [...new Set(idsToResolve.map((id) => String(id)))];\n\n if (ids.length === 0) {\n return {};\n }\n\n const drafts = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('id', ids)\n .transacting(trx);\n\n if (drafts.length === 0) {\n return {};\n }\n\n const documentIds = [\n ...new Set(drafts.map((entry: { document_id: Data.ID }) => entry.document_id)),\n ];\n\n const counterpartsQuery = strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('document_id', documentIds)\n .transacting(trx);\n\n const counterparts =\n status === 'published'\n ? await counterpartsQuery.whereNotNull('published_at')\n : await counterpartsQuery.whereNull('published_at');\n\n const counterpartByDocument = keyBy(entryKey, counterparts);\n\n return drafts.reduce(\n (\n acc: Record<string, Data.ID>,\n draft: { id: Data.ID; document_id: unknown; locale: unknown }\n ) => {\n const counterpart = counterpartByDocument[entryKey(draft)];\n\n if (counterpart) {\n acc[String(draft.id)] = counterpart.id;\n }\n\n return acc;\n },\n {}\n );\n};\n\n/**\n * Preserves self-referential relations during publish/discard operations.\n *\n * When publishing or discarding a draft, self-referential relations (where both sides\n * of the relation belong to the same content type) are lost because:\n *\n * 1. The old entry is deleted\n * 2. A new entry is created with relations resolved via documentId → entity ID mapping\n * 3. At mapping time, the old entity is already deleted and the new one doesn't exist yet\n * 4. The relation is silently dropped\n *\n * This utility:\n * 1. Captures self-referential join table rows before deletion\n * 2. Remaps old entity IDs to new entity IDs after creation\n * 3. Inserts the remapped relations\n */\n\n/**\n * Loads self-referential relations from source entries before they are deleted/recreated.\n */\nconst load = async (\n uid: UID.ContentType,\n sourceEntries: VersionEntry[],\n targetStatus: TargetStatus\n): Promise<RelationData[]> => {\n const updates: RelationData[] = [];\n const dbModel = strapi.db.metadata.get(uid);\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const attribute of Object.values(dbModel.attributes) as any) {\n if (attribute.type !== 'relation' || attribute.target !== uid) {\n continue;\n }\n\n // Bidirectional inverse side (e.g. `children` mappedBy `parent`) shares the same physical\n // join table as the owning attribute; processing both would duplicate rows and inserts.\n if (attribute.mappedBy) {\n continue;\n }\n\n const joinTable = attribute.joinTable;\n if (!joinTable) {\n continue;\n }\n\n const { name: sourceColumnName } = joinTable.joinColumn;\n const { name: targetColumnName } = joinTable.inverseJoinColumn;\n\n const sourceIds = sourceEntries.map((entry) => String(entry.id));\n\n // Load relations where both source and target are among the entries being processed.\n // These are the self-referential relations that would be lost during the\n // delete-and-recreate cycle.\n const selfRelations = await strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(sourceColumnName, sourceIds)\n .whereIn(targetColumnName, sourceIds)\n .transacting(trx);\n\n if (selfRelations.length > 0) {\n updates.push({\n joinTable,\n relations: selfRelations,\n remap: { source: true, target: true },\n });\n }\n\n // Use rows from the state being copied as the source of truth for one-sided\n // self-relations. Publishing maps untouched targets to published counterparts and drops\n // draft-only targets; discarding maps untouched targets to draft counterparts. This avoids\n // restoring stale old rows that were removed from the copied state.\n const [sourceDraftRelations, targetDraftRelations] = await Promise.all([\n strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(sourceColumnName, sourceIds)\n .whereNotIn(targetColumnName, sourceIds)\n .transacting(trx),\n strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(targetColumnName, sourceIds)\n .whereNotIn(sourceColumnName, sourceIds)\n .transacting(trx),\n ]);\n\n const [targetCounterparts, sourceCounterparts] = await Promise.all([\n getCounterparts(\n trx,\n dbModel.tableName,\n sourceDraftRelations.map((relation) => relation[targetColumnName]),\n targetStatus\n ),\n getCounterparts(\n trx,\n dbModel.tableName,\n targetDraftRelations.map((relation) => relation[sourceColumnName]),\n targetStatus\n ),\n ]);\n\n if (sourceDraftRelations.length > 0) {\n const relations = sourceDraftRelations\n .map((relation) => {\n const targetCounterpart = targetCounterparts[String(relation[targetColumnName])];\n\n if (targetCounterpart == null) {\n return null;\n }\n\n return { ...relation, [targetColumnName]: targetCounterpart };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n if (relations.length > 0) {\n updates.push({\n joinTable,\n relations,\n remap: { source: true, target: false },\n });\n }\n }\n\n if (targetDraftRelations.length > 0) {\n const relations = targetDraftRelations\n .map((relation) => {\n const sourceCounterpart = sourceCounterparts[String(relation[sourceColumnName])];\n\n if (sourceCounterpart == null) {\n return null;\n }\n\n return { ...relation, [sourceColumnName]: sourceCounterpart };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n if (relations.length > 0) {\n updates.push({\n joinTable,\n relations,\n remap: { source: false, target: true },\n });\n }\n }\n\n // One-sided rows from the replaced state are intentionally not restored here. The rows\n // captured above represent the current logical relation set; restoring stale old rows can\n // resurrect relations that were removed before publishing or discarding.\n }\n });\n\n return updates;\n};\n\n/**\n * Syncs self-referential relations by remapping old entry IDs to new entry IDs\n * and inserting the remapped relations into the join table.\n */\nconst sync = async (\n sourceEntries: VersionEntry[],\n targetEntries: VersionEntry[],\n relationData: RelationData[]\n) => {\n if (relationData.length === 0) return;\n\n const targetEntriesByLocale = keyBy('locale', targetEntries);\n\n // Keys stringified for object lookup; values keep the original DB type so PostgreSQL integer columns receive integers, not strings\n const idMapping = sourceEntries.reduce(\n (acc, sourceEntry) => {\n const targetEntry = targetEntriesByLocale[sourceEntry.locale];\n if (!targetEntry) return acc;\n acc[String(sourceEntry.id)] = targetEntry.id;\n return acc;\n },\n {} as Record<string, Data.ID>\n );\n\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const { joinTable, relations, remap = { source: true, target: true } } of relationData) {\n const sourceColumn = joinTable.joinColumn.name;\n const targetColumn = joinTable.inverseJoinColumn.name;\n\n const newRelations = relations\n .map((relation) => {\n const oldSourceId = String(relation[sourceColumn]);\n const oldTargetId = String(relation[targetColumn]);\n const newSourceId = remap.source ? idMapping[oldSourceId] : relation[sourceColumn];\n const newTargetId = remap.target ? idMapping[oldTargetId] : relation[targetColumn];\n\n // Any side being remapped must resolve to a new entry.\n if (newSourceId == null || newTargetId == null) return null;\n\n return {\n ...omit(strapi.db.metadata.identifiers.ID_COLUMN, relation),\n [sourceColumn]: newSourceId,\n [targetColumn]: newTargetId,\n };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n const pairKey = (r: Record<string, unknown>) =>\n `${String(r[sourceColumn])}:${String(r[targetColumn])}`;\n const seenPairs = new Set<string>();\n const deduped = newRelations.filter((r) => {\n const key = pairKey(r);\n if (seenPairs.has(key)) return false;\n seenPairs.add(key);\n return true;\n });\n\n if (deduped.length === 0) continue;\n\n // Relation writes may have already recreated the remapped pair. In that case restore\n // the saved join-row metadata (notably order columns) instead of inserting a duplicate.\n const newSourceIds = [...new Set(deduped.map((r) => String(r[sourceColumn])))];\n const existingRows = await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .select(sourceColumn, targetColumn);\n\n const existingSet = new Set(existingRows.map((r: Record<string, unknown>) => pairKey(r)));\n const toUpdate = deduped.filter((r) => existingSet.has(pairKey(r)));\n const toInsert = deduped.filter((r) => !existingSet.has(pairKey(r)));\n\n await Promise.all(\n toUpdate.map((relation) => {\n const sourceId = relation[sourceColumn];\n const targetId = relation[targetColumn];\n const dataToRestore = Object.fromEntries(\n [joinTable.orderColumnName, joinTable.inverseOrderColumnName]\n .filter((columnName): columnName is string => columnName != null)\n .filter((columnName) => columnName in relation)\n .map((columnName) => [columnName, relation[columnName]])\n );\n\n if (Object.keys(dataToRestore).length === 0) {\n return Promise.resolve();\n }\n\n return trx(joinTable.name)\n .where({ [sourceColumn]: sourceId, [targetColumn]: targetId })\n .update(dataToRestore);\n })\n );\n\n if (toInsert.length > 0) {\n await trx.batchInsert(joinTable.name, toInsert as any[], batchSize);\n }\n }\n });\n};\n\nexport { load, sync };\n"],"names":["entryKey","entry","String","document_id","locale","getCounterparts","trx","tableName","idsToResolve","status","ids","Set","map","id","length","drafts","strapi","db","getConnection","select","from","whereIn","transacting","documentIds","counterpartsQuery","counterparts","whereNotNull","whereNull","counterpartByDocument","keyBy","reduce","acc","draft","counterpart","load","uid","sourceEntries","targetStatus","updates","dbModel","metadata","get","transaction","attribute","Object","values","attributes","type","target","mappedBy","joinTable","name","sourceColumnName","joinColumn","targetColumnName","inverseJoinColumn","sourceIds","selfRelations","push","relations","remap","source","sourceDraftRelations","targetDraftRelations","Promise","all","whereNotIn","targetCounterparts","sourceCounterparts","relation","targetCounterpart","filter","Boolean","sourceCounterpart","sync","targetEntries","relationData","targetEntriesByLocale","idMapping","sourceEntry","targetEntry","batchSize","dialect","getBatchInsertSize","sourceColumn","targetColumn","newRelations","oldSourceId","oldTargetId","newSourceId","newTargetId","omit","identifiers","ID_COLUMN","pairKey","r","seenPairs","deduped","key","has","add","newSourceIds","existingRows","existingSet","toUpdate","toInsert","sourceId","targetId","dataToRestore","fromEntries","orderColumnName","inverseOrderColumnName","columnName","keys","resolve","where","update","batchInsert"],"mappings":"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"}
1
+ {"version":3,"file":"self-referential-relations.js","sources":["../../../../src/services/document-service/utils/self-referential-relations.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport { keyBy, omit } from 'lodash';\nimport type { Data, UID } from '@strapi/types';\nimport type { Database, JoinTable } from '@strapi/database';\n\ninterface VersionEntry {\n id: Data.ID;\n locale: string;\n}\n\ninterface RelationData {\n joinTable: JoinTable;\n relations: Record<string, unknown>[];\n remap?: {\n source: boolean;\n target: boolean;\n };\n}\n\ntype TargetStatus = 'draft' | 'published';\ntype DatabaseQueryBuilder = ReturnType<Database['getConnection']>;\ntype DatabaseTransaction = Parameters<DatabaseQueryBuilder['transacting']>[0];\n\nconst entryKey = (entry: { document_id: unknown; locale: unknown }) =>\n `${String(entry.document_id)}:${String(entry.locale)}`;\n\nconst getCounterparts = async (\n trx: DatabaseTransaction,\n tableName: string,\n idsToResolve: unknown[],\n status: TargetStatus\n): Promise<Record<string, Data.ID>> => {\n const ids = [...new Set(idsToResolve.map((id) => String(id)))];\n\n if (ids.length === 0) {\n return {};\n }\n\n const drafts = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('id', ids)\n .transacting(trx);\n\n if (drafts.length === 0) {\n return {};\n }\n\n const documentIds = [\n ...new Set(drafts.map((entry: { document_id: Data.ID }) => entry.document_id)),\n ];\n\n const counterpartsQuery = strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('document_id', documentIds)\n .transacting(trx);\n\n const counterparts =\n status === 'published'\n ? await counterpartsQuery.whereNotNull('published_at')\n : await counterpartsQuery.whereNull('published_at');\n\n const counterpartByDocument = keyBy(counterparts, entryKey);\n\n return drafts.reduce(\n (\n acc: Record<string, Data.ID>,\n draft: { id: Data.ID; document_id: unknown; locale: unknown }\n ) => {\n const counterpart = counterpartByDocument[entryKey(draft)];\n\n if (counterpart) {\n acc[String(draft.id)] = counterpart.id;\n }\n\n return acc;\n },\n {}\n );\n};\n\n/**\n * Preserves self-referential relations during publish/discard operations.\n *\n * When publishing or discarding a draft, self-referential relations (where both sides\n * of the relation belong to the same content type) are lost because:\n *\n * 1. The old entry is deleted\n * 2. A new entry is created with relations resolved via documentId → entity ID mapping\n * 3. At mapping time, the old entity is already deleted and the new one doesn't exist yet\n * 4. The relation is silently dropped\n *\n * This utility:\n * 1. Captures self-referential join table rows before deletion\n * 2. Remaps old entity IDs to new entity IDs after creation\n * 3. Inserts the remapped relations\n */\n\n/**\n * Loads self-referential relations from source entries before they are deleted/recreated.\n */\nconst load = async (\n uid: UID.ContentType,\n sourceEntries: VersionEntry[],\n targetStatus: TargetStatus\n): Promise<RelationData[]> => {\n const updates: RelationData[] = [];\n const dbModel = strapi.db.metadata.get(uid);\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const attribute of Object.values(dbModel.attributes) as any) {\n if (attribute.type !== 'relation' || attribute.target !== uid) {\n continue;\n }\n\n // Bidirectional inverse side (e.g. `children` mappedBy `parent`) shares the same physical\n // join table as the owning attribute; processing both would duplicate rows and inserts.\n if (attribute.mappedBy) {\n continue;\n }\n\n const joinTable = attribute.joinTable;\n if (!joinTable) {\n continue;\n }\n\n const { name: sourceColumnName } = joinTable.joinColumn;\n const { name: targetColumnName } = joinTable.inverseJoinColumn;\n\n const sourceIds = sourceEntries.map((entry) => String(entry.id));\n\n // Load relations where both source and target are among the entries being processed.\n // These are the self-referential relations that would be lost during the\n // delete-and-recreate cycle.\n const selfRelations = await strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(sourceColumnName, sourceIds)\n .whereIn(targetColumnName, sourceIds)\n .transacting(trx);\n\n if (selfRelations.length > 0) {\n updates.push({\n joinTable,\n relations: selfRelations,\n remap: { source: true, target: true },\n });\n }\n\n // Use rows from the state being copied as the source of truth for one-sided\n // self-relations. Publishing maps untouched targets to published counterparts and drops\n // draft-only targets; discarding maps untouched targets to draft counterparts. This avoids\n // restoring stale old rows that were removed from the copied state.\n const [sourceDraftRelations, targetDraftRelations] = await Promise.all([\n strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(sourceColumnName, sourceIds)\n .whereNotIn(targetColumnName, sourceIds)\n .transacting(trx),\n strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(targetColumnName, sourceIds)\n .whereNotIn(sourceColumnName, sourceIds)\n .transacting(trx),\n ]);\n\n const [targetCounterparts, sourceCounterparts] = await Promise.all([\n getCounterparts(\n trx,\n dbModel.tableName,\n sourceDraftRelations.map((relation) => relation[targetColumnName]),\n targetStatus\n ),\n getCounterparts(\n trx,\n dbModel.tableName,\n targetDraftRelations.map((relation) => relation[sourceColumnName]),\n targetStatus\n ),\n ]);\n\n if (sourceDraftRelations.length > 0) {\n const relations = sourceDraftRelations\n .map((relation) => {\n const targetCounterpart = targetCounterparts[String(relation[targetColumnName])];\n\n if (targetCounterpart == null) {\n return null;\n }\n\n return { ...relation, [targetColumnName]: targetCounterpart };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n if (relations.length > 0) {\n updates.push({\n joinTable,\n relations,\n remap: { source: true, target: false },\n });\n }\n }\n\n if (targetDraftRelations.length > 0) {\n const relations = targetDraftRelations\n .map((relation) => {\n const sourceCounterpart = sourceCounterparts[String(relation[sourceColumnName])];\n\n if (sourceCounterpart == null) {\n return null;\n }\n\n return { ...relation, [sourceColumnName]: sourceCounterpart };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n if (relations.length > 0) {\n updates.push({\n joinTable,\n relations,\n remap: { source: false, target: true },\n });\n }\n }\n\n // One-sided rows from the replaced state are intentionally not restored here. The rows\n // captured above represent the current logical relation set; restoring stale old rows can\n // resurrect relations that were removed before publishing or discarding.\n }\n });\n\n return updates;\n};\n\n/**\n * Syncs self-referential relations by remapping old entry IDs to new entry IDs\n * and inserting the remapped relations into the join table.\n */\nconst sync = async (\n sourceEntries: VersionEntry[],\n targetEntries: VersionEntry[],\n relationData: RelationData[]\n) => {\n if (relationData.length === 0) return;\n\n const targetEntriesByLocale = keyBy(targetEntries, 'locale');\n\n // Keys stringified for object lookup; values keep the original DB type so PostgreSQL integer columns receive integers, not strings\n const idMapping = sourceEntries.reduce(\n (acc, sourceEntry) => {\n const targetEntry = targetEntriesByLocale[sourceEntry.locale];\n if (!targetEntry) return acc;\n acc[String(sourceEntry.id)] = targetEntry.id;\n return acc;\n },\n {} as Record<string, Data.ID>\n );\n\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const { joinTable, relations, remap = { source: true, target: true } } of relationData) {\n const sourceColumn = joinTable.joinColumn.name;\n const targetColumn = joinTable.inverseJoinColumn.name;\n\n const newRelations = relations\n .map((relation) => {\n const oldSourceId = String(relation[sourceColumn]);\n const oldTargetId = String(relation[targetColumn]);\n const newSourceId = remap.source ? idMapping[oldSourceId] : relation[sourceColumn];\n const newTargetId = remap.target ? idMapping[oldTargetId] : relation[targetColumn];\n\n // Any side being remapped must resolve to a new entry.\n if (newSourceId == null || newTargetId == null) return null;\n\n return {\n ...omit(relation, strapi.db.metadata.identifiers.ID_COLUMN),\n [sourceColumn]: newSourceId,\n [targetColumn]: newTargetId,\n };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n const pairKey = (r: Record<string, unknown>) =>\n `${String(r[sourceColumn])}:${String(r[targetColumn])}`;\n const seenPairs = new Set<string>();\n const deduped = newRelations.filter((r) => {\n const key = pairKey(r);\n if (seenPairs.has(key)) return false;\n seenPairs.add(key);\n return true;\n });\n\n if (deduped.length === 0) continue;\n\n // Relation writes may have already recreated the remapped pair. In that case restore\n // the saved join-row metadata (notably order columns) instead of inserting a duplicate.\n const newSourceIds = [...new Set(deduped.map((r) => String(r[sourceColumn])))];\n const existingRows = await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .select(sourceColumn, targetColumn);\n\n const existingSet = new Set(existingRows.map((r: Record<string, unknown>) => pairKey(r)));\n const toUpdate = deduped.filter((r) => existingSet.has(pairKey(r)));\n const toInsert = deduped.filter((r) => !existingSet.has(pairKey(r)));\n\n await Promise.all(\n toUpdate.map((relation) => {\n const sourceId = relation[sourceColumn];\n const targetId = relation[targetColumn];\n const dataToRestore = Object.fromEntries(\n [joinTable.orderColumnName, joinTable.inverseOrderColumnName]\n .filter((columnName): columnName is string => columnName != null)\n .filter((columnName) => columnName in relation)\n .map((columnName) => [columnName, relation[columnName]])\n );\n\n if (Object.keys(dataToRestore).length === 0) {\n return Promise.resolve();\n }\n\n return trx(joinTable.name)\n .where({ [sourceColumn]: sourceId, [targetColumn]: targetId })\n .update(dataToRestore);\n })\n );\n\n if (toInsert.length > 0) {\n await trx.batchInsert(joinTable.name, toInsert as any[], batchSize);\n }\n }\n });\n};\n\nexport { load, sync };\n"],"names":["entryKey","entry","String","document_id","locale","getCounterparts","trx","tableName","idsToResolve","status","ids","Set","map","id","length","drafts","strapi","db","getConnection","select","from","whereIn","transacting","documentIds","counterpartsQuery","counterparts","whereNotNull","whereNull","counterpartByDocument","keyBy","reduce","acc","draft","counterpart","load","uid","sourceEntries","targetStatus","updates","dbModel","metadata","get","transaction","attribute","Object","values","attributes","type","target","mappedBy","joinTable","name","sourceColumnName","joinColumn","targetColumnName","inverseJoinColumn","sourceIds","selfRelations","push","relations","remap","source","sourceDraftRelations","targetDraftRelations","Promise","all","whereNotIn","targetCounterparts","sourceCounterparts","relation","targetCounterpart","filter","Boolean","sourceCounterpart","sync","targetEntries","relationData","targetEntriesByLocale","idMapping","sourceEntry","targetEntry","batchSize","dialect","getBatchInsertSize","sourceColumn","targetColumn","newRelations","oldSourceId","oldTargetId","newSourceId","newTargetId","omit","identifiers","ID_COLUMN","pairKey","r","seenPairs","deduped","key","has","add","newSourceIds","existingRows","existingSet","toUpdate","toInsert","sourceId","targetId","dataToRestore","fromEntries","orderColumnName","inverseOrderColumnName","columnName","keys","resolve","where","update","batchInsert"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { keyBy, omit } from 'lodash/fp';
1
+ import { keyBy, omit } from 'lodash';
2
2
 
3
3
  const entryKey = (entry)=>`${String(entry.document_id)}:${String(entry.locale)}`;
4
4
  const getCounterparts = async (trx, tableName, idsToResolve, status)=>{
@@ -17,7 +17,7 @@ const getCounterparts = async (trx, tableName, idsToResolve, status)=>{
17
17
  ];
18
18
  const counterpartsQuery = strapi.db.getConnection().select('id', 'document_id', 'locale').from(tableName).whereIn('document_id', documentIds).transacting(trx);
19
19
  const counterparts = status === 'published' ? await counterpartsQuery.whereNotNull('published_at') : await counterpartsQuery.whereNull('published_at');
20
- const counterpartByDocument = keyBy(entryKey, counterparts);
20
+ const counterpartByDocument = keyBy(counterparts, entryKey);
21
21
  return drafts.reduce((acc, draft)=>{
22
22
  const counterpart = counterpartByDocument[entryKey(draft)];
23
23
  if (counterpart) {
@@ -145,7 +145,7 @@ const getCounterparts = async (trx, tableName, idsToResolve, status)=>{
145
145
  * and inserting the remapped relations into the join table.
146
146
  */ const sync = async (sourceEntries, targetEntries, relationData)=>{
147
147
  if (relationData.length === 0) return;
148
- const targetEntriesByLocale = keyBy('locale', targetEntries);
148
+ const targetEntriesByLocale = keyBy(targetEntries, 'locale');
149
149
  // Keys stringified for object lookup; values keep the original DB type so PostgreSQL integer columns receive integers, not strings
150
150
  const idMapping = sourceEntries.reduce((acc, sourceEntry)=>{
151
151
  const targetEntry = targetEntriesByLocale[sourceEntry.locale];
@@ -169,7 +169,7 @@ const getCounterparts = async (trx, tableName, idsToResolve, status)=>{
169
169
  // Any side being remapped must resolve to a new entry.
170
170
  if (newSourceId == null || newTargetId == null) return null;
171
171
  return {
172
- ...omit(strapi.db.metadata.identifiers.ID_COLUMN, relation),
172
+ ...omit(relation, strapi.db.metadata.identifiers.ID_COLUMN),
173
173
  [sourceColumn]: newSourceId,
174
174
  [targetColumn]: newTargetId
175
175
  };
@@ -1 +1 @@
1
- {"version":3,"file":"self-referential-relations.mjs","sources":["../../../../src/services/document-service/utils/self-referential-relations.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport { keyBy, omit } from 'lodash/fp';\nimport type { Data, UID } from '@strapi/types';\nimport type { Database, JoinTable } from '@strapi/database';\n\ninterface VersionEntry {\n id: Data.ID;\n locale: string;\n}\n\ninterface RelationData {\n joinTable: JoinTable;\n relations: Record<string, unknown>[];\n remap?: {\n source: boolean;\n target: boolean;\n };\n}\n\ntype TargetStatus = 'draft' | 'published';\ntype DatabaseQueryBuilder = ReturnType<Database['getConnection']>;\ntype DatabaseTransaction = Parameters<DatabaseQueryBuilder['transacting']>[0];\n\nconst entryKey = (entry: { document_id: unknown; locale: unknown }) =>\n `${String(entry.document_id)}:${String(entry.locale)}`;\n\nconst getCounterparts = async (\n trx: DatabaseTransaction,\n tableName: string,\n idsToResolve: unknown[],\n status: TargetStatus\n): Promise<Record<string, Data.ID>> => {\n const ids = [...new Set(idsToResolve.map((id) => String(id)))];\n\n if (ids.length === 0) {\n return {};\n }\n\n const drafts = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('id', ids)\n .transacting(trx);\n\n if (drafts.length === 0) {\n return {};\n }\n\n const documentIds = [\n ...new Set(drafts.map((entry: { document_id: Data.ID }) => entry.document_id)),\n ];\n\n const counterpartsQuery = strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('document_id', documentIds)\n .transacting(trx);\n\n const counterparts =\n status === 'published'\n ? await counterpartsQuery.whereNotNull('published_at')\n : await counterpartsQuery.whereNull('published_at');\n\n const counterpartByDocument = keyBy(entryKey, counterparts);\n\n return drafts.reduce(\n (\n acc: Record<string, Data.ID>,\n draft: { id: Data.ID; document_id: unknown; locale: unknown }\n ) => {\n const counterpart = counterpartByDocument[entryKey(draft)];\n\n if (counterpart) {\n acc[String(draft.id)] = counterpart.id;\n }\n\n return acc;\n },\n {}\n );\n};\n\n/**\n * Preserves self-referential relations during publish/discard operations.\n *\n * When publishing or discarding a draft, self-referential relations (where both sides\n * of the relation belong to the same content type) are lost because:\n *\n * 1. The old entry is deleted\n * 2. A new entry is created with relations resolved via documentId → entity ID mapping\n * 3. At mapping time, the old entity is already deleted and the new one doesn't exist yet\n * 4. The relation is silently dropped\n *\n * This utility:\n * 1. Captures self-referential join table rows before deletion\n * 2. Remaps old entity IDs to new entity IDs after creation\n * 3. Inserts the remapped relations\n */\n\n/**\n * Loads self-referential relations from source entries before they are deleted/recreated.\n */\nconst load = async (\n uid: UID.ContentType,\n sourceEntries: VersionEntry[],\n targetStatus: TargetStatus\n): Promise<RelationData[]> => {\n const updates: RelationData[] = [];\n const dbModel = strapi.db.metadata.get(uid);\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const attribute of Object.values(dbModel.attributes) as any) {\n if (attribute.type !== 'relation' || attribute.target !== uid) {\n continue;\n }\n\n // Bidirectional inverse side (e.g. `children` mappedBy `parent`) shares the same physical\n // join table as the owning attribute; processing both would duplicate rows and inserts.\n if (attribute.mappedBy) {\n continue;\n }\n\n const joinTable = attribute.joinTable;\n if (!joinTable) {\n continue;\n }\n\n const { name: sourceColumnName } = joinTable.joinColumn;\n const { name: targetColumnName } = joinTable.inverseJoinColumn;\n\n const sourceIds = sourceEntries.map((entry) => String(entry.id));\n\n // Load relations where both source and target are among the entries being processed.\n // These are the self-referential relations that would be lost during the\n // delete-and-recreate cycle.\n const selfRelations = await strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(sourceColumnName, sourceIds)\n .whereIn(targetColumnName, sourceIds)\n .transacting(trx);\n\n if (selfRelations.length > 0) {\n updates.push({\n joinTable,\n relations: selfRelations,\n remap: { source: true, target: true },\n });\n }\n\n // Use rows from the state being copied as the source of truth for one-sided\n // self-relations. Publishing maps untouched targets to published counterparts and drops\n // draft-only targets; discarding maps untouched targets to draft counterparts. This avoids\n // restoring stale old rows that were removed from the copied state.\n const [sourceDraftRelations, targetDraftRelations] = await Promise.all([\n strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(sourceColumnName, sourceIds)\n .whereNotIn(targetColumnName, sourceIds)\n .transacting(trx),\n strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(targetColumnName, sourceIds)\n .whereNotIn(sourceColumnName, sourceIds)\n .transacting(trx),\n ]);\n\n const [targetCounterparts, sourceCounterparts] = await Promise.all([\n getCounterparts(\n trx,\n dbModel.tableName,\n sourceDraftRelations.map((relation) => relation[targetColumnName]),\n targetStatus\n ),\n getCounterparts(\n trx,\n dbModel.tableName,\n targetDraftRelations.map((relation) => relation[sourceColumnName]),\n targetStatus\n ),\n ]);\n\n if (sourceDraftRelations.length > 0) {\n const relations = sourceDraftRelations\n .map((relation) => {\n const targetCounterpart = targetCounterparts[String(relation[targetColumnName])];\n\n if (targetCounterpart == null) {\n return null;\n }\n\n return { ...relation, [targetColumnName]: targetCounterpart };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n if (relations.length > 0) {\n updates.push({\n joinTable,\n relations,\n remap: { source: true, target: false },\n });\n }\n }\n\n if (targetDraftRelations.length > 0) {\n const relations = targetDraftRelations\n .map((relation) => {\n const sourceCounterpart = sourceCounterparts[String(relation[sourceColumnName])];\n\n if (sourceCounterpart == null) {\n return null;\n }\n\n return { ...relation, [sourceColumnName]: sourceCounterpart };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n if (relations.length > 0) {\n updates.push({\n joinTable,\n relations,\n remap: { source: false, target: true },\n });\n }\n }\n\n // One-sided rows from the replaced state are intentionally not restored here. The rows\n // captured above represent the current logical relation set; restoring stale old rows can\n // resurrect relations that were removed before publishing or discarding.\n }\n });\n\n return updates;\n};\n\n/**\n * Syncs self-referential relations by remapping old entry IDs to new entry IDs\n * and inserting the remapped relations into the join table.\n */\nconst sync = async (\n sourceEntries: VersionEntry[],\n targetEntries: VersionEntry[],\n relationData: RelationData[]\n) => {\n if (relationData.length === 0) return;\n\n const targetEntriesByLocale = keyBy('locale', targetEntries);\n\n // Keys stringified for object lookup; values keep the original DB type so PostgreSQL integer columns receive integers, not strings\n const idMapping = sourceEntries.reduce(\n (acc, sourceEntry) => {\n const targetEntry = targetEntriesByLocale[sourceEntry.locale];\n if (!targetEntry) return acc;\n acc[String(sourceEntry.id)] = targetEntry.id;\n return acc;\n },\n {} as Record<string, Data.ID>\n );\n\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const { joinTable, relations, remap = { source: true, target: true } } of relationData) {\n const sourceColumn = joinTable.joinColumn.name;\n const targetColumn = joinTable.inverseJoinColumn.name;\n\n const newRelations = relations\n .map((relation) => {\n const oldSourceId = String(relation[sourceColumn]);\n const oldTargetId = String(relation[targetColumn]);\n const newSourceId = remap.source ? idMapping[oldSourceId] : relation[sourceColumn];\n const newTargetId = remap.target ? idMapping[oldTargetId] : relation[targetColumn];\n\n // Any side being remapped must resolve to a new entry.\n if (newSourceId == null || newTargetId == null) return null;\n\n return {\n ...omit(strapi.db.metadata.identifiers.ID_COLUMN, relation),\n [sourceColumn]: newSourceId,\n [targetColumn]: newTargetId,\n };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n const pairKey = (r: Record<string, unknown>) =>\n `${String(r[sourceColumn])}:${String(r[targetColumn])}`;\n const seenPairs = new Set<string>();\n const deduped = newRelations.filter((r) => {\n const key = pairKey(r);\n if (seenPairs.has(key)) return false;\n seenPairs.add(key);\n return true;\n });\n\n if (deduped.length === 0) continue;\n\n // Relation writes may have already recreated the remapped pair. In that case restore\n // the saved join-row metadata (notably order columns) instead of inserting a duplicate.\n const newSourceIds = [...new Set(deduped.map((r) => String(r[sourceColumn])))];\n const existingRows = await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .select(sourceColumn, targetColumn);\n\n const existingSet = new Set(existingRows.map((r: Record<string, unknown>) => pairKey(r)));\n const toUpdate = deduped.filter((r) => existingSet.has(pairKey(r)));\n const toInsert = deduped.filter((r) => !existingSet.has(pairKey(r)));\n\n await Promise.all(\n toUpdate.map((relation) => {\n const sourceId = relation[sourceColumn];\n const targetId = relation[targetColumn];\n const dataToRestore = Object.fromEntries(\n [joinTable.orderColumnName, joinTable.inverseOrderColumnName]\n .filter((columnName): columnName is string => columnName != null)\n .filter((columnName) => columnName in relation)\n .map((columnName) => [columnName, relation[columnName]])\n );\n\n if (Object.keys(dataToRestore).length === 0) {\n return Promise.resolve();\n }\n\n return trx(joinTable.name)\n .where({ [sourceColumn]: sourceId, [targetColumn]: targetId })\n .update(dataToRestore);\n })\n );\n\n if (toInsert.length > 0) {\n await trx.batchInsert(joinTable.name, toInsert as any[], batchSize);\n }\n }\n });\n};\n\nexport { load, sync };\n"],"names":["entryKey","entry","String","document_id","locale","getCounterparts","trx","tableName","idsToResolve","status","ids","Set","map","id","length","drafts","strapi","db","getConnection","select","from","whereIn","transacting","documentIds","counterpartsQuery","counterparts","whereNotNull","whereNull","counterpartByDocument","keyBy","reduce","acc","draft","counterpart","load","uid","sourceEntries","targetStatus","updates","dbModel","metadata","get","transaction","attribute","Object","values","attributes","type","target","mappedBy","joinTable","name","sourceColumnName","joinColumn","targetColumnName","inverseJoinColumn","sourceIds","selfRelations","push","relations","remap","source","sourceDraftRelations","targetDraftRelations","Promise","all","whereNotIn","targetCounterparts","sourceCounterparts","relation","targetCounterpart","filter","Boolean","sourceCounterpart","sync","targetEntries","relationData","targetEntriesByLocale","idMapping","sourceEntry","targetEntry","batchSize","dialect","getBatchInsertSize","sourceColumn","targetColumn","newRelations","oldSourceId","oldTargetId","newSourceId","newTargetId","omit","identifiers","ID_COLUMN","pairKey","r","seenPairs","deduped","key","has","add","newSourceIds","existingRows","existingSet","toUpdate","toInsert","sourceId","targetId","dataToRestore","fromEntries","orderColumnName","inverseOrderColumnName","columnName","keys","resolve","where","update","batchInsert"],"mappings":"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"}
1
+ {"version":3,"file":"self-referential-relations.mjs","sources":["../../../../src/services/document-service/utils/self-referential-relations.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport { keyBy, omit } from 'lodash';\nimport type { Data, UID } from '@strapi/types';\nimport type { Database, JoinTable } from '@strapi/database';\n\ninterface VersionEntry {\n id: Data.ID;\n locale: string;\n}\n\ninterface RelationData {\n joinTable: JoinTable;\n relations: Record<string, unknown>[];\n remap?: {\n source: boolean;\n target: boolean;\n };\n}\n\ntype TargetStatus = 'draft' | 'published';\ntype DatabaseQueryBuilder = ReturnType<Database['getConnection']>;\ntype DatabaseTransaction = Parameters<DatabaseQueryBuilder['transacting']>[0];\n\nconst entryKey = (entry: { document_id: unknown; locale: unknown }) =>\n `${String(entry.document_id)}:${String(entry.locale)}`;\n\nconst getCounterparts = async (\n trx: DatabaseTransaction,\n tableName: string,\n idsToResolve: unknown[],\n status: TargetStatus\n): Promise<Record<string, Data.ID>> => {\n const ids = [...new Set(idsToResolve.map((id) => String(id)))];\n\n if (ids.length === 0) {\n return {};\n }\n\n const drafts = await strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('id', ids)\n .transacting(trx);\n\n if (drafts.length === 0) {\n return {};\n }\n\n const documentIds = [\n ...new Set(drafts.map((entry: { document_id: Data.ID }) => entry.document_id)),\n ];\n\n const counterpartsQuery = strapi.db\n .getConnection()\n .select('id', 'document_id', 'locale')\n .from(tableName)\n .whereIn('document_id', documentIds)\n .transacting(trx);\n\n const counterparts =\n status === 'published'\n ? await counterpartsQuery.whereNotNull('published_at')\n : await counterpartsQuery.whereNull('published_at');\n\n const counterpartByDocument = keyBy(counterparts, entryKey);\n\n return drafts.reduce(\n (\n acc: Record<string, Data.ID>,\n draft: { id: Data.ID; document_id: unknown; locale: unknown }\n ) => {\n const counterpart = counterpartByDocument[entryKey(draft)];\n\n if (counterpart) {\n acc[String(draft.id)] = counterpart.id;\n }\n\n return acc;\n },\n {}\n );\n};\n\n/**\n * Preserves self-referential relations during publish/discard operations.\n *\n * When publishing or discarding a draft, self-referential relations (where both sides\n * of the relation belong to the same content type) are lost because:\n *\n * 1. The old entry is deleted\n * 2. A new entry is created with relations resolved via documentId → entity ID mapping\n * 3. At mapping time, the old entity is already deleted and the new one doesn't exist yet\n * 4. The relation is silently dropped\n *\n * This utility:\n * 1. Captures self-referential join table rows before deletion\n * 2. Remaps old entity IDs to new entity IDs after creation\n * 3. Inserts the remapped relations\n */\n\n/**\n * Loads self-referential relations from source entries before they are deleted/recreated.\n */\nconst load = async (\n uid: UID.ContentType,\n sourceEntries: VersionEntry[],\n targetStatus: TargetStatus\n): Promise<RelationData[]> => {\n const updates: RelationData[] = [];\n const dbModel = strapi.db.metadata.get(uid);\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const attribute of Object.values(dbModel.attributes) as any) {\n if (attribute.type !== 'relation' || attribute.target !== uid) {\n continue;\n }\n\n // Bidirectional inverse side (e.g. `children` mappedBy `parent`) shares the same physical\n // join table as the owning attribute; processing both would duplicate rows and inserts.\n if (attribute.mappedBy) {\n continue;\n }\n\n const joinTable = attribute.joinTable;\n if (!joinTable) {\n continue;\n }\n\n const { name: sourceColumnName } = joinTable.joinColumn;\n const { name: targetColumnName } = joinTable.inverseJoinColumn;\n\n const sourceIds = sourceEntries.map((entry) => String(entry.id));\n\n // Load relations where both source and target are among the entries being processed.\n // These are the self-referential relations that would be lost during the\n // delete-and-recreate cycle.\n const selfRelations = await strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(sourceColumnName, sourceIds)\n .whereIn(targetColumnName, sourceIds)\n .transacting(trx);\n\n if (selfRelations.length > 0) {\n updates.push({\n joinTable,\n relations: selfRelations,\n remap: { source: true, target: true },\n });\n }\n\n // Use rows from the state being copied as the source of truth for one-sided\n // self-relations. Publishing maps untouched targets to published counterparts and drops\n // draft-only targets; discarding maps untouched targets to draft counterparts. This avoids\n // restoring stale old rows that were removed from the copied state.\n const [sourceDraftRelations, targetDraftRelations] = await Promise.all([\n strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(sourceColumnName, sourceIds)\n .whereNotIn(targetColumnName, sourceIds)\n .transacting(trx),\n strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(targetColumnName, sourceIds)\n .whereNotIn(sourceColumnName, sourceIds)\n .transacting(trx),\n ]);\n\n const [targetCounterparts, sourceCounterparts] = await Promise.all([\n getCounterparts(\n trx,\n dbModel.tableName,\n sourceDraftRelations.map((relation) => relation[targetColumnName]),\n targetStatus\n ),\n getCounterparts(\n trx,\n dbModel.tableName,\n targetDraftRelations.map((relation) => relation[sourceColumnName]),\n targetStatus\n ),\n ]);\n\n if (sourceDraftRelations.length > 0) {\n const relations = sourceDraftRelations\n .map((relation) => {\n const targetCounterpart = targetCounterparts[String(relation[targetColumnName])];\n\n if (targetCounterpart == null) {\n return null;\n }\n\n return { ...relation, [targetColumnName]: targetCounterpart };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n if (relations.length > 0) {\n updates.push({\n joinTable,\n relations,\n remap: { source: true, target: false },\n });\n }\n }\n\n if (targetDraftRelations.length > 0) {\n const relations = targetDraftRelations\n .map((relation) => {\n const sourceCounterpart = sourceCounterparts[String(relation[sourceColumnName])];\n\n if (sourceCounterpart == null) {\n return null;\n }\n\n return { ...relation, [sourceColumnName]: sourceCounterpart };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n if (relations.length > 0) {\n updates.push({\n joinTable,\n relations,\n remap: { source: false, target: true },\n });\n }\n }\n\n // One-sided rows from the replaced state are intentionally not restored here. The rows\n // captured above represent the current logical relation set; restoring stale old rows can\n // resurrect relations that were removed before publishing or discarding.\n }\n });\n\n return updates;\n};\n\n/**\n * Syncs self-referential relations by remapping old entry IDs to new entry IDs\n * and inserting the remapped relations into the join table.\n */\nconst sync = async (\n sourceEntries: VersionEntry[],\n targetEntries: VersionEntry[],\n relationData: RelationData[]\n) => {\n if (relationData.length === 0) return;\n\n const targetEntriesByLocale = keyBy(targetEntries, 'locale');\n\n // Keys stringified for object lookup; values keep the original DB type so PostgreSQL integer columns receive integers, not strings\n const idMapping = sourceEntries.reduce(\n (acc, sourceEntry) => {\n const targetEntry = targetEntriesByLocale[sourceEntry.locale];\n if (!targetEntry) return acc;\n acc[String(sourceEntry.id)] = targetEntry.id;\n return acc;\n },\n {} as Record<string, Data.ID>\n );\n\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n\n await strapi.db.transaction(async ({ trx }) => {\n for (const { joinTable, relations, remap = { source: true, target: true } } of relationData) {\n const sourceColumn = joinTable.joinColumn.name;\n const targetColumn = joinTable.inverseJoinColumn.name;\n\n const newRelations = relations\n .map((relation) => {\n const oldSourceId = String(relation[sourceColumn]);\n const oldTargetId = String(relation[targetColumn]);\n const newSourceId = remap.source ? idMapping[oldSourceId] : relation[sourceColumn];\n const newTargetId = remap.target ? idMapping[oldTargetId] : relation[targetColumn];\n\n // Any side being remapped must resolve to a new entry.\n if (newSourceId == null || newTargetId == null) return null;\n\n return {\n ...omit(relation, strapi.db.metadata.identifiers.ID_COLUMN),\n [sourceColumn]: newSourceId,\n [targetColumn]: newTargetId,\n };\n })\n .filter(Boolean) as Record<string, unknown>[];\n\n const pairKey = (r: Record<string, unknown>) =>\n `${String(r[sourceColumn])}:${String(r[targetColumn])}`;\n const seenPairs = new Set<string>();\n const deduped = newRelations.filter((r) => {\n const key = pairKey(r);\n if (seenPairs.has(key)) return false;\n seenPairs.add(key);\n return true;\n });\n\n if (deduped.length === 0) continue;\n\n // Relation writes may have already recreated the remapped pair. In that case restore\n // the saved join-row metadata (notably order columns) instead of inserting a duplicate.\n const newSourceIds = [...new Set(deduped.map((r) => String(r[sourceColumn])))];\n const existingRows = await trx(joinTable.name)\n .whereIn(sourceColumn, newSourceIds)\n .select(sourceColumn, targetColumn);\n\n const existingSet = new Set(existingRows.map((r: Record<string, unknown>) => pairKey(r)));\n const toUpdate = deduped.filter((r) => existingSet.has(pairKey(r)));\n const toInsert = deduped.filter((r) => !existingSet.has(pairKey(r)));\n\n await Promise.all(\n toUpdate.map((relation) => {\n const sourceId = relation[sourceColumn];\n const targetId = relation[targetColumn];\n const dataToRestore = Object.fromEntries(\n [joinTable.orderColumnName, joinTable.inverseOrderColumnName]\n .filter((columnName): columnName is string => columnName != null)\n .filter((columnName) => columnName in relation)\n .map((columnName) => [columnName, relation[columnName]])\n );\n\n if (Object.keys(dataToRestore).length === 0) {\n return Promise.resolve();\n }\n\n return trx(joinTable.name)\n .where({ [sourceColumn]: sourceId, [targetColumn]: targetId })\n .update(dataToRestore);\n })\n );\n\n if (toInsert.length > 0) {\n await trx.batchInsert(joinTable.name, toInsert as any[], batchSize);\n }\n }\n });\n};\n\nexport { load, sync };\n"],"names":["entryKey","entry","String","document_id","locale","getCounterparts","trx","tableName","idsToResolve","status","ids","Set","map","id","length","drafts","strapi","db","getConnection","select","from","whereIn","transacting","documentIds","counterpartsQuery","counterparts","whereNotNull","whereNull","counterpartByDocument","keyBy","reduce","acc","draft","counterpart","load","uid","sourceEntries","targetStatus","updates","dbModel","metadata","get","transaction","attribute","Object","values","attributes","type","target","mappedBy","joinTable","name","sourceColumnName","joinColumn","targetColumnName","inverseJoinColumn","sourceIds","selfRelations","push","relations","remap","source","sourceDraftRelations","targetDraftRelations","Promise","all","whereNotIn","targetCounterparts","sourceCounterparts","relation","targetCounterpart","filter","Boolean","sourceCounterpart","sync","targetEntries","relationData","targetEntriesByLocale","idMapping","sourceEntry","targetEntry","batchSize","dialect","getBatchInsertSize","sourceColumn","targetColumn","newRelations","oldSourceId","oldTargetId","newSourceId","newTargetId","omit","identifiers","ID_COLUMN","pairKey","r","seenPairs","deduped","key","has","add","newSourceIds","existingRows","existingSet","toUpdate","toInsert","sourceId","targetId","dataToRestore","fromEntries","orderColumnName","inverseOrderColumnName","columnName","keys","resolve","where","update","batchInsert"],"mappings":";;AAuBA,MAAMA,QAAAA,GAAW,CAACC,KAAAA,GAChB,CAAA,EAAGC,MAAAA,CAAOD,KAAAA,CAAME,WAAW,CAAA,CAAE,CAAC,EAAED,MAAAA,CAAOD,KAAAA,CAAMG,MAAM,CAAA,CAAA,CAAG;AAExD,MAAMC,eAAAA,GAAkB,OACtBC,GAAAA,EACAC,SAAAA,EACAC,YAAAA,EACAC,MAAAA,GAAAA;AAEA,IAAA,MAAMC,GAAAA,GAAM;AAAI,QAAA,GAAA,IAAIC,IAAIH,YAAAA,CAAaI,GAAG,CAAC,CAACC,KAAOX,MAAAA,CAAOW,EAAAA,CAAAA,CAAAA;AAAM,KAAA;IAE9D,IAAIH,GAAAA,CAAII,MAAM,KAAK,CAAA,EAAG;AACpB,QAAA,OAAO,EAAC;AACV,IAAA;IAEA,MAAMC,MAAAA,GAAS,MAAMC,MAAAA,CAAOC,EAAE,CAC3BC,aAAa,EAAA,CACbC,MAAM,CAAC,IAAA,EAAM,eAAe,QAAA,CAAA,CAC5BC,IAAI,CAACb,SAAAA,CAAAA,CACLc,OAAO,CAAC,IAAA,EAAMX,GAAAA,CAAAA,CACdY,WAAW,CAAChB,GAAAA,CAAAA;IAEf,IAAIS,MAAAA,CAAOD,MAAM,KAAK,CAAA,EAAG;AACvB,QAAA,OAAO,EAAC;AACV,IAAA;AAEA,IAAA,MAAMS,WAAAA,GAAc;AACf,QAAA,GAAA,IAAIZ,IAAII,MAAAA,CAAOH,GAAG,CAAC,CAACX,KAAAA,GAAoCA,MAAME,WAAW,CAAA;AAC7E,KAAA;AAED,IAAA,MAAMqB,oBAAoBR,MAAAA,CAAOC,EAAE,CAChCC,aAAa,EAAA,CACbC,MAAM,CAAC,IAAA,EAAM,eAAe,QAAA,CAAA,CAC5BC,IAAI,CAACb,SAAAA,CAAAA,CACLc,OAAO,CAAC,aAAA,EAAeE,WAAAA,CAAAA,CACvBD,WAAW,CAAChB,GAAAA,CAAAA;IAEf,MAAMmB,YAAAA,GACJhB,MAAAA,KAAW,WAAA,GACP,MAAMe,iBAAAA,CAAkBE,YAAY,CAAC,cAAA,CAAA,GACrC,MAAMF,iBAAAA,CAAkBG,SAAS,CAAC,cAAA,CAAA;IAExC,MAAMC,qBAAAA,GAAwBC,MAAMJ,YAAAA,EAAczB,QAAAA,CAAAA;AAElD,IAAA,OAAOe,MAAAA,CAAOe,MAAM,CAClB,CACEC,GAAAA,EACAC,KAAAA,GAAAA;AAEA,QAAA,MAAMC,WAAAA,GAAcL,qBAAqB,CAAC5B,QAAAA,CAASgC,KAAAA,CAAAA,CAAO;AAE1D,QAAA,IAAIC,WAAAA,EAAa;AACfF,YAAAA,GAAG,CAAC7B,MAAAA,CAAO8B,KAAAA,CAAMnB,EAAE,CAAA,CAAE,GAAGoB,YAAYpB,EAAE;AACxC,QAAA;QAEA,OAAOkB,GAAAA;AACT,IAAA,CAAA,EACA,EAAC,CAAA;AAEL,CAAA;AAEA;;;;;;;;;;;;;;;;;AAmBC,IACD,MAAMG,IAAAA,GAAO,OACXC,GAAAA,EACAC,aAAAA,EACAC,YAAAA,GAAAA;AAEA,IAAA,MAAMC,UAA0B,EAAE;AAClC,IAAA,MAAMC,UAAUvB,MAAAA,CAAOC,EAAE,CAACuB,QAAQ,CAACC,GAAG,CAACN,GAAAA,CAAAA;IAEvC,MAAMnB,MAAAA,CAAOC,EAAE,CAACyB,WAAW,CAAC,OAAO,EAAEpC,GAAG,EAAE,GAAA;AACxC,QAAA,KAAK,MAAMqC,SAAAA,IAAaC,MAAAA,CAAOC,MAAM,CAACN,OAAAA,CAAQO,UAAU,CAAA,CAAU;AAChE,YAAA,IAAIH,UAAUI,IAAI,KAAK,cAAcJ,SAAAA,CAAUK,MAAM,KAAKb,GAAAA,EAAK;AAC7D,gBAAA;AACF,YAAA;;;YAIA,IAAIQ,SAAAA,CAAUM,QAAQ,EAAE;AACtB,gBAAA;AACF,YAAA;YAEA,MAAMC,SAAAA,GAAYP,UAAUO,SAAS;AACrC,YAAA,IAAI,CAACA,SAAAA,EAAW;AACd,gBAAA;AACF,YAAA;AAEA,YAAA,MAAM,EAAEC,IAAAA,EAAMC,gBAAgB,EAAE,GAAGF,UAAUG,UAAU;AACvD,YAAA,MAAM,EAAEF,IAAAA,EAAMG,gBAAgB,EAAE,GAAGJ,UAAUK,iBAAiB;YAE9D,MAAMC,SAAAA,GAAYpB,cAAcxB,GAAG,CAAC,CAACX,KAAAA,GAAUC,MAAAA,CAAOD,MAAMY,EAAE,CAAA,CAAA;;;;YAK9D,MAAM4C,aAAAA,GAAgB,MAAMzC,MAAAA,CAAOC,EAAE,CAClCC,aAAa,EAAA,CACbC,MAAM,CAAC,GAAA,CAAA,CACPC,IAAI,CAAC8B,UAAUC,IAAI,CAAA,CACnB9B,OAAO,CAAC+B,gBAAAA,EAAkBI,SAAAA,CAAAA,CAC1BnC,OAAO,CAACiC,gBAAAA,EAAkBE,SAAAA,CAAAA,CAC1BlC,WAAW,CAAChB,GAAAA,CAAAA;YAEf,IAAImD,aAAAA,CAAc3C,MAAM,GAAG,CAAA,EAAG;AAC5BwB,gBAAAA,OAAAA,CAAQoB,IAAI,CAAC;AACXR,oBAAAA,SAAAA;oBACAS,SAAAA,EAAWF,aAAAA;oBACXG,KAAAA,EAAO;wBAAEC,MAAAA,EAAQ,IAAA;wBAAMb,MAAAA,EAAQ;AAAK;AACtC,iBAAA,CAAA;AACF,YAAA;;;;;AAMA,YAAA,MAAM,CAACc,oBAAAA,EAAsBC,oBAAAA,CAAqB,GAAG,MAAMC,OAAAA,CAAQC,GAAG,CAAC;gBACrEjD,MAAAA,CAAOC,EAAE,CACNC,aAAa,EAAA,CACbC,MAAM,CAAC,GAAA,CAAA,CACPC,IAAI,CAAC8B,SAAAA,CAAUC,IAAI,CAAA,CACnB9B,OAAO,CAAC+B,gBAAAA,EAAkBI,SAAAA,CAAAA,CAC1BU,UAAU,CAACZ,gBAAAA,EAAkBE,SAAAA,CAAAA,CAC7BlC,WAAW,CAAChB,GAAAA,CAAAA;gBACfU,MAAAA,CAAOC,EAAE,CACNC,aAAa,EAAA,CACbC,MAAM,CAAC,GAAA,CAAA,CACPC,IAAI,CAAC8B,SAAAA,CAAUC,IAAI,CAAA,CACnB9B,OAAO,CAACiC,gBAAAA,EAAkBE,SAAAA,CAAAA,CAC1BU,UAAU,CAACd,gBAAAA,EAAkBI,SAAAA,CAAAA,CAC7BlC,WAAW,CAAChB,GAAAA;AAChB,aAAA,CAAA;AAED,YAAA,MAAM,CAAC6D,kBAAAA,EAAoBC,kBAAAA,CAAmB,GAAG,MAAMJ,OAAAA,CAAQC,GAAG,CAAC;AACjE5D,gBAAAA,eAAAA,CACEC,GAAAA,EACAiC,OAAAA,CAAQhC,SAAS,EACjBuD,oBAAAA,CAAqBlD,GAAG,CAAC,CAACyD,QAAAA,GAAaA,QAAQ,CAACf,gBAAAA,CAAiB,CAAA,EACjEjB,YAAAA,CAAAA;AAEFhC,gBAAAA,eAAAA,CACEC,GAAAA,EACAiC,OAAAA,CAAQhC,SAAS,EACjBwD,oBAAAA,CAAqBnD,GAAG,CAAC,CAACyD,QAAAA,GAAaA,QAAQ,CAACjB,gBAAAA,CAAiB,CAAA,EACjEf,YAAAA;AAEH,aAAA,CAAA;YAED,IAAIyB,oBAAAA,CAAqBhD,MAAM,GAAG,CAAA,EAAG;AACnC,gBAAA,MAAM6C,SAAAA,GAAYG,oBAAAA,CACflD,GAAG,CAAC,CAACyD,QAAAA,GAAAA;AACJ,oBAAA,MAAMC,oBAAoBH,kBAAkB,CAACjE,OAAOmE,QAAQ,CAACf,iBAAiB,CAAA,CAAE;AAEhF,oBAAA,IAAIgB,qBAAqB,IAAA,EAAM;wBAC7B,OAAO,IAAA;AACT,oBAAA;oBAEA,OAAO;AAAE,wBAAA,GAAGD,QAAQ;AAAE,wBAAA,CAACf,mBAAmBgB;AAAkB,qBAAA;AAC9D,gBAAA,CAAA,CAAA,CACCC,MAAM,CAACC,OAAAA,CAAAA;gBAEV,IAAIb,SAAAA,CAAU7C,MAAM,GAAG,CAAA,EAAG;AACxBwB,oBAAAA,OAAAA,CAAQoB,IAAI,CAAC;AACXR,wBAAAA,SAAAA;AACAS,wBAAAA,SAAAA;wBACAC,KAAAA,EAAO;4BAAEC,MAAAA,EAAQ,IAAA;4BAAMb,MAAAA,EAAQ;AAAM;AACvC,qBAAA,CAAA;AACF,gBAAA;AACF,YAAA;YAEA,IAAIe,oBAAAA,CAAqBjD,MAAM,GAAG,CAAA,EAAG;AACnC,gBAAA,MAAM6C,SAAAA,GAAYI,oBAAAA,CACfnD,GAAG,CAAC,CAACyD,QAAAA,GAAAA;AACJ,oBAAA,MAAMI,oBAAoBL,kBAAkB,CAAClE,OAAOmE,QAAQ,CAACjB,iBAAiB,CAAA,CAAE;AAEhF,oBAAA,IAAIqB,qBAAqB,IAAA,EAAM;wBAC7B,OAAO,IAAA;AACT,oBAAA;oBAEA,OAAO;AAAE,wBAAA,GAAGJ,QAAQ;AAAE,wBAAA,CAACjB,mBAAmBqB;AAAkB,qBAAA;AAC9D,gBAAA,CAAA,CAAA,CACCF,MAAM,CAACC,OAAAA,CAAAA;gBAEV,IAAIb,SAAAA,CAAU7C,MAAM,GAAG,CAAA,EAAG;AACxBwB,oBAAAA,OAAAA,CAAQoB,IAAI,CAAC;AACXR,wBAAAA,SAAAA;AACAS,wBAAAA,SAAAA;wBACAC,KAAAA,EAAO;4BAAEC,MAAAA,EAAQ,KAAA;4BAAOb,MAAAA,EAAQ;AAAK;AACvC,qBAAA,CAAA;AACF,gBAAA;AACF,YAAA;;;;AAKF,QAAA;AACF,IAAA,CAAA,CAAA;IAEA,OAAOV,OAAAA;AACT;AAEA;;;AAGC,IACD,MAAMoC,IAAAA,GAAO,OACXtC,aAAAA,EACAuC,aAAAA,EACAC,YAAAA,GAAAA;IAEA,IAAIA,YAAAA,CAAa9D,MAAM,KAAK,CAAA,EAAG;IAE/B,MAAM+D,qBAAAA,GAAwBhD,MAAM8C,aAAAA,EAAe,QAAA,CAAA;;AAGnD,IAAA,MAAMG,SAAAA,GAAY1C,aAAAA,CAAcN,MAAM,CACpC,CAACC,GAAAA,EAAKgD,WAAAA,GAAAA;AACJ,QAAA,MAAMC,WAAAA,GAAcH,qBAAqB,CAACE,WAAAA,CAAY3E,MAAM,CAAC;QAC7D,IAAI,CAAC4E,aAAa,OAAOjD,GAAAA;AACzBA,QAAAA,GAAG,CAAC7B,MAAAA,CAAO6E,WAAAA,CAAYlE,EAAE,CAAA,CAAE,GAAGmE,YAAYnE,EAAE;QAC5C,OAAOkB,GAAAA;AACT,IAAA,CAAA,EACA,EAAC,CAAA;AAGH,IAAA,MAAMkD,YAAYjE,MAAAA,CAAOC,EAAE,CAACiE,OAAO,CAACC,kBAAkB,EAAA;IAEtD,MAAMnE,MAAAA,CAAOC,EAAE,CAACyB,WAAW,CAAC,OAAO,EAAEpC,GAAG,EAAE,GAAA;AACxC,QAAA,KAAK,MAAM,EAAE4C,SAAS,EAAES,SAAS,EAAEC,KAAAA,GAAQ;YAAEC,MAAAA,EAAQ,IAAA;YAAMb,MAAAA,EAAQ;SAAM,EAAE,IAAI4B,YAAAA,CAAc;AAC3F,YAAA,MAAMQ,YAAAA,GAAelC,SAAAA,CAAUG,UAAU,CAACF,IAAI;AAC9C,YAAA,MAAMkC,YAAAA,GAAenC,SAAAA,CAAUK,iBAAiB,CAACJ,IAAI;AAErD,YAAA,MAAMmC,YAAAA,GAAe3B,SAAAA,CAClB/C,GAAG,CAAC,CAACyD,QAAAA,GAAAA;AACJ,gBAAA,MAAMkB,WAAAA,GAAcrF,MAAAA,CAAOmE,QAAQ,CAACe,YAAAA,CAAa,CAAA;AACjD,gBAAA,MAAMI,WAAAA,GAActF,MAAAA,CAAOmE,QAAQ,CAACgB,YAAAA,CAAa,CAAA;gBACjD,MAAMI,WAAAA,GAAc7B,KAAAA,CAAMC,MAAM,GAAGiB,SAAS,CAACS,WAAAA,CAAY,GAAGlB,QAAQ,CAACe,YAAAA,CAAa;gBAClF,MAAMM,WAAAA,GAAc9B,KAAAA,CAAMZ,MAAM,GAAG8B,SAAS,CAACU,WAAAA,CAAY,GAAGnB,QAAQ,CAACgB,YAAAA,CAAa;;AAGlF,gBAAA,IAAII,WAAAA,IAAe,IAAA,IAAQC,WAAAA,IAAe,IAAA,EAAM,OAAO,IAAA;gBAEvD,OAAO;oBACL,GAAGC,IAAAA,CAAKtB,QAAAA,EAAUrD,MAAAA,CAAOC,EAAE,CAACuB,QAAQ,CAACoD,WAAW,CAACC,SAAS,CAAC;AAC3D,oBAAA,CAACT,eAAeK,WAAAA;AAChB,oBAAA,CAACJ,eAAeK;AAClB,iBAAA;AACF,YAAA,CAAA,CAAA,CACCnB,MAAM,CAACC,OAAAA,CAAAA;AAEV,YAAA,MAAMsB,OAAAA,GAAU,CAACC,CAAAA,GACf,CAAA,EAAG7F,OAAO6F,CAAC,CAACX,YAAAA,CAAa,CAAA,CAAE,CAAC,EAAElF,MAAAA,CAAO6F,CAAC,CAACV,aAAa,CAAA,CAAA,CAAG;AACzD,YAAA,MAAMW,YAAY,IAAIrF,GAAAA,EAAAA;AACtB,YAAA,MAAMsF,OAAAA,GAAUX,YAAAA,CAAaf,MAAM,CAAC,CAACwB,CAAAA,GAAAA;AACnC,gBAAA,MAAMG,MAAMJ,OAAAA,CAAQC,CAAAA,CAAAA;AACpB,gBAAA,IAAIC,SAAAA,CAAUG,GAAG,CAACD,GAAAA,CAAAA,EAAM,OAAO,KAAA;AAC/BF,gBAAAA,SAAAA,CAAUI,GAAG,CAACF,GAAAA,CAAAA;gBACd,OAAO,IAAA;AACT,YAAA,CAAA,CAAA;YAEA,IAAID,OAAAA,CAAQnF,MAAM,KAAK,CAAA,EAAG;;;AAI1B,YAAA,MAAMuF,YAAAA,GAAe;mBAAI,IAAI1F,GAAAA,CAAIsF,QAAQrF,GAAG,CAAC,CAACmF,CAAAA,GAAM7F,MAAAA,CAAO6F,CAAC,CAACX,YAAAA,CAAa,CAAA,CAAA;AAAI,aAAA;AAC9E,YAAA,MAAMkB,YAAAA,GAAe,MAAMhG,GAAAA,CAAI4C,SAAAA,CAAUC,IAAI,CAAA,CAC1C9B,OAAO,CAAC+D,YAAAA,EAAciB,YAAAA,CAAAA,CACtBlF,MAAM,CAACiE,YAAAA,EAAcC,YAAAA,CAAAA;YAExB,MAAMkB,WAAAA,GAAc,IAAI5F,GAAAA,CAAI2F,YAAAA,CAAa1F,GAAG,CAAC,CAACmF,IAA+BD,OAAAA,CAAQC,CAAAA,CAAAA,CAAAA,CAAAA;YACrF,MAAMS,QAAAA,GAAWP,QAAQ1B,MAAM,CAAC,CAACwB,CAAAA,GAAMQ,WAAAA,CAAYJ,GAAG,CAACL,OAAAA,CAAQC,CAAAA,CAAAA,CAAAA,CAAAA;YAC/D,MAAMU,QAAAA,GAAWR,OAAAA,CAAQ1B,MAAM,CAAC,CAACwB,IAAM,CAACQ,WAAAA,CAAYJ,GAAG,CAACL,OAAAA,CAAQC,CAAAA,CAAAA,CAAAA,CAAAA;AAEhE,YAAA,MAAM/B,QAAQC,GAAG,CACfuC,QAAAA,CAAS5F,GAAG,CAAC,CAACyD,QAAAA,GAAAA;gBACZ,MAAMqC,QAAAA,GAAWrC,QAAQ,CAACe,YAAAA,CAAa;gBACvC,MAAMuB,QAAAA,GAAWtC,QAAQ,CAACgB,YAAAA,CAAa;gBACvC,MAAMuB,aAAAA,GAAgBhE,MAAAA,CAAOiE,WAAW,CACtC;AAAC3D,oBAAAA,SAAAA,CAAU4D,eAAe;AAAE5D,oBAAAA,SAAAA,CAAU6D;AAAuB,iBAAA,CAC1DxC,MAAM,CAAC,CAACyC,UAAAA,GAAqCA,cAAc,IAAA,CAAA,CAC3DzC,MAAM,CAAC,CAACyC,aAAeA,UAAAA,IAAc3C,QAAAA,CAAAA,CACrCzD,GAAG,CAAC,CAACoG,UAAAA,GAAe;AAACA,wBAAAA,UAAAA;AAAY3C,wBAAAA,QAAQ,CAAC2C,UAAAA;AAAY,qBAAA,CAAA,CAAA;AAG3D,gBAAA,IAAIpE,OAAOqE,IAAI,CAACL,aAAAA,CAAAA,CAAe9F,MAAM,KAAK,CAAA,EAAG;AAC3C,oBAAA,OAAOkD,QAAQkD,OAAO,EAAA;AACxB,gBAAA;AAEA,gBAAA,OAAO5G,GAAAA,CAAI4C,SAAAA,CAAUC,IAAI,CAAA,CACtBgE,KAAK,CAAC;AAAE,oBAAA,CAAC/B,eAAesB,QAAAA;AAAU,oBAAA,CAACrB,eAAesB;AAAS,iBAAA,CAAA,CAC3DS,MAAM,CAACR,aAAAA,CAAAA;AACZ,YAAA,CAAA,CAAA,CAAA;YAGF,IAAIH,QAAAA,CAAS3F,MAAM,GAAG,CAAA,EAAG;AACvB,gBAAA,MAAMR,IAAI+G,WAAW,CAACnE,SAAAA,CAAUC,IAAI,EAAEsD,QAAAA,EAAmBxB,SAAAA,CAAAA;AAC3D,YAAA;AACF,QAAA;AACF,IAAA,CAAA,CAAA;AACF;;;;"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var fp = require('lodash/fp');
3
+ var _ = require('lodash');
4
4
 
5
5
  /**
6
6
  * Loads lingering relations that need to be updated when overriding a published or draft entry.
@@ -89,7 +89,7 @@ var fp = require('lodash/fp');
89
89
  return oldRelation[sourceColumnName] === relation[sourceColumnName];
90
90
  });
91
91
  return !matchingOldVersion;
92
- }).map(fp.omit(strapi.db.metadata.identifiers.ID_COLUMN));
92
+ }).map((value)=>_.omit(value, strapi.db.metadata.identifiers.ID_COLUMN));
93
93
  updates.push({
94
94
  joinTable,
95
95
  relations: discardToAdd
@@ -116,7 +116,7 @@ var fp = require('lodash/fp');
116
116
  * Create a map of old entry ids to new entry ids
117
117
  *
118
118
  * Will be used to update the relation target ids
119
- */ const newEntryByLocale = fp.keyBy('locale', newEntries);
119
+ */ const newEntryByLocale = _.keyBy(newEntries, 'locale');
120
120
  const oldEntriesMap = oldEntries.reduce((acc, entry)=>{
121
121
  const newEntry = newEntryByLocale[entry.locale];
122
122
  if (!newEntry) return acc;
@@ -1 +1 @@
1
- {"version":3,"file":"unidirectional-relations.js","sources":["../../../../src/services/document-service/utils/unidirectional-relations.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport { keyBy, omit } from 'lodash/fp';\n\nimport type { Data, UID, Schema } from '@strapi/types';\n\nimport type { JoinTable } from '@strapi/database';\n\ninterface LoadContext {\n oldVersions: { id: Data.ID; locale: string }[];\n newVersions: { id: Data.ID; locale: string }[];\n}\n\ninterface RelationUpdate {\n joinTable: JoinTable;\n relations: Record<string, any>[];\n}\n\ninterface RelationFilterOptions {\n /**\n * Function to determine if a relation should be propagated to new document versions\n * This replaces the hardcoded component-specific logic\n */\n shouldPropagateRelation?: (\n relation: Record<string, any>,\n model: Schema.Component | Schema.ContentType,\n trx: any\n ) => Promise<boolean>;\n}\n\n/**\n * Loads lingering relations that need to be updated when overriding a published or draft entry.\n * This is necessary because the relations are uni-directional and the target entry is not aware of the source entry.\n * This is not the case for bi-directional relations, where the target entry is also linked to the source entry.\n */\nconst load = async (\n uid: UID.ContentType,\n { oldVersions, newVersions }: LoadContext,\n options: RelationFilterOptions = {}\n): Promise<RelationUpdate[]> => {\n const updates: RelationUpdate[] = [];\n\n // Iterate all components and content types to find relations that need to be updated\n await strapi.db.transaction(async ({ trx }) => {\n const contentTypes = Object.values(strapi.contentTypes) as Schema.ContentType[];\n const components = Object.values(strapi.components) as Schema.Component[];\n\n for (const model of [...contentTypes, ...components]) {\n const dbModel = strapi.db.metadata.get(model.uid);\n\n for (const attribute of Object.values(dbModel.attributes) as any) {\n /**\n * Only consider unidirectional relations.\n * Bidirectional relations (inversedBy/mappedBy) are handled by bidirectionalRelations.\n * Self-referential relations (model.uid === uid) are included here, but rows where\n * the source entry is also being republished in this same operation are excluded —\n * those are handled by selfReferentialRelations, which remaps both sides simultaneously.\n * Without this guard, we would insert rows pointing to a source entry that is about\n * to be deleted, creating stale foreign-key values.\n */\n if (\n attribute.type !== 'relation' ||\n attribute.target !== uid ||\n attribute.inversedBy ||\n attribute.mappedBy\n ) {\n continue;\n }\n\n // TODO: joinColumn relations\n const joinTable = attribute.joinTable;\n if (!joinTable) {\n continue;\n }\n\n const { name: sourceColumnName } = joinTable.joinColumn;\n const { name: targetColumnName } = joinTable.inverseJoinColumn;\n\n /**\n * Load all relations that need to be updated\n */\n // NOTE: when the model has draft and publish, we can assume relation are only draft to draft & published to published\n const ids = oldVersions.map((entry) => entry.id);\n\n let oldVersionsQuery = strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(targetColumnName, ids);\n\n /**\n * For self-referential relations, exclude join rows where the source entry is also\n * being republished. When both sides are in the same publish batch, selfReferentialRelations\n * already handles remapping them. Including them here too would insert a row whose\n * source FK points at an entry that is about to be deleted.\n */\n if (model.uid === uid && ids.length > 0) {\n oldVersionsQuery = oldVersionsQuery.whereNotIn(sourceColumnName, ids);\n }\n\n const oldVersionsRelations = await oldVersionsQuery.transacting(trx);\n\n if (oldVersionsRelations.length > 0) {\n updates.push({ joinTable, relations: oldVersionsRelations });\n }\n\n /**\n * if publishing\n * if published version exists\n * updated published versions links\n * else\n * create link to newly published version\n *\n * if discarding\n * if published version link exists & not draft version link\n * create link to new draft version\n */\n if (!model.options?.draftAndPublish) {\n const ids = newVersions.map((entry) => entry.id);\n\n // This is the step were we query the join table based on the id of the document\n const newVersionsRelations = await strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(targetColumnName, ids)\n .transacting(trx);\n\n let versionRelations = newVersionsRelations;\n if (options.shouldPropagateRelation) {\n const relationsToPropagate = [];\n for (const relation of newVersionsRelations) {\n if (await options.shouldPropagateRelation(relation, model, trx)) {\n relationsToPropagate.push(relation);\n }\n }\n versionRelations = relationsToPropagate;\n }\n\n if (versionRelations.length > 0) {\n // when publishing a draft that doesn't have a published version yet,\n // copy the links to the draft over to the published version\n // when discarding a published version, if no drafts exists\n const discardToAdd = versionRelations\n .filter((relation) => {\n const matchingOldVersion = oldVersionsRelations.find((oldRelation) => {\n return oldRelation[sourceColumnName] === relation[sourceColumnName];\n });\n\n return !matchingOldVersion;\n })\n .map(omit(strapi.db.metadata.identifiers.ID_COLUMN));\n\n updates.push({ joinTable, relations: discardToAdd });\n }\n }\n }\n }\n });\n\n return updates;\n};\n\n/**\n * Updates uni directional relations to target the right entries when overriding published or draft entries.\n *\n * This function:\n * 1. Creates new relations pointing to the new entry versions\n * 2. Precisely deletes only the old relations being replaced to prevent orphaned links\n *\n * @param oldEntries The old entries that are being overridden\n * @param newEntries The new entries that are overriding the old ones\n * @param oldRelations The relations that were previously loaded with `load` @see load\n */\nconst sync = async (\n oldEntries: { id: Data.ID; locale: string }[],\n newEntries: { id: Data.ID; locale: string }[],\n oldRelations: { joinTable: any; relations: any[] }[]\n) => {\n /**\n * Create a map of old entry ids to new entry ids\n *\n * Will be used to update the relation target ids\n */\n const newEntryByLocale = keyBy('locale', newEntries);\n const oldEntriesMap = oldEntries.reduce(\n (acc, entry) => {\n const newEntry = newEntryByLocale[entry.locale];\n if (!newEntry) return acc;\n acc[String(entry.id)] = newEntry.id;\n return acc;\n },\n {} as Record<string, Data.ID>\n );\n\n await strapi.db.transaction(async ({ trx }) => {\n // Iterate old relations that are deleted and insert the new ones\n for (const { joinTable, relations } of oldRelations) {\n // Update old ids with the new ones\n const column = joinTable.inverseJoinColumn.name;\n\n const newRelations = relations.map((relation) => {\n const newId = oldEntriesMap[relation[column]];\n return { ...relation, [column]: newId };\n });\n\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n await trx.batchInsert(joinTable.name, newRelations, batchSize);\n }\n });\n};\n\nexport { load, sync };\nexport type { RelationFilterOptions };\n"],"names":["load","uid","oldVersions","newVersions","options","updates","strapi","db","transaction","trx","contentTypes","Object","values","components","model","dbModel","metadata","get","attribute","attributes","type","target","inversedBy","mappedBy","joinTable","name","sourceColumnName","joinColumn","targetColumnName","inverseJoinColumn","ids","map","entry","id","oldVersionsQuery","getConnection","select","from","whereIn","length","whereNotIn","oldVersionsRelations","transacting","push","relations","draftAndPublish","newVersionsRelations","versionRelations","shouldPropagateRelation","relationsToPropagate","relation","discardToAdd","filter","matchingOldVersion","find","oldRelation","omit","identifiers","ID_COLUMN","sync","oldEntries","newEntries","oldRelations","newEntryByLocale","keyBy","oldEntriesMap","reduce","acc","newEntry","locale","String","column","newRelations","newId","batchSize","dialect","getBatchInsertSize","batchInsert"],"mappings":"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"}
1
+ {"version":3,"file":"unidirectional-relations.js","sources":["../../../../src/services/document-service/utils/unidirectional-relations.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport { keyBy, omit } from 'lodash';\n\nimport type { Data, UID, Schema } from '@strapi/types';\n\nimport type { JoinTable } from '@strapi/database';\n\ninterface LoadContext {\n oldVersions: { id: Data.ID; locale: string }[];\n newVersions: { id: Data.ID; locale: string }[];\n}\n\ninterface RelationUpdate {\n joinTable: JoinTable;\n relations: Record<string, any>[];\n}\n\ninterface RelationFilterOptions {\n /**\n * Function to determine if a relation should be propagated to new document versions\n * This replaces the hardcoded component-specific logic\n */\n shouldPropagateRelation?: (\n relation: Record<string, any>,\n model: Schema.Component | Schema.ContentType,\n trx: any\n ) => Promise<boolean>;\n}\n\n/**\n * Loads lingering relations that need to be updated when overriding a published or draft entry.\n * This is necessary because the relations are uni-directional and the target entry is not aware of the source entry.\n * This is not the case for bi-directional relations, where the target entry is also linked to the source entry.\n */\nconst load = async (\n uid: UID.ContentType,\n { oldVersions, newVersions }: LoadContext,\n options: RelationFilterOptions = {}\n): Promise<RelationUpdate[]> => {\n const updates: RelationUpdate[] = [];\n\n // Iterate all components and content types to find relations that need to be updated\n await strapi.db.transaction(async ({ trx }) => {\n const contentTypes = Object.values(strapi.contentTypes) as Schema.ContentType[];\n const components = Object.values(strapi.components) as Schema.Component[];\n\n for (const model of [...contentTypes, ...components]) {\n const dbModel = strapi.db.metadata.get(model.uid);\n\n for (const attribute of Object.values(dbModel.attributes) as any) {\n /**\n * Only consider unidirectional relations.\n * Bidirectional relations (inversedBy/mappedBy) are handled by bidirectionalRelations.\n * Self-referential relations (model.uid === uid) are included here, but rows where\n * the source entry is also being republished in this same operation are excluded —\n * those are handled by selfReferentialRelations, which remaps both sides simultaneously.\n * Without this guard, we would insert rows pointing to a source entry that is about\n * to be deleted, creating stale foreign-key values.\n */\n if (\n attribute.type !== 'relation' ||\n attribute.target !== uid ||\n attribute.inversedBy ||\n attribute.mappedBy\n ) {\n continue;\n }\n\n // TODO: joinColumn relations\n const joinTable = attribute.joinTable;\n if (!joinTable) {\n continue;\n }\n\n const { name: sourceColumnName } = joinTable.joinColumn;\n const { name: targetColumnName } = joinTable.inverseJoinColumn;\n\n /**\n * Load all relations that need to be updated\n */\n // NOTE: when the model has draft and publish, we can assume relation are only draft to draft & published to published\n const ids = oldVersions.map((entry) => entry.id);\n\n let oldVersionsQuery = strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(targetColumnName, ids);\n\n /**\n * For self-referential relations, exclude join rows where the source entry is also\n * being republished. When both sides are in the same publish batch, selfReferentialRelations\n * already handles remapping them. Including them here too would insert a row whose\n * source FK points at an entry that is about to be deleted.\n */\n if (model.uid === uid && ids.length > 0) {\n oldVersionsQuery = oldVersionsQuery.whereNotIn(sourceColumnName, ids);\n }\n\n const oldVersionsRelations = await oldVersionsQuery.transacting(trx);\n\n if (oldVersionsRelations.length > 0) {\n updates.push({ joinTable, relations: oldVersionsRelations });\n }\n\n /**\n * if publishing\n * if published version exists\n * updated published versions links\n * else\n * create link to newly published version\n *\n * if discarding\n * if published version link exists & not draft version link\n * create link to new draft version\n */\n if (!model.options?.draftAndPublish) {\n const ids = newVersions.map((entry) => entry.id);\n\n // This is the step were we query the join table based on the id of the document\n const newVersionsRelations = await strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(targetColumnName, ids)\n .transacting(trx);\n\n let versionRelations = newVersionsRelations;\n if (options.shouldPropagateRelation) {\n const relationsToPropagate = [];\n for (const relation of newVersionsRelations) {\n if (await options.shouldPropagateRelation(relation, model, trx)) {\n relationsToPropagate.push(relation);\n }\n }\n versionRelations = relationsToPropagate;\n }\n\n if (versionRelations.length > 0) {\n // when publishing a draft that doesn't have a published version yet,\n // copy the links to the draft over to the published version\n // when discarding a published version, if no drafts exists\n const discardToAdd = versionRelations\n .filter((relation) => {\n const matchingOldVersion = oldVersionsRelations.find((oldRelation) => {\n return oldRelation[sourceColumnName] === relation[sourceColumnName];\n });\n\n return !matchingOldVersion;\n })\n .map((value) => omit(value, strapi.db.metadata.identifiers.ID_COLUMN));\n\n updates.push({ joinTable, relations: discardToAdd });\n }\n }\n }\n }\n });\n\n return updates;\n};\n\n/**\n * Updates uni directional relations to target the right entries when overriding published or draft entries.\n *\n * This function:\n * 1. Creates new relations pointing to the new entry versions\n * 2. Precisely deletes only the old relations being replaced to prevent orphaned links\n *\n * @param oldEntries The old entries that are being overridden\n * @param newEntries The new entries that are overriding the old ones\n * @param oldRelations The relations that were previously loaded with `load` @see load\n */\nconst sync = async (\n oldEntries: { id: Data.ID; locale: string }[],\n newEntries: { id: Data.ID; locale: string }[],\n oldRelations: { joinTable: any; relations: any[] }[]\n) => {\n /**\n * Create a map of old entry ids to new entry ids\n *\n * Will be used to update the relation target ids\n */\n const newEntryByLocale = keyBy(newEntries, 'locale');\n const oldEntriesMap = oldEntries.reduce(\n (acc, entry) => {\n const newEntry = newEntryByLocale[entry.locale];\n if (!newEntry) return acc;\n acc[String(entry.id)] = newEntry.id;\n return acc;\n },\n {} as Record<string, Data.ID>\n );\n\n await strapi.db.transaction(async ({ trx }) => {\n // Iterate old relations that are deleted and insert the new ones\n for (const { joinTable, relations } of oldRelations) {\n // Update old ids with the new ones\n const column = joinTable.inverseJoinColumn.name;\n\n const newRelations = relations.map((relation) => {\n const newId = oldEntriesMap[relation[column]];\n return { ...relation, [column]: newId };\n });\n\n const batchSize = strapi.db.dialect.getBatchInsertSize();\n await trx.batchInsert(joinTable.name, newRelations, batchSize);\n }\n });\n};\n\nexport { load, sync };\nexport type { RelationFilterOptions };\n"],"names":["load","uid","oldVersions","newVersions","options","updates","strapi","db","transaction","trx","contentTypes","Object","values","components","model","dbModel","metadata","get","attribute","attributes","type","target","inversedBy","mappedBy","joinTable","name","sourceColumnName","joinColumn","targetColumnName","inverseJoinColumn","ids","map","entry","id","oldVersionsQuery","getConnection","select","from","whereIn","length","whereNotIn","oldVersionsRelations","transacting","push","relations","draftAndPublish","newVersionsRelations","versionRelations","shouldPropagateRelation","relationsToPropagate","relation","discardToAdd","filter","matchingOldVersion","find","oldRelation","value","omit","identifiers","ID_COLUMN","sync","oldEntries","newEntries","oldRelations","newEntryByLocale","keyBy","oldEntriesMap","reduce","acc","newEntry","locale","String","column","newRelations","newId","batchSize","dialect","getBatchInsertSize","batchInsert"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { omit, keyBy } from 'lodash/fp';
1
+ import { omit, keyBy } from 'lodash';
2
2
 
3
3
  /**
4
4
  * Loads lingering relations that need to be updated when overriding a published or draft entry.
@@ -87,7 +87,7 @@ import { omit, keyBy } from 'lodash/fp';
87
87
  return oldRelation[sourceColumnName] === relation[sourceColumnName];
88
88
  });
89
89
  return !matchingOldVersion;
90
- }).map(omit(strapi.db.metadata.identifiers.ID_COLUMN));
90
+ }).map((value)=>omit(value, strapi.db.metadata.identifiers.ID_COLUMN));
91
91
  updates.push({
92
92
  joinTable,
93
93
  relations: discardToAdd
@@ -114,7 +114,7 @@ import { omit, keyBy } from 'lodash/fp';
114
114
  * Create a map of old entry ids to new entry ids
115
115
  *
116
116
  * Will be used to update the relation target ids
117
- */ const newEntryByLocale = keyBy('locale', newEntries);
117
+ */ const newEntryByLocale = keyBy(newEntries, 'locale');
118
118
  const oldEntriesMap = oldEntries.reduce((acc, entry)=>{
119
119
  const newEntry = newEntryByLocale[entry.locale];
120
120
  if (!newEntry) return acc;