"""Performer Persister. Handles doing CRUD operations on the performer table. """ from backend.connectors import mysql from backend.constants import performer as pfmr_const from backend.models.performer import Performer from backend.models.performer import PerformerRole from backend.utils import api as api_utils class PerformerPersister(object): """Handles high level operations for performers.""" @classmethod @mysql.ows_track_db_session_wrap def get_performers_by_tuid(cls, tuid, session): """Get track performers for a tuid. Args: tuid (int): The track primary key. session (object): SQLAlchemy database session (optional) Returns: response: List of performers wrapped with pagination info """ performers = cls._get_performers_by_tuid(tuid, session) roles = {role['performer_role_id']: role['performer_role'] for role in cls.get_performer_roles().message['items']} result = [] for performer in performers: performer_dict = performer.to_dict() performer_dict['performer_role'] = \ roles[performer_dict['performer_role_id']] result.append(performer_dict) return api_utils.create_get_list_response(result) @classmethod @mysql.ows_track_db_session_wrap def get_performers_by_tuids(cls, tuids, session): """Get track performers for a list of tuids. Args: tuids (list): List of track primary keys. session (object): SQLAlchemy database session (optional) Returns: response: List of performers wrapped with pagination info """ if not tuids: performers = [] else: performers = cls._get_performers_by_tuids(tuids, session) return api_utils.create_get_list_response( [performer.to_dict() for performer in performers]) @classmethod @mysql.ows_track_db_session_wrap def sync_track_performers(cls, tuid, performers, session): """Sync track performer data. Args: tuid (int): The track primary key. performers (list): List of performer dicts to update session (Session): SQLAlchemy database session (optional) Returns: response.Response """ existing_performers = cls._get_performers_by_tuid( tuid, session).all() updated_performers = cls._sync_performers( tuid, existing_performers, performers, session) session.commit() return api_utils.create_get_list_response( [performer.to_dict() for performer in updated_performers]) @classmethod @mysql.ows_track_db_session_wrap def sync_by_performer_type_for_tracks( cls, tuids, performer_type, performers, session): """Sync performers for type for multiple tracks. Args: tuids (list): Primary keys of tracks performers (list): List of target performer dicts session (object): SQLAlchemy database session (optional) Returns: response.Response: List of performers """ if not tuids: return api_utils.create_validation_error_response() # The passed in performers needs have the 'type' field populated so # it is properly saved in the database performers = [p.copy() for p in performers] for p in performers: p['type'] = p.get('type', performer_type) if p['type'] != performer_type: return api_utils.create_validation_error_response() # Make a list of existing performers for each tuid # A tuid may not have any performers existing_performers = cls._get_performers_by_tuids( tuids, session).with_for_update().all() grouped_performers = {tuid: [] for tuid in tuids} for p in existing_performers: if p.performer_type == performer_type: grouped_performers[p.tuid].append(p) # Sync performers for each track updated_performers = [] for tuid, track_performers in grouped_performers.items(): updated_performers += cls._sync_performers( tuid, track_performers, performers, session) # TODO: Verify no duplicate performer birth names session.commit() return api_utils.create_get_list_response( [p.to_dict() for p in updated_performers]) @classmethod @mysql.ows_track_db_session_wrap def delete_performers_by_tuid(cls, tuid, session): """Delete performers with given tuid. Args: tuid (int): The track primary key. session (object): SQLAlchemy database session (optional) Returns: response.Response: result of deletion """ result = cls.bulk_delete_performers_by_tuids([tuid], session=session) return result @classmethod @mysql.ows_track_db_session_wrap def bulk_delete_performers_by_tuids(cls, tuids, session): """Delete performers with given tuids. Args: tuids (list): unique ids of tracks session (object): SQLAlchemy database session (optional) Returns: response.Response: result of deletion """ session.query(Performer).filter(Performer.tuid.in_(tuids)).delete( synchronize_session=False) return api_utils.create_ok_response() @classmethod def _get_performers_by_tuid(cls, tuid, session): return session.query(Performer).filter_by(tuid=tuid).order_by( Performer.performer_id) @classmethod def _get_performers_by_tuids(cls, tuids, session): return session.query(Performer) \ .filter(Performer.tuid.in_(tuids)) \ .order_by(Performer.tuid, Performer.performer_id) @classmethod def _sync_performers( cls, tuid, existing_performers, performers_data, session): """Sync performer data for a track. Args: tuid (int): The track primary key. existing_performers (list): List of performer dicts to update performers_data (list): List of performers from payload session (Session): SQLAlchemy database session (optional) Returns: List: List of Performer model objects """ updated_performers = [] keep_performers = existing_performers[:len(performers_data)] for data in performers_data: if len(updated_performers) < len(keep_performers): performer = keep_performers[len(updated_performers)] performer.performer_type = data['type'] performer.performer_role_id = \ data[pfmr_const.PERFORMER_ROLE_ID] performer.birth_name = data[pfmr_const.BIRTH_NAME] session.merge(performer) else: performer = Performer( tuid=tuid, performer_type=data['type'], performer_role_id=data[pfmr_const.PERFORMER_ROLE_ID], birth_name=data[pfmr_const.BIRTH_NAME]) session.add(performer) updated_performers.append(performer) # Remove any leftover performers remove_performers = existing_performers[len(performers_data):] for performer in remove_performers: session.delete(performer) return updated_performers @classmethod @mysql.ows_track_db_session_wrap def get_performer_roles(cls, session): """Get performer roles from DB. Args: session (object): SQLAlchemy database session (optional) Returns: response.Response: list of performer roles """ performer_roles = session.query(PerformerRole) \ .order_by(PerformerRole.display_order).all() return api_utils.create_get_list_response( [p.to_dict() for p in performer_roles])