diff --git a/data/src/commonMain/kotlin/org/tasks/data/dao/CaldavDao.kt b/data/src/commonMain/kotlin/org/tasks/data/dao/CaldavDao.kt index eda7b5d65..d0dc2054d 100644 --- a/data/src/commonMain/kotlin/org/tasks/data/dao/CaldavDao.kt +++ b/data/src/commonMain/kotlin/org/tasks/data/dao/CaldavDao.kt @@ -4,13 +4,13 @@ import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert import androidx.room.Query +import androidx.room.Transaction import androidx.room.Update import kotlinx.coroutines.flow.Flow import org.tasks.data.CaldavFilters import org.tasks.data.CaldavTaskContainer import org.tasks.data.NO_ORDER import org.tasks.data.TaskContainer -import org.tasks.data.db.Database import org.tasks.data.db.DbUtils.dbchunk import org.tasks.data.db.SuspendDbUtils.chunkedMap import org.tasks.data.entity.CaldavAccount @@ -22,13 +22,12 @@ import org.tasks.data.entity.CaldavAccount.Companion.TYPE_TASKS import org.tasks.data.entity.CaldavCalendar import org.tasks.data.entity.CaldavTask import org.tasks.data.entity.Task -import org.tasks.data.withTransaction import org.tasks.time.DateTimeUtils2.currentTimeMillis const val APPLE_EPOCH = 978307200000L // 1/1/2001 GMT @Dao -abstract class CaldavDao(private val database: Database) { +abstract class CaldavDao { @Query("SELECT COUNT(*) FROM caldav_lists WHERE cdl_account = :account") abstract suspend fun listCount(account: String): Int @@ -99,24 +98,24 @@ ORDER BY CASE cda_account_type @Update abstract suspend fun update(caldavCalendar: CaldavCalendar) - suspend fun insert(task: Task, caldavTask: CaldavTask, addToTop: Boolean): Long = - database.withTransaction { - if (task.order != null) { - return@withTransaction insert(caldavTask) - } - if (addToTop) { - task.order = findFirstTask(caldavTask.calendar!!, task.parent) - ?.takeIf { task.creationDate.toAppleEpoch() >= it } - ?.minus(1) - } else { - task.order = findLastTask(caldavTask.calendar!!, task.parent) - ?.takeIf { task.creationDate.toAppleEpoch() <= it } - ?.plus(1) - } - val id = insert(caldavTask) - update(task) - id + @Transaction + open suspend fun insert(task: Task, caldavTask: CaldavTask, addToTop: Boolean): Long { + if (task.order != null) { + return insert(caldavTask) } + if (addToTop) { + task.order = findFirstTask(caldavTask.calendar!!, task.parent) + ?.takeIf { task.creationDate.toAppleEpoch() >= it } + ?.minus(1) + } else { + task.order = findLastTask(caldavTask.calendar!!, task.parent) + ?.takeIf { task.creationDate.toAppleEpoch() <= it } + ?.plus(1) + } + val id = insert(caldavTask) + update(task) + return id + } @Query(""" SELECT MIN(IFNULL(`order`, (created - $APPLE_EPOCH) / 1000)) @@ -312,49 +311,47 @@ GROUP BY caldav_lists.cdl_uuid + "WHERE _id IN (SELECT _id FROM tasks INNER JOIN caldav_tasks ON _id = cd_task WHERE cd_deleted = 0 AND cd_calendar = :calendar)") abstract suspend fun updateParents(calendar: String) - suspend fun move( + @Transaction + open suspend fun move( task: TaskContainer, previousParent: Long, newParent: Long, newPosition: Long?, ) { - database.withTransaction { - val previousPosition = task.caldavSortOrder - if (newPosition != null) { - if (newParent == previousParent && newPosition < previousPosition) { - shiftDown(task.caldav!!, newParent, newPosition, previousPosition) - } else { - val list = - newParent.takeIf { it > 0 }?.let { getTask(it)?.calendar } ?: task.caldav!! - shiftDown(list, newParent, newPosition) - } + val previousPosition = task.caldavSortOrder + if (newPosition != null) { + if (newParent == previousParent && newPosition < previousPosition) { + shiftDown(task.caldav!!, newParent, newPosition, previousPosition) + } else { + val list = + newParent.takeIf { it > 0 }?.let { getTask(it)?.calendar } ?: task.caldav!! + shiftDown(list, newParent, newPosition) } - task.task.order = newPosition - setTaskOrder(task.id, newPosition) } + task.task.order = newPosition + setTaskOrder(task.id, newPosition) } - suspend fun shiftDown(calendar: String, parent: Long, from: Long, to: Long? = null) { - database.withTransaction { - val updated = ArrayList() - val tasks = getTasksToShift(calendar, parent, from, to) - for (i in tasks.indices) { - val task = tasks[i] - val current = from + i - if (task.sortOrder == current) { - val task = task.task - task.order = current + 1 - updated.add(task) - } else if (task.sortOrder > current) { - break - } + @Transaction + open suspend fun shiftDown(calendar: String, parent: Long, from: Long, to: Long? = null) { + val updated = ArrayList() + val tasks = getTasksToShift(calendar, parent, from, to) + for (i in tasks.indices) { + val task = tasks[i] + val current = from + i + if (task.sortOrder == current) { + val task = task.task + task.order = current + 1 + updated.add(task) + } else if (task.sortOrder > current) { + break } - updateTasks(updated) - updated - .map(Task::id) - .dbchunk() - .forEach { touchInternal(it) } } + updateTasks(updated) + updated + .map(Task::id) + .dbchunk() + .forEach { touchInternal(it) } } @Query("UPDATE tasks SET modified = :modificationTime WHERE _id in (:ids)") diff --git a/data/src/commonMain/kotlin/org/tasks/data/dao/DeletionDao.kt b/data/src/commonMain/kotlin/org/tasks/data/dao/DeletionDao.kt index b50282c27..19f54cc0c 100644 --- a/data/src/commonMain/kotlin/org/tasks/data/dao/DeletionDao.kt +++ b/data/src/commonMain/kotlin/org/tasks/data/dao/DeletionDao.kt @@ -3,16 +3,15 @@ package org.tasks.data.dao import androidx.room.Dao import androidx.room.Delete import androidx.room.Query +import androidx.room.Transaction import org.tasks.data.dao.CaldavDao.Companion.LOCAL -import org.tasks.data.db.Database import org.tasks.data.db.SuspendDbUtils.chunkedMap import org.tasks.data.db.SuspendDbUtils.eachChunk import org.tasks.data.entity.CaldavAccount import org.tasks.data.entity.CaldavCalendar -import org.tasks.data.withTransaction @Dao -abstract class DeletionDao(private val database: Database) { +abstract class DeletionDao { @Query("DELETE FROM tasks WHERE _id IN(:ids)") internal abstract suspend fun deleteTasks(ids: List) @@ -59,13 +58,13 @@ WHERE recurring = 1 @Delete internal abstract suspend fun deleteCaldavCalendar(caldavCalendar: CaldavCalendar) - suspend fun delete(caldavCalendar: CaldavCalendar): List = - database.withTransaction { - val tasks = getActiveCaldavTasks(caldavCalendar.uuid!!) - delete(tasks) - deleteCaldavCalendar(caldavCalendar) - tasks - } + @Transaction + open suspend fun delete(caldavCalendar: CaldavCalendar): List { + val tasks = getActiveCaldavTasks(caldavCalendar.uuid!!) + delete(tasks) + deleteCaldavCalendar(caldavCalendar) + return tasks + } @Query("SELECT * FROM caldav_lists WHERE cdl_account = :account") abstract suspend fun getCalendars(account: String): List @@ -76,13 +75,13 @@ WHERE recurring = 1 @Query("DELETE FROM tasks WHERE _id IN (SELECT _id FROM tasks INNER JOIN caldav_tasks ON _id = cd_task INNER JOIN caldav_lists ON cdl_uuid = cd_calendar WHERE cdl_account = '$LOCAL' AND deleted > 0 AND cd_deleted = 0)") abstract suspend fun purgeDeleted() - suspend fun delete(caldavAccount: CaldavAccount): List = - database.withTransaction { - val deleted = ArrayList() - for (calendar in getCalendars(caldavAccount.uuid!!)) { - deleted.addAll(delete(calendar)) - } - deleteCaldavAccount(caldavAccount) - deleted + @Transaction + open suspend fun delete(caldavAccount: CaldavAccount): List { + val deleted = ArrayList() + for (calendar in getCalendars(caldavAccount.uuid!!)) { + deleted.addAll(delete(calendar)) } + deleteCaldavAccount(caldavAccount) + return deleted + } } \ No newline at end of file diff --git a/data/src/commonMain/kotlin/org/tasks/data/dao/GoogleTaskDao.kt b/data/src/commonMain/kotlin/org/tasks/data/dao/GoogleTaskDao.kt index 27a95de01..855bc87be 100644 --- a/data/src/commonMain/kotlin/org/tasks/data/dao/GoogleTaskDao.kt +++ b/data/src/commonMain/kotlin/org/tasks/data/dao/GoogleTaskDao.kt @@ -4,32 +4,30 @@ import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert import androidx.room.Query +import androidx.room.Transaction import androidx.room.Update -import org.tasks.data.db.Database import org.tasks.data.entity.CaldavAccount.Companion.TYPE_GOOGLE_TASKS import org.tasks.data.entity.CaldavTask import org.tasks.data.entity.Task -import org.tasks.data.withTransaction @Dao -abstract class GoogleTaskDao(private val database: Database) { +abstract class GoogleTaskDao { @Insert abstract suspend fun insert(task: CaldavTask): Long @Insert abstract suspend fun insert(tasks: Iterable) - suspend fun insertAndShift(task: Task, caldavTask: CaldavTask, top: Boolean) { - database.withTransaction { - if (top) { - task.order = 0 - shiftDown(caldavTask.calendar!!, task.parent, 0) - } else { - task.order = getBottom(caldavTask.calendar!!, task.parent) - } - insert(caldavTask) - update(task) + @Transaction + open suspend fun insertAndShift(task: Task, caldavTask: CaldavTask, top: Boolean) { + if (top) { + task.order = 0 + shiftDown(caldavTask.calendar!!, task.parent, 0) + } else { + task.order = getBottom(caldavTask.calendar!!, task.parent) } + insert(caldavTask) + update(task) } @Query("UPDATE tasks SET `order` = `order` + 1 WHERE parent = :parent AND `order` >= :position AND _id IN (SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :listId)") @@ -44,25 +42,24 @@ abstract class GoogleTaskDao(private val database: Database) { @Query("UPDATE tasks SET `order` = `order` - 1 WHERE parent = :parent AND `order` >= :position AND _id IN (SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :listId)") internal abstract suspend fun shiftUp(listId: String, parent: Long, position: Long) - suspend fun move(task: Task, list: String, newParent: Long, newPosition: Long) { - database.withTransaction { - val previousParent = task.parent - val previousPosition = task.order!! - if (newParent == previousParent) { - if (previousPosition < newPosition) { - shiftUp(list, newParent, previousPosition, newPosition) - } else { - shiftDown(list, newParent, previousPosition, newPosition) - } + @Transaction + open suspend fun move(task: Task, list: String, newParent: Long, newPosition: Long) { + val previousParent = task.parent + val previousPosition = task.order!! + if (newParent == previousParent) { + if (previousPosition < newPosition) { + shiftUp(list, newParent, previousPosition, newPosition) } else { - shiftUp(list, previousParent, previousPosition) - shiftDown(list, newParent, newPosition) + shiftDown(list, newParent, previousPosition, newPosition) } - task.parent = newParent - task.order = newPosition - update(task) - setMoved(task.id, list) + } else { + shiftUp(list, previousParent, previousPosition) + shiftDown(list, newParent, newPosition) } + task.parent = newParent + task.order = newPosition + update(task) + setMoved(task.id, list) } @Query("UPDATE caldav_tasks SET gt_moved = 1 WHERE cd_task = :task and cd_calendar = :list") @@ -168,27 +165,26 @@ WHERE cd_remote_id = :id """) abstract suspend fun updatePosition(id: String, parent: String?, position: String) - suspend fun reposition(caldavDao: CaldavDao, listId: String) { - database.withTransaction { - caldavDao.updateParents(listId) - val orderedTasks = getByRemoteOrder(listId) - var subtasks = 0L - var parent = 0L - for (task in orderedTasks) { - if (task.parent > 0) { - if (task.order != subtasks) { - task.order = subtasks - update(task) - } - subtasks++ - } else { - subtasks = 0 - if (task.order != parent) { - task.order = parent - update(task) - } - parent++ + @Transaction + open suspend fun reposition(caldavDao: CaldavDao, listId: String) { + caldavDao.updateParents(listId) + val orderedTasks = getByRemoteOrder(listId) + var subtasks = 0L + var parent = 0L + for (task in orderedTasks) { + if (task.parent > 0) { + if (task.order != subtasks) { + task.order = subtasks + update(task) } + subtasks++ + } else { + subtasks = 0 + if (task.order != parent) { + task.order = parent + update(task) + } + parent++ } } } diff --git a/data/src/commonMain/kotlin/org/tasks/data/dao/PrincipalDao.kt b/data/src/commonMain/kotlin/org/tasks/data/dao/PrincipalDao.kt index 6fc229383..a9cc790a5 100644 --- a/data/src/commonMain/kotlin/org/tasks/data/dao/PrincipalDao.kt +++ b/data/src/commonMain/kotlin/org/tasks/data/dao/PrincipalDao.kt @@ -4,43 +4,39 @@ import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert import androidx.room.Query +import androidx.room.Transaction import androidx.room.Update import kotlinx.coroutines.flow.Flow import org.tasks.data.PrincipalWithAccess -import org.tasks.data.db.Database import org.tasks.data.entity.CaldavAccount import org.tasks.data.entity.CaldavCalendar import org.tasks.data.entity.Principal import org.tasks.data.entity.PrincipalAccess -import org.tasks.data.withTransaction @Dao -abstract class PrincipalDao(private val database: Database) { +interface PrincipalDao { @Insert - abstract suspend fun insert(principal: Principal): Long + suspend fun insert(principal: Principal): Long @Insert - abstract suspend fun insert(access: PrincipalAccess): Long + suspend fun insert(access: PrincipalAccess): Long @Update - abstract suspend fun update(access: PrincipalAccess) + suspend fun update(access: PrincipalAccess) @Query(""" DELETE FROM principal_access WHERE list = :list AND id NOT IN (:access)""") - abstract suspend fun deleteRemoved(list: Long, access: List) + suspend fun deleteRemoved(list: Long, access: List) @Delete - abstract suspend fun delete(access: PrincipalAccess) - - suspend fun getAll(): List = database.withTransaction { - getAllInternal() - } + suspend fun delete(access: PrincipalAccess) + @Transaction @Query("SELECT * FROM principal_access") - internal abstract suspend fun getAllInternal(): List + suspend fun getAll(): List suspend fun getOrCreatePrincipal(account: CaldavAccount, href: String, displayName: String? = null) = findPrincipal(account.id, href) @@ -69,12 +65,12 @@ WHERE list = :list ).apply { id = insert(this) } @Query("SELECT * FROM principals WHERE account = :account AND href = :href") - abstract suspend fun findPrincipal(account: Long, href: String): Principal? + suspend fun findPrincipal(account: Long, href: String): Principal? @Query("SELECT * FROM principal_access WHERE list = :list and principal = :principal") - abstract suspend fun findAccess(list: Long, principal: Long): PrincipalAccess? + suspend fun findAccess(list: Long, principal: Long): PrincipalAccess? + @Transaction @Query("SELECT * FROM principal_access WHERE list = :id") - abstract fun getPrincipals(id: Long): Flow> - -} \ No newline at end of file + fun getPrincipals(id: Long): Flow> +} diff --git a/data/src/commonMain/kotlin/org/tasks/data/dao/TagDao.kt b/data/src/commonMain/kotlin/org/tasks/data/dao/TagDao.kt index 00bcd2e93..f9a5d5f0b 100644 --- a/data/src/commonMain/kotlin/org/tasks/data/dao/TagDao.kt +++ b/data/src/commonMain/kotlin/org/tasks/data/dao/TagDao.kt @@ -4,14 +4,13 @@ import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert import androidx.room.Query -import org.tasks.data.db.Database +import androidx.room.Transaction import org.tasks.data.entity.Tag import org.tasks.data.entity.TagData import org.tasks.data.entity.Task -import org.tasks.data.withTransaction @Dao -abstract class TagDao(private val database: Database) { +abstract class TagDao { @Query("UPDATE tags SET name = :name WHERE tag_uid = :tagUid") abstract suspend fun rename(tagUid: String, name: String) @@ -36,16 +35,15 @@ abstract class TagDao(private val database: Database) { @Delete abstract suspend fun delete(tags: List) + @Transaction open suspend fun applyTags(task: Task, tagDataDao: TagDataDao, current: List) { - database.withTransaction { - val taskId = task.id - val existing = HashSet(tagDataDao.getTagDataForTask(taskId)) - val selected = HashSet(current) - val added = selected subtract existing - val removed = existing subtract selected - deleteTags(taskId, removed.map { td -> td.remoteId!! }) - insert(task, added) - } + val taskId = task.id + val existing = HashSet(tagDataDao.getTagDataForTask(taskId)) + val selected = HashSet(current) + val added = selected subtract existing + val removed = existing subtract selected + deleteTags(taskId, removed.map { td -> td.remoteId!! }) + insert(task, added) } suspend fun insert(task: Task, tags: Collection) { diff --git a/data/src/commonMain/kotlin/org/tasks/data/dao/TagDataDao.kt b/data/src/commonMain/kotlin/org/tasks/data/dao/TagDataDao.kt index 2c4d0eb0f..9aba9b161 100644 --- a/data/src/commonMain/kotlin/org/tasks/data/dao/TagDataDao.kt +++ b/data/src/commonMain/kotlin/org/tasks/data/dao/TagDataDao.kt @@ -4,20 +4,19 @@ import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert import androidx.room.Query +import androidx.room.Transaction import androidx.room.Update import kotlinx.coroutines.flow.Flow import org.tasks.data.NO_ORDER import org.tasks.data.TagFilters -import org.tasks.data.db.Database import org.tasks.data.db.DbUtils import org.tasks.data.entity.Tag import org.tasks.data.entity.TagData import org.tasks.data.entity.Task -import org.tasks.data.withTransaction import org.tasks.time.DateTimeUtils2.currentTimeMillis @Dao -abstract class TagDataDao(private val database: Database) { +abstract class TagDataDao { @Query("SELECT * FROM tagdata") abstract fun subscribeToTags(): Flow> @@ -80,11 +79,12 @@ abstract class TagDataDao(private val database: Database) { + " GROUP BY tasks._id") internal abstract suspend fun getAllTags(tasks: List): List - suspend fun applyTags( + @Transaction + open suspend fun applyTags( tasks: List, partiallySelected: List, selected: List - ): List = database.withTransaction { + ): List { val modified = HashSet() val keep = partiallySelected.plus(selected).map { it.remoteId!! } for (sublist in tasks.chunked(DbUtils.MAX_SQLITE_ARGS - keep.size)) { @@ -108,14 +108,13 @@ abstract class TagDataDao(private val database: Database) { ) } } - ArrayList(modified) + return ArrayList(modified) } - suspend fun delete(tagData: TagData) { - database.withTransaction { - deleteTags(tagData.remoteId!!) - deleteTagData(tagData) - } + @Transaction + open suspend fun delete(tagData: TagData) { + deleteTags(tagData.remoteId!!) + deleteTagData(tagData) } @Delete