diff --git a/src/actors.js b/src/actors.js index 256c6fe..f4283e9 100644 --- a/src/actors.js +++ b/src/actors.js @@ -616,9 +616,11 @@ export async function mergeActors(targetActorId, sourceActorIds, reqUser) { let mergedActorStashes = []; try { - const [existingProfiles] = await Promise.all([ + const [existingProfiles, sourceProfiles] = await Promise.all([ trx('actors_profiles') .where('actor_id', targetActorId), + trx('actors_profiles') + .whereIn('actor_id', sourceActorIds), trx('actors') .update('alias_for', targetActorId) .whereIn('id', sourceActorIds) @@ -629,11 +631,19 @@ export async function mergeActors(targetActorId, sourceActorIds, reqUser) { .whereIn('actor_id', sourceActorIds), ]); + // multiple source actors may provide profiles for the same entity, but we can only assign one to the target actor; prefer the newest + const newestSourceProfileMap = Object.fromEntries(sourceProfiles + .toSorted((profileA, profileB) => profileA.updated_at - profileB.updated_at) + .map((profile) => [profile.entity_id, profile.id])); + + const duplicateSourceProfiles = sourceProfiles.filter((profile) => newestSourceProfileMap[profile.entity_id] && newestSourceProfileMap[profile.entity_id] !== profile.id); + // assign source actor profiles to target actor, unless a profile for that entity is already present mergedProfiles = await trx('actors_profiles') .update('actor_id', targetActorId) .whereIn('actor_id', sourceActorIds) .whereNotIn('entity_id', existingProfiles.map((profile) => profile.entity_id)) + .whereNotIn('id', duplicateSourceProfiles.map((profile) => profile.id)) .returning('id'); // find releases that have more than one source actor assigned