Fix favourites and history deletion

This commit is contained in:
Koitharu
2022-07-21 11:15:08 +03:00
parent 9360787897
commit feb19c4eb5
6 changed files with 61 additions and 30 deletions

View File

@@ -24,8 +24,7 @@ abstract class FavouriteCategoriesDao {
@Update @Update
abstract suspend fun update(category: FavouriteCategoryEntity): Int abstract suspend fun update(category: FavouriteCategoryEntity): Int
@Query("UPDATE favourite_categories SET deleted_at = :now WHERE category_id = :id") suspend fun delete(id: Long) = setDeletedAt(id, System.currentTimeMillis())
abstract suspend fun delete(id: Long, now: Long = System.currentTimeMillis())
@Query("UPDATE favourite_categories SET title = :title, `order` = :order, `track` = :tracker WHERE category_id = :id") @Query("UPDATE favourite_categories SET title = :title, `order` = :order, `track` = :tracker WHERE category_id = :id")
abstract suspend fun update(id: Long, title: String, order: String, tracker: Boolean) abstract suspend fun update(id: Long, title: String, order: String, tracker: Boolean)
@@ -33,8 +32,8 @@ abstract class FavouriteCategoriesDao {
@Query("UPDATE favourite_categories SET `order` = :order WHERE category_id = :id") @Query("UPDATE favourite_categories SET `order` = :order WHERE category_id = :id")
abstract suspend fun updateOrder(id: Long, order: String) abstract suspend fun updateOrder(id: Long, order: String)
@Query("UPDATE favourite_categories SET `track` = :isEnabled WHERE category_id = :id") // @Query("UPDATE favourite_categories SET `track` = :isEnabled WHERE category_id = :id")
abstract suspend fun updateTracking(id: Long, isEnabled: Boolean) // abstract suspend fun updateTracking(id: Long, isEnabled: Boolean)
@Query("UPDATE favourite_categories SET `show_in_lib` = :isEnabled WHERE category_id = :id") @Query("UPDATE favourite_categories SET `show_in_lib` = :isEnabled WHERE category_id = :id")
abstract suspend fun updateLibVisibility(id: Long, isEnabled: Boolean) abstract suspend fun updateLibVisibility(id: Long, isEnabled: Boolean)
@@ -58,4 +57,7 @@ abstract class FavouriteCategoriesDao {
insert(entity) insert(entity)
} }
} }
@Query("UPDATE favourite_categories SET deleted_at = :deletedAt WHERE category_id = :id")
protected abstract suspend fun setDeletedAt(id: Long, deletedAt: Long)
} }

View File

@@ -11,6 +11,8 @@ import org.koitharu.kotatsu.parsers.model.SortOrder
@Dao @Dao
abstract class FavouritesDao { abstract class FavouritesDao {
/** SELECT **/
@Transaction @Transaction
@Query("SELECT * FROM favourites WHERE deleted_at = 0 GROUP BY manga_id ORDER BY created_at DESC") @Query("SELECT * FROM favourites WHERE deleted_at = 0 GROUP BY manga_id ORDER BY created_at DESC")
abstract suspend fun findAll(): List<FavouriteManga> abstract suspend fun findAll(): List<FavouriteManga>
@@ -61,12 +63,12 @@ abstract class FavouritesDao {
) )
abstract suspend fun findAllManga(categoryId: Int): List<MangaEntity> abstract suspend fun findAllManga(categoryId: Int): List<MangaEntity>
suspend fun findCovers(categoryId: Long, order: SortOrder, limit: Int): List<String> { suspend fun findCovers(categoryId: Long, order: SortOrder): List<String> {
val orderBy = getOrderBy(order) val orderBy = getOrderBy(order)
@Language("RoomSql") val query = SimpleSQLiteQuery( @Language("RoomSql") val query = SimpleSQLiteQuery(
"SELECT m.cover_url FROM favourites AS f LEFT JOIN manga AS m ON f.manga_id = m.manga_id " + "SELECT m.cover_url FROM favourites AS f LEFT JOIN manga AS m ON f.manga_id = m.manga_id " +
"WHERE f.category_id = ? AND deleted_at = 0 ORDER BY $orderBy LIMIT ?", "WHERE f.category_id = ? AND deleted_at = 0 ORDER BY $orderBy",
arrayOf<Any>(categoryId, limit), arrayOf<Any>(categoryId),
) )
return findCoversImpl(query) return findCoversImpl(query)
} }
@@ -85,25 +87,33 @@ abstract class FavouritesDao {
@Query("SELECT DISTINCT category_id FROM favourites WHERE manga_id = :id AND deleted_at = 0") @Query("SELECT DISTINCT category_id FROM favourites WHERE manga_id = :id AND deleted_at = 0")
abstract fun observeIds(id: Long): Flow<List<Long>> abstract fun observeIds(id: Long): Flow<List<Long>>
/** INSERT **/
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
abstract suspend fun insert(favourite: FavouriteEntity) abstract suspend fun insert(favourite: FavouriteEntity)
/** UPDATE **/
@Update @Update
abstract suspend fun update(favourite: FavouriteEntity): Int abstract suspend fun update(favourite: FavouriteEntity): Int
@Query("UPDATE favourites SET deleted_at = :now WHERE manga_id = :mangaId") /** DELETE **/
abstract suspend fun delete(mangaId: Long, now: Long = System.currentTimeMillis())
@Query("UPDATE favourites SET deleted_at = :now WHERE manga_id = :mangaId AND category_id = :categoryId") suspend fun delete(mangaId: Long) = setDeletedAt(mangaId, System.currentTimeMillis())
abstract suspend fun delete(categoryId: Long, mangaId: Long, now: Long = System.currentTimeMillis())
suspend fun recover(mangaId: Long) = delete(mangaId, 0L) suspend fun delete(mangaId: Long, categoryId: Long) = setDeletedAt(mangaId, categoryId, System.currentTimeMillis())
suspend fun recover(categoryId: Long, mangaId: Long) = delete(categoryId, mangaId, 0L) suspend fun deleteAll(categoryId: Long) = setDeletedAtAll(categoryId, System.currentTimeMillis())
suspend fun recover(mangaId: Long) = setDeletedAt(mangaId, 0L)
suspend fun recover(mangaId: Long, categoryId: Long) = setDeletedAt(categoryId, mangaId, 0L)
@Query("DELETE FROM favourites WHERE deleted_at != 0 AND deleted_at < :maxDeletionTime") @Query("DELETE FROM favourites WHERE deleted_at != 0 AND deleted_at < :maxDeletionTime")
abstract suspend fun gc(maxDeletionTime: Long) abstract suspend fun gc(maxDeletionTime: Long)
/** TOOLS **/
@Transaction @Transaction
open suspend fun upsert(entity: FavouriteEntity) { open suspend fun upsert(entity: FavouriteEntity) {
if (update(entity) == 0) { if (update(entity) == 0) {
@@ -118,6 +128,15 @@ abstract class FavouritesDao {
@RawQuery @RawQuery
protected abstract suspend fun findCoversImpl(query: SupportSQLiteQuery): List<String> protected abstract suspend fun findCoversImpl(query: SupportSQLiteQuery): List<String>
@Query("UPDATE favourites SET deleted_at = :deletedAt WHERE manga_id = :mangaId")
protected abstract suspend fun setDeletedAt(mangaId: Long, deletedAt: Long)
@Query("UPDATE favourites SET deleted_at = :deletedAt WHERE manga_id = :mangaId AND category_id = :categoryId")
abstract suspend fun setDeletedAt(mangaId: Long, categoryId: Long, deletedAt: Long)
@Query("UPDATE favourites SET deleted_at = :deletedAt WHERE category_id = :categoryId AND deleted_at = 0")
protected abstract suspend fun setDeletedAtAll(categoryId: Long, deletedAt: Long)
private fun getOrderBy(sortOrder: SortOrder) = when (sortOrder) { private fun getOrderBy(sortOrder: SortOrder) = when (sortOrder) {
SortOrder.RATING -> "rating DESC" SortOrder.RATING -> "rating DESC"
SortOrder.NEWEST, SortOrder.NEWEST,

View File

@@ -51,7 +51,7 @@ class FavouritesRepository(
}.distinctUntilChanged() }.distinctUntilChanged()
} }
fun observeCategoriesWithCovers(coversLimit: Int): Flow<Map<FavouriteCategory, List<String>>> { fun observeCategoriesWithCovers(): Flow<Map<FavouriteCategory, List<String>>> {
return db.favouriteCategoriesDao.observeAll() return db.favouriteCategoriesDao.observeAll()
.map { .map {
db.withTransaction { db.withTransaction {
@@ -61,7 +61,6 @@ class FavouritesRepository(
res[cat] = db.favouritesDao.findCovers( res[cat] = db.favouritesDao.findCovers(
categoryId = cat.id, categoryId = cat.id,
order = cat.order, order = cat.order,
limit = coversLimit,
) )
} }
res res
@@ -108,16 +107,24 @@ class FavouritesRepository(
} }
suspend fun removeCategory(id: Long) { suspend fun removeCategory(id: Long) {
db.favouriteCategoriesDao.delete(id) db.withTransaction {
db.favouriteCategoriesDao.delete(id)
db.favouritesDao.deleteAll(id)
}
channels.deleteChannel(id) channels.deleteChannel(id)
} }
suspend fun removeCategories(ids: Collection<Long>) { suspend fun removeCategories(ids: Collection<Long>) {
db.withTransaction { db.withTransaction {
for (id in ids) { for (id in ids) {
removeCategory(id) db.favouriteCategoriesDao.delete(id)
db.favouritesDao.deleteAll(id)
} }
} }
// run after transaction success
for (id in ids) {
channels.deleteChannel(id)
}
} }
suspend fun setCategoryOrder(id: Long, order: SortOrder) { suspend fun setCategoryOrder(id: Long, order: SortOrder) {
@@ -179,7 +186,7 @@ class FavouritesRepository(
private suspend fun recoverToFavourites(ids: Collection<Long>) { private suspend fun recoverToFavourites(ids: Collection<Long>) {
db.withTransaction { db.withTransaction {
for (id in ids) { for (id in ids) {
db.favouritesDao.recover(id) db.favouritesDao.recover(mangaId = id)
} }
} }
} }
@@ -187,7 +194,7 @@ class FavouritesRepository(
private suspend fun recoverToCategory(categoryId: Long, ids: Collection<Long>) { private suspend fun recoverToCategory(categoryId: Long, ids: Collection<Long>) {
db.withTransaction { db.withTransaction {
for (id in ids) { for (id in ids) {
db.favouritesDao.recover(categoryId, id) db.favouritesDao.recover(mangaId = id, categoryId = categoryId)
} }
} }
} }

View File

@@ -39,13 +39,13 @@ class FavouritesCategoriesViewModel(
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) }.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
val detalizedCategories = combine( val detalizedCategories = combine(
repository.observeCategoriesWithCovers(coversLimit = 3), repository.observeCategoriesWithCovers(),
isReorder, isReorder,
) { list, reordering -> ) { list, reordering ->
list.map { (category, covers) -> list.map { (category, covers) ->
CategoryListModel( CategoryListModel(
mangaCount = covers.size, mangaCount = covers.size,
covers = covers, covers = covers.take(3),
category = category, category = category,
isReorderMode = reordering, isReorderMode = reordering,
) )

View File

@@ -43,9 +43,6 @@ abstract class HistoryDao {
@Query("SELECT COUNT(*) FROM history WHERE deleted_at = 0") @Query("SELECT COUNT(*) FROM history WHERE deleted_at = 0")
abstract fun observeCount(): Flow<Int> abstract fun observeCount(): Flow<Int>
@Query("UPDATE history SET deleted_at = :now WHERE deleted_at = 0")
abstract suspend fun clear(now: Long = System.currentTimeMillis())
@Query("SELECT percent FROM history WHERE manga_id = :id AND deleted_at = 0") @Query("SELECT percent FROM history WHERE manga_id = :id AND deleted_at = 0")
abstract suspend fun findProgress(id: Long): Float? abstract suspend fun findProgress(id: Long): Float?
@@ -62,16 +59,16 @@ abstract class HistoryDao {
updatedAt: Long, updatedAt: Long,
): Int ): Int
@Query("UPDATE history SET deleted_at = :now WHERE manga_id = :mangaId") suspend fun delete(mangaId: Long) = setDeletedAt(mangaId, System.currentTimeMillis())
abstract suspend fun delete(mangaId: Long, now: Long = System.currentTimeMillis())
suspend fun recover(mangaId: Long) = delete(mangaId, 0L) suspend fun recover(mangaId: Long) = setDeletedAt(mangaId, 0L)
@Query("DELETE FROM history WHERE deleted_at != 0 AND deleted_at < :maxDeletionTime") @Query("DELETE FROM history WHERE deleted_at != 0 AND deleted_at < :maxDeletionTime")
abstract suspend fun gc(maxDeletionTime: Long) abstract suspend fun gc(maxDeletionTime: Long)
@Query("DELETE FROM history WHERE created_at >= :minDate") suspend fun deleteAfter(minDate: Long) = setDeletedAtAfter(minDate, System.currentTimeMillis())
abstract suspend fun deleteAfter(minDate: Long)
suspend fun clear() = setDeletedAtAfter(0L, System.currentTimeMillis())
suspend fun update(entity: HistoryEntity) = update( suspend fun update(entity: HistoryEntity) = update(
mangaId = entity.mangaId, mangaId = entity.mangaId,
@@ -98,4 +95,10 @@ abstract class HistoryDao {
} }
} }
} }
@Query("UPDATE history SET deleted_at = :deletedAt WHERE manga_id = :mangaId")
protected abstract suspend fun setDeletedAt(mangaId: Long, deletedAt: Long)
@Query("UPDATE history SET deleted_at = :deletedAt WHERE created_at >= :minDate AND deleted_at = 0")
protected abstract suspend fun setDeletedAtAfter(minDate: Long, deletedAt: Long)
} }

View File

@@ -109,7 +109,7 @@ class HistoryRepository(
} }
suspend fun deleteAfter(minDate: Long) { suspend fun deleteAfter(minDate: Long) {
db.historyDao.delete(minDate) db.historyDao.deleteAfter(minDate)
} }
suspend fun delete(ids: Collection<Long>): ReversibleHandle { suspend fun delete(ids: Collection<Long>): ReversibleHandle {