import datetime from apollo_utils.core.constants.dsp import DSP from sqlalchemy import and_, case, func from sqlalchemy.orm import Query from typing import List, Optional from apollo_main_db.apollo import ApolloRecentSearch from src.constants.search.recent import RecentSearchSourceMapping, RecentSearchType, RecentSearchTypeMapping from src.db.base import session as db_session def get_users_recent_search_query(user_id: str, type_list: List[RecentSearchType], dsp_list: List[str] = None) -> Query: """Get users recent search items [playlists or tracks] Args: user_id: User ID. type_list: Search type filter. dsp_list: List of dsp ["apple", "amazon", "spotify"]. Returns: Query. """ source_list = [RecentSearchSourceMapping[dsp] for dsp in dsp_list] filters = [ ApolloRecentSearch.user_id == user_id, ApolloRecentSearch.source.in_(source_list), ] if type_list: # We need this strange logic when searching for playlists because .Net applemusicsearchhistory/ endpoint saved # apple playlist items with ApolloRecentSearch.search_type = 0 because of wrong logic, and we still want to get # those playlists to show them in recent search (for spotify spotifysearchhistory/ endpoint it worked correctly # and was assigned ApolloRecentSearch.search_type = 3 for playlists). # We are going to fix this later but for now our new POST search/recent/ will save searched items with their # correct ApolloRecentSearch.search_type = 3 values for "apple", "amazon" & spotify playlists fixed_type_list = [] for search_type in type_list: if search_type == RecentSearchType.PLAYLIST: fixed_type_list.extend( [ RecentSearchTypeMapping[RecentSearchType.USER.value], RecentSearchTypeMapping[RecentSearchType.PLAYLIST.value], ] ) else: fixed_type_list.append(RecentSearchTypeMapping[search_type.value]) filters.append(ApolloRecentSearch.search_type.in_(fixed_type_list)) query = ( db_session.query( ApolloRecentSearch.uri, func.max(ApolloRecentSearch.created_at).label("timestamp"), case( [(ApolloRecentSearch.source == "AppleMusic", DSP.APPLE.value)], else_=func.lower(ApolloRecentSearch.source), ).label("vendor"), func.IF( and_( ApolloRecentSearch.source == "AppleMusic", ApolloRecentSearch.country_code.is_(None), ApolloRecentSearch.search_type.in_( [ RecentSearchTypeMapping[RecentSearchType.USER.value], RecentSearchTypeMapping[RecentSearchType.PLAYLIST.value], ] ), ), "us", ApolloRecentSearch.country_code, ).label("country_code"), ApolloRecentSearch.search_type, ) .filter(*filters) .group_by(ApolloRecentSearch.user_id, ApolloRecentSearch.uri) ) return query def add_users_recent_search( user_id: str, uri: str, timestamp: int, search_term: Optional[str], dsp: str, search_type: str = RecentSearchType.PLAYLIST.value, country_code: Optional[str] = None, ): """Add users search result to recent Args: user_id: uri: search_type: One of ["track", "playlist"] timestamp: search_term: Word or phrase that was passed by user in the search box dsp: One of ["apple", "spotify", "amazon"] country_code: playlists country_code """ db_session.add( ApolloRecentSearch( user_id=user_id, uri=uri, created_at=datetime.datetime.fromtimestamp((timestamp / 1000)), search_term=search_term, search_type=RecentSearchTypeMapping[search_type], source=RecentSearchSourceMapping[dsp], country_code=country_code, ) ) db_session.commit()