fix: unidirectional sync for non dp source

This commit is contained in:
Alexandre Bodin 2024-09-24 10:32:01 +02:00
parent 7002f0b916
commit f8a68bc03b
5 changed files with 76 additions and 29 deletions

View File

@ -501,8 +501,8 @@ const transformData = (data: Record<string, any>): any => {
}
if (typeof data === 'object' && data !== null) {
if ('api_data' in data) {
return data.api_data;
if ('apiData' in data) {
return data.apiData;
}
return mapValues(transformData)(data);

View File

@ -86,7 +86,7 @@ function useHandleDisconnect(fieldName: string, consumerName: string) {
addFieldRow(`${fieldName}.disconnect`, {
id: relation.id,
api_data: {
apiData: {
documentId: relation.documentId,
},
});
@ -150,10 +150,10 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
const isMorph = props.attribute.relation.toLowerCase().includes('morph');
const isDisabled = isMorph || disabled;
const { id: componentId, uid: componentUID } = useComponent(
'RelationsField',
({ uid, id }) => ({ id, uid })
);
const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id }) => ({
componentId: id,
componentUID: uid,
}));
/**
* We'll always have a documentId in a created entry, so we look for a componentId first.
@ -267,7 +267,7 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
const item = {
id: relation.id,
api_data: {
apiData: {
documentId: relation.documentId,
locale: relation.locale,
},

View File

@ -458,7 +458,10 @@ export default {
ordering: 'desc',
});
const relationsUnion = uniqBy('documentId', concat(sanitizedRes.results, res.results));
const relationsUnion = uniqBy(
(res: any) => `${res.documentId}-${res.locale}`,
concat(sanitizedRes.results, res.results)
);
ctx.body = {
pagination: res.pagination || {

View File

@ -291,7 +291,10 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
]);
// Load any unidirectional relation targetting the old published entries
const relationsToSync = await unidirectionalRelations.load(uid, oldPublishedVersions);
const relationsToSync = await unidirectionalRelations.load(uid, {
draftVersions: draftsToPublish,
publishedVersions: oldPublishedVersions,
});
// Delete old published versions
await async.map(oldPublishedVersions, (entry: any) => entries.delete(entry.id));
@ -302,7 +305,11 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
);
// Sync unidirectional relations with the new published entries
await unidirectionalRelations.sync(oldPublishedVersions, publishedEntries, relationsToSync);
await unidirectionalRelations.sync(
[...oldPublishedVersions, ...draftsToPublish],
publishedEntries,
relationsToSync
);
publishedEntries.forEach(emitEvent('entry.publish'));
@ -358,7 +365,10 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
]);
// Load any unidirectional relation targeting the old drafts
const relationsToSync = await unidirectionalRelations.load(uid, oldDrafts);
const relationsToSync = await unidirectionalRelations.load(uid, {
draftVersions: [],
publishedVersions: oldDrafts,
});
// Delete old drafts
await async.map(oldDrafts, (entry: any) => entries.delete(entry.id));

View File

@ -1,18 +1,19 @@
/* eslint-disable no-continue */
import { keyBy } from 'lodash/fp';
import { keyBy, omit } from 'lodash/fp';
import { UID, Schema } from '@strapi/types';
interface LoadContext {
publishedVersions: { id: string; locale: string }[];
draftVersions: { id: string; locale: string }[];
}
/**
* Loads lingering relations that need to be updated when overriding a published or draft entry.
* This is necessary because the relations are uni-directional and the target entry is not aware of the source entry.
* This is not the case for bi-directional relations, where the target entry is also linked to the source entry.
*
* @param uid The content type uid
* @param oldEntries The old entries that are being overridden
* @returns An array of relations that need to be updated with the join table reference.
*/
const load = async (uid: UID.ContentType, oldEntries: { id: string; locale: string }[]) => {
const load = async (uid: UID.ContentType, { publishedVersions, draftVersions }: LoadContext) => {
const updates = [] as any;
// Iterate all components and content types to find relations that need to be updated
@ -27,29 +28,61 @@ const load = async (uid: UID.ContentType, oldEntries: { id: string; locale: stri
/**
* Only consider unidirectional relations
*/
if (attribute.type !== 'relation') continue;
if (attribute.target !== uid) continue;
if (attribute.inversedBy || attribute.mappedBy) continue;
const joinTable = attribute.joinTable;
if (
attribute.type !== 'relation' ||
attribute.target !== uid ||
attribute.inversedBy ||
attribute.mappedBy
) {
continue;
}
// TODO: joinColumn relations
if (!joinTable) continue;
const joinTable = attribute.joinTable;
if (!joinTable) {
continue;
}
const { name } = joinTable.inverseJoinColumn;
/**
* Load all relations that need to be updated
*/
const oldEntriesIds = oldEntries.map((entry) => entry.id);
const relations = await strapi.db
const oldPublishedByLocale = keyBy('locale', publishedVersions);
// NOTE: when the model has draft and publish, we can assume relation are only draft to draft & published to published
const oldEntriesIds = publishedVersions.map((entry) => entry.id);
const oldPublishedRelations = await strapi.db
.getConnection()
.select('*')
.from(joinTable.name)
.whereIn(name, oldEntriesIds)
.transacting(trx);
if (relations.length === 0) continue;
if (oldPublishedRelations.length > 0) {
updates.push({ joinTable, relations: oldPublishedRelations });
}
updates.push({ joinTable, relations });
if (!model.options?.draftAndPublish) {
const oldEntriesIds = draftVersions
.filter((entry) => {
return !oldPublishedByLocale[entry.locale];
})
.map((entry) => entry.id);
const draftRelations = await strapi.db
.getConnection()
.select('*')
.from(joinTable.name)
.whereIn(name, oldEntriesIds)
.transacting(trx);
if (draftRelations.length > 0) {
updates.push({ joinTable, relations: draftRelations.map(omit('id')) });
}
}
}
}
});
@ -67,7 +100,7 @@ const load = async (uid: UID.ContentType, oldEntries: { id: string; locale: stri
const sync = async (
oldEntries: { id: string; locale: string }[],
newEntries: { id: string; locale: string }[],
oldRelations: { joinTable: any; relations: any[] }[]
oldRelations: { joinTable: any; relations: any[]; replace?: boolean }[]
) => {
/**
* Create a map of old entry ids to new entry ids
@ -89,8 +122,9 @@ const sync = async (
// Iterate old relations that are deleted and insert the new ones
for (const { joinTable, relations } of oldRelations) {
// Update old ids with the new ones
const column = joinTable.inverseJoinColumn.name;
const newRelations = relations.map((relation) => {
const column = joinTable.inverseJoinColumn.name;
const newId = oldEntriesMap[relation[column]];
return { ...relation, [column]: newId };
});