Make daos suspending

pull/1043/head
Alex Baker 4 years ago
parent 72e59bdcd0
commit 122a2c2170

@ -24,8 +24,8 @@ import org.tasks.data.Place
import org.tasks.data.SubtaskInfo
import org.tasks.data.TaskContainer
import org.tasks.data.TaskListQuery
import org.tasks.db.DbUtils.chunkedMap
import org.tasks.db.DbUtils.eachChunk
import org.tasks.db.SuspendDbUtils.chunkedMap
import org.tasks.db.SuspendDbUtils.eachChunk
import org.tasks.jobs.WorkManager
import org.tasks.preferences.Preferences
import org.tasks.time.DateTimeUtils.currentTimeMillis
@ -39,56 +39,52 @@ abstract class TaskDao(private val database: Database) {
this.workManager = workManager
}
fun needsRefresh(): List<Task> {
return needsRefresh(DateUtilities.now())
}
@Query("SELECT * FROM tasks WHERE completed = 0 AND deleted = 0 AND (hideUntil > :now OR dueDate > :now)")
abstract fun needsRefresh(now: Long): List<Task>
abstract suspend fun needsRefresh(now: Long = DateUtilities.now()): List<Task>
fun fetchBlocking(id: Long) = runBlocking {
suspend fun fetchBlocking(id: Long) = runBlocking {
fetch(id)
}
@Query("SELECT * FROM tasks WHERE _id = :id LIMIT 1")
abstract suspend fun fetch(id: Long): Task?
fun fetch(ids: List<Long>): List<Task> = ids.chunkedMap(this::fetchInternal)
suspend fun fetch(ids: List<Long>): List<Task> = ids.chunkedMap(this::fetchInternal)
@Query("SELECT * FROM tasks WHERE _id IN (:ids)")
internal abstract fun fetchInternal(ids: List<Long>): List<Task>
internal abstract suspend fun fetchInternal(ids: List<Long>): List<Task>
@Query("SELECT COUNT(1) FROM tasks WHERE timerStart > 0 AND deleted = 0")
abstract fun activeTimers(): Int
abstract suspend fun activeTimers(): Int
@Query("SELECT tasks.* FROM tasks INNER JOIN notification ON tasks._id = notification.task")
abstract fun activeNotifications(): List<Task>
abstract suspend fun activeNotifications(): List<Task>
@Query("SELECT * FROM tasks WHERE remoteId = :remoteId")
abstract fun fetch(remoteId: String): Task?
abstract suspend fun fetch(remoteId: String): Task?
@Query("SELECT * FROM tasks WHERE completed = 0 AND deleted = 0")
abstract fun getActiveTasks(): List<Task>
abstract suspend fun getActiveTasks(): List<Task>
@Query("SELECT * FROM tasks WHERE hideUntil < (strftime('%s','now')*1000)")
abstract fun getVisibleTasks(): List<Task>
abstract suspend fun getVisibleTasks(): List<Task>
@Query("SELECT * FROM tasks WHERE remoteId IN (:remoteIds) "
+ "AND recurrence IS NOT NULL AND LENGTH(recurrence) > 0")
abstract fun getRecurringTasks(remoteIds: List<String>): List<Task>
abstract suspend fun getRecurringTasks(remoteIds: List<String>): List<Task>
@Query("UPDATE tasks SET completed = :completionDate " + "WHERE remoteId = :remoteId")
abstract fun setCompletionDate(remoteId: String, completionDate: Long)
abstract suspend fun setCompletionDate(remoteId: String, completionDate: Long)
@Query("UPDATE tasks SET snoozeTime = :millis WHERE _id in (:taskIds)")
abstract fun snooze(taskIds: List<Long>, millis: Long)
abstract suspend fun snooze(taskIds: List<Long>, millis: Long)
@Query("SELECT tasks.* FROM tasks "
+ "LEFT JOIN google_tasks ON tasks._id = google_tasks.gt_task "
+ "WHERE gt_list_id IN (SELECT gtl_remote_id FROM google_task_lists WHERE gtl_account = :account)"
+ "AND (tasks.modified > google_tasks.gt_last_sync OR google_tasks.gt_remote_id = '' OR google_tasks.gt_deleted > 0) "
+ "ORDER BY CASE WHEN gt_parent = 0 THEN 0 ELSE 1 END, gt_order ASC")
abstract fun getGoogleTasksToPush(account: String): List<Task>
abstract suspend fun getGoogleTasksToPush(account: String): List<Task>
@Query("""
SELECT tasks.*
@ -96,39 +92,37 @@ abstract class TaskDao(private val database: Database) {
INNER JOIN caldav_tasks ON tasks._id = caldav_tasks.cd_task
WHERE caldav_tasks.cd_calendar = :calendar
AND (tasks.modified > caldav_tasks.cd_last_sync OR caldav_tasks.cd_last_sync = 0)""")
abstract fun getCaldavTasksToPush(calendar: String): List<Task>
abstract suspend fun getCaldavTasksToPush(calendar: String): List<Task>
@Query("SELECT * FROM TASKS "
+ "WHERE completed = 0 AND deleted = 0 AND (notificationFlags > 0 OR notifications > 0)")
abstract fun getTasksWithReminders(): List<Task>
abstract suspend fun getTasksWithReminders(): List<Task>
// --- SQL clause generators
@Query("SELECT * FROM tasks")
abstract fun getAll(): List<Task>
abstract suspend fun getAll(): List<Task>
@Query("SELECT calendarUri FROM tasks " + "WHERE calendarUri IS NOT NULL AND calendarUri != ''")
abstract fun getAllCalendarEvents(): List<String>
abstract suspend fun getAllCalendarEvents(): List<String>
@Query("UPDATE tasks SET calendarUri = '' " + "WHERE calendarUri IS NOT NULL AND calendarUri != ''")
abstract fun clearAllCalendarEvents(): Int
abstract suspend fun clearAllCalendarEvents(): Int
@Query("SELECT calendarUri FROM tasks "
+ "WHERE completed > 0 AND calendarUri IS NOT NULL AND calendarUri != ''")
abstract fun getCompletedCalendarEvents(): List<String>
abstract suspend fun getCompletedCalendarEvents(): List<String>
@Query("UPDATE tasks SET calendarUri = '' "
+ "WHERE completed > 0 AND calendarUri IS NOT NULL AND calendarUri != ''")
abstract fun clearCompletedCalendarEvents(): Int
abstract suspend fun clearCompletedCalendarEvents(): Int
@Transaction
open fun fetchTasks(callback: (SubtaskInfo) -> List<String>): List<TaskContainer> {
return runBlocking {
fetchTasks(callback, getSubtaskInfo())
}
open suspend fun fetchTasks(callback: (SubtaskInfo) -> List<String>): List<TaskContainer> {
return fetchTasks(callback, getSubtaskInfo())
}
@Transaction
open fun fetchTasks(callback: (SubtaskInfo) -> List<String>, subtasks: SubtaskInfo): List<TaskContainer> {
open suspend fun fetchTasks(callback: (SubtaskInfo) -> List<String>, subtasks: SubtaskInfo): List<TaskContainer> {
assertNotMainThread()
val start = if (BuildConfig.DEBUG) DateUtilities.now() else 0
@ -143,17 +137,17 @@ abstract class TaskDao(private val database: Database) {
return result
}
fun fetchTasks(preferences: Preferences, filter: Filter): List<TaskContainer> {
suspend fun fetchTasks(preferences: Preferences, filter: Filter): List<TaskContainer> {
return fetchTasks {
TaskListQuery.getQuery(preferences, filter, it)
}
}
@RawQuery
abstract fun fetchTasks(query: SimpleSQLiteQuery): List<TaskContainer>
abstract suspend fun fetchTasks(query: SimpleSQLiteQuery): List<TaskContainer>
@RawQuery
abstract fun count(query: SimpleSQLiteQuery): Int
abstract suspend fun count(query: SimpleSQLiteQuery): Int
@Query("""
SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtasks,
@ -167,31 +161,30 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
abstract suspend fun getSubtaskInfo(): SubtaskInfo
@RawQuery(observedEntities = [Place::class])
abstract fun getTaskFactory(
query: SimpleSQLiteQuery): DataSource.Factory<Int, TaskContainer>
abstract fun getTaskFactory(query: SimpleSQLiteQuery): DataSource.Factory<Int, TaskContainer>
fun touch(id: Long) = touch(listOf(id))
suspend fun touch(id: Long) = touch(listOf(id))
fun touch(ids: List<Long>) {
suspend fun touch(ids: List<Long>) {
ids.eachChunk { touchInternal(it) }
workManager.sync(false)
}
@Query("UPDATE tasks SET modified = :now WHERE _id in (:ids)")
abstract fun touchInternal(ids: List<Long>, now: Long = currentTimeMillis())
abstract suspend fun touchInternal(ids: List<Long>, now: Long = currentTimeMillis())
fun setParent(parent: Long, tasks: List<Long>) =
suspend fun setParent(parent: Long, tasks: List<Long>) =
tasks.eachChunk { setParentInternal(parent, it) }
@Query("UPDATE tasks SET parent = :parent WHERE _id IN (:children)")
internal abstract fun setParentInternal(parent: Long, children: List<Long>)
internal abstract suspend fun setParentInternal(parent: Long, children: List<Long>)
@Transaction
open fun fetchChildren(id: Long): List<Task> {
open suspend fun fetchChildren(id: Long): List<Task> {
return fetch(getChildren(id))
}
fun getChildren(id: Long): List<Long> {
suspend fun getChildren(id: Long): List<Long> {
return getChildren(listOf(id))
}
@ -207,13 +200,13 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
+ " ON recursive_tasks.task = tasks.parent"
+ " WHERE tasks.deleted = 0)"
+ "SELECT task FROM recursive_tasks")
abstract fun getChildren(ids: List<Long>): List<Long>
abstract suspend fun getChildren(ids: List<Long>): List<Long>
@Query("UPDATE tasks SET collapsed = :collapsed WHERE _id = :id")
abstract fun setCollapsed(id: Long, collapsed: Boolean)
abstract suspend fun setCollapsed(id: Long, collapsed: Boolean)
@Transaction
open fun setCollapsed(preferences: Preferences, filter: Filter, collapsed: Boolean) {
open suspend fun setCollapsed(preferences: Preferences, filter: Filter, collapsed: Boolean) {
fetchTasks(preferences, filter)
.filter(TaskContainer::hasChildren)
.map(TaskContainer::getId)
@ -221,7 +214,7 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
}
@Query("UPDATE tasks SET collapsed = :collapsed WHERE _id IN (:ids)")
abstract fun collapse(ids: List<Long>, collapsed: Boolean)
abstract suspend fun collapse(ids: List<Long>, collapsed: Boolean)
// --- save
// TODO: get rid of this super-hack
@ -229,8 +222,10 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
* Saves the given task to the database.getDatabase(). Task must already exist. Returns true on
* success.
*/
@JvmOverloads
fun save(task: Task, original: Task? = fetchBlocking(task.id)) {
suspend fun save(task: Task) = save(task, fetchBlocking(task.id))
suspend fun save(task: Task, original: Task?) {
if (!task.insignificantChange(original)) {
task.modificationDate = DateUtilities.now()
}
@ -240,12 +235,12 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
}
@Insert
abstract fun insert(task: Task): Long
abstract suspend fun insert(task: Task): Long
@Update
abstract fun update(task: Task): Int
abstract suspend fun update(task: Task): Int
fun createNew(task: Task) {
suspend fun createNew(task: Task) {
task.id = NO_ID
if (task.creationDate == 0L) {
task.creationDate = DateUtilities.now()
@ -257,7 +252,7 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
task.id = insert
}
fun count(filter: Filter): Int {
suspend fun count(filter: Filter): Int {
val query = getQuery(filter.sqlQuery, Field.COUNT)
val start = if (BuildConfig.DEBUG) DateUtilities.now() else 0
val count = count(query)
@ -265,11 +260,11 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
return count
}
fun fetchFiltered(filter: Filter): List<Task> {
suspend fun fetchFiltered(filter: Filter): List<Task> {
return fetchFiltered(filter.getSqlQuery())
}
fun fetchFiltered(queryTemplate: String): List<Task> {
suspend fun fetchFiltered(queryTemplate: String): List<Task> {
val query = getQuery(queryTemplate, Task.FIELDS)
val start = if (BuildConfig.DEBUG) DateUtilities.now() else 0
val tasks = fetchTasks(query)
@ -278,7 +273,7 @@ SELECT EXISTS(SELECT 1 FROM tasks WHERE parent > 0 AND deleted = 0) AS hasSubtas
}
@Query("SELECT _id FROM tasks LEFT JOIN google_tasks ON _id = gt_task AND gt_deleted = 0 LEFT JOIN caldav_tasks ON _id = cd_task AND cd_deleted = 0 WHERE gt_id IS NULL AND cd_id IS NULL AND parent = 0")
abstract fun getLocalTasks(): List<Long>
abstract suspend fun getLocalTasks(): List<Long>
/** Generates SQL clauses */
object TaskCriteria {

@ -10,22 +10,22 @@ interface AlarmDao {
@Query("SELECT alarms.* FROM alarms INNER JOIN tasks ON tasks._id = alarms.task "
+ "WHERE tasks.completed = 0 AND tasks.deleted = 0 AND tasks.lastNotified < alarms.time "
+ "ORDER BY time ASC")
fun getActiveAlarms(): List<Alarm>
suspend fun getActiveAlarms(): List<Alarm>
@Query("SELECT alarms.* FROM alarms INNER JOIN tasks ON tasks._id = alarms.task "
+ "WHERE tasks._id = :taskId AND tasks.completed = 0 AND tasks.deleted = 0 AND tasks.lastNotified < alarms.time "
+ "ORDER BY time ASC")
fun getActiveAlarms(taskId: Long): List<Alarm>
suspend fun getActiveAlarms(taskId: Long): List<Alarm>
@Query("SELECT * FROM alarms WHERE task = :taskId ORDER BY time ASC")
fun getAlarms(taskId: Long): List<Alarm>
suspend fun getAlarms(taskId: Long): List<Alarm>
@Delete
fun delete(alarm: Alarm)
suspend fun delete(alarm: Alarm)
@Insert
fun insert(alarm: Alarm): Long
suspend fun insert(alarm: Alarm): Long
@Insert
fun insert(alarms: Iterable<Alarm>)
suspend fun insert(alarms: Iterable<Alarm>)
}

@ -10,7 +10,7 @@ import com.todoroo.astrid.data.Task
import com.todoroo.astrid.helper.UUIDHelper
import org.tasks.R
import org.tasks.date.DateTimeUtils.toAppleEpoch
import org.tasks.db.DbUtils.chunkedMap
import org.tasks.db.SuspendDbUtils.chunkedMap
import org.tasks.filters.CaldavFilters
import org.tasks.time.DateTimeUtils.currentTimeMillis
@ -20,41 +20,41 @@ abstract class CaldavDao {
abstract fun subscribeToCalendars(): LiveData<List<CaldavCalendar>>
@Query("SELECT * FROM caldav_lists WHERE cdl_uuid = :uuid LIMIT 1")
abstract fun getCalendarByUuid(uuid: String): CaldavCalendar?
abstract suspend fun getCalendarByUuid(uuid: String): CaldavCalendar?
@Query("SELECT * FROM caldav_lists WHERE cdl_account = :uuid")
abstract fun getCalendarsByAccount(uuid: String): List<CaldavCalendar>
abstract suspend fun getCalendarsByAccount(uuid: String): List<CaldavCalendar>
@Query("SELECT * FROM caldav_accounts WHERE cda_uuid = :uuid LIMIT 1")
abstract fun getAccountByUuid(uuid: String): CaldavAccount?
abstract suspend fun getAccountByUuid(uuid: String): CaldavAccount?
@Query("SELECT COUNT(*) FROM caldav_accounts WHERE cda_account_type != 2")
abstract fun accountCount(): Int
abstract suspend fun accountCount(): Int
@Query("SELECT * FROM caldav_accounts ORDER BY cda_account_type, UPPER(cda_name)")
abstract fun getAccounts(): List<CaldavAccount>
abstract suspend fun getAccounts(): List<CaldavAccount>
@Query("UPDATE caldav_accounts SET cda_collapsed = :collapsed WHERE cda_id = :id")
abstract fun setCollapsed(id: Long, collapsed: Boolean)
abstract suspend fun setCollapsed(id: Long, collapsed: Boolean)
@Insert
abstract fun insert(caldavAccount: CaldavAccount): Long
abstract suspend fun insert(caldavAccount: CaldavAccount): Long
@Update
abstract fun update(caldavAccount: CaldavAccount)
abstract suspend fun update(caldavAccount: CaldavAccount)
fun insert(caldavCalendar: CaldavCalendar) {
suspend fun insert(caldavCalendar: CaldavCalendar) {
caldavCalendar.id = insertInternal(caldavCalendar)
}
@Insert
abstract fun insertInternal(caldavCalendar: CaldavCalendar): Long
abstract suspend fun insertInternal(caldavCalendar: CaldavCalendar): Long
@Update
abstract fun update(caldavCalendar: CaldavCalendar)
abstract suspend fun update(caldavCalendar: CaldavCalendar)
@Transaction
open fun insert(task: Task, caldavTask: CaldavTask, addToTop: Boolean): Long {
open suspend fun insert(task: Task, caldavTask: CaldavTask, addToTop: Boolean): Long {
if (caldavTask.order != null) {
return insert(caldavTask)
}
@ -71,104 +71,104 @@ abstract class CaldavDao {
}
@Query("SELECT MIN(IFNULL(cd_order, (created - $APPLE_EPOCH) / 1000)) FROM caldav_tasks INNER JOIN tasks ON _id = cd_task WHERE cd_calendar = :calendar AND cd_deleted = 0 AND deleted = 0 AND parent = :parent")
internal abstract fun findFirstTask(calendar: String, parent: Long): Long?
internal abstract suspend fun findFirstTask(calendar: String, parent: Long): Long?
@Query("SELECT MAX(IFNULL(cd_order, (created - $APPLE_EPOCH) / 1000)) FROM caldav_tasks INNER JOIN tasks ON _id = cd_task WHERE cd_calendar = :calendar AND cd_deleted = 0 AND deleted = 0 AND parent = :parent")
internal abstract fun findLastTask(calendar: String, parent: Long): Long?
internal abstract suspend fun findLastTask(calendar: String, parent: Long): Long?
@Insert
abstract fun insert(caldavTask: CaldavTask): Long
abstract suspend fun insert(caldavTask: CaldavTask): Long
@Insert
abstract fun insert(tasks: Iterable<CaldavTask>)
abstract suspend fun insert(tasks: Iterable<CaldavTask>)
@Update
abstract fun update(caldavTask: CaldavTask)
abstract suspend fun update(caldavTask: CaldavTask)
fun update(caldavTask: SubsetCaldav) {
suspend fun update(caldavTask: SubsetCaldav) {
update(caldavTask.cd_id, caldavTask.cd_order, caldavTask.cd_remote_parent)
}
@Query("UPDATE caldav_tasks SET cd_order = :position, cd_remote_parent = :parent WHERE cd_id = :id")
internal abstract fun update(id: Long, position: Long?, parent: String?)
internal abstract suspend fun update(id: Long, position: Long?, parent: String?)
@Query("UPDATE caldav_tasks SET cd_order = :position WHERE cd_id = :id")
internal abstract fun update(id: Long, position: Long?)
internal abstract suspend fun update(id: Long, position: Long?)
@Query("UPDATE caldav_tasks SET cd_remote_parent = :remoteParent WHERE cd_id = :id")
internal abstract fun update(id: Long, remoteParent: String?)
internal abstract suspend fun update(id: Long, remoteParent: String?)
@Update
abstract fun update(tasks: Iterable<CaldavTask>)
abstract suspend fun update(tasks: Iterable<CaldavTask>)
@Delete
abstract fun delete(caldavTask: CaldavTask)
abstract suspend fun delete(caldavTask: CaldavTask)
@Query("SELECT * FROM caldav_tasks WHERE cd_deleted > 0 AND cd_calendar = :calendar")
abstract fun getDeleted(calendar: String): List<CaldavTask>
abstract suspend fun getDeleted(calendar: String): List<CaldavTask>
@Query("UPDATE caldav_tasks SET cd_deleted = :now WHERE cd_task IN (:tasks)")
abstract fun markDeleted(tasks: List<Long>, now: Long = currentTimeMillis())
abstract suspend fun markDeleted(tasks: List<Long>, now: Long = currentTimeMillis())
@Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId AND cd_deleted = 0 LIMIT 1")
abstract fun getTask(taskId: Long): CaldavTask?
abstract suspend fun getTask(taskId: Long): CaldavTask?
@Query("SELECT cd_remote_id FROM caldav_tasks WHERE cd_task = :taskId AND cd_deleted = 0")
abstract fun getRemoteIdForTask(taskId: Long): String?
abstract suspend fun getRemoteIdForTask(taskId: Long): String?
@Query("SELECT * FROM caldav_tasks WHERE cd_calendar = :calendar AND cd_object = :obj LIMIT 1")
abstract fun getTask(calendar: String, obj: String): CaldavTask?
abstract suspend fun getTask(calendar: String, obj: String): CaldavTask?
@Query("SELECT * FROM caldav_tasks WHERE cd_calendar = :calendar AND cd_remote_id = :remoteId")
abstract fun getTaskByRemoteId(calendar: String, remoteId: String): CaldavTask?
abstract suspend fun getTaskByRemoteId(calendar: String, remoteId: String): CaldavTask?
@Query("SELECT * FROM caldav_tasks WHERE cd_task = :taskId")
abstract fun getTasks(taskId: Long): List<CaldavTask>
abstract suspend fun getTasks(taskId: Long): List<CaldavTask>
@Query("SELECT * FROM caldav_tasks WHERE cd_task in (:taskIds) AND cd_deleted = 0")
abstract fun getTasks(taskIds: List<Long>): List<CaldavTask>
abstract suspend fun getTasks(taskIds: List<Long>): List<CaldavTask>
@Query("SELECT task.*, caldav_task.* FROM tasks AS task "
+ "INNER JOIN caldav_tasks AS caldav_task ON _id = cd_task "
+ "WHERE cd_deleted = 0 AND cd_vtodo IS NOT NULL AND cd_vtodo != ''")
abstract fun getTasks(): List<CaldavTaskContainer>
abstract suspend fun getTasks(): List<CaldavTaskContainer>
@Query("SELECT task.*, caldav_task.* FROM tasks AS task "
+ "INNER JOIN caldav_tasks AS caldav_task ON _id = cd_task "
+ "WHERE cd_calendar = :calendar "
+ "AND modified > cd_last_sync "
+ "AND cd_deleted = 0")
abstract fun getCaldavTasksToPush(calendar: String): List<CaldavTaskContainer>
abstract suspend fun getCaldavTasksToPush(calendar: String): List<CaldavTaskContainer>
@Query("SELECT * FROM caldav_lists ORDER BY cdl_name COLLATE NOCASE")
abstract fun getCalendars(): List<CaldavCalendar>
abstract suspend fun getCalendars(): List<CaldavCalendar>
@Query("SELECT * FROM caldav_lists WHERE cdl_uuid = :uuid LIMIT 1")
abstract fun getCalendar(uuid: String): CaldavCalendar?
abstract suspend fun getCalendar(uuid: String): CaldavCalendar?
@Query("SELECT cd_object FROM caldav_tasks WHERE cd_calendar = :calendar")
abstract fun getObjects(calendar: String): List<String>
abstract suspend fun getObjects(calendar: String): List<String>
fun getTasks(calendar: String, objects: List<String>): List<Long> =
suspend fun getTasks(calendar: String, objects: List<String>): List<Long> =
objects.chunkedMap { getTasksInternal(calendar, it) }
@Query("SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :calendar AND cd_object IN (:objects)")
abstract fun getTasksInternal(calendar: String, objects: List<String>): List<Long>
abstract suspend fun getTasksInternal(calendar: String, objects: List<String>): List<Long>
@Query("SELECT * FROM caldav_lists WHERE cdl_account = :account AND cdl_url NOT IN (:urls)")
abstract fun findDeletedCalendars(account: String, urls: List<String>): List<CaldavCalendar>
abstract suspend fun findDeletedCalendars(account: String, urls: List<String>): List<CaldavCalendar>
@Query("SELECT * FROM caldav_lists WHERE cdl_account = :account AND cdl_url = :url LIMIT 1")
abstract fun getCalendarByUrl(account: String, url: String): CaldavCalendar?
abstract suspend fun getCalendarByUrl(account: String, url: String): CaldavCalendar?
@Query("SELECT caldav_accounts.* from caldav_accounts"
+ " INNER JOIN caldav_tasks ON cd_task = :task"
+ " INNER JOIN caldav_lists ON cd_calendar = cdl_uuid"
+ " WHERE cdl_account = cda_uuid")
abstract fun getAccountForTask(task: Long): CaldavAccount?
abstract suspend fun getAccountForTask(task: Long): CaldavAccount?
@Query("SELECT DISTINCT cd_calendar FROM caldav_tasks WHERE cd_deleted = 0 AND cd_task IN (:tasks)")
abstract fun getCalendars(tasks: List<Long>): List<String>
abstract suspend fun getCalendars(tasks: List<Long>): List<String>
@Query("SELECT caldav_lists.*, COUNT(tasks._id) AS count"
+ " FROM caldav_lists"
@ -176,13 +176,13 @@ abstract class CaldavDao {
+ " LEFT JOIN tasks ON caldav_tasks.cd_task = tasks._id AND tasks.deleted = 0 AND tasks.completed = 0 AND tasks.hideUntil < :now AND cd_deleted = 0"
+ " WHERE caldav_lists.cdl_account = :uuid"
+ " GROUP BY caldav_lists.cdl_uuid")
abstract fun getCaldavFilters(uuid: String, now: Long = currentTimeMillis()): List<CaldavFilters>
abstract suspend fun getCaldavFilters(uuid: String, now: Long = currentTimeMillis()): List<CaldavFilters>
@Query("SELECT tasks._id FROM tasks "
+ "INNER JOIN tags ON tags.task = tasks._id "
+ "INNER JOIN caldav_tasks ON cd_task = tasks._id "
+ "GROUP BY tasks._id")
abstract fun getTasksWithTags(): List<Long>
abstract suspend fun getTasksWithTags(): List<Long>
@Query("UPDATE tasks SET parent = IFNULL(("
+ " SELECT p.cd_task FROM caldav_tasks AS p"
@ -191,7 +191,7 @@ abstract class CaldavDao {
+ " AND p.cd_calendar = caldav_tasks.cd_calendar"
+ " AND p.cd_deleted = 0), 0)"
+ "WHERE _id IN (SELECT _id FROM tasks INNER JOIN caldav_tasks ON _id = cd_task WHERE cd_deleted = 0)")
abstract fun updateParents()
abstract suspend fun updateParents()
@Query("UPDATE tasks SET parent = IFNULL(("
+ " SELECT p.cd_task FROM caldav_tasks AS p"
@ -202,10 +202,10 @@ abstract class CaldavDao {
+ " AND p.cd_calendar = caldav_tasks.cd_calendar"
+ " AND caldav_tasks.cd_deleted = 0), 0)"
+ "WHERE _id IN (SELECT _id FROM tasks INNER JOIN caldav_tasks ON _id = cd_task WHERE cd_deleted = 0 AND cd_calendar = :calendar)")
abstract fun updateParents(calendar: String)
abstract suspend fun updateParents(calendar: String)
@Transaction
open fun move(task: TaskContainer, newParent: Long, newPosition: Long?) {
open suspend fun move(task: TaskContainer, newParent: Long, newPosition: Long?) {
val previousParent = task.parent
val caldavTask = task.caldavTask
val previousPosition = task.caldavSortOrder
@ -221,7 +221,7 @@ abstract class CaldavDao {
}
@Transaction
open fun shiftDown(calendar: String, parent: Long, from: Long, to: Long? = null) {
open suspend fun shiftDown(calendar: String, parent: Long, from: Long, to: Long? = null) {
val updated = ArrayList<CaldavTask>()
val tasks = getTasksToShift(calendar, parent, from, to)
for (i in tasks.indices) {
@ -240,32 +240,32 @@ abstract class CaldavDao {
}
@Query("UPDATE tasks SET modified = :modificationTime WHERE _id in (:ids)")
internal abstract fun touchInternal(ids: List<Long>, modificationTime: Long = now())
internal abstract suspend fun touchInternal(ids: List<Long>, modificationTime: Long = now())
@Query("SELECT task.*, caldav_task.*, IFNULL(cd_order, (created - $APPLE_EPOCH) / 1000) AS primary_sort FROM caldav_tasks AS caldav_task INNER JOIN tasks AS task ON _id = cd_task WHERE cd_calendar = :calendar AND parent = :parent AND cd_deleted = 0 AND deleted = 0 AND primary_sort >= :from AND primary_sort < IFNULL(:to, ${Long.MAX_VALUE}) ORDER BY primary_sort")
internal abstract fun getTasksToShift(calendar: String, parent: Long, from: Long, to: Long?): List<CaldavTaskContainer>
internal abstract suspend fun getTasksToShift(calendar: String, parent: Long, from: Long, to: Long?): List<CaldavTaskContainer>
@Query("UPDATE caldav_lists SET cdl_order = $NO_ORDER")
abstract fun resetOrders()
abstract suspend fun resetOrders()
@Query("UPDATE caldav_lists SET cdl_order = :order WHERE cdl_id = :id")
abstract fun setOrder(id: Long, order: Int)
abstract suspend fun setOrder(id: Long, order: Int)
fun setupLocalAccount(context: Context): CaldavAccount {
suspend fun setupLocalAccount(context: Context): CaldavAccount {
val account = getLocalAccount()
getLocalList(context, account)
return account
}
fun getLocalList(context: Context) = getLocalList(context, getLocalAccount())
suspend fun getLocalList(context: Context) = getLocalList(context, getLocalAccount())
private fun getLocalAccount() = getAccountByUuid(LOCAL) ?: CaldavAccount().apply {
private suspend fun getLocalAccount() = getAccountByUuid(LOCAL) ?: CaldavAccount().apply {
accountType = CaldavAccount.TYPE_LOCAL
uuid = LOCAL
id = insert(this)
}
private fun getLocalList(context: Context, account: CaldavAccount): CaldavCalendar =
private suspend fun getLocalList(context: Context, account: CaldavAccount): CaldavCalendar =
getCalendarsByAccount(account.uuid!!).getOrNull(0)
?: CaldavCalendar(context.getString(R.string.default_list), UUIDHelper.newUUID()).apply {
this.account = account.uuid

@ -10,7 +10,7 @@ import com.todoroo.astrid.data.Task
@Dao
interface ContentProviderDao {
@Query("SELECT name FROM tags WHERE task = :taskId ORDER BY UPPER(name) ASC")
fun getTagNames(taskId: Long): List<String>
suspend fun getTagNames(taskId: Long): List<String>
@Query("""
SELECT *
@ -25,10 +25,10 @@ interface ContentProviderDao {
172800000 * importance
ASC
LIMIT 100""")
fun getAstrid2TaskProviderTasks(): List<Task>
suspend fun getAstrid2TaskProviderTasks(): List<Task>
@Query("SELECT * FROM tagdata WHERE name IS NOT NULL AND name != '' ORDER BY UPPER(name) ASC")
fun tagDataOrderedByName(): List<TagData>
suspend fun tagDataOrderedByName(): List<TagData>
@Query("SELECT * FROM tasks")
fun getTasks(): Cursor

@ -5,31 +5,31 @@ import androidx.room.Delete
import androidx.room.Query
import androidx.room.Transaction
import org.tasks.data.CaldavDao.Companion.LOCAL
import org.tasks.db.DbUtils.eachChunk
import org.tasks.db.SuspendDbUtils.eachChunk
import java.util.*
@Dao
abstract class DeletionDao {
@Query("DELETE FROM caldav_tasks WHERE cd_task IN(:ids)")
abstract fun deleteCaldavTasks(ids: List<Long>)
abstract suspend fun deleteCaldavTasks(ids: List<Long>)
@Query("DELETE FROM google_tasks WHERE gt_task IN(:ids)")
abstract fun deleteGoogleTasks(ids: List<Long>)
abstract suspend fun deleteGoogleTasks(ids: List<Long>)
@Query("DELETE FROM tags WHERE task IN(:ids)")
abstract fun deleteTags(ids: List<Long>)
abstract suspend fun deleteTags(ids: List<Long>)
@Query("DELETE FROM geofences WHERE task IN(:ids)")
abstract fun deleteGeofences(ids: List<Long>)
abstract suspend fun deleteGeofences(ids: List<Long>)
@Query("DELETE FROM alarms WHERE task IN(:ids)")
abstract fun deleteAlarms(ids: List<Long>)
abstract suspend fun deleteAlarms(ids: List<Long>)
@Query("DELETE FROM tasks WHERE _id IN(:ids)")
abstract fun deleteTasks(ids: List<Long>)
abstract suspend fun deleteTasks(ids: List<Long>)
@Transaction
open fun delete(ids: List<Long>) {
open suspend fun delete(ids: List<Long>) {
ids.eachChunk {
deleteAlarms(it)
deleteGeofences(it)
@ -43,20 +43,20 @@ abstract class DeletionDao {
@Query("UPDATE tasks "
+ "SET modified = (strftime('%s','now')*1000), deleted = (strftime('%s','now')*1000)"
+ "WHERE _id IN(:ids)")
abstract fun markDeletedInternal(ids: List<Long>)
abstract suspend fun markDeletedInternal(ids: List<Long>)
fun markDeleted(ids: Iterable<Long>) {
suspend fun markDeleted(ids: Iterable<Long>) {
ids.eachChunk(this::markDeletedInternal)
}
@Query("SELECT gt_task FROM google_tasks WHERE gt_deleted = 0 AND gt_list_id = :listId")
abstract fun getActiveGoogleTasks(listId: String): List<Long>
abstract suspend fun getActiveGoogleTasks(listId: String): List<Long>
@Delete
abstract fun deleteGoogleTaskList(googleTaskList: GoogleTaskList)
abstract suspend fun deleteGoogleTaskList(googleTaskList: GoogleTaskList)
@Transaction
open fun delete(googleTaskList: GoogleTaskList): List<Long> {
open suspend fun delete(googleTaskList: GoogleTaskList): List<Long> {
val tasks = getActiveGoogleTasks(googleTaskList.remoteId!!)
delete(tasks)
deleteGoogleTaskList(googleTaskList)
@ -64,13 +64,13 @@ abstract class DeletionDao {
}
@Delete
abstract fun deleteGoogleTaskAccount(googleTaskAccount: GoogleTaskAccount)
abstract suspend fun deleteGoogleTaskAccount(googleTaskAccount: GoogleTaskAccount)
@Query("SELECT * FROM google_task_lists WHERE gtl_account = :account ORDER BY gtl_title ASC")
abstract fun getLists(account: String): List<GoogleTaskList>
abstract suspend fun getLists(account: String): List<GoogleTaskList>
@Transaction
open fun delete(googleTaskAccount: GoogleTaskAccount): List<Long> {
open suspend fun delete(googleTaskAccount: GoogleTaskAccount): List<Long> {
val deleted = ArrayList<Long>()
for (list in getLists(googleTaskAccount.account!!)) {
deleted.addAll(delete(list))
@ -80,13 +80,13 @@ abstract class DeletionDao {
}
@Query("SELECT cd_task FROM caldav_tasks WHERE cd_calendar = :calendar AND cd_deleted = 0")
abstract fun getActiveCaldavTasks(calendar: String): List<Long>
abstract suspend fun getActiveCaldavTasks(calendar: String): List<Long>
@Delete
abstract fun deleteCaldavCalendar(caldavCalendar: CaldavCalendar)
abstract suspend fun deleteCaldavCalendar(caldavCalendar: CaldavCalendar)
@Transaction
open fun delete(caldavCalendar: CaldavCalendar): List<Long> {
open suspend fun delete(caldavCalendar: CaldavCalendar): List<Long> {
val tasks = getActiveCaldavTasks(caldavCalendar.uuid!!)
delete(tasks)
deleteCaldavCalendar(caldavCalendar)
@ -94,16 +94,16 @@ abstract class DeletionDao {
}
@Query("SELECT * FROM caldav_lists WHERE cdl_account = :account")
abstract fun getCalendars(account: String): List<CaldavCalendar>
abstract suspend fun getCalendars(account: String): List<CaldavCalendar>
@Delete
abstract fun deleteCaldavAccount(caldavAccount: CaldavAccount)
abstract suspend fun deleteCaldavAccount(caldavAccount: CaldavAccount)
@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)")
abstract fun purgeDeleted()
abstract suspend fun purgeDeleted()
@Transaction
open fun delete(caldavAccount: CaldavAccount): List<Long> {
open suspend fun delete(caldavAccount: CaldavAccount): List<Long> {
val deleted = ArrayList<Long>()
for (calendar in getCalendars(caldavAccount.uuid!!)) {
deleted.addAll(delete(calendar))

@ -9,29 +9,29 @@ import com.todoroo.astrid.api.FilterListItem.NO_ORDER
@Dao
interface FilterDao {
@Update
fun update(filter: Filter)
suspend fun update(filter: Filter)
@Query("DELETE FROM filters WHERE _id = :id")
fun delete(id: Long)
suspend fun delete(id: Long)
@Query("SELECT * FROM filters WHERE title = :title COLLATE NOCASE LIMIT 1")
fun getByName(title: String): Filter?
suspend fun getByName(title: String): Filter?
@Insert
fun insert(filter: Filter): Long
suspend fun insert(filter: Filter): Long
@Query("SELECT * FROM filters")
fun getFilters(): List<Filter>
suspend fun getFilters(): List<Filter>
@Query("SELECT * FROM filters WHERE _id = :id LIMIT 1")
fun getById(id: Long): Filter?
suspend fun getById(id: Long): Filter?
@Query("SELECT * FROM filters")
fun getAll(): List<Filter>
suspend fun getAll(): List<Filter>
@Query("UPDATE filters SET f_order = $NO_ORDER")
fun resetOrders()
suspend fun resetOrders()
@Query("UPDATE filters SET f_order = :order WHERE _id = :id")
fun setOrder(id: Long, order: Int)
suspend fun setOrder(id: Long, order: Int)
}

@ -7,13 +7,13 @@ import org.tasks.time.DateTimeUtils.currentTimeMillis
@Dao
abstract class GoogleTaskDao {
@Insert
abstract fun insert(task: GoogleTask): Long
abstract suspend fun insert(task: GoogleTask): Long
@Insert
abstract fun insert(tasks: Iterable<GoogleTask>)
abstract suspend fun insert(tasks: Iterable<GoogleTask>)
@Transaction
open fun insertAndShift(task: GoogleTask, top: Boolean) {
open suspend fun insertAndShift(task: GoogleTask, top: Boolean) {
if (top) {
task.order = 0
shiftDown(task.listId!!, task.parent, 0)
@ -24,19 +24,19 @@ abstract class GoogleTaskDao {
}
@Query("UPDATE google_tasks SET gt_order = gt_order + 1 WHERE gt_list_id = :listId AND gt_parent = :parent AND gt_order >= :position")
abstract fun shiftDown(listId: String, parent: Long, position: Long)
abstract suspend fun shiftDown(listId: String, parent: Long, position: Long)
@Query("UPDATE google_tasks SET gt_order = gt_order - 1 WHERE gt_list_id = :listId AND gt_parent = :parent AND gt_order > :from AND gt_order <= :to")
abstract fun shiftUp(listId: String, parent: Long, from: Long, to: Long)
abstract suspend fun shiftUp(listId: String, parent: Long, from: Long, to: Long)
@Query("UPDATE google_tasks SET gt_order = gt_order + 1 WHERE gt_list_id = :listId AND gt_parent = :parent AND gt_order < :from AND gt_order >= :to")
abstract fun shiftDown(listId: String, parent: Long, from: Long, to: Long)
abstract suspend fun shiftDown(listId: String, parent: Long, from: Long, to: Long)
@Query("UPDATE google_tasks SET gt_order = gt_order - 1 WHERE gt_list_id = :listId AND gt_parent = :parent AND gt_order >= :position")
abstract fun shiftUp(listId: String, parent: Long, position: Long)
abstract suspend fun shiftUp(listId: String, parent: Long, position: Long)
@Transaction
open fun move(task: SubsetGoogleTask, newParent: Long, newPosition: Long) {
open suspend fun move(task: SubsetGoogleTask, newParent: Long, newPosition: Long) {
val previousParent = task.parent
val previousPosition = task.order
if (newParent == previousParent) {
@ -55,67 +55,67 @@ abstract class GoogleTaskDao {
}
@Query("UPDATE google_task_accounts SET gta_collapsed = :collapsed WHERE gta_id = :id")
abstract fun setCollapsed(id: Long, collapsed: Boolean)
abstract suspend fun setCollapsed(id: Long, collapsed: Boolean)
@Query("SELECT * FROM google_tasks WHERE gt_task = :taskId AND gt_deleted = 0 LIMIT 1")
abstract fun getByTaskId(taskId: Long): GoogleTask?
abstract suspend fun getByTaskId(taskId: Long): GoogleTask?
@Update
abstract fun update(googleTask: GoogleTask)
abstract suspend fun update(googleTask: GoogleTask)
private fun update(googleTask: SubsetGoogleTask) {
private suspend fun update(googleTask: SubsetGoogleTask) {
update(googleTask.id, googleTask.parent, googleTask.order)
}
@Query("UPDATE google_tasks SET gt_order = :order, gt_parent = :parent, gt_moved = 1 WHERE gt_id = :id")
abstract fun update(id: Long, parent: Long, order: Long)
abstract suspend fun update(id: Long, parent: Long, order: Long)
@Query("UPDATE google_tasks SET gt_deleted = :now WHERE gt_task = :task OR gt_parent = :task")
abstract fun markDeleted(task: Long, now: Long = currentTimeMillis())
abstract suspend fun markDeleted(task: Long, now: Long = currentTimeMillis())
@Delete
abstract fun delete(deleted: GoogleTask)
abstract suspend fun delete(deleted: GoogleTask)
@Query("SELECT * FROM google_tasks WHERE gt_remote_id = :remoteId LIMIT 1")
abstract fun getByRemoteId(remoteId: String): GoogleTask?
abstract suspend fun getByRemoteId(remoteId: String): GoogleTask?
@Query("SELECT * FROM google_tasks WHERE gt_task = :taskId AND gt_deleted > 0")
abstract fun getDeletedByTaskId(taskId: Long): List<GoogleTask>
abstract suspend fun getDeletedByTaskId(taskId: Long): List<GoogleTask>
@Query("SELECT * FROM google_tasks WHERE gt_task = :taskId")
abstract fun getAllByTaskId(taskId: Long): List<GoogleTask>
abstract suspend fun getAllByTaskId(taskId: Long): List<GoogleTask>
@Query("SELECT DISTINCT gt_list_id FROM google_tasks WHERE gt_deleted = 0 AND gt_task IN (:tasks)")
abstract fun getLists(tasks: List<Long>): List<String>
abstract suspend fun getLists(tasks: List<Long>): List<String>
@Query("SELECT gt_task FROM google_tasks WHERE gt_parent IN (:ids) AND gt_deleted = 0")
abstract fun getChildren(ids: List<Long>): List<Long>
abstract suspend fun getChildren(ids: List<Long>): List<Long>
@Query("SELECT tasks.* FROM tasks JOIN google_tasks ON tasks._id = gt_task WHERE gt_parent = :taskId")
abstract fun getChildTasks(taskId: Long): List<Task>
abstract suspend fun getChildTasks(taskId: Long): List<Task>
@Query("SELECT * FROM google_tasks WHERE gt_parent = :id AND gt_deleted = 0")
abstract fun getChildren(id: Long): List<GoogleTask>
abstract suspend fun getChildren(id: Long): List<GoogleTask>
@Query("SELECT IFNULL(MAX(gt_order), -1) + 1 FROM google_tasks WHERE gt_list_id = :listId AND gt_parent = :parent")
abstract fun getBottom(listId: String, parent: Long): Long
abstract suspend fun getBottom(listId: String, parent: Long): Long
@Query("SELECT gt_remote_id FROM google_tasks JOIN tasks ON tasks._id = gt_task WHERE deleted = 0 AND gt_list_id = :listId AND gt_parent = :parent AND gt_order < :order AND gt_remote_id IS NOT NULL AND gt_remote_id != '' ORDER BY gt_order DESC")
abstract fun getPrevious(listId: String, parent: Long, order: Long): String?
abstract suspend fun getPrevious(listId: String, parent: Long, order: Long): String?
@Query("SELECT gt_remote_id FROM google_tasks WHERE gt_task = :task")
abstract fun getRemoteId(task: Long): String?
abstract suspend fun getRemoteId(task: Long): String?
@Query("SELECT gt_task FROM google_tasks WHERE gt_remote_id = :remoteId")
abstract fun getTask(remoteId: String): Long
abstract suspend fun getTask(remoteId: String): Long
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
@Query("SELECT google_tasks.*, gt_order AS primary_sort, NULL AS secondary_sort FROM google_tasks JOIN tasks ON tasks._id = gt_task WHERE gt_parent = 0 AND gt_list_id = :listId AND tasks.deleted = 0 UNION SELECT c.*, p.gt_order AS primary_sort, c.gt_order AS secondary_sort FROM google_tasks AS c LEFT JOIN google_tasks AS p ON c.gt_parent = p.gt_task JOIN tasks ON tasks._id = c.gt_task WHERE c.gt_parent > 0 AND c.gt_list_id = :listId AND tasks.deleted = 0 ORDER BY primary_sort ASC, secondary_sort ASC")
abstract fun getByLocalOrder(listId: String): List<GoogleTask>
abstract suspend fun getByLocalOrder(listId: String): List<GoogleTask>
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
@Query("SELECT google_tasks.*, gt_remote_order AS primary_sort, NULL AS secondary_sort FROM google_tasks JOIN tasks ON tasks._id = gt_task WHERE gt_parent = 0 AND gt_list_id = :listId AND tasks.deleted = 0 UNION SELECT c.*, p.gt_remote_order AS primary_sort, c.gt_remote_order AS secondary_sort FROM google_tasks AS c LEFT JOIN google_tasks AS p ON c.gt_parent = p.gt_task JOIN tasks ON tasks._id = c.gt_task WHERE c.gt_parent > 0 AND c.gt_list_id = :listId AND tasks.deleted = 0 ORDER BY primary_sort ASC, secondary_sort ASC")
abstract fun getByRemoteOrder(listId: String): List<GoogleTask>
abstract suspend fun getByRemoteOrder(listId: String): List<GoogleTask>
@Query("UPDATE google_tasks"
+ " SET gt_parent = IFNULL(("
@ -125,16 +125,16 @@ abstract class GoogleTaskDao {
+ " AND p.gt_deleted = 0),"
+ " 0)"
+ " WHERE gt_moved = 0")
abstract fun updateParents()
abstract suspend fun updateParents()
@Query("UPDATE google_tasks SET gt_parent = IFNULL((SELECT gt_task FROM google_tasks AS p WHERE p.gt_remote_id = google_tasks.gt_remote_parent), 0) WHERE gt_list_id = :listId AND gt_moved = 0")
abstract fun updateParents(listId: String)
abstract suspend fun updateParents(listId: String)
@Query("UPDATE google_tasks SET gt_remote_parent = :parent, gt_remote_order = :position WHERE gt_remote_id = :id")
abstract fun updatePosition(id: String, parent: String, position: String)
abstract suspend fun updatePosition(id: String, parent: String, position: String)
@Transaction
open fun reposition(listId: String) {
open suspend fun reposition(listId: String) {
updateParents(listId)
val orderedTasks = getByRemoteOrder(listId)
var subtasks = 0L
@ -157,7 +157,7 @@ abstract class GoogleTaskDao {
}
}
fun validateSorting(listId: String) {
suspend fun validateSorting(listId: String) {
val orderedTasks = getByLocalOrder(listId)
var subtasks = 0L
var parent = 0L

@ -9,52 +9,52 @@ import org.tasks.time.DateTimeUtils.currentTimeMillis
@Dao
interface GoogleTaskListDao {
@Query("SELECT COUNT(*) FROM google_task_accounts")
fun accountCount(): Int
suspend fun accountCount(): Int
@Query("SELECT * FROM google_task_accounts")
fun getAccounts(): List<GoogleTaskAccount>
suspend fun getAccounts(): List<GoogleTaskAccount>
@Query("SELECT * FROM google_task_accounts WHERE gta_account = :account COLLATE NOCASE LIMIT 1")
fun getAccount(account: String): GoogleTaskAccount?
suspend fun getAccount(account: String): GoogleTaskAccount?
@Query("SELECT * FROM google_task_lists WHERE gtl_id = :id")
fun getById(id: Long): GoogleTaskList?
suspend fun getById(id: Long): GoogleTaskList?
@Query("SELECT * FROM google_task_lists WHERE gtl_account = :account ORDER BY gtl_title ASC")
fun getLists(account: String): List<GoogleTaskList>
suspend fun getLists(account: String): List<GoogleTaskList>
@Query("SELECT * FROM google_task_lists WHERE gtl_remote_id = :remoteId LIMIT 1")
fun getByRemoteId(remoteId: String): GoogleTaskList?
suspend fun getByRemoteId(remoteId: String): GoogleTaskList?
@Query("SELECT * FROM google_task_lists WHERE gtl_remote_id IN (:remoteIds)")
fun getByRemoteId(remoteIds: List<String>): List<GoogleTaskList>
suspend fun getByRemoteId(remoteIds: List<String>): List<GoogleTaskList>
@Query("SELECT * FROM google_task_lists")
fun subscribeToLists(): LiveData<List<GoogleTaskList>>
@Query("SELECT * FROM google_task_lists WHERE gtl_remote_id = :remoteId AND IFNULL(gtl_account, '') = ''")
fun findExistingList(remoteId: String): GoogleTaskList?
suspend fun findExistingList(remoteId: String): GoogleTaskList?
@Query("SELECT * FROM google_task_lists")
fun getAllLists(): List<GoogleTaskList>
suspend fun getAllLists(): List<GoogleTaskList>
@Query("UPDATE google_task_lists SET gtl_last_sync = 0 WHERE gtl_account = :account")
fun resetLastSync(account: String)
suspend fun resetLastSync(account: String)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertOrReplace(googleTaskList: GoogleTaskList): Long
suspend fun insertOrReplace(googleTaskList: GoogleTaskList): Long
@Insert
fun insert(googleTaskList: GoogleTaskList): Long
suspend fun insert(googleTaskList: GoogleTaskList): Long
@Insert
fun insert(googleTaskAccount: GoogleTaskAccount)
suspend fun insert(googleTaskAccount: GoogleTaskAccount)
@Update
fun update(account: GoogleTaskAccount)
suspend fun update(account: GoogleTaskAccount)
@Update
fun update(list: GoogleTaskList)
suspend fun update(list: GoogleTaskList)
@Query("SELECT google_task_lists.*, COUNT(tasks._id) AS count"
+ " FROM google_task_lists "
@ -62,11 +62,11 @@ interface GoogleTaskListDao {
+ " LEFT JOIN tasks ON google_tasks.gt_task = tasks._id AND tasks.deleted = 0 AND tasks.completed = 0 AND tasks.hideUntil < :now AND gt_deleted = 0"
+ " WHERE google_task_lists.gtl_account = :account"
+ " GROUP BY google_task_lists.gtl_remote_id")
fun getGoogleTaskFilters(account: String, now: Long = currentTimeMillis()): List<GoogleTaskFilters>
suspend fun getGoogleTaskFilters(account: String, now: Long = currentTimeMillis()): List<GoogleTaskFilters>
@Query("UPDATE google_task_lists SET gtl_remote_order = $NO_ORDER")
fun resetOrders()
suspend fun resetOrders()
@Query("UPDATE google_task_lists SET gtl_remote_order = :order WHERE gtl_id = :id")
fun setOrder(id: Long, order: Int)
suspend fun setOrder(id: Long, order: Int)
}

@ -15,7 +15,7 @@ interface LocationDao {
+ " WHERE tasks.completed = 0 AND tasks.deleted = 0"
+ " AND (geofences.arrival > 0 OR geofences.departure > 0)"
+ " GROUP BY places.uid")
fun getPlacesWithGeofences(): List<Place>
suspend fun getPlacesWithGeofences(): List<Place>
@Query("SELECT places.*,"
+ " max(geofences.arrival) as arrival,"
@ -27,92 +27,92 @@ interface LocationDao {
+ " WHERE place = :uid AND tasks.completed = 0 AND tasks.deleted = 0"
+ " AND (geofences.arrival > 0 OR geofences.departure > 0)"
+ " GROUP BY places.uid")
fun getGeofencesByPlace(uid: String): MergedGeofence?
suspend fun getGeofencesByPlace(uid: String): MergedGeofence?
@Query("DELETE FROM geofences WHERE place = :place")
fun deleteGeofencesByPlace(place: String)
suspend fun deleteGeofencesByPlace(place: String)
@Query("SELECT geofences.* FROM geofences"
+ " INNER JOIN tasks ON tasks._id = geofences.task"
+ " WHERE place = :place AND arrival = 1 AND tasks.completed = 0"
+ " AND tasks.deleted = 0 AND tasks.snoozeTime < :now AND tasks.hideUntil < :now")
fun getArrivalGeofences(place: String, now: Long): List<Geofence>
suspend fun getArrivalGeofences(place: String, now: Long): List<Geofence>
@Query("SELECT geofences.* FROM geofences"
+ " INNER JOIN tasks ON tasks._id = geofences.task"
+ " WHERE place = :place AND departure = 1 AND tasks.completed = 0"
+ " AND tasks.deleted = 0 AND tasks.snoozeTime < :now AND tasks.hideUntil < :now")
fun getDepartureGeofences(place: String, now: Long): List<Geofence>
suspend fun getDepartureGeofences(place: String, now: Long): List<Geofence>
@Query("SELECT * FROM geofences"
+ " INNER JOIN places ON geofences.place = places.uid"
+ " WHERE task = :taskId ORDER BY name ASC LIMIT 1")
fun getGeofences(taskId: Long): Location?
suspend fun getGeofences(taskId: Long): Location?
@Query("SELECT geofences.*, places.* FROM geofences INNER JOIN places ON geofences.place = places.uid INNER JOIN tasks ON tasks._id = geofences.task WHERE tasks._id = :taskId AND tasks.deleted = 0 AND tasks.completed = 0")
fun getActiveGeofences(taskId: Long): List<Location>
suspend fun getActiveGeofences(taskId: Long): List<Location>
@Query("SELECT places.*"
+ " FROM places"
+ " INNER JOIN geofences ON geofences.place = places.uid"
+ " WHERE geofences.task = :taskId")
fun getPlaceForTask(taskId: Long): Place?
suspend fun getPlaceForTask(taskId: Long): Place?
@Query("SELECT geofences.*, places.* FROM geofences INNER JOIN places ON geofences.place = places.uid INNER JOIN tasks ON tasks._id = geofences.task WHERE tasks.deleted = 0 AND tasks.completed = 0")
fun getActiveGeofences(): List<Location>
suspend fun getActiveGeofences(): List<Location>
@Query("SELECT COUNT(*) FROM geofences")
suspend fun geofenceCount(): Int
@Delete
fun delete(location: Geofence)
suspend fun delete(location: Geofence)
@Delete
fun delete(place: Place)
suspend fun delete(place: Place)
@Insert
fun insert(location: Geofence): Long
suspend fun insert(location: Geofence): Long
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(place: Place): Long
suspend fun insert(place: Place): Long
@Update
fun update(place: Place)
suspend fun update(place: Place)
@Update
fun update(geofence: Geofence)
suspend fun update(geofence: Geofence)
@Query("SELECT * FROM places WHERE uid = :uid LIMIT 1")
fun getByUid(uid: String): Place?
suspend fun getByUid(uid: String): Place?
@Query("SELECT * FROM geofences WHERE task = :taskId")
fun getGeofencesForTask(taskId: Long): List<Geofence>
suspend fun getGeofencesForTask(taskId: Long): List<Geofence>
@Query("SELECT * FROM places")
fun getPlaces(): List<Place>
suspend fun getPlaces(): List<Place>
@Query("SELECT * FROM places WHERE place_id = :id")
fun getPlace(id: Long): Place?
suspend fun getPlace(id: Long): Place?
@Query("SELECT * FROM places WHERE uid = :uid")
fun getPlace(uid: String): Place?
suspend fun getPlace(uid: String): Place?
@Query("SELECT places.*, IFNULL(COUNT(geofence_id),0) AS count FROM places LEFT OUTER JOIN geofences ON geofences.place = places.uid GROUP BY uid ORDER BY COUNT(geofence_id) DESC")
fun getPlaceUsage(): LiveData<List<PlaceUsage>>
@Query("SELECT * FROM places WHERE latitude LIKE :latitude AND longitude LIKE :longitude")
fun findPlace(latitude: String, longitude: String): Place?
suspend fun findPlace(latitude: String, longitude: String): Place?
@Query("SELECT places.*, COUNT(tasks._id) AS count FROM places "
+ " LEFT JOIN geofences ON geofences.place = places.uid "
+ " LEFT JOIN tasks ON geofences.task = tasks._id AND tasks.completed = 0 AND tasks.deleted = 0 AND tasks.hideUntil < :now"
+ " GROUP BY places.uid"
+ " ORDER BY name COLLATE NOCASE ASC")
fun getPlaceFilters(now: Long = currentTimeMillis()): List<LocationFilters>
suspend fun getPlaceFilters(now: Long = currentTimeMillis()): List<LocationFilters>
@Query("UPDATE places SET place_order = $NO_ORDER")
fun resetOrders()
suspend fun resetOrders()
@Query("UPDATE places SET place_order = :order WHERE place_id = :id")
fun setOrder(id: Long, order: Int)
suspend fun setOrder(id: Long, order: Int)
}

@ -6,31 +6,31 @@ import com.todoroo.astrid.data.Task
@Dao
abstract class TagDao {
@Query("UPDATE tags SET name = :name WHERE tag_uid = :tagUid")
abstract fun rename(tagUid: String, name: String)
abstract suspend fun rename(tagUid: String, name: String)
@Insert
abstract fun insert(tag: Tag)
abstract suspend fun insert(tag: Tag)
@Insert
abstract fun insert(tags: Iterable<Tag>)
abstract suspend fun insert(tags: Iterable<Tag>)
@Query("DELETE FROM tags WHERE task = :taskId AND tag_uid in (:tagUids)")
abstract fun deleteTags(taskId: Long, tagUids: List<String>)
abstract suspend fun deleteTags(taskId: Long, tagUids: List<String>)
@Query("SELECT * FROM tags WHERE tag_uid = :tagUid")
abstract fun getByTagUid(tagUid: String): List<Tag>
abstract suspend fun getByTagUid(tagUid: String): List<Tag>
@Query("SELECT * FROM tags WHERE task = :taskId")
abstract fun getTagsForTask(taskId: Long): List<Tag>
abstract suspend fun getTagsForTask(taskId: Long): List<Tag>
@Query("SELECT * FROM tags WHERE task = :taskId AND tag_uid = :tagUid")
abstract fun getTagByTaskAndTagUid(taskId: Long, tagUid: String): Tag?
abstract suspend fun getTagByTaskAndTagUid(taskId: Long, tagUid: String): Tag?
@Delete
abstract fun delete(tags: List<Tag>)
abstract suspend fun delete(tags: List<Tag>)
@Transaction
open fun applyTags(task: Task, tagDataDao: TagDataDaoBlocking, current: List<TagData>): Boolean {
open suspend fun applyTags(task: Task, tagDataDao: TagDataDaoBlocking, current: List<TagData>): Boolean {
val taskId = task.id
val existing = HashSet(tagDataDao.getTagDataForTask(taskId))
val selected = HashSet<TagData>(current)
@ -41,7 +41,7 @@ abstract class TagDao {
return removed.isNotEmpty() || added.isNotEmpty()
}
fun insert(task: Task, tags: Collection<TagData>) {
suspend fun insert(task: Task, tags: Collection<TagData>) {
if (!tags.isEmpty()) {
insert(tags.map { Tag(task, it) })
}

@ -19,47 +19,47 @@ abstract class TagDataDao {
abstract fun subscribeToTags(): LiveData<List<TagData>>
@Query("SELECT * FROM tagdata WHERE name = :name COLLATE NOCASE LIMIT 1")
abstract fun getTagByName(name: String): TagData?
abstract suspend fun getTagByName(name: String): TagData?
/**
* If a tag already exists in the database that case insensitively matches the given tag, return
* that. Otherwise, return the argument
*/
fun getTagWithCase(tag: String): String? {
suspend fun getTagWithCase(tag: String): String? {
return getTagByName(tag)?.name ?: tag
}
fun searchTags(query: String): List<TagData> {
suspend fun searchTags(query: String): List<TagData> {
return searchTagsInternal("%$query%")
.sortedWith(AlphanumComparator(TagData::name))
.toMutableList()
}
@Query("SELECT * FROM tagdata WHERE name LIKE :query AND name NOT NULL AND name != ''")
protected abstract fun searchTagsInternal(query: String): List<TagData>
protected abstract suspend fun searchTagsInternal(query: String): List<TagData>
@Query("SELECT * FROM tagdata")
abstract fun getAll(): List<TagData>
abstract suspend fun getAll(): List<TagData>
@Query("SELECT * FROM tagdata WHERE remoteId = :uuid LIMIT 1")
abstract fun getByUuid(uuid: String): TagData?
abstract suspend fun getByUuid(uuid: String): TagData?
@Query("SELECT * FROM tagdata WHERE remoteId IN (:uuids)")
abstract fun getByUuid(uuids: Collection<String>): List<TagData>
abstract suspend fun getByUuid(uuids: Collection<String>): List<TagData>
@Query("SELECT * FROM tagdata WHERE name IS NOT NULL AND name != '' ORDER BY UPPER(name) ASC")
abstract fun tagDataOrderedByName(): List<TagData>
abstract suspend fun tagDataOrderedByName(): List<TagData>
@Delete
abstract fun deleteTagData(tagData: TagData)
abstract suspend fun deleteTagData(tagData: TagData)
@Query("DELETE FROM tags WHERE tag_uid = :tagUid")
abstract fun deleteTags(tagUid: String)
abstract suspend fun deleteTags(tagUid: String)
@Query("SELECT * FROM tags WHERE task IN (:tasks) AND tag_uid NOT IN (:tagsToKeep)")
abstract fun tagsToDelete(tasks: List<Long>, tagsToKeep: List<String>): List<Tag>
abstract suspend fun tagsToDelete(tasks: List<Long>, tagsToKeep: List<String>): List<Tag>
fun getTagSelections(tasks: List<Long>): Pair<Set<String>, Set<String>> {
suspend fun getTagSelections(tasks: List<Long>): Pair<Set<String>, Set<String>> {
val allTags = getAllTags(tasks)
val tags = allTags.map { t: String? -> HashSet<String>(t?.split(",") ?: emptySet()) }
val partialTags = tags.flatten().toMutableSet()
@ -83,10 +83,10 @@ abstract class TagDataDao {
+ " LEFT JOIN tags ON tags.task = tasks._id"
+ " WHERE tasks._id IN (:tasks)"
+ " GROUP BY tasks._id")
abstract fun getAllTags(tasks: List<Long>): List<String>
abstract suspend fun getAllTags(tasks: List<Long>): List<String>
@Transaction
open fun applyTags(
open suspend fun applyTags(
tasks: List<Task>, partiallySelected: List<TagData>, selected: List<TagData>): List<Long> {
val modified = HashSet<Long>()
val keep = partiallySelected.plus(selected).map { it.remoteId!! }
@ -106,36 +106,36 @@ abstract class TagDataDao {
}
@Transaction
open fun delete(tagData: TagData) {
open suspend fun delete(tagData: TagData) {
deleteTags(tagData.remoteId!!)
deleteTagData(tagData)
}
@Delete
abstract fun delete(tagData: List<TagData>)
abstract suspend fun delete(tagData: List<TagData>)
@Delete
abstract fun deleteTags(tags: List<Tag>)
abstract suspend fun deleteTags(tags: List<Tag>)
@Query("SELECT tagdata.* FROM tagdata "
+ "INNER JOIN tags ON tags.tag_uid = tagdata.remoteId "
+ "WHERE tags.task = :id "
+ "ORDER BY UPPER(tagdata.name) ASC")
abstract fun getTagDataForTask(id: Long): List<TagData>
abstract suspend fun getTagDataForTask(id: Long): List<TagData>
@Query("SELECT * FROM tagdata WHERE name IN (:names)")
abstract fun getTags(names: List<String>): List<TagData>
abstract suspend fun getTags(names: List<String>): List<TagData>
@Update
abstract fun update(tagData: TagData)
abstract suspend fun update(tagData: TagData)
@Insert
abstract fun insert(tag: TagData): Long
abstract suspend fun insert(tag: TagData): Long
@Insert
abstract fun insert(tags: Iterable<Tag>)
abstract suspend fun insert(tags: Iterable<Tag>)
fun createNew(tag: TagData) {
suspend fun createNew(tag: TagData) {
if (Task.isUuidEmpty(tag.remoteId)) {
tag.remoteId = UUIDHelper.newUUID()
}
@ -148,11 +148,11 @@ abstract class TagDataDao {
+ " LEFT JOIN tasks ON tags.task = tasks._id AND tasks.deleted = 0 AND tasks.completed = 0 AND tasks.hideUntil < :now"
+ " WHERE tagdata.name IS NOT NULL AND tagdata.name != ''"
+ " GROUP BY tagdata.remoteId")
abstract fun getTagFilters(now: Long = currentTimeMillis()): List<TagFilters>
abstract suspend fun getTagFilters(now: Long = currentTimeMillis()): List<TagFilters>
@Query("UPDATE tagdata SET td_order = $NO_ORDER")
abstract fun resetOrders()
abstract suspend fun resetOrders()
@Query("UPDATE tagdata SET td_order = :order WHERE _id = :id")
abstract fun setOrder(id: Long, order: Int)
abstract suspend fun setOrder(id: Long, order: Int)
}

@ -7,24 +7,24 @@ import com.todoroo.astrid.helper.UUIDHelper
@Dao
abstract class TaskAttachmentDao {
@Query("SELECT * FROM task_attachments WHERE task_id = :taskUuid")
abstract fun getAttachments(taskUuid: String): List<TaskAttachment>
abstract suspend fun getAttachments(taskUuid: String): List<TaskAttachment>
@Query("SELECT task_attachments.* FROM task_attachments INNER JOIN tasks ON tasks._id = :task WHERE task_id = tasks.remoteId")
abstract fun getAttachments(task: Long): List<TaskAttachment>
abstract suspend fun getAttachments(task: Long): List<TaskAttachment>
@Query("SELECT * FROM task_attachments")
abstract fun getAttachments(): List<TaskAttachment>
abstract suspend fun getAttachments(): List<TaskAttachment>
@Delete
abstract fun delete(taskAttachment: TaskAttachment)
abstract suspend fun delete(taskAttachment: TaskAttachment)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insert(attachment: TaskAttachment)
abstract suspend fun insert(attachment: TaskAttachment)
@Update
abstract fun update(attachment: TaskAttachment)
abstract suspend fun update(attachment: TaskAttachment)
fun createNew(attachment: TaskAttachment) {
suspend fun createNew(attachment: TaskAttachment) {
if (Task.isUuidEmpty(attachment.remoteId)) {
attachment.remoteId = UUIDHelper.newUUID()
}

@ -8,18 +8,18 @@ import androidx.room.Update
@Dao
abstract class TaskListMetadataDao {
@Query("SELECT * from task_list_metadata where tag_uuid = :tagUuid OR filter = :tagUuid LIMIT 1")
abstract fun fetchByTagOrFilter(tagUuid: String): TaskListMetadata?
abstract suspend fun fetchByTagOrFilter(tagUuid: String): TaskListMetadata?
@Query("SELECT * FROM task_list_metadata")
abstract fun getAll(): List<TaskListMetadata>
abstract suspend fun getAll(): List<TaskListMetadata>
@Update
abstract fun update(taskListMetadata: TaskListMetadata)
abstract suspend fun update(taskListMetadata: TaskListMetadata)
@Insert
abstract fun insert(taskListMetadata: TaskListMetadata): Long
abstract suspend fun insert(taskListMetadata: TaskListMetadata): Long
fun createNew(taskListMetadata: TaskListMetadata) {
suspend fun createNew(taskListMetadata: TaskListMetadata) {
taskListMetadata.id = insert(taskListMetadata)
}
}

@ -8,24 +8,24 @@ import com.todoroo.astrid.helper.UUIDHelper
@Dao
abstract class UserActivityDao {
@Insert
abstract fun insert(userActivity: UserActivity)
abstract suspend fun insert(userActivity: UserActivity)
@Update
abstract fun update(userActivity: UserActivity)
abstract suspend fun update(userActivity: UserActivity)
@Delete
abstract fun delete(userActivity: UserActivity)
abstract suspend fun delete(userActivity: UserActivity)
@Query("SELECT * FROM userActivity WHERE target_id = :taskUuid ORDER BY created_at DESC ")
abstract fun getCommentsForTask(taskUuid: String): List<UserActivity>
abstract suspend fun getCommentsForTask(taskUuid: String): List<UserActivity>
@Query("SELECT userActivity.* FROM userActivity INNER JOIN tasks ON tasks._id = :task WHERE target_id = tasks.remoteId")
abstract fun getComments(task: Long): List<UserActivity>
abstract suspend fun getComments(task: Long): List<UserActivity>
@Query("SELECT * FROM userActivity")
abstract fun getComments(): List<UserActivity>
abstract suspend fun getComments(): List<UserActivity>
fun createNew(item: UserActivity) {
suspend fun createNew(item: UserActivity) {
if (item.created == null || item.created == 0L) {
item.created = DateUtilities.now()
}

@ -0,0 +1,11 @@
package org.tasks.db
import org.tasks.db.DbUtils.dbchunk
object SuspendDbUtils {
suspend fun <T> Iterable<T>.eachChunk(action: suspend (List<T>) -> Unit) =
dbchunk().forEach { action.invoke(it) }
suspend fun <T, R> Iterable<T>.chunkedMap(transform: suspend (List<T>) -> Iterable<R>): List<R> =
dbchunk().flatMap { transform.invoke(it) }
}

@ -8,20 +8,20 @@ import androidx.room.Query
@Dao
interface NotificationDao {
@Query("SELECT task FROM notification")
fun getAll(): List<Long>
suspend fun getAll(): List<Long>
@Query("SELECT * FROM notification ORDER BY timestamp DESC")
fun getAllOrdered(): List<Notification>
suspend fun getAllOrdered(): List<Notification>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(notifications: List<Notification>)
suspend fun insertAll(notifications: List<Notification>)
@Query("DELETE FROM notification WHERE task = :taskId")
fun delete(taskId: Long)
suspend fun delete(taskId: Long)
@Query("DELETE FROM notification WHERE task IN(:taskIds)")
fun deleteAll(taskIds: List<Long>)
suspend fun deleteAll(taskIds: List<Long>)
@Query("SELECT MAX(timestamp) FROM notification")
fun latestTimestamp(): Long
suspend fun latestTimestamp(): Long
}
Loading…
Cancel
Save