diff --git a/src/main/kotlin/controller/api/AudioApiController.kt b/src/main/kotlin/controller/api/AudioApiController.kt index fe26b9f..6530669 100644 --- a/src/main/kotlin/controller/api/AudioApiController.kt +++ b/src/main/kotlin/controller/api/AudioApiController.kt @@ -22,7 +22,6 @@ private const val PAGE_LIMIT = 50 } - // TODO 複数キーワード対応 @GetMapping fun getAudioList( @RequestParam("audio", required = false) audioName: String?, @@ -48,7 +47,7 @@ fun updateHistory( @PathVariable("slug") slug: String ): ResponseEntity { - audioService.updateHistory(slug) + audioService.updateHistory(slug, PAGE_LIMIT) return ResponseEntity.ok(null) } @@ -60,4 +59,12 @@ audioService.update(slug, request) return ResponseEntity.ok(null) } + + @DeleteMapping("{slug}") + fun deleteAudio( + @PathVariable("slug") slug: String + ): ResponseEntity { + audioService.delete(slug) + return ResponseEntity.ok(null) + } } \ No newline at end of file diff --git a/src/main/kotlin/dao/AlbumDao.kt b/src/main/kotlin/dao/AlbumDao.kt index c8fcdcc..fa12669 100644 --- a/src/main/kotlin/dao/AlbumDao.kt +++ b/src/main/kotlin/dao/AlbumDao.kt @@ -47,6 +47,9 @@ @UpdateProvider(type = Sql::class, method = "updateOne") fun updateOne(@Param("entity") entity: AlbumEntity) + @Delete("DELETE FROM album WHERE id = #{id}") + fun deleteOneById(@Param("id") id: Long): Boolean + class Sql { companion object { @JvmStatic diff --git a/src/main/kotlin/dao/AudioDao.kt b/src/main/kotlin/dao/AudioDao.kt index 1214fd4..654dd5d 100644 --- a/src/main/kotlin/dao/AudioDao.kt +++ b/src/main/kotlin/dao/AudioDao.kt @@ -54,6 +54,9 @@ @UpdateProvider(type = Sql::class, method = "updateOne") fun updateOne(@Param("entity") entity: AudioEntity) + @Delete("DELETE FROM audio WHERE slug = #{slug}") + fun deleteOneBySlug(@Param("slug") slug: String): Boolean + class Sql { companion object { @JvmStatic diff --git a/src/main/kotlin/dao/AudioPlayHistoryDao.kt b/src/main/kotlin/dao/AudioPlayHistoryDao.kt index d535a84..d8ad53c 100644 --- a/src/main/kotlin/dao/AudioPlayHistoryDao.kt +++ b/src/main/kotlin/dao/AudioPlayHistoryDao.kt @@ -5,7 +5,10 @@ package net.piedpiper.bremer.dao import net.piedpiper.bremer.entity.AudioPlayHistoryEntity +import net.piedpiper.bremer.utils.SelectSQLBuilder +import net.piedpiper.bremer.utils.WHERE_IN import org.apache.ibatis.annotations.* +import org.apache.ibatis.jdbc.SQL import org.springframework.stereotype.Repository @Repository("bremer.dao.AudioPlayHistoryDao") @@ -13,8 +16,14 @@ interface AudioPlayHistoryDao { @ResultMap("net.piedpiper.bremer.AudioPlayHistoryEntity") - @Select("SELECT * FROM audio_play_history ORDER BY last_played_at DESC LIMIT #{limit}") - fun findAllOrderLastPlayedAtDescLimit(@Param("limit") limit: Int): List + @Select( + "SELECT * FROM audio_play_history ORDER BY last_played_at DESC " + + "LIMIT #{limit} OFFSET #{offset}" + ) + fun findAllOrderLastPlayedAtDescLimit( + @Param("limit") limit: Int, + @Param("offset") offset: Long + ): List @Insert( """ @@ -25,4 +34,17 @@ ) @Options(useGeneratedKeys = true, keyProperty = "id") fun insertOrUpdateOne(@Param("entity") entity: AudioPlayHistoryEntity): Boolean + + @DeleteProvider(type = Sql::class, method = "deleteAllByIds") + fun deleteAllByIds(@Param("ids") ids: List): Long + + class Sql { + companion object { + @JvmStatic + fun deleteAllByIds(@Param("ids") ids: List): String = SQL() + .DELETE_FROM("audio_play_history") + .WHERE_IN("id", "ids", ids.size) + .toString() + } + } } \ No newline at end of file diff --git a/src/main/kotlin/dao/PlaylistDao.kt b/src/main/kotlin/dao/PlaylistDao.kt index c616ec7..01d9e0a 100644 --- a/src/main/kotlin/dao/PlaylistDao.kt +++ b/src/main/kotlin/dao/PlaylistDao.kt @@ -36,7 +36,7 @@ fun insertOne(@Param("entity") entity: PlaylistEntity): Boolean @Delete("DELETE FROM playlist WHERE slug = #{slug}") - fun deleteBySlug(@Param("slug") slug: String): Boolean + fun deleteOneBySlug(@Param("slug") slug: String): Boolean @UpdateProvider(type = Sql::class, method = "updateOne") fun updateOne(@Param("entity") entity: PlaylistEntity) diff --git a/src/main/kotlin/service/AudioService.kt b/src/main/kotlin/service/AudioService.kt index 0fcbdd7..9d28abf 100644 --- a/src/main/kotlin/service/AudioService.kt +++ b/src/main/kotlin/service/AudioService.kt @@ -74,7 +74,7 @@ /** 最近再生した曲一覧を取得 */ @Transactional fun getLeastRecentlyAccessedAudio(pageSize: Int): AudioListResponse { - val historyMap = audioPlayHistoryDao.findAllOrderLastPlayedAtDescLimit(pageSize) + val historyMap = audioPlayHistoryDao.findAllOrderLastPlayedAtDescLimit(pageSize, 0L) .associateBy { it.audioId } return if (historyMap.isNotEmpty()) audioDao.findAllByIdIn(historyMap.keys.map { it }) @@ -86,6 +86,7 @@ else AudioListResponse() } + /** 更新 */ @Transactional fun update(slug: String, request: AudioRequest) = audioDao.findOneBySlugWithLock(slug) ?.let { @@ -107,14 +108,37 @@ } } ?: throw NotFoundException() - fun updateHistory(slug: String) { - audioDao.findOneBySlug(slug)?.let { + /** 音楽削除 */ + @Transactional + fun delete(slug: String) = audioDao.findOneBySlugWithLock(slug) + ?.let { + audioDao.deleteOneBySlug(it.slug) + if (audioDao.findAllByAlbumIdIn(listOf(it.albumId)) + .isEmpty() + ) { + albumDao.deleteOneById(it.albumId); + } + } ?: throw NotFoundException() + + /** 履歴更新 */ + @Transactional + fun updateHistory(slug: String, pageSize: Int) { + audioDao.findOneBySlug(slug)?.let { it -> audioPlayHistoryDao.insertOrUpdateOne( AudioPlayHistoryEntity( audioId = it.id, lastPlayedAt = LocalDateTime.now(ZoneId.of("Asia/Tokyo")) ) ) + while (true) { + audioPlayHistoryDao.findAllOrderLastPlayedAtDescLimit(pageSize, 1L) + ?.let { result -> + if (result.isEmpty()) { + return + } + audioPlayHistoryDao.deleteAllByIds(result.map { history -> history.id }) + } + } } } @@ -133,13 +157,19 @@ return audioDao.findAllByAlbumIdIn(albums.map { it.id }.distinct()) } - private fun findAllByAlbumNamesLikeLimit(albumNamesLike: List, limit: Int): List { + private fun findAllByAlbumNamesLikeLimit( + albumNamesLike: List, + limit: Int + ): List { val albums = albumDao.findAllByNamesLikeLimit(albumNamesLike, limit) return if (albums.isNotEmpty()) audioDao .findAllByAlbumIdIn(albums.map { it.id }) else emptyList() } - private fun findAllByTagNamesLikeLimit(tagNamesLike: List, limit: Int): List { + private fun findAllByTagNamesLikeLimit( + tagNamesLike: List, + limit: Int + ): List { val tags = tagDao.findAllByNamesLikeLimit(tagNamesLike, limit) return if (tags.isNotEmpty()) audioDao.findAllByTagIdIn(tags.map { it.id }) else emptyList() } diff --git a/src/main/kotlin/service/PlaylistService.kt b/src/main/kotlin/service/PlaylistService.kt index ce5ef04..5bd58b7 100644 --- a/src/main/kotlin/service/PlaylistService.kt +++ b/src/main/kotlin/service/PlaylistService.kt @@ -89,7 +89,7 @@ playlistAudioDao.deleteAllByIds( playlist.playlistAudio.map { it.id }) } - playlistDao.deleteBySlug(slug) + playlistDao.deleteOneBySlug(slug) } @Transactional