--liquibase formatted cypher --changeset mstead:1 runOnChange: false -- BUSINESS CONTEXT: -- When GlobalParticipants are merged (via MERGED_TO relationship), LabelParticipants -- connected ONLY to the merged GP become orphaned from the canonical data model. -- This migration re-points such LabelParticipants to the canonical GP. -- -- SAFETY: Only affects LPs that have: -- 1. A REPRESENTS relationship to a merged GP -- 2. NO REPRESENTS relationship to any canonical (non-merged) GP -- 3. NO existing REPRESENTS relationship to the target canonical GP MATCH (mergedGP:GlobalParticipant)-[m:MERGED_TO]->(canonicalGP:GlobalParticipant) MATCH (mergedGP)-[r:REPRESENTS]->(lp:LabelParticipant) WHERE NOT EXISTS { MATCH (otherGP:GlobalParticipant)-[r2:REPRESENTS]->(lp) WHERE NOT (otherGP)-[:MERGED_TO]->() } AND NOT EXISTS { MATCH (canonicalGP)-[:REPRESENTS]->(lp) } WITH mergedGP, canonicalGP, lp, r, properties(r) as relProps SET lp._original_spotifyId = lp.spotifyId , lp.spotifyId = canonicalGP.spotifyId , lp.updatedAt = datetime() , lp.updatedBy = 'database/IN-MAINT-fix-broken-lp-gps' MERGE (canonicalGP)-[newR:REPRESENTS]->(lp) ON CREATE SET newR = relProps , newR._original_createdAt = r.createdAt , newR._original_createdBy = r.createdBy , newR._migratedFromMergedGpSpotifyId = mergedGP.spotifyId , newR.createdAt = datetime() , newR.createdBy = 'database/IN-MAINT-fix-broken-lp-gps' ON MATCH SET newR._migration_conflict = true , newR._migratedFromMergedGpSpotifyId = mergedGP.spotifyId CREATE (mergedGP)-[deletedR:DELETED_REPRESENTS]->(lp) SET deletedR = relProps , deletedR.deletedAt = datetime() , deletedR.deletedBy = 'database/IN-MAINT-fix-broken-lp-gps' , deletedR._replacedByCanonicalGpSpotifyId = canonicalGP.spotifyId DELETE r --rollback MATCH (mergedGP:GlobalParticipant)-[deletedR:DELETED_REPRESENTS]->(lp:LabelParticipant) --rollback WHERE deletedR.deletedBy = 'database/IN-MAINT-fix-broken-lp-gps' --rollback AND lp.updatedBy = 'database/IN-MAINT-fix-broken-lp-gps' --rollback AND EXISTS(lp._original_spotifyId) --rollback WITH mergedGP, lp, deletedR, --rollback deletedR._replacedByCanonicalGpSpotifyId as canonicalSpotifyId --rollback MATCH (canonicalGP:GlobalParticipant {spotifyId: canonicalSpotifyId}) --rollback MATCH (canonicalGP)-[newR:REPRESENTS]->(lp) --rollback WHERE newR._migratedFromMergedGpSpotifyId = mergedGP.spotifyId --rollback SET lp.spotifyId = lp._original_spotifyId --rollback , lp.updatedAt = datetime() --rollback CREATE (mergedGP)-[r:REPRESENTS]->(lp) --rollback SET r = properties(deletedR) --rollback REMOVE r.deletedAt, r.deletedBy, r._replacedByCanonicalGpSpotifyId --rollback DELETE newR, deletedR --rollback REMOVE lp._original_spotifyId, lp.updatedBy