"""Neo4j queries for track participations.""" from typing import Any from ddtrace import tracer from neo4j import Session from pydantic import UUID4 get_track_artist_participations_by_track_ids = """ UNWIND $track_ids AS track_id MATCH (t:Track:Orchard {id: track_id}) OPTIONAL MATCH (t)<-[rel:PARTICIPATED_IN]-(lp:LabelParticipant) WHERE lp IS NULL OR $is_admin OR EXISTS { MATCH (prof:Profile {profileType: 'LabelProfile'}) -[:HAS_ACCESS_TO|HAS_ADMIN_ACCESS_TO]->() -[:HAS_LABEL_PARTICIPANT]->(lp) WHERE prof.profileId IN $profile_ids } WITH t, rel, lp OPTIONAL MATCH (lp)-[:CREATED_FROM]-> (ta:TrackArtist {type: rel.participated_as})<-[:HAS_SOURCE_ARTIST]-(t) USING JOIN ON ta WITH t, rel, lp, t.id AS track_id, min(ta.id) AS track_artist_id, CASE rel.participated_as WHEN 'performer' THEN 1 WHEN 'featuring' THEN 2 WHEN 'remixer' THEN 3 WHEN 'producer' THEN 4 ELSE 5 END AS role_value ORDER BY track_id, role_value, track_artist_id RETURN {tuid: track_id} AS track, collect( CASE WHEN rel IS NOT NULL THEN { contributor: {uuid: lp.uuid}, participated_as: rel.participated_as, tuid: track_id, track_artist_id: track_artist_id } END ) AS participations """ get_track_writer_participations_by_track_ids = """ UNWIND $track_ids AS track_id MATCH (t:Track:Orchard {id: track_id}) OPTIONAL MATCH (t)<-[rel:PARTICIPATED_IN]- (lp:LabelParticipant)-[:CREATED_FROM]-> (tw:TrackWriter)<-[:HAS_SOURCE_ARTIST]-(t) WHERE (rel IS NULL OR rel.participated_as = 'track_writer') AND (lp IS NULL OR $is_admin OR EXISTS { MATCH (prof:Profile {profileType: 'LabelProfile'}) -[:HAS_ACCESS_TO|HAS_ADMIN_ACCESS_TO]->() -[:HAS_LABEL_PARTICIPANT]->(lp) WHERE prof.profileId IN $profile_ids }) WITH t, rel, lp, t.id AS track_id ORDER BY track_id RETURN {tuid: track_id} AS track, collect( CASE WHEN rel IS NOT NULL THEN { contributor: {uuid: lp.uuid}, participated_as: rel.participated_as, tuid: track_id, track_artist_id: null } END ) AS participations """ get_track_participations_by_label_participant_uuid = """ MATCH (lp:LabelParticipant {uuid: $uuid}) WHERE $is_admin OR EXISTS { MATCH (p:Profile {profileType: 'LabelProfile'}) -[:HAS_ACCESS_TO|HAS_ADMIN_ACCESS_TO]->() -[:HAS_LABEL_PARTICIPANT]->(lp) WHERE p.profileId IN $profile_ids } WITH DISTINCT lp OPTIONAL MATCH (lp)-[rel:PARTICIPATED_IN]->(t:Track:Orchard) OPTIONAL MATCH (lp)-[:CREATED_FROM]-> (ta:TrackArtist {type: rel.participated_as}) <-[:HAS_SOURCE_ARTIST]-(t) RETURN {uuid: lp.uuid} AS contributor, collect({ contributor: {uuid: lp.uuid}, participated_as: rel.participated_as, track_id: t.id, track_artist_id: ta.id }) AS participations """ def _participations_from_record(record: Any) -> list[dict[str, Any]]: return [ { "contributor": {"uuid": p["contributor"]["uuid"]}, "participated_as": p["participated_as"], "track": {"tuid": p["tuid"]}, "track_artist_id": p["track_artist_id"], } for p in record["participations"] if p is not None and p.get("participated_as") is not None ] @tracer.wrap() def get_by_track_id( session: Session, track_id: int, profile_ids: list[int], identity_uuid: UUID4 | None = None, is_admin: bool = False, ) -> dict[str, Any] | None: results = get_by_track_ids( session, track_ids=[track_id], identity_uuid=identity_uuid, profile_ids=profile_ids, is_admin=is_admin, ) return results[0] if results else None @tracer.wrap() def get_by_track_ids( session: Session, track_ids: list[int], profile_ids: list[int], identity_uuid: UUID4 | None = None, is_admin: bool = False, ) -> list[dict[str, Any]]: """Get contributor participations for tracks. Runs two queries — TrackArtist and TrackWriter branches — and unions the results per track, matching the legacy LabelTrackParticipation.getByTrackId behaviour in graphql-participant. """ artist_result = session.run( query=get_track_artist_participations_by_track_ids, track_ids=track_ids, profile_ids=profile_ids, is_admin=is_admin, ) by_track: dict[int, dict[str, Any]] = {} for record in artist_result: track = record["track"] by_track[track["tuid"]] = { "track": track, "participations": _participations_from_record(record), } writer_result = session.run( query=get_track_writer_participations_by_track_ids, track_ids=track_ids, profile_ids=profile_ids, is_admin=is_admin, ) for record in writer_result: track = record["track"] tuid = track["tuid"] writer_participations = _participations_from_record(record) if tuid in by_track: by_track[tuid]["participations"].extend(writer_participations) else: by_track[tuid] = { "track": track, "participations": writer_participations, } return [by_track[tid] for tid in track_ids if tid in by_track] @tracer.wrap() def get_by_label_participant_uuid( session: Session, uuid: str, profile_ids: list[int], identity_uuid: UUID4 | None = None, is_admin: bool = False, ) -> dict[str, Any] | None: result = session.run( get_track_participations_by_label_participant_uuid, uuid=uuid, identity_uuid=identity_uuid, profile_ids=profile_ids, is_admin=is_admin, ) record = result.single() if record is None: return None participations = [ { "contributor": {"uuid": p["contributor"]["uuid"]}, "participated_as": p["participated_as"], "track": {"tuid": p["track_id"]}, "track_artist_id": p["track_artist_id"], } for p in record["participations"] if p.get("participated_as") is not None ] return { "contributor": record["contributor"], "participations": participations, }