/* * Copyright (c) 2023. yo-saito. All Rights Reserved. */ package net.piedpiper.bremer.service import net.piedpiper.bremer.dao.AudioDao import net.piedpiper.bremer.dao.PlaylistAudioDao import net.piedpiper.bremer.dao.PlaylistDao import net.piedpiper.bremer.entity.AudioEntity import net.piedpiper.bremer.entity.PlaylistAudioEntity import net.piedpiper.bremer.entity.PlaylistEntity import net.piedpiper.bremer.exception.BadRequestException import net.piedpiper.bremer.exception.NotFoundException import net.piedpiper.bremer.model.api.AllPlaylistResponse import net.piedpiper.bremer.model.api.PlaylistAudioRequest import net.piedpiper.bremer.model.api.PlaylistAudioResponse import net.piedpiper.bremer.model.api.PlaylistRequest import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.* @Service("bremer.service.PlaylistService") class PlaylistService( @Qualifier("bremer.dao.PlaylistDao") private val playlistDao: PlaylistDao, @Qualifier("bremer.dao.PlaylistAudioDao") private val playlistAudioDao: PlaylistAudioDao, @Qualifier("bremer.dao.AudioDao") private val audioDao: AudioDao ) { @Transactional fun getAllPlaylists(): AllPlaylistResponse = AllPlaylistResponse(playlistDao.findAllOrderBySequence()) @Transactional fun getPlaylist(slug: String): PlaylistAudioResponse = playlistDao.findOneBySlug(slug) ?.let { PlaylistAudioResponse( playlistEntity = it, audioEntityList = it?.playlistAudio ?.mapNotNull { it.audioId } ?.let { ids -> findAllByOrderedIds(ids) } ) } ?: throw NotFoundException() private fun findAllByOrderedIds(ids: List<Long>): List<AudioEntity> { val id2idx = ids.mapIndexed { index, id -> id to index }.toMap() return audioDao.findAllByIdIn(ids) .sortedBy { id2idx[it.id] } } private fun findAllByOrderedSlugs(slugs: List<String>): List<AudioEntity> { if (slugs.isEmpty()) { return emptyList() } val slug2idx = slugs.mapIndexed { index, slug -> slug to index }.toMap() return audioDao.findAllBySlugIn(slugs) .sortedBy { slug2idx[it.slug] } } @Transactional fun createPlaylist(request: PlaylistRequest) { playlistDao.insertOne( PlaylistEntity( slug = UUID.randomUUID().toString(), name = request.name ) ) } @Transactional fun updatePlaylist(slug: String, request: PlaylistRequest) { val entity = playlistDao.findOneBySlugWithLock(slug) ?: throw NotFoundException() entity.name = request.name playlistDao.updateOne(entity) } @Transactional fun updatePlaylistAudioList( slug: String, request: PlaylistAudioRequest ) { playlistDao.findOneBySlug(slug) ?.let { playlist -> val audioList = findAllByOrderedSlugs(request.audioSlugs) if (request.audioSlugs.size != audioList.size) { throw BadRequestException() } val registeredAudioIds = playlist.playlistAudio.map { it.audioId }.toSet() val requestAudioIds = audioList.map { it.id }.toSet() val playlistSize = playlist.playlistAudio?.size ?: 0 // delete val deleteIds = playlist.playlistAudio .filter { !requestAudioIds.contains(it.audioId) } .map { it.id } .toList() if (deleteIds.isNotEmpty()) { playlistAudioDao.deleteAllByIds( playlist.playlistAudio .filter { !requestAudioIds.contains(it.audioId) } .map { it.id } .toList() ) } audioList.forEachIndexed { idx, audio -> if (registeredAudioIds.contains(audio.id)) { // ignore return@forEachIndexed } // add playlistAudioDao.insertOne( PlaylistAudioEntity( id = if (idx >= playlistSize) 0L else playlist?.playlistAudio!![idx].id, playlistId = playlist.id, sequence = idx, audioId = audio.id ) ) } } ?: throw NotFoundException() } private fun convertToPlaylistAudioResponse(entity: PlaylistEntity): PlaylistAudioResponse { val audioList = entity?.playlistAudio?.mapNotNull { it.audioId } ?.let { findAllByOrderedIds(it) } ?: emptyList() return PlaylistAudioResponse( playlistEntity = entity, audioEntityList = audioList ) } }