"""Model class for Track Sample and Track Sample Artists.""" from oto import response from sqlalchemy import BigInteger from sqlalchemy import Column from sqlalchemy import Enum from sqlalchemy import ForeignKey from sqlalchemy import func from sqlalchemy import Integer from sqlalchemy import String from sqlalchemy import Text from sqlalchemy import TIMESTAMP from sqlalchemy.orm import relationship from backend.connectors import mysql from backend.constants import error from backend.constants import track_sample as const from backend.utils import api as api_utils class TrackSample(mysql.OwsTrackBaseModel): """Model class for Track Sample.""" __tablename__ = 'track_sample' sample_id = Column( 'id', BigInteger().with_variant(Integer, 'sqlite'), primary_key=True, autoincrement=True) unique_track_id = Column(Integer, nullable=False) sample_type = Column(Enum(*const.CLEARANCE_TYPES), nullable=False) track_name = Column(String(length=1000), nullable=False) isrc = Column(String(length=16)) p_line = Column(String(length=255)) track_length = Column(Integer()) notes = Column(Text) updated_date = Column( TIMESTAMP, server_default=func.now(), server_onupdate=func.now()) artists = relationship( 'TrackSampleArtists', backref='track_sample', cascade='all, delete-orphan') def to_dict(self): """Dictionary representation of object.""" result = { 'sample_id': self.sample_id, 'unique_track_id': self.unique_track_id, 'sample_type': self.sample_type, 'track_name': self.track_name, 'isrc': self.isrc, 'p_line': self.p_line, 'track_length': self.track_length, 'notes': self.notes, 'updated_date': self.updated_date, 'artists': []} for artist in self.artists: if artist.artist_type in const.ARTIST_TYPES: result['artists'].append(artist.to_dict()) return result def update(self, **kwargs): """Update object with kwargs data.""" for key, value in kwargs.items(): setattr(self, key, value) class TrackSampleArtists(mysql.OwsTrackBaseModel): """Model class for Track Sample Artists.""" __tablename__ = 'track_sample_artists' artist_id = Column( 'id', BigInteger().with_variant(Integer, 'sqlite'), primary_key=True, autoincrement=True) sample_id = Column( ForeignKey('track_sample.id', ondelete='CASCADE'), nullable=False) artist_type = Column(Enum(*const.ARTIST_TYPES), nullable=False) artist_name = Column(String(length=255), nullable=False) def to_dict(self): """Dictionary representation of object.""" return { 'artist_id': self.artist_id, 'artist_name': self.artist_name, 'artist_type': self.artist_type} def update(self, **kwargs): """Update object with kwargs data.""" for key, value in kwargs.items(): setattr(self, key, value) @mysql.wrap_db_errors @mysql.ows_track_db_session_wrap def create_new_sample(unique_track_id, sample_data, artist_data, session): """Add a new track sample with its artists. Args: unique_track_id (int): track table identifier. sample_data (dict): dictionary of sample data. artist_data (dict): dict of {artist type: [names..]}. session (object): SQLAlchemy database session (optional) Returns: dict: track sample object with it's artists. """ sample_data['unique_track_id'] = unique_track_id new_sample = TrackSample() new_sample.update(**sample_data) session.add(new_sample) for artist in artist_data: new_artist = TrackSampleArtists(**artist) new_sample.artists.append(new_artist) session.add(new_artist) session.commit() return response.Response(message=new_sample.to_dict()) @mysql.wrap_db_errors @mysql.ows_track_db_session_wrap def copy_multiple_samples(all_samples, mapping, session): """Copy track sample with its artists to new tracks from mapping. Args: all_samples (list): list of track sample data. mapping (dict): dictionary of source and dest track id mapping. session (object): SQLAlchemy database session (optional) Returns: dict: track sample object with it's artists. """ for source_sample in all_samples: dest_tuid = mapping[source_sample['unique_track_id']] source_artists = source_sample['artists'] del (source_sample['artists']) del (source_sample['sample_id']) list(map(lambda d: d.pop('artist_id'), source_artists)) source_sample['unique_track_id'] = dest_tuid new_sample = TrackSample() new_sample.update(**source_sample) session.add(new_sample) for artist in source_artists: new_artist = TrackSampleArtists(**artist) new_sample.artists.append(new_artist) session.add(new_artist) session.commit() return api_utils.create_ok_response() @mysql.wrap_db_errors @mysql.ows_track_db_session_wrap def update_sample_data(sample_id, sample_data, artist_data, session): """Add a new track sample with its artists. Args: sample_id (int): track sample identifier. sample_data (dict): dictionary of sample data. artist_data (dict): dict of {artist type: [names..]}. session (object): SQLAlchemy database session (optional) Returns: dict: track sample object with it's artists. """ sample = session.query(TrackSample).get(sample_id) if not sample: return response.create_not_found_response( error.ERROR_MESSAGE_TRACK_SAMPLE_NOT_FOUND) sample.update(**sample_data) if artist_data: for old_artist in sample.artists: if len(artist_data) < 1: session.delete(old_artist) else: new_artist = artist_data.pop() old_artist.update(**new_artist) session.merge(old_artist) # some more artists left after update, add them as new. if artist_data: for extra_artist in artist_data: new_artist = TrackSampleArtists(**extra_artist) sample.artists.append(new_artist) session.add(new_artist) session.commit() return response.Response(message=sample.to_dict()) @mysql.wrap_db_errors @mysql.ows_track_db_session_wrap def get_sample_data(sample_id, session): """Get track sample with its artists. Args: sample_id (int): track_sample table identifier. session (object): SQLAlchemy database session (optional) Returns: dict: track sample object with it's artists. """ sample = session.query(TrackSample).get(sample_id) if not sample: return response.create_not_found_response( error.ERROR_MESSAGE_TRACK_SAMPLE_NOT_FOUND) return response.Response(message=sample.to_dict()) @mysql.wrap_db_errors @mysql.ows_track_db_session_wrap def delete_sample_data(sample_id, session): """Delete track sample with its artists. Args: sample_id (int): track_sample table identifier. session (object): SQLAlchemy database session (optional) Returns: dict: track sample object with it's artists. """ sample = session.query(TrackSample).get(sample_id) if not sample: return response.create_not_found_response( error.ERROR_MESSAGE_TRACK_SAMPLE_NOT_FOUND) session.delete(sample) session.commit() return api_utils.create_ok_response() @mysql.wrap_db_errors @mysql.ows_track_db_session_wrap def get_track_samples(tuid, session): """Get all track samples for a track. Args: tuid (int): track table identifier. session (object): SQLAlchemy database session (optional) Returns: dict: track samples object with it's artists. """ samples = session.query(TrackSample).filter( TrackSample.unique_track_id == tuid) samples_data = [each.to_dict() for each in samples] return response.Response(message=samples_data) @mysql.wrap_db_errors @mysql.ows_track_db_session_wrap def bulk_delete_by_tuids(tuids, session): """Delete all track samples for bulk tuids. Args: tuids (list): unique ids of tracks session (object): SQLAlchemy database session (optional) Returns: response.Response: result of deletion """ session.query(TrackSample).filter(TrackSample.unique_track_id.in_(tuids))\ .delete(synchronize_session=False) return api_utils.create_ok_response() @mysql.wrap_db_errors @mysql.ows_track_db_session_wrap def get_samples_by_tuids(tuids, session): """Get all track samples for a track. Args: tuid (int): track table identifier. session (object): SQLAlchemy database session (optional) Returns: dict: track samples object with it's artists. """ samples = session.query(TrackSample).filter( TrackSample.unique_track_id.in_(tuids)) samples_data = [each.to_dict() for each in samples] return response.Response(message=samples_data)