{"version":3,"file":"bidirectional-relations.mjs","sources":["../../../../src/services/document-service/utils/bidirectional-relations.ts"],"sourcesContent":["import { keyBy, omit } from 'lodash/fp';\nimport type { UID, Schema } from '@strapi/types';\nimport type { JoinTable } from '@strapi/database';\n\ninterface LoadContext {\n  oldVersions: { id: string; locale: string }[];\n  newVersions: { id: string; locale: string }[];\n}\n\ninterface RelationEntry {\n  joinTable: JoinTable;\n  relations: Record<string, unknown>[];\n  /** FK column for the entity being published */\n  entityColumn: string;\n  /** FK column for the related entity */\n  relatedColumn: string;\n}\n\n/** Draft id → published id for rows that already have a published counterpart (same document_id + locale). */\nconst draftToPublishedMap = async (trx: any, tableName: string, rowIds: unknown[]) => {\n  const uniqueIds = [...new Set(rowIds)];\n  if (uniqueIds.length === 0) {\n    return new Map<string, string>();\n  }\n\n  const draftEntries = await strapi.db\n    .getConnection()\n    .select('id', 'document_id', 'locale')\n    .from(tableName)\n    .whereIn('id', uniqueIds as any)\n    .transacting(trx);\n\n  if (draftEntries.length === 0) {\n    return new Map<string, string>();\n  }\n\n  const pubEntries = await strapi.db\n    .getConnection()\n    .select('id', 'document_id', 'locale')\n    .from(tableName)\n    .whereNotNull('published_at')\n    .whereIn(\n      'document_id',\n      draftEntries.map((e: any) => e.document_id)\n    )\n    .transacting(trx);\n\n  const pubByDocLocale = new Map(\n    pubEntries.map((e: any) => [`${e.document_id}_${e.locale}`, e.id])\n  );\n\n  const map = new Map<string, string>();\n  for (const d of draftEntries) {\n    const pubId = pubByDocLocale.get(`${d.document_id}_${d.locale}`);\n    if (pubId) {\n      map.set(String(d.id), String(pubId));\n    }\n  }\n  return map;\n};\n\nconst remapRelatedIds = (rows: any[], relatedCol: string, idMap: Map<string, string>) =>\n  rows.map((row) => {\n    const next = idMap.get(String(row[relatedCol]));\n    return next ? { ...row, [relatedCol]: next } : row;\n  });\n\n/**\n * Reads join rows tied to the entry being published (`publishedCol` IN draft/old ids) and returns\n * batches for `sync()`. When the FK in `relatedCol` points at a D&P type, maps known draft ids to\n * published ids; otherwise keeps draft ids so sync can still run after both sides exist.\n */\nconst captureJoinBatches = async (\n  trx: any,\n  opts: {\n    joinTable: any;\n    /** Column holding ids of the document being published (the `uid` passed to load). */\n    publishedCol: string;\n    /** The other FK; may be remapped via draftToPublishedMap. */\n    relatedCol: string;\n    /** Content type behind `relatedCol` (used for D&P + table name). */\n    relatedUid: UID.ContentType;\n    relatedHasDraftAndPublish: boolean;\n    /** Model that owns this attribute; draft capture is skipped for components. */\n    schemaUid: UID.ContentType;\n    oldVersions: LoadContext['oldVersions'];\n    newVersions: LoadContext['newVersions'];\n  }\n): Promise<RelationEntry[]> => {\n  const {\n    joinTable,\n    publishedCol,\n    relatedCol,\n    relatedUid,\n    relatedHasDraftAndPublish,\n    schemaUid,\n    oldVersions,\n    newVersions,\n  } = opts;\n\n  const batches: RelationEntry[] = [];\n  const { name: table } = joinTable;\n\n  const oldIds = oldVersions.map((e) => e.id);\n  if (oldIds.length > 0) {\n    const existing = await strapi.db\n      .getConnection()\n      .select('*')\n      .from(table)\n      .whereIn(publishedCol, oldIds)\n      .transacting(trx);\n    if (existing.length > 0) {\n      batches.push({\n        joinTable,\n        relations: existing,\n        entityColumn: publishedCol,\n        relatedColumn: relatedCol,\n      });\n    }\n  }\n\n  if (!strapi.contentTypes[schemaUid]) {\n    return batches;\n  }\n\n  const oldLocales = new Set(oldVersions.map((e) => e.locale));\n  const draftsOnly = newVersions.filter((v) => !oldLocales.has(v.locale));\n  if (draftsOnly.length === 0) {\n    return batches;\n  }\n\n  const draftIds = draftsOnly.map((e) => e.id);\n  const draftRows = await strapi.db\n    .getConnection()\n    .select('*')\n    .from(table)\n    .whereIn(publishedCol, draftIds)\n    .transacting(trx);\n\n  if (draftRows.length === 0) {\n    return batches;\n  }\n\n  let relations = draftRows;\n  if (relatedHasDraftAndPublish) {\n    const meta = strapi.db.metadata.get(relatedUid);\n    const relatedIds = draftRows.map((r: any) => r[relatedCol]);\n    const map = await draftToPublishedMap(trx, meta.tableName, relatedIds);\n    relations = remapRelatedIds(draftRows, relatedCol, map);\n  }\n\n  batches.push({ joinTable, relations, entityColumn: publishedCol, relatedColumn: relatedCol });\n  return batches;\n};\n\n/**\n * Loads all bidirectional relations that need to be synchronized when content entries change state\n * (e.g., during publish/unpublish operations).\n *\n * In Strapi, bidirectional relations allow maintaining order from both sides of the relation.\n * When an entry is published, the following occurs:\n *\n * 1. The old published entry is deleted\n * 2. A new entry is created with all its relations\n *\n * This process affects relation ordering in the following way:\n *\n * Initial state (Entry A related to X, Y, Z):\n * ```\n *   Entry A (draft)     Entry A (published)\n *      │                     │\n *      ├──(1)→ X            ├──(1)→ X\n *      ├──(2)→ Y            ├──(2)→ Y\n *      └──(3)→ Z            └──(3)→ Z\n *\n *   X's perspective:         Y's perspective:         Z's perspective:\n *      └──(2)→ Entry A         └──(1)→ Entry A         └──(3)→ Entry A\n * ```\n *\n * After publishing Entry A (without relation order sync):\n * ```\n *   Entry A (draft)     Entry A (new published)\n *      │                     │\n *      ├──(1)→ X            ├──(1)→ X\n *      ├──(2)→ Y            ├──(2)→ Y\n *      └──(3)→ Z            └──(3)→ Z\n *\n *   X's perspective:         Y's perspective:         Z's perspective:\n *      └──(3)→ Entry A         └──(3)→ Entry A         └──(3)→ Entry A\n *                           (all relations appear last in order)\n * ```\n *\n * This module preserves the original ordering from both perspectives by:\n * 1. Capturing the relation order before the entry state changes\n * 2. Restoring this order after the new relations are created\n *\n * @param uid - The unique identifier of the content type being processed\n * @param context - Object containing arrays of old and new entry versions\n * @returns Array of objects containing join table metadata and relations to be updated\n */\nconst load = async (uid: UID.ContentType, { oldVersions, newVersions }: LoadContext) => {\n  const relationsToUpdate: RelationEntry[] = [];\n\n  await strapi.db.transaction(async ({ trx }) => {\n    const models = [\n      ...(Object.values(strapi.contentTypes) as Schema.ContentType[]),\n      ...Object.values(strapi.components),\n    ];\n\n    for (const model of models) {\n      const dbModel = strapi.db.metadata.get(model.uid);\n\n      for (const attribute of Object.values(dbModel.attributes) as Record<string, any>[]) {\n        const joinTable = attribute.joinTable;\n\n        if (attribute.type !== 'relation' || !joinTable) {\n          continue;\n        }\n\n        if (!(attribute.inversedBy || attribute.mappedBy)) {\n          continue;\n        }\n\n        // Owning side: e.g. Author.articles when publishing an Author.\n        const isOwningSide =\n          !!attribute.inversedBy &&\n          model.uid === uid &&\n          attribute.relation === 'manyToMany' &&\n          model.uid !== attribute.target;\n\n        // Inverse side: e.g. Article.authors when publishing an Article.\n        const isInverseSide = attribute.target === uid && model.uid !== uid;\n\n        if (!isOwningSide && !isInverseSide) {\n          continue;\n        }\n\n        // Direction determines which join column belongs to the entity being published\n        const publishedCol = isOwningSide\n          ? joinTable.joinColumn.name\n          : joinTable.inverseJoinColumn.name;\n        const relatedCol = isOwningSide\n          ? joinTable.inverseJoinColumn.name\n          : joinTable.joinColumn.name;\n\n        const relatedUid = (isOwningSide ? attribute.target : model.uid) as UID.ContentType;\n\n        const batches = await captureJoinBatches(trx, {\n          joinTable,\n          publishedCol,\n          relatedCol,\n          relatedUid,\n          relatedHasDraftAndPublish: isOwningSide\n            ? !!strapi.contentTypes[relatedUid]?.options?.draftAndPublish\n            : !!model.options?.draftAndPublish,\n          schemaUid: model.uid as UID.ContentType,\n          oldVersions,\n          newVersions,\n        });\n        relationsToUpdate.push(...batches);\n      }\n    }\n  });\n\n  return relationsToUpdate;\n};\n\n/**\n * Synchronizes the order of bidirectional relations after content entries have changed state.\n *\n * When entries change state (e.g., draft → published), their IDs change and all relations are recreated.\n * While the order of relations from the entry's perspective is maintained (as they're created in order),\n * the inverse relations (from related entries' perspective) would all appear last in order since they're new.\n *\n * Example:\n * ```\n * Before publish:\n *   Article(id:1) →(order:1)→ Category(id:5)\n *   Category(id:5) →(order:3)→ Article(id:1)\n *\n * After publish (without sync):\n *   Article(id:2) →(order:1)→ Category(id:5)    [order preserved]\n *   Category(id:5) →(order:99)→ Article(id:2)   [order lost - appears last]\n *\n * After sync:\n *   Article(id:2) →(order:1)→ Category(id:5)    [order preserved]\n *   Category(id:5) →(order:3)→ Article(id:2)    [order restored]\n * ```\n *\n * @param oldEntries - Array of previous entry versions with their IDs and locales\n * @param newEntries - Array of new entry versions with their IDs and locales\n * @param existingRelations - Array of join table data containing the relations to be updated\n */\nconst sync = async (\n  oldEntries: { id: string; locale: string }[],\n  newEntries: { id: string; locale: string }[],\n  existingRelations: RelationEntry[]\n) => {\n  const newEntriesByLocale = keyBy('locale', newEntries);\n\n  const entryIdMapping = oldEntries.reduce(\n    (acc, oldEntry) => {\n      const newEntry = newEntriesByLocale[oldEntry.locale];\n      if (!newEntry) {\n        return acc;\n      }\n      acc[oldEntry.id] = newEntry.id;\n      return acc;\n    },\n    {} as Record<string, string>\n  );\n\n  const republishedEntryIds = new Set(newEntries.map((e) => String(e.id)));\n  const isRepublishedEntry = (id: string | number) => republishedEntryIds.has(String(id));\n\n  await strapi.db.transaction(async ({ trx }) => {\n    for (const {\n      joinTable,\n      relations,\n      entityColumn: sourceColumn,\n      relatedColumn: targetColumn,\n    } of existingRelations) {\n      const orderColumn = joinTable.orderColumnName;\n\n      // Failsafe in case those don't exist\n      if (!sourceColumn || !targetColumn || !orderColumn) {\n        continue;\n      }\n\n      const mappedRelations = relations\n        .map((relation) => ({\n          relation,\n          oldSourceId: relation[sourceColumn] as string,\n          targetId: relation[targetColumn] as string,\n          originalOrder: relation[orderColumn],\n          newSourceId: entryIdMapping[relation[sourceColumn] as string],\n        }))\n        .filter((r): r is typeof r & { newSourceId: string } => Boolean(r.newSourceId));\n\n      if (!mappedRelations.length) continue;\n\n      const newSourceIds = mappedRelations.map((r) => r.newSourceId);\n\n      // Batch UPDATE: set each row's order in a single statement using CASE\n      const caseFragments = mappedRelations.map(() => `WHEN ?? = ? AND ?? = ? THEN ?`);\n      const caseBindings = mappedRelations.flatMap(({ newSourceId, targetId, originalOrder }) => [\n        sourceColumn,\n        newSourceId,\n        targetColumn,\n        targetId,\n        originalOrder,\n      ]);\n\n      await trx(joinTable.name)\n        .whereIn(sourceColumn, newSourceIds)\n        .update({\n          [orderColumn]: trx.raw(`CASE ${caseFragments.join(' ')} ELSE ?? END`, [\n            ...caseBindings,\n            orderColumn,\n          ]),\n        });\n\n      // Batch SELECT: find which rows exist so we know what to insert\n      const existingRows = await trx(joinTable.name)\n        .whereIn(sourceColumn, newSourceIds)\n        .select(sourceColumn, targetColumn);\n\n      const existingSet = new Set(\n        existingRows.map((r: Record<string, unknown>) => `${r[sourceColumn]}:${r[targetColumn]}`)\n      );\n\n      // Batch INSERT: insert cascade-deleted rows that aren't from republished sources\n      const toInsert = mappedRelations\n        .filter(\n          ({ newSourceId, targetId }) =>\n            !existingSet.has(`${newSourceId}:${targetId}`) && !isRepublishedEntry(newSourceId)\n        )\n        .map(({ relation, newSourceId, originalOrder }) => ({\n          ...omit(strapi.db.metadata.identifiers.ID_COLUMN, relation),\n          [sourceColumn]: newSourceId,\n          [orderColumn]: originalOrder,\n        }));\n\n      if (toInsert.length) {\n        const batchSize = strapi.db.dialect.getBatchInsertSize();\n        await trx.batchInsert(joinTable.name, toInsert, batchSize);\n      }\n    }\n  });\n};\n\nexport { load, sync };\n"],"names":["draftToPublishedMap","trx","tableName","rowIds","uniqueIds","Set","length","Map","draftEntries","strapi","db","getConnection","select","from","whereIn","transacting","pubEntries","whereNotNull","map","e","document_id","pubByDocLocale","locale","id","d","pubId","get","set","String","remapRelatedIds","rows","relatedCol","idMap","row","next","captureJoinBatches","opts","joinTable","publishedCol","relatedUid","relatedHasDraftAndPublish","schemaUid","oldVersions","newVersions","batches","name","table","oldIds","existing","push","relations","entityColumn","relatedColumn","contentTypes","oldLocales","draftsOnly","filter","v","has","draftIds","draftRows","meta","metadata","relatedIds","r","load","uid","relationsToUpdate","transaction","models","Object","values","components","model","dbModel","attribute","attributes","type","inversedBy","mappedBy","isOwningSide","relation","target","isInverseSide","joinColumn","inverseJoinColumn","options","draftAndPublish","sync","oldEntries","newEntries","existingRelations","newEntriesByLocale","keyBy","entryIdMapping","reduce","acc","oldEntry","newEntry","republishedEntryIds","isRepublishedEntry","sourceColumn","targetColumn","orderColumn","orderColumnName","mappedRelations","oldSourceId","targetId","originalOrder","newSourceId","Boolean","newSourceIds","caseFragments","caseBindings","flatMap","update","raw","join","existingRows","existingSet","toInsert","omit","identifiers","ID_COLUMN","batchSize","dialect","getBatchInsertSize","batchInsert"],"mappings":"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"}