Migrate to bundled sqlite

pull/2898/head
Alex Baker 1 month ago
parent 60211355e0
commit 19de0e08a5

@ -200,6 +200,7 @@ dependencies {
implementation(libs.androidx.lifecycle.runtime)
implementation(libs.androidx.lifecycle.viewmodel)
implementation(libs.androidx.room)
implementation(libs.androidx.sqlite)
implementation(libs.androidx.appcompat)
implementation(libs.markwon)
implementation(libs.markwon.editor)

@ -43,15 +43,12 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.room.withTransaction
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.bottomappbar.BottomAppBar
import com.google.android.material.composethemeadapter.MdcTheme
import com.google.android.material.snackbar.Snackbar
import org.tasks.data.sql.Join
import org.tasks.data.sql.QueryTemplate
import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.adapter.TaskAdapter
import com.todoroo.astrid.adapter.TaskAdapterProvider
@ -93,15 +90,18 @@ import org.tasks.billing.PurchaseActivity
import org.tasks.caldav.BaseCaldavCalendarSettingsActivity
import org.tasks.compose.SubscriptionNagBanner
import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.data.TaskContainer
import org.tasks.data.dao.CaldavDao
import org.tasks.data.dao.TagDataDao
import org.tasks.data.db.Database
import org.tasks.data.db.SuspendDbUtils.chunkedMap
import org.tasks.data.entity.Tag
import org.tasks.data.dao.TagDataDao
import org.tasks.data.entity.Task
import org.tasks.data.TaskContainer
import org.tasks.data.listSettingsClass
import org.tasks.data.sql.Join
import org.tasks.data.sql.QueryTemplate
import org.tasks.data.withTransaction
import org.tasks.databinding.FragmentTaskListBinding
import org.tasks.data.db.SuspendDbUtils.chunkedMap
import org.tasks.dialogs.DateTimePicker.Companion.newDateTimePicker
import org.tasks.dialogs.DialogBuilder
import org.tasks.dialogs.FilterPicker.Companion.newFilterPicker

@ -5,7 +5,6 @@ import android.content.Context
import android.media.AudioAttributes
import android.media.AudioAttributes.USAGE_NOTIFICATION_EVENT
import android.media.RingtoneManager
import androidx.room.withTransaction
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.gcal.GCalHelper
import com.todoroo.astrid.repeats.RepeatTaskHelper
@ -14,6 +13,7 @@ import org.tasks.LocalBroadcastManager
import org.tasks.data.dao.CaldavDao
import org.tasks.data.db.Database
import org.tasks.data.entity.Task
import org.tasks.data.withTransaction
import org.tasks.jobs.WorkManager
import org.tasks.notifications.NotificationManager
import org.tasks.preferences.Preferences

@ -1,7 +1,6 @@
package com.todoroo.astrid.service
import android.content.Context
import androidx.room.withTransaction
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.withContext
@ -17,6 +16,8 @@ import org.tasks.data.db.SuspendDbUtils.chunkedMap
import org.tasks.data.entity.CaldavAccount
import org.tasks.data.entity.CaldavCalendar
import org.tasks.data.entity.Task
import org.tasks.data.inTransaction
import org.tasks.data.withTransaction
import org.tasks.files.FileHelper
import org.tasks.location.GeofenceApi
import org.tasks.notifications.NotificationManager

@ -1,15 +1,19 @@
package org.tasks.data
import android.database.Cursor
import androidx.sqlite.db.SupportSQLiteQuery
import org.tasks.data.entity.Task
import android.database.MatrixCursor
import androidx.sqlite.SQLiteStatement
import kotlinx.coroutines.runBlocking
import org.tasks.data.dao.ContentProviderDao
import org.tasks.data.dao.Astrid2ContentProviderDao
import org.tasks.data.db.Database
import org.tasks.data.entity.TagData
import org.tasks.data.entity.Task
import javax.inject.Inject
@Deprecated("use coroutines")
class ContentProviderDaoBlocking @Inject constructor(private val dao: ContentProviderDao) {
class ContentProviderDaoBlocking @Inject constructor(
private val dao: Astrid2ContentProviderDao,
private val database: Database,
) {
fun getTagNames(taskId: Long): List<String> = runBlocking {
dao.getTagNames(taskId)
}
@ -22,9 +26,24 @@ class ContentProviderDaoBlocking @Inject constructor(private val dao: ContentPro
dao.tagDataOrderedByName()
}
fun getTasks(): Cursor = dao.getTasks()
fun getTasks(): Cursor = runBlocking { rawQuery("SELECT * FROM tasks") }
fun getLists(): Cursor = dao.getLists()
fun getLists(): Cursor = runBlocking {
rawQuery("""
SELECT caldav_lists.*, caldav_accounts.cda_name
FROM caldav_lists
INNER JOIN caldav_accounts ON cdl_account = cda_uuid
""".trimIndent()
)
}
fun rawQuery(query: SupportSQLiteQuery): Cursor = dao.rawQuery(query)
}
fun rawQuery(query: String): Cursor = runBlocking { database.rawQuery(query) { it.toCursor() } }
}
private fun SQLiteStatement.toCursor(): Cursor {
val cursor = MatrixCursor(getColumnNames().toTypedArray())
while (step()) {
cursor.addRow((0 until getColumnCount()).map { getText(it) })
}
return cursor
}

@ -1,13 +1,12 @@
package org.tasks.data
import androidx.sqlite.db.SimpleSQLiteQuery
import org.tasks.data.sql.Field
import org.tasks.data.sql.Query
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.PermaSql
import org.tasks.data.entity.Task
import org.tasks.data.dao.TaskDao
import org.tasks.data.db.SuspendDbUtils.eachChunk
import org.tasks.data.entity.Task
import org.tasks.data.sql.Field
import org.tasks.data.sql.Query
import org.tasks.preferences.QueryPreferences
import org.tasks.time.DateTimeUtils2.currentTimeMillis
import timber.log.Timber
@ -30,7 +29,7 @@ suspend fun TaskDao.fetchFiltered(queryTemplate: String): List<Task> {
val query = getQuery(queryTemplate, Task.FIELDS)
val start = if (BuildConfig.DEBUG) currentTimeMillis() else 0
val tasks = fetchTasks(query)
Timber.v("%sms: %s", currentTimeMillis() - start, query.sql)
Timber.v("%sms: %s", currentTimeMillis() - start, query)
return tasks.map(TaskContainer::task)
}
@ -38,13 +37,12 @@ suspend fun TaskDao.count(filter: Filter): Int {
val query = getQuery(filter.sql!!, Field.COUNT)
val start = if (BuildConfig.DEBUG) currentTimeMillis() else 0
val count = countRaw(query)
Timber.v("%sms: %s", currentTimeMillis() - start, query.sql)
Timber.v("%sms: %s", currentTimeMillis() - start, query)
return count
}
private fun getQuery(queryTemplate: String, vararg fields: Field): SimpleSQLiteQuery =
SimpleSQLiteQuery(
Query.select(*fields)
.withQueryTemplate(PermaSql.replacePlaceholdersForQuery(queryTemplate))
.from(Task.TABLE)
.toString())
private fun getQuery(queryTemplate: String, vararg fields: Field): String =
Query.select(*fields)
.withQueryTemplate(PermaSql.replacePlaceholdersForQuery(queryTemplate))
.from(Task.TABLE)
.toString()

@ -2,13 +2,13 @@ package org.tasks.db
import android.content.Context
import android.database.sqlite.SQLiteException
import androidx.core.database.getStringOrNull
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.SQLiteConnection
import androidx.sqlite.execSQL
import androidx.sqlite.use
import org.tasks.R
import org.tasks.caldav.FileStorage
import org.tasks.data.NO_ORDER
import org.tasks.data.OpenTaskDao.Companion.getLong
import org.tasks.data.entity.Alarm.Companion.TYPE_RANDOM
import org.tasks.data.entity.Alarm.Companion.TYPE_REL_END
import org.tasks.data.entity.Alarm.Companion.TYPE_REL_START
@ -21,8 +21,6 @@ import org.tasks.data.entity.Task
import org.tasks.data.entity.Task.Companion.NOTIFY_AFTER_DEADLINE
import org.tasks.data.entity.Task.Companion.NOTIFY_AT_DEADLINE
import org.tasks.data.entity.Task.Companion.NOTIFY_AT_START
import org.tasks.extensions.getLongOrNull
import org.tasks.extensions.getString
import org.tasks.preferences.DefaultFilterProvider
import org.tasks.preferences.Preferences
import org.tasks.repeats.RecurrenceUtils.newRecur
@ -34,21 +32,21 @@ import java.util.concurrent.TimeUnit.HOURS
object Migrations {
private val MIGRATION_35_36: Migration = object : Migration(35, 36) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `tagdata` ADD COLUMN `color` INTEGER DEFAULT -1")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `tagdata` ADD COLUMN `color` INTEGER DEFAULT -1")
}
}
private val MIGRATION_36_37: Migration = object : Migration(36, 37) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `store` ADD COLUMN `deleted` INTEGER DEFAULT 0")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `store` ADD COLUMN `deleted` INTEGER DEFAULT 0")
}
}
private val MIGRATION_37_38: Migration = object : Migration(37, 38) {
override fun migrate(db: SupportSQLiteDatabase) {
override fun migrate(connection: SQLiteConnection) {
try {
db.execSQL("ALTER TABLE `store` ADD COLUMN `value4` TEXT DEFAULT -1")
connection.execSQL("ALTER TABLE `store` ADD COLUMN `value4` TEXT DEFAULT -1")
} catch (e: SQLiteException) {
Timber.w(e)
}
@ -56,263 +54,263 @@ object Migrations {
}
private val MIGRATION_38_39: Migration = object : Migration(38, 39) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `notification` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `type` INTEGER NOT NULL)")
db.execSQL(
connection.execSQL(
"CREATE UNIQUE INDEX `index_notification_task` ON `notification` (`task`)")
}
}
private val MIGRATION_46_47: Migration = object : Migration(46, 47) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `alarms` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `time` INTEGER NOT NULL)")
db.execSQL(
connection.execSQL(
"INSERT INTO `alarms` (`task`, `time`) SELECT `task`, `value` FROM `metadata` WHERE `key` = 'alarm' AND `deleted` = 0")
db.execSQL("DELETE FROM `metadata` WHERE `key` = 'alarm'")
connection.execSQL("DELETE FROM `metadata` WHERE `key` = 'alarm'")
}
}
private val MIGRATION_47_48: Migration = object : Migration(47, 48) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `locations` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `latitude` REAL NOT NULL, `longitude` REAL NOT NULL, `radius` INTEGER NOT NULL)")
db.execSQL("INSERT INTO `locations` (`task`, `name`, `latitude`, `longitude`, `radius`) "
connection.execSQL("INSERT INTO `locations` (`task`, `name`, `latitude`, `longitude`, `radius`) "
+ "SELECT `task`, `value`, `value2`, `value3`, `value4` FROM `metadata` WHERE `key` = 'geofence' AND `deleted` = 0")
db.execSQL("DELETE FROM `metadata` WHERE `key` = 'geofence'")
connection.execSQL("DELETE FROM `metadata` WHERE `key` = 'geofence'")
}
}
private val MIGRATION_48_49: Migration = object : Migration(48, 49) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `tags` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `tag_uid` TEXT, `task_uid` TEXT)")
db.execSQL("INSERT INTO `tags` (`task`, `name`, `tag_uid`, `task_uid`) "
connection.execSQL("INSERT INTO `tags` (`task`, `name`, `tag_uid`, `task_uid`) "
+ "SELECT `task`, `value`, `value2`, `value3` FROM `metadata` WHERE `key` = 'tags-tag' AND `deleted` = 0")
db.execSQL("DELETE FROM `metadata` WHERE `key` = 'tags-tag'")
connection.execSQL("DELETE FROM `metadata` WHERE `key` = 'tags-tag'")
}
}
private val MIGRATION_49_50: Migration = object : Migration(49, 50) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `google_tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `remote_id` TEXT, `list_id` TEXT, `parent` INTEGER NOT NULL, `indent` INTEGER NOT NULL, `order` INTEGER NOT NULL, `remote_order` INTEGER NOT NULL, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL)")
db.execSQL("INSERT INTO `google_tasks` (`task`, `remote_id`, `list_id`, `parent`, `indent`, `order`, `remote_order`, `last_sync`, `deleted`) "
connection.execSQL("INSERT INTO `google_tasks` (`task`, `remote_id`, `list_id`, `parent`, `indent`, `order`, `remote_order`, `last_sync`, `deleted`) "
+ "SELECT `task`, `value`, `value2`, IFNULL(`value3`, 0), IFNULL(`value4`, 0), IFNULL(`value5`, 0), IFNULL(`value6`, 0), IFNULL(`value7`, 0), IFNULL(`deleted`, 0) FROM `metadata` WHERE `key` = 'gtasks'")
db.execSQL("DROP TABLE IF EXISTS `metadata`")
connection.execSQL("DROP TABLE IF EXISTS `metadata`")
}
}
private val MIGRATION_50_51: Migration = object : Migration(50, 51) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `filters` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `sql` TEXT, `values` TEXT, `criterion` TEXT)")
db.execSQL("INSERT INTO `filters` (`title`, `sql`, `values`, `criterion`) "
connection.execSQL("INSERT INTO `filters` (`title`, `sql`, `values`, `criterion`) "
+ "SELECT `item`, `value`, `value2`, `value3` FROM `store` WHERE `type` = 'filter' AND `deleted` = 0")
db.execSQL("DELETE FROM `store` WHERE `type` = 'filter'")
connection.execSQL("DELETE FROM `store` WHERE `type` = 'filter'")
}
}
private val MIGRATION_51_52: Migration = object : Migration(51, 52) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `google_task_lists` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `remote_id` TEXT, `title` TEXT, `remote_order` INTEGER NOT NULL, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `color` INTEGER)")
db.execSQL("INSERT INTO `google_task_lists` (`remote_id`, `title`, `remote_order`, `last_sync`, `color`, `deleted`) "
connection.execSQL("INSERT INTO `google_task_lists` (`remote_id`, `title`, `remote_order`, `last_sync`, `color`, `deleted`) "
+ "SELECT `item`, `value`, `value2`, `value3`, `value4`, `deleted` FROM `store` WHERE `type` = 'gtasks-list'")
db.execSQL("DROP TABLE IF EXISTS `store`")
connection.execSQL("DROP TABLE IF EXISTS `store`")
}
}
private val MIGRATION_52_53: Migration = object : Migration(52, 53) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `tagdata` RENAME TO `tagdata-temp`")
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `tagdata` RENAME TO `tagdata-temp`")
connection.execSQL(
"CREATE TABLE `tagdata` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `name` TEXT, `color` INTEGER, `tagOrdering` TEXT)")
db.execSQL("INSERT INTO `tagdata` (`remoteId`, `name`, `color`, `tagOrdering`) "
connection.execSQL("INSERT INTO `tagdata` (`remoteId`, `name`, `color`, `tagOrdering`) "
+ "SELECT `remoteId`, `name`, `color`, `tagOrdering` FROM `tagdata-temp`")
db.execSQL("DROP TABLE `tagdata-temp`")
db.execSQL("ALTER TABLE `userActivity` RENAME TO `userActivity-temp`")
db.execSQL(
connection.execSQL("DROP TABLE `tagdata-temp`")
connection.execSQL("ALTER TABLE `userActivity` RENAME TO `userActivity-temp`")
connection.execSQL(
"CREATE TABLE `userActivity` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `message` TEXT, `picture` TEXT, `target_id` TEXT, `created_at` INTEGER)")
db.execSQL("INSERT INTO `userActivity` (`remoteId`, `message`, `picture`, `target_id`, `created_at`) "
connection.execSQL("INSERT INTO `userActivity` (`remoteId`, `message`, `picture`, `target_id`, `created_at`) "
+ "SELECT `remoteId`, `message`, `picture`, `target_id`, `created_at` FROM `userActivity-temp`")
db.execSQL("DROP TABLE `userActivity-temp`")
db.execSQL("ALTER TABLE `task_attachments` RENAME TO `task_attachments-temp`")
db.execSQL(
connection.execSQL("DROP TABLE `userActivity-temp`")
connection.execSQL("ALTER TABLE `task_attachments` RENAME TO `task_attachments-temp`")
connection.execSQL(
"CREATE TABLE `task_attachments` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `task_id` TEXT, `name` TEXT, `path` TEXT, `content_type` TEXT)")
db.execSQL("INSERT INTO `task_attachments` (`remoteId`, `task_id`, `name`, `path`, `content_type`) "
connection.execSQL("INSERT INTO `task_attachments` (`remoteId`, `task_id`, `name`, `path`, `content_type`) "
+ "SELECT `remoteId`, `task_id`, `name`, `path`, `content_type` FROM `task_attachments-temp`")
db.execSQL("DROP TABLE `task_attachments-temp`")
connection.execSQL("DROP TABLE `task_attachments-temp`")
}
}
private val MIGRATION_53_54: Migration = object : Migration(53, 54) {
override fun migrate(db: SupportSQLiteDatabase) {
override fun migrate(connection: SQLiteConnection) {
// need to drop columns that were removed in the past
db.execSQL("ALTER TABLE `task_list_metadata` RENAME TO `task_list_metadata-temp`")
db.execSQL(
connection.execSQL("ALTER TABLE `task_list_metadata` RENAME TO `task_list_metadata-temp`")
connection.execSQL(
"CREATE TABLE `task_list_metadata` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `tag_uuid` TEXT, `filter` TEXT, `task_ids` TEXT)")
db.execSQL("INSERT INTO `task_list_metadata` (`remoteId`, `tag_uuid`, `filter`, `task_ids`) "
connection.execSQL("INSERT INTO `task_list_metadata` (`remoteId`, `tag_uuid`, `filter`, `task_ids`) "
+ "SELECT `remoteId`, `tag_uuid`, `filter`, `task_ids` FROM `task_list_metadata-temp`")
db.execSQL("DROP TABLE `task_list_metadata-temp`")
db.execSQL("ALTER TABLE `tasks` RENAME TO `tasks-temp`")
db.execSQL(
connection.execSQL("DROP TABLE `task_list_metadata-temp`")
connection.execSQL("ALTER TABLE `tasks` RENAME TO `tasks-temp`")
connection.execSQL(
"CREATE TABLE `tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `importance` INTEGER, `dueDate` INTEGER, `hideUntil` INTEGER, `created` INTEGER, `modified` INTEGER, `completed` INTEGER, `deleted` INTEGER, `notes` TEXT, `estimatedSeconds` INTEGER, `elapsedSeconds` INTEGER, `timerStart` INTEGER, `notificationFlags` INTEGER, `notifications` INTEGER, `lastNotified` INTEGER, `snoozeTime` INTEGER, `recurrence` TEXT, `repeatUntil` INTEGER, `calendarUri` TEXT, `remoteId` TEXT)")
db.execSQL("DROP INDEX `t_rid`")
db.execSQL("CREATE UNIQUE INDEX `t_rid` ON `tasks` (`remoteId`)")
db.execSQL("INSERT INTO `tasks` (`_id`, `title`, `importance`, `dueDate`, `hideUntil`, `created`, `modified`, `completed`, `deleted`, `notes`, `estimatedSeconds`, `elapsedSeconds`, `timerStart`, `notificationFlags`, `notifications`, `lastNotified`, `snoozeTime`, `recurrence`, `repeatUntil`, `calendarUri`, `remoteId`) "
connection.execSQL("DROP INDEX `t_rid`")
connection.execSQL("CREATE UNIQUE INDEX `t_rid` ON `tasks` (`remoteId`)")
connection.execSQL("INSERT INTO `tasks` (`_id`, `title`, `importance`, `dueDate`, `hideUntil`, `created`, `modified`, `completed`, `deleted`, `notes`, `estimatedSeconds`, `elapsedSeconds`, `timerStart`, `notificationFlags`, `notifications`, `lastNotified`, `snoozeTime`, `recurrence`, `repeatUntil`, `calendarUri`, `remoteId`) "
+ "SELECT `_id`, `title`, `importance`, `dueDate`, `hideUntil`, `created`, `modified`, `completed`, `deleted`, `notes`, `estimatedSeconds`, `elapsedSeconds`, `timerStart`, `notificationFlags`, `notifications`, `lastNotified`, `snoozeTime`, `recurrence`, `repeatUntil`, `calendarUri`, `remoteId` FROM `tasks-temp`")
db.execSQL("DROP TABLE `tasks-temp`")
connection.execSQL("DROP TABLE `tasks-temp`")
}
}
private val MIGRATION_54_58: Migration = object : Migration(54, 58) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `caldav_account` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uuid` TEXT, `name` TEXT, `url` TEXT, `username` TEXT, `password` TEXT)")
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `caldav_calendar` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account` TEXT, `uuid` TEXT, `name` TEXT, `color` INTEGER NOT NULL, `ctag` TEXT, `url` TEXT)")
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `caldav_tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `calendar` TEXT, `object` TEXT, `remote_id` TEXT, `etag` TEXT, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `vtodo` TEXT)")
}
}
private val MIGRATION_58_59: Migration = object : Migration(58, 59) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `google_task_accounts` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account` TEXT, `error` TEXT)")
db.execSQL("ALTER TABLE `google_task_lists` ADD COLUMN `account` TEXT")
db.execSQL("ALTER TABLE `caldav_account` ADD COLUMN `error` TEXT")
connection.execSQL("ALTER TABLE `google_task_lists` ADD COLUMN `account` TEXT")
connection.execSQL("ALTER TABLE `caldav_account` ADD COLUMN `error` TEXT")
}
}
private val MIGRATION_59_60: Migration = object : Migration(59, 60) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `locations` ADD COLUMN `address` TEXT")
db.execSQL("ALTER TABLE `locations` ADD COLUMN `phone` TEXT")
db.execSQL("ALTER TABLE `locations` ADD COLUMN `url` TEXT")
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `locations` ADD COLUMN `address` TEXT")
connection.execSQL("ALTER TABLE `locations` ADD COLUMN `phone` TEXT")
connection.execSQL("ALTER TABLE `locations` ADD COLUMN `url` TEXT")
connection.execSQL(
"ALTER TABLE `locations` ADD COLUMN `arrival` INTEGER DEFAULT 1 NOT NULL")
db.execSQL(
connection.execSQL(
"ALTER TABLE `locations` ADD COLUMN `departure` INTEGER DEFAULT 0 NOT NULL")
db.execSQL("ALTER TABLE `notification` ADD COLUMN `location` INTEGER")
connection.execSQL("ALTER TABLE `notification` ADD COLUMN `location` INTEGER")
}
}
private val MIGRATION_60_61: Migration = object : Migration(60, 61) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `places` (`place_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uid` TEXT, `name` TEXT, `address` TEXT, `phone` TEXT, `url` TEXT, `latitude` REAL NOT NULL, `longitude` REAL NOT NULL)")
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `geofences` (`geofence_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `place` TEXT, `radius` INTEGER NOT NULL, `arrival` INTEGER NOT NULL, `departure` INTEGER NOT NULL)")
db.execSQL(
connection.execSQL(
"INSERT INTO `places` (`place_id`, `uid`, `name`, `address`, `phone`, `url`, `latitude`, `longitude`) SELECT `_id`, hex(randomblob(16)), `name`, `address`, `phone`, `url`, `latitude`, `longitude` FROM `locations`")
db.execSQL(
connection.execSQL(
"INSERT INTO `geofences` (`geofence_id`, `task`, `place`, `radius`, `arrival`, `departure`) SELECT `_id`, `task`, `uid`, `radius`, `arrival`, `departure` FROM `locations` INNER JOIN `places` ON `_id` = `place_id`")
db.execSQL("DROP TABLE `locations`")
connection.execSQL("DROP TABLE `locations`")
}
}
private val MIGRATION_61_62: Migration = object : Migration(61, 62) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `google_task_accounts` ADD COLUMN `etag` TEXT")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `google_task_accounts` ADD COLUMN `etag` TEXT")
}
}
private val MIGRATION_62_63: Migration = object : Migration(62, 63) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `google_tasks` RENAME TO `gt-temp`")
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `google_tasks` RENAME TO `gt-temp`")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `google_tasks` (`gt_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `gt_task` INTEGER NOT NULL, `gt_remote_id` TEXT, `gt_list_id` TEXT, `gt_parent` INTEGER NOT NULL, `gt_remote_parent` TEXT, `gt_moved` INTEGER NOT NULL, `gt_order` INTEGER NOT NULL, `gt_remote_order` INTEGER NOT NULL, `gt_last_sync` INTEGER NOT NULL, `gt_deleted` INTEGER NOT NULL)")
db.execSQL("INSERT INTO `google_tasks` (`gt_id`, `gt_task`, `gt_remote_id`, `gt_list_id`, `gt_parent`, `gt_remote_parent`, `gt_moved`, `gt_order`, `gt_remote_order`, `gt_last_sync`, `gt_deleted`) "
connection.execSQL("INSERT INTO `google_tasks` (`gt_id`, `gt_task`, `gt_remote_id`, `gt_list_id`, `gt_parent`, `gt_remote_parent`, `gt_moved`, `gt_order`, `gt_remote_order`, `gt_last_sync`, `gt_deleted`) "
+ "SELECT `_id`, `task`, `remote_id`, `list_id`, `parent`, '', 0, `order`, `remote_order`, `last_sync`, `deleted` FROM `gt-temp`")
db.execSQL("DROP TABLE `gt-temp`")
db.execSQL("UPDATE `google_task_lists` SET `last_sync` = 0")
connection.execSQL("DROP TABLE `gt-temp`")
connection.execSQL("UPDATE `google_task_lists` SET `last_sync` = 0")
}
}
private val MIGRATION_63_64: Migration = object : Migration(63, 64) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `caldav_tasks` RENAME TO `caldav-temp`")
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `caldav_tasks` RENAME TO `caldav-temp`")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `caldav_tasks` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_vtodo` TEXT)")
db.execSQL("INSERT INTO `caldav_tasks` (`cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_vtodo`)"
connection.execSQL("INSERT INTO `caldav_tasks` (`cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_vtodo`)"
+ "SELECT `_id`, `task`, `calendar`, `object`, `remote_id`, `etag`, `last_sync`, `deleted`, `vtodo` FROM `caldav-temp`")
db.execSQL("DROP TABLE `caldav-temp`")
db.execSQL(
connection.execSQL("DROP TABLE `caldav-temp`")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `caldav_accounts` (`cda_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cda_uuid` TEXT, `cda_name` TEXT, `cda_url` TEXT, `cda_username` TEXT, `cda_password` TEXT, `cda_error` TEXT)")
db.execSQL("INSERT INTO `caldav_accounts` (`cda_id`, `cda_uuid`, `cda_name`, `cda_url`, `cda_username`, `cda_password`, `cda_error`) "
connection.execSQL("INSERT INTO `caldav_accounts` (`cda_id`, `cda_uuid`, `cda_name`, `cda_url`, `cda_username`, `cda_password`, `cda_error`) "
+ "SELECT `_id`, `uuid`, `name`, `url`, `username`, `password`, `error` FROM `caldav_account`")
db.execSQL("DROP TABLE `caldav_account`")
db.execSQL(
connection.execSQL("DROP TABLE `caldav_account`")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `caldav_lists` (`cdl_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cdl_account` TEXT, `cdl_uuid` TEXT, `cdl_name` TEXT, `cdl_color` INTEGER NOT NULL, `cdl_ctag` TEXT, `cdl_url` TEXT, `cdl_icon` INTEGER)")
db.execSQL("INSERT INTO `caldav_lists` (`cdl_id`, `cdl_account`, `cdl_uuid`, `cdl_name`, `cdl_color`, `cdl_ctag`, `cdl_url`) "
connection.execSQL("INSERT INTO `caldav_lists` (`cdl_id`, `cdl_account`, `cdl_uuid`, `cdl_name`, `cdl_color`, `cdl_ctag`, `cdl_url`) "
+ "SELECT `_id`, `account`, `uuid`, `name`, `color`, `ctag`, `url` FROM caldav_calendar")
db.execSQL("DROP TABLE `caldav_calendar`")
db.execSQL("ALTER TABLE `google_task_accounts` RENAME TO `gta-temp`")
db.execSQL(
connection.execSQL("DROP TABLE `caldav_calendar`")
connection.execSQL("ALTER TABLE `google_task_accounts` RENAME TO `gta-temp`")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `google_task_accounts` (`gta_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `gta_account` TEXT, `gta_error` TEXT, `gta_etag` TEXT)")
db.execSQL("INSERT INTO `google_task_accounts` (`gta_id`, `gta_account`, `gta_error`, `gta_etag`) "
connection.execSQL("INSERT INTO `google_task_accounts` (`gta_id`, `gta_account`, `gta_error`, `gta_etag`) "
+ "SELECT `_id`, `account`, `error`, `etag` FROM `gta-temp`")
db.execSQL("DROP TABLE `gta-temp`")
db.execSQL("ALTER TABLE `google_task_lists` RENAME TO `gtl-temp`")
db.execSQL(
connection.execSQL("DROP TABLE `gta-temp`")
connection.execSQL("ALTER TABLE `google_task_lists` RENAME TO `gtl-temp`")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `google_task_lists` (`gtl_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `gtl_account` TEXT, `gtl_remote_id` TEXT, `gtl_title` TEXT, `gtl_remote_order` INTEGER NOT NULL, `gtl_last_sync` INTEGER NOT NULL, `gtl_color` INTEGER, `gtl_icon` INTEGER)")
db.execSQL("INSERT INTO `google_task_lists` (`gtl_id`, `gtl_account`, `gtl_remote_id`, `gtl_title`, `gtl_remote_order`, `gtl_last_sync`, `gtl_color`) "
connection.execSQL("INSERT INTO `google_task_lists` (`gtl_id`, `gtl_account`, `gtl_remote_id`, `gtl_title`, `gtl_remote_order`, `gtl_last_sync`, `gtl_color`) "
+ "SELECT `_id`, `account`, `remote_id`, `title`, `remote_order`, `last_sync`, `color` FROM `gtl-temp`")
db.execSQL("DROP TABLE `gtl-temp`")
db.execSQL("ALTER TABLE `filters` ADD COLUMN `f_color` INTEGER")
db.execSQL("ALTER TABLE `filters` ADD COLUMN `f_icon` INTEGER")
db.execSQL("ALTER TABLE `tagdata` ADD COLUMN `td_icon` INTEGER")
connection.execSQL("DROP TABLE `gtl-temp`")
connection.execSQL("ALTER TABLE `filters` ADD COLUMN `f_color` INTEGER")
connection.execSQL("ALTER TABLE `filters` ADD COLUMN `f_icon` INTEGER")
connection.execSQL("ALTER TABLE `tagdata` ADD COLUMN `td_icon` INTEGER")
}
}
private val MIGRATION_64_65: Migration = object : Migration(64, 65) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"ALTER TABLE `caldav_tasks` ADD COLUMN `cd_parent` INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE `caldav_tasks` ADD COLUMN `cd_remote_parent` TEXT")
connection.execSQL("ALTER TABLE `caldav_tasks` ADD COLUMN `cd_remote_parent` TEXT")
}
}
private val MIGRATION_65_66: Migration = object : Migration(65, 66) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("CREATE UNIQUE INDEX `place_uid` ON `places` (`uid`)")
db.execSQL("CREATE INDEX `geo_task` ON `geofences` (`task`)")
db.execSQL("CREATE INDEX `tag_task` ON `tags` (`task`)")
db.execSQL("CREATE INDEX `gt_list_parent` ON `google_tasks` (`gt_list_id`, `gt_parent`)")
db.execSQL("CREATE INDEX `gt_task` ON `google_tasks` (`gt_task`)")
db.execSQL("CREATE INDEX `cd_calendar_parent` ON `caldav_tasks` (`cd_calendar`, `cd_parent`)")
db.execSQL("CREATE INDEX `cd_task` ON `caldav_tasks` (`cd_task`)")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("CREATE UNIQUE INDEX `place_uid` ON `places` (`uid`)")
connection.execSQL("CREATE INDEX `geo_task` ON `geofences` (`task`)")
connection.execSQL("CREATE INDEX `tag_task` ON `tags` (`task`)")
connection.execSQL("CREATE INDEX `gt_list_parent` ON `google_tasks` (`gt_list_id`, `gt_parent`)")
connection.execSQL("CREATE INDEX `gt_task` ON `google_tasks` (`gt_task`)")
connection.execSQL("CREATE INDEX `cd_calendar_parent` ON `caldav_tasks` (`cd_calendar`, `cd_parent`)")
connection.execSQL("CREATE INDEX `cd_task` ON `caldav_tasks` (`cd_task`)")
}
}
private val MIGRATION_66_67: Migration = object : Migration(66, 67) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"ALTER TABLE `caldav_accounts` ADD COLUMN `cda_repeat` INTEGER NOT NULL DEFAULT 0")
}
}
private val MIGRATION_67_68: Migration = object : Migration(67, 68) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE INDEX `active_and_visible` ON `tasks` (`completed`, `deleted`, `hideUntil`)")
}
}
private val MIGRATION_68_69: Migration = object : Migration(68, 69) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"ALTER TABLE `tasks` ADD COLUMN `collapsed` INTEGER NOT NULL DEFAULT 0")
}
}
private val MIGRATION_69_70: Migration = object : Migration(69, 70) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `tasks` ADD COLUMN `parent` INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE `tasks` ADD COLUMN `parent_uuid` TEXT")
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `tasks` ADD COLUMN `parent` INTEGER NOT NULL DEFAULT 0")
connection.execSQL("ALTER TABLE `tasks` ADD COLUMN `parent_uuid` TEXT")
connection.execSQL(
"UPDATE `tasks` SET `parent` = IFNULL(("
+ " SELECT p.cd_task FROM caldav_tasks"
+ " INNER JOIN caldav_tasks AS p ON p.cd_remote_id = caldav_tasks.cd_remote_parent"
@ -320,133 +318,133 @@ object Migrations {
+ " AND caldav_tasks.cd_deleted = 0"
+ " AND p.cd_calendar = caldav_tasks.cd_calendar"
+ " AND p.cd_deleted = 0), 0)")
db.execSQL("ALTER TABLE `caldav_tasks` RENAME TO `caldav_tasks-temp`")
db.execSQL(
connection.execSQL("ALTER TABLE `caldav_tasks` RENAME TO `caldav_tasks-temp`")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `caldav_tasks` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_vtodo` TEXT, `cd_remote_parent` TEXT)")
db.execSQL("INSERT INTO `caldav_tasks` (`cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_vtodo`, `cd_remote_parent`) "
connection.execSQL("INSERT INTO `caldav_tasks` (`cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_vtodo`, `cd_remote_parent`) "
+ "SELECT `cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_vtodo`, `cd_remote_parent` FROM `caldav_tasks-temp`")
db.execSQL("DROP TABLE `caldav_tasks-temp`")
db.execSQL("CREATE INDEX `cd_task` ON `caldav_tasks` (`cd_task`)")
connection.execSQL("DROP TABLE `caldav_tasks-temp`")
connection.execSQL("CREATE INDEX `cd_task` ON `caldav_tasks` (`cd_task`)")
}
}
private val MIGRATION_70_71: Migration = object : Migration(70, 71) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `caldav_accounts` ADD COLUMN `cda_encryption_key` TEXT")
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `caldav_accounts` ADD COLUMN `cda_encryption_key` TEXT")
connection.execSQL(
"ALTER TABLE `caldav_accounts` ADD COLUMN `cda_account_type` INTEGER NOT NULL DEFAULT 0")
}
}
private val MIGRATION_71_72: Migration = object : Migration(71, 72) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"ALTER TABLE `caldav_accounts` ADD COLUMN `cda_collapsed` INTEGER NOT NULL DEFAULT 0")
db.execSQL(
connection.execSQL(
"ALTER TABLE `google_task_accounts` ADD COLUMN `gta_collapsed` INTEGER NOT NULL DEFAULT 0")
}
}
private val MIGRATION_72_73: Migration = object : Migration(72, 73) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `places` ADD COLUMN `place_color` INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE `places` ADD COLUMN `place_icon` INTEGER NOT NULL DEFAULT -1")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `places` ADD COLUMN `place_color` INTEGER NOT NULL DEFAULT 0")
connection.execSQL("ALTER TABLE `places` ADD COLUMN `place_icon` INTEGER NOT NULL DEFAULT -1")
}
}
private val MIGRATION_73_74: Migration = object : Migration(73, 74) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `tasks` RENAME TO `tasks-temp`")
db.execSQL("DROP INDEX `t_rid`")
db.execSQL("DROP INDEX `active_and_visible`")
db.execSQL("CREATE TABLE IF NOT EXISTS `tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `importance` INTEGER NOT NULL, `dueDate` INTEGER NOT NULL, `hideUntil` INTEGER NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `completed` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `notes` TEXT, `estimatedSeconds` INTEGER NOT NULL, `elapsedSeconds` INTEGER NOT NULL, `timerStart` INTEGER NOT NULL, `notificationFlags` INTEGER NOT NULL, `notifications` INTEGER NOT NULL, `lastNotified` INTEGER NOT NULL, `snoozeTime` INTEGER NOT NULL, `recurrence` TEXT, `repeatUntil` INTEGER NOT NULL, `calendarUri` TEXT, `remoteId` TEXT, `collapsed` INTEGER NOT NULL, `parent` INTEGER NOT NULL, `parent_uuid` TEXT)")
db.execSQL("INSERT INTO `tasks` (`_id`, `title`, `importance`, `dueDate`, `hideUntil`, `created`, `modified`, `completed`, `deleted`, `notes`, `estimatedSeconds`, `elapsedSeconds`, `timerStart`, `notificationFlags`, `notifications`, `lastNotified`, `snoozeTime`, `recurrence`, `repeatUntil`, `calendarUri`, `remoteId`, `collapsed`, `parent`, `parent_uuid`) "
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `tasks` RENAME TO `tasks-temp`")
connection.execSQL("DROP INDEX `t_rid`")
connection.execSQL("DROP INDEX `active_and_visible`")
connection.execSQL("CREATE TABLE IF NOT EXISTS `tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `importance` INTEGER NOT NULL, `dueDate` INTEGER NOT NULL, `hideUntil` INTEGER NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `completed` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `notes` TEXT, `estimatedSeconds` INTEGER NOT NULL, `elapsedSeconds` INTEGER NOT NULL, `timerStart` INTEGER NOT NULL, `notificationFlags` INTEGER NOT NULL, `notifications` INTEGER NOT NULL, `lastNotified` INTEGER NOT NULL, `snoozeTime` INTEGER NOT NULL, `recurrence` TEXT, `repeatUntil` INTEGER NOT NULL, `calendarUri` TEXT, `remoteId` TEXT, `collapsed` INTEGER NOT NULL, `parent` INTEGER NOT NULL, `parent_uuid` TEXT)")
connection.execSQL("INSERT INTO `tasks` (`_id`, `title`, `importance`, `dueDate`, `hideUntil`, `created`, `modified`, `completed`, `deleted`, `notes`, `estimatedSeconds`, `elapsedSeconds`, `timerStart`, `notificationFlags`, `notifications`, `lastNotified`, `snoozeTime`, `recurrence`, `repeatUntil`, `calendarUri`, `remoteId`, `collapsed`, `parent`, `parent_uuid`) "
+ "SELECT `_id`, `title`, IFNULL(`importance`, 3), IFNULL(`dueDate`, 0), IFNULL(`hideUntil`, 0), IFNULL(`created`, 0), IFNULL(`modified`, 0), IFNULL(`completed`, 0), IFNULL(`deleted`, 0), `notes`, IFNULL(`estimatedSeconds`, 0), IFNULL(`elapsedSeconds`, 0), IFNULL(`timerStart`, 0), IFNULL(`notificationFlags`, 0), IFNULL(`notifications`, 0), IFNULL(`lastNotified`, 0), IFNULL(`snoozeTime`, 0), `recurrence`, IFNULL(`repeatUntil`, 0), `calendarUri`, `remoteId`, `collapsed`, IFNULL(`parent`, 0), `parent_uuid` FROM `tasks-temp`")
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `t_rid` ON `tasks` (`remoteId`)")
db.execSQL("CREATE INDEX IF NOT EXISTS `active_and_visible` ON `tasks` (`completed`, `deleted`, `hideUntil`)")
db.execSQL("DROP TABLE `tasks-temp`")
connection.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `t_rid` ON `tasks` (`remoteId`)")
connection.execSQL("CREATE INDEX IF NOT EXISTS `active_and_visible` ON `tasks` (`completed`, `deleted`, `hideUntil`)")
connection.execSQL("DROP TABLE `tasks-temp`")
}
}
private val MIGRATION_74_75: Migration = object : Migration(74, 75) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `caldav_tasks` ADD COLUMN `cd_order` INTEGER")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `caldav_tasks` ADD COLUMN `cd_order` INTEGER")
}
}
private val MIGRATION_75_76: Migration = object : Migration(75, 76) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `tagdata` ADD COLUMN `td_order` INTEGER NOT NULL DEFAULT $NO_ORDER")
db.execSQL("ALTER TABLE `caldav_lists` ADD COLUMN `cdl_order` INTEGER NOT NULL DEFAULT $NO_ORDER")
db.execSQL("ALTER TABLE `filters` ADD COLUMN `f_order` INTEGER NOT NULL DEFAULT $NO_ORDER")
db.execSQL("ALTER TABLE `places` ADD COLUMN `place_order` INTEGER NOT NULL DEFAULT $NO_ORDER")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `tagdata` ADD COLUMN `td_order` INTEGER NOT NULL DEFAULT $NO_ORDER")
connection.execSQL("ALTER TABLE `caldav_lists` ADD COLUMN `cdl_order` INTEGER NOT NULL DEFAULT $NO_ORDER")
connection.execSQL("ALTER TABLE `filters` ADD COLUMN `f_order` INTEGER NOT NULL DEFAULT $NO_ORDER")
connection.execSQL("ALTER TABLE `places` ADD COLUMN `place_order` INTEGER NOT NULL DEFAULT $NO_ORDER")
}
}
private val MIGRATION_76_77: Migration = object : Migration(76, 77) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"ALTER TABLE `caldav_lists` ADD COLUMN `cdl_access` INTEGER NOT NULL DEFAULT 0")
}
}
private val MIGRATION_77_78: Migration = object : Migration(77, 78) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `principals` (`principal_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `principal_list` INTEGER NOT NULL, `principal` TEXT, `display_name` TEXT, `invite` INTEGER NOT NULL, `access` INTEGER NOT NULL, FOREIGN KEY(`principal_list`) REFERENCES `caldav_lists`(`cdl_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
db.execSQL(
connection.execSQL(
"CREATE UNIQUE INDEX IF NOT EXISTS `index_principals_principal_list_principal` ON `principals` (`principal_list`, `principal`)"
)
}
}
private val MIGRATION_78_79: Migration = object : Migration(78, 79) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"ALTER TABLE `caldav_accounts` ADD COLUMN `cda_server_type` INTEGER NOT NULL DEFAULT $SERVER_UNKNOWN"
)
}
}
private val MIGRATION_79_80 = object : Migration(79, 80) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE `principals`")
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("DROP TABLE `principals`")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `principals` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `account` INTEGER NOT NULL, `href` TEXT NOT NULL, `email` TEXT, `display_name` TEXT, FOREIGN KEY(`account`) REFERENCES `caldav_accounts`(`cda_id`) ON UPDATE NO ACTION ON DELETE CASCADE )"
)
db.execSQL(
connection.execSQL(
"CREATE UNIQUE INDEX IF NOT EXISTS `index_principals_account_href` ON `principals` (`account`, `href`)"
)
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `principal_access` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `principal` INTEGER NOT NULL, `list` INTEGER NOT NULL, `invite` INTEGER NOT NULL, `access` INTEGER NOT NULL, FOREIGN KEY(`principal`) REFERENCES `principals`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`list`) REFERENCES `caldav_lists`(`cdl_id`) ON UPDATE NO ACTION ON DELETE CASCADE )"
)
db.execSQL(
connection.execSQL(
"CREATE UNIQUE INDEX IF NOT EXISTS `index_principal_access_list_principal` ON `principal_access` (`list`, `principal`)"
)
db.execSQL(
connection.execSQL(
"CREATE INDEX IF NOT EXISTS `index_principal_access_principal` ON `principal_access` (`principal`)"
)
}
}
private val MIGRATION_80_81 = object : Migration(80, 81) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `alarms` ADD COLUMN `type` INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE `alarms` ADD COLUMN `repeat` INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE `alarms` ADD COLUMN `interval` INTEGER NOT NULL DEFAULT 0")
db.execSQL(
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `alarms` ADD COLUMN `type` INTEGER NOT NULL DEFAULT 0")
connection.execSQL("ALTER TABLE `alarms` ADD COLUMN `repeat` INTEGER NOT NULL DEFAULT 0")
connection.execSQL("ALTER TABLE `alarms` ADD COLUMN `interval` INTEGER NOT NULL DEFAULT 0")
connection.execSQL(
"INSERT INTO `alarms` (`task`, `time`, `type`) SELECT `_id`, 0, $TYPE_REL_START FROM `tasks` WHERE `hideUntil` > 0 AND `notificationFlags` & $NOTIFY_AT_START = $NOTIFY_AT_START"
)
db.execSQL(
connection.execSQL(
"INSERT INTO `alarms` (`task`, `time`, `type`) SELECT `_id`, 0, $TYPE_REL_END FROM `tasks` WHERE `dueDate` > 0 AND `notificationFlags` & $NOTIFY_AT_DEADLINE = $NOTIFY_AT_DEADLINE"
)
db.execSQL(
connection.execSQL(
"INSERT INTO `alarms` (`task`, `time`, `type`, `repeat`, `interval`) SELECT `_id`, ${HOURS.toMillis(24)}, $TYPE_REL_END, 6, ${HOURS.toMillis(24)} FROM `tasks` WHERE `dueDate` > 0 AND `notificationFlags` & $NOTIFY_AFTER_DEADLINE = $NOTIFY_AFTER_DEADLINE"
)
db.execSQL(
connection.execSQL(
"INSERT INTO `alarms` (`task`, `time`, `type`) SELECT `_id`, `notifications`, $TYPE_RANDOM FROM `tasks` WHERE `notifications` > 0"
)
db.execSQL(
connection.execSQL(
"INSERT INTO `alarms` (`task`, `time`, `type`) SELECT `_id`, `snoozeTime`, $TYPE_SNOOZE FROM `tasks` WHERE `snoozeTime` > 0"
)
}
@ -454,171 +452,176 @@ object Migrations {
@Suppress("FunctionName")
private fun migration_81_82(fileStorage: FileStorage) = object : Migration(81, 82) {
override fun migrate(db: SupportSQLiteDatabase) {
db
.query("SELECT `cdl_account`, `cd_calendar`, `cd_object`, `cd_vtodo` FROM `caldav_tasks` INNER JOIN `caldav_lists` ON `cdl_uuid` = `cd_calendar`")
override fun migrate(connection: SQLiteConnection) {
connection
.prepare("SELECT `cdl_account`, `cd_calendar`, `cd_object`, `cd_vtodo` FROM `caldav_tasks` INNER JOIN `caldav_lists` ON `cdl_uuid` = `cd_calendar`")
.use {
while (it.moveToNext()) {
while (it.step()) {
val file = fileStorage.getFile(
it.getString("cdl_account"),
it.getString("cd_calendar"),
it.getText(0),
it.getText(1),
)
?.apply { mkdirs() }
?: continue
val `object` = it.getString("cd_object") ?: continue
fileStorage.write(File(file, `object`), it.getString("cd_vtodo"))
if (it.isNull(2)) continue
val `object` = it.getText(2)
fileStorage.write(File(file, `object`), it.getText(3))
}
}
db.execSQL("ALTER TABLE `caldav_tasks` RENAME TO `caldav_tasks-temp`")
db.execSQL(
connection.execSQL("ALTER TABLE `caldav_tasks` RENAME TO `caldav_tasks-temp`")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `caldav_tasks` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_remote_parent` TEXT, `cd_order` INTEGER)"
)
db.execSQL("DROP INDEX `cd_task`")
db.execSQL("CREATE INDEX IF NOT EXISTS `cd_task` ON `caldav_tasks` (`cd_task`)")
db.execSQL(
connection.execSQL("DROP INDEX `cd_task`")
connection.execSQL("CREATE INDEX IF NOT EXISTS `cd_task` ON `caldav_tasks` (`cd_task`)")
connection.execSQL(
"INSERT INTO `caldav_tasks` (`cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_remote_parent`, `cd_order`) SELECT `cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_remote_parent`, `cd_order` FROM `caldav_tasks-temp`"
)
db.execSQL("DROP TABLE `caldav_tasks-temp`")
connection.execSQL("DROP TABLE `caldav_tasks-temp`")
}
}
private val MIGRATION_82_83 = object : Migration(82, 83) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `places` ADD COLUMN `radius` INTEGER NOT NULL DEFAULT 250")
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_alarms` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `time` INTEGER NOT NULL, `type` INTEGER NOT NULL DEFAULT 0, `repeat` INTEGER NOT NULL DEFAULT 0, `interval` INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
db.execSQL("INSERT INTO `_new_alarms` (`task`,`repeat`,`interval`,`_id`,`time`,`type`) SELECT `task`,`repeat`,`interval`,`alarms`.`_id`,`time`,`type` FROM `alarms` INNER JOIN `tasks` ON `tasks`.`_id` = `task`")
db.execSQL("DROP TABLE `alarms`")
db.execSQL("ALTER TABLE `_new_alarms` RENAME TO `alarms`")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_alarms_task` ON `alarms` (`task`)")
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_google_tasks` (`gt_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `gt_task` INTEGER NOT NULL, `gt_remote_id` TEXT, `gt_list_id` TEXT, `gt_parent` INTEGER NOT NULL, `gt_remote_parent` TEXT, `gt_moved` INTEGER NOT NULL, `gt_order` INTEGER NOT NULL, `gt_remote_order` INTEGER NOT NULL, `gt_last_sync` INTEGER NOT NULL, `gt_deleted` INTEGER NOT NULL, FOREIGN KEY(`gt_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
db.execSQL("INSERT INTO `_new_google_tasks` (`gt_parent`,`gt_task`,`gt_remote_parent`,`gt_order`,`gt_last_sync`,`gt_id`,`gt_remote_id`,`gt_list_id`,`gt_moved`,`gt_remote_order`,`gt_deleted`) SELECT `gt_parent`,`gt_task`,`gt_remote_parent`,`gt_order`,`gt_last_sync`,`gt_id`,`gt_remote_id`,`gt_list_id`,`gt_moved`,`gt_remote_order`,`gt_deleted` FROM `google_tasks` INNER JOIN `tasks` ON `tasks`.`_id` = `gt_task`")
db.execSQL("DROP TABLE `google_tasks`")
db.execSQL("ALTER TABLE `_new_google_tasks` RENAME TO `google_tasks`")
db.execSQL("CREATE INDEX IF NOT EXISTS `gt_list_parent` ON `google_tasks` (`gt_list_id`, `gt_parent`)")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_google_tasks_gt_task` ON `google_tasks` (`gt_task`)")
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_tags` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `tag_uid` TEXT, `task_uid` TEXT, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
db.execSQL("INSERT INTO `_new_tags` (`task`,`task_uid`,`name`,`tag_uid`,`_id`) SELECT `task`,`task_uid`,`name`,`tag_uid`,`tags`.`_id` FROM `tags` INNER JOIN `tasks` ON `tasks`.`_id` = `task`")
db.execSQL("DROP TABLE `tags`")
db.execSQL("ALTER TABLE `_new_tags` RENAME TO `tags`")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_tags_task` ON `tags` (`task`)")
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_notification` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `type` INTEGER NOT NULL, `location` INTEGER, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
db.execSQL("INSERT INTO `_new_notification` (`uid`,`task`,`location`,`type`,`timestamp`) SELECT `uid`,`task`,`location`,`type`,`timestamp` FROM `notification` INNER JOIN `tasks` ON `tasks`.`_id` = `task`")
db.execSQL("DROP TABLE `notification`")
db.execSQL("ALTER TABLE `_new_notification` RENAME TO `notification`")
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_notification_task` ON `notification` (`task`)")
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_caldav_tasks` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_remote_parent` TEXT, `cd_order` INTEGER, FOREIGN KEY(`cd_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
db.execSQL("INSERT INTO `_new_caldav_tasks` (`cd_object`,`cd_deleted`,`cd_order`,`cd_remote_parent`,`cd_etag`,`cd_id`,`cd_calendar`,`cd_remote_id`,`cd_last_sync`,`cd_task`) SELECT `cd_object`,`cd_deleted`,`cd_order`,`cd_remote_parent`,`cd_etag`,`cd_id`,`cd_calendar`,`cd_remote_id`,`cd_last_sync`,`cd_task` FROM `caldav_tasks` INNER JOIN `tasks` ON `tasks`.`_id` = `cd_task`")
db.execSQL("DROP TABLE `caldav_tasks`")
db.execSQL("ALTER TABLE `_new_caldav_tasks` RENAME TO `caldav_tasks`")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_caldav_tasks_cd_task` ON `caldav_tasks` (`cd_task`)")
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_geofences` (`geofence_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `place` TEXT, `arrival` INTEGER NOT NULL, `departure` INTEGER NOT NULL, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
db.execSQL("INSERT INTO `_new_geofences` (`task`,`geofence_id`,`arrival`,`place`,`departure`) SELECT `task`,`geofence_id`,`arrival`,`place`,`departure` FROM `geofences` INNER JOIN `tasks` ON `tasks`.`_id` = `task`")
db.execSQL("DROP TABLE `geofences`")
db.execSQL("ALTER TABLE `_new_geofences` RENAME TO `geofences`")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_geofences_task` ON `geofences` (`task`)")
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_task_list_metadata` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `tag_uuid` TEXT, `filter` TEXT, `task_ids` TEXT)")
db.execSQL("INSERT INTO `_new_task_list_metadata` (`filter`,`tag_uuid`,`_id`,`task_ids`) SELECT `filter`,`tag_uuid`,`_id`,`task_ids` FROM `task_list_metadata`")
db.execSQL("DROP TABLE `task_list_metadata`")
db.execSQL("ALTER TABLE `_new_task_list_metadata` RENAME TO `task_list_metadata`")
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `importance` INTEGER NOT NULL, `dueDate` INTEGER NOT NULL, `hideUntil` INTEGER NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `completed` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `notes` TEXT, `estimatedSeconds` INTEGER NOT NULL, `elapsedSeconds` INTEGER NOT NULL, `timerStart` INTEGER NOT NULL, `notificationFlags` INTEGER NOT NULL, `lastNotified` INTEGER NOT NULL, `recurrence` TEXT, `repeatUntil` INTEGER NOT NULL, `calendarUri` TEXT, `remoteId` TEXT, `collapsed` INTEGER NOT NULL, `parent` INTEGER NOT NULL)")
db.execSQL("INSERT INTO `_new_tasks` (`parent`,`notes`,`timerStart`,`estimatedSeconds`,`importance`,`created`,`collapsed`,`dueDate`,`completed`,`repeatUntil`,`title`,`hideUntil`,`remoteId`,`recurrence`,`deleted`,`notificationFlags`,`calendarUri`,`modified`,`_id`,`lastNotified`,`elapsedSeconds`) SELECT `parent`,`notes`,`timerStart`,`estimatedSeconds`,`importance`,`created`,`collapsed`,`dueDate`,`completed`,`repeatUntil`,`title`,`hideUntil`,`remoteId`,`recurrence`,`deleted`,`notificationFlags`,`calendarUri`,`modified`,`_id`,`lastNotified`,`elapsedSeconds` FROM `tasks`")
db.execSQL("DROP TABLE `tasks`")
db.execSQL("ALTER TABLE `_new_tasks` RENAME TO `tasks`")
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `t_rid` ON `tasks` (`remoteId`)")
db.execSQL("CREATE INDEX IF NOT EXISTS `active_and_visible` ON `tasks` (`completed`, `deleted`, `hideUntil`)")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `places` ADD COLUMN `radius` INTEGER NOT NULL DEFAULT 250")
connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_alarms` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `time` INTEGER NOT NULL, `type` INTEGER NOT NULL DEFAULT 0, `repeat` INTEGER NOT NULL DEFAULT 0, `interval` INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
connection.execSQL("INSERT INTO `_new_alarms` (`task`,`repeat`,`interval`,`_id`,`time`,`type`) SELECT `task`,`repeat`,`interval`,`alarms`.`_id`,`time`,`type` FROM `alarms` INNER JOIN `tasks` ON `tasks`.`_id` = `task`")
connection.execSQL("DROP TABLE `alarms`")
connection.execSQL("ALTER TABLE `_new_alarms` RENAME TO `alarms`")
connection.execSQL("CREATE INDEX IF NOT EXISTS `index_alarms_task` ON `alarms` (`task`)")
connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_google_tasks` (`gt_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `gt_task` INTEGER NOT NULL, `gt_remote_id` TEXT, `gt_list_id` TEXT, `gt_parent` INTEGER NOT NULL, `gt_remote_parent` TEXT, `gt_moved` INTEGER NOT NULL, `gt_order` INTEGER NOT NULL, `gt_remote_order` INTEGER NOT NULL, `gt_last_sync` INTEGER NOT NULL, `gt_deleted` INTEGER NOT NULL, FOREIGN KEY(`gt_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
connection.execSQL("INSERT INTO `_new_google_tasks` (`gt_parent`,`gt_task`,`gt_remote_parent`,`gt_order`,`gt_last_sync`,`gt_id`,`gt_remote_id`,`gt_list_id`,`gt_moved`,`gt_remote_order`,`gt_deleted`) SELECT `gt_parent`,`gt_task`,`gt_remote_parent`,`gt_order`,`gt_last_sync`,`gt_id`,`gt_remote_id`,`gt_list_id`,`gt_moved`,`gt_remote_order`,`gt_deleted` FROM `google_tasks` INNER JOIN `tasks` ON `tasks`.`_id` = `gt_task`")
connection.execSQL("DROP TABLE `google_tasks`")
connection.execSQL("ALTER TABLE `_new_google_tasks` RENAME TO `google_tasks`")
connection.execSQL("CREATE INDEX IF NOT EXISTS `gt_list_parent` ON `google_tasks` (`gt_list_id`, `gt_parent`)")
connection.execSQL("CREATE INDEX IF NOT EXISTS `index_google_tasks_gt_task` ON `google_tasks` (`gt_task`)")
connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_tags` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `tag_uid` TEXT, `task_uid` TEXT, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
connection.execSQL("INSERT INTO `_new_tags` (`task`,`task_uid`,`name`,`tag_uid`,`_id`) SELECT `task`,`task_uid`,`name`,`tag_uid`,`tags`.`_id` FROM `tags` INNER JOIN `tasks` ON `tasks`.`_id` = `task`")
connection.execSQL("DROP TABLE `tags`")
connection.execSQL("ALTER TABLE `_new_tags` RENAME TO `tags`")
connection.execSQL("CREATE INDEX IF NOT EXISTS `index_tags_task` ON `tags` (`task`)")
connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_notification` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `type` INTEGER NOT NULL, `location` INTEGER, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
connection.execSQL("INSERT INTO `_new_notification` (`uid`,`task`,`location`,`type`,`timestamp`) SELECT `uid`,`task`,`location`,`type`,`timestamp` FROM `notification` INNER JOIN `tasks` ON `tasks`.`_id` = `task`")
connection.execSQL("DROP TABLE `notification`")
connection.execSQL("ALTER TABLE `_new_notification` RENAME TO `notification`")
connection.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_notification_task` ON `notification` (`task`)")
connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_caldav_tasks` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_remote_parent` TEXT, `cd_order` INTEGER, FOREIGN KEY(`cd_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
connection.execSQL("INSERT INTO `_new_caldav_tasks` (`cd_object`,`cd_deleted`,`cd_order`,`cd_remote_parent`,`cd_etag`,`cd_id`,`cd_calendar`,`cd_remote_id`,`cd_last_sync`,`cd_task`) SELECT `cd_object`,`cd_deleted`,`cd_order`,`cd_remote_parent`,`cd_etag`,`cd_id`,`cd_calendar`,`cd_remote_id`,`cd_last_sync`,`cd_task` FROM `caldav_tasks` INNER JOIN `tasks` ON `tasks`.`_id` = `cd_task`")
connection.execSQL("DROP TABLE `caldav_tasks`")
connection.execSQL("ALTER TABLE `_new_caldav_tasks` RENAME TO `caldav_tasks`")
connection.execSQL("CREATE INDEX IF NOT EXISTS `index_caldav_tasks_cd_task` ON `caldav_tasks` (`cd_task`)")
connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_geofences` (`geofence_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `place` TEXT, `arrival` INTEGER NOT NULL, `departure` INTEGER NOT NULL, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
connection.execSQL("INSERT INTO `_new_geofences` (`task`,`geofence_id`,`arrival`,`place`,`departure`) SELECT `task`,`geofence_id`,`arrival`,`place`,`departure` FROM `geofences` INNER JOIN `tasks` ON `tasks`.`_id` = `task`")
connection.execSQL("DROP TABLE `geofences`")
connection.execSQL("ALTER TABLE `_new_geofences` RENAME TO `geofences`")
connection.execSQL("CREATE INDEX IF NOT EXISTS `index_geofences_task` ON `geofences` (`task`)")
connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_task_list_metadata` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `tag_uuid` TEXT, `filter` TEXT, `task_ids` TEXT)")
connection.execSQL("INSERT INTO `_new_task_list_metadata` (`filter`,`tag_uuid`,`_id`,`task_ids`) SELECT `filter`,`tag_uuid`,`_id`,`task_ids` FROM `task_list_metadata`")
connection.execSQL("DROP TABLE `task_list_metadata`")
connection.execSQL("ALTER TABLE `_new_task_list_metadata` RENAME TO `task_list_metadata`")
connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `importance` INTEGER NOT NULL, `dueDate` INTEGER NOT NULL, `hideUntil` INTEGER NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `completed` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `notes` TEXT, `estimatedSeconds` INTEGER NOT NULL, `elapsedSeconds` INTEGER NOT NULL, `timerStart` INTEGER NOT NULL, `notificationFlags` INTEGER NOT NULL, `lastNotified` INTEGER NOT NULL, `recurrence` TEXT, `repeatUntil` INTEGER NOT NULL, `calendarUri` TEXT, `remoteId` TEXT, `collapsed` INTEGER NOT NULL, `parent` INTEGER NOT NULL)")
connection.execSQL("INSERT INTO `_new_tasks` (`parent`,`notes`,`timerStart`,`estimatedSeconds`,`importance`,`created`,`collapsed`,`dueDate`,`completed`,`repeatUntil`,`title`,`hideUntil`,`remoteId`,`recurrence`,`deleted`,`notificationFlags`,`calendarUri`,`modified`,`_id`,`lastNotified`,`elapsedSeconds`) SELECT `parent`,`notes`,`timerStart`,`estimatedSeconds`,`importance`,`created`,`collapsed`,`dueDate`,`completed`,`repeatUntil`,`title`,`hideUntil`,`remoteId`,`recurrence`,`deleted`,`notificationFlags`,`calendarUri`,`modified`,`_id`,`lastNotified`,`elapsedSeconds` FROM `tasks`")
connection.execSQL("DROP TABLE `tasks`")
connection.execSQL("ALTER TABLE `_new_tasks` RENAME TO `tasks`")
connection.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `t_rid` ON `tasks` (`remoteId`)")
connection.execSQL("CREATE INDEX IF NOT EXISTS `active_and_visible` ON `tasks` (`completed`, `deleted`, `hideUntil`)")
}
}
private val MIGRATION_84_85 = object : Migration(84, 85) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `tasks` ADD COLUMN `repeat_from` INTEGER NOT NULL DEFAULT ${Task.RepeatFrom.DUE_DATE}")
db
.query("SELECT `_id`, `repeatUntil`, `recurrence` FROM `tasks` WHERE `recurrence` IS NOT NULL AND `recurrence` != ''")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `tasks` ADD COLUMN `repeat_from` INTEGER NOT NULL DEFAULT ${Task.RepeatFrom.DUE_DATE}")
connection
.prepare("SELECT `_id`, `repeatUntil`, `recurrence` FROM `tasks` WHERE `recurrence` IS NOT NULL AND `recurrence` != ''")
.use { cursor ->
while (cursor.moveToNext()) {
val id = cursor.getLong("_id")
val recurrence =
cursor.getString("recurrence")?.takeIf { it.isNotBlank() } ?: continue
while (cursor.step()) {
val id = cursor.getLong(0)
val recurrence = if (!cursor.isNull(2)) {
cursor.getText(2).takeIf { it.isNotBlank() }
} else {
null
} ?: continue
val recur = newRecur(recurrence.withoutFrom()!!)
cursor.getLongOrNull("repeatUntil")
?.takeIf { it > 0 }
?.let { recur.until = DateTime(it).toDate() }
if (!cursor.isNull(1)) {
cursor.getLong(1).takeIf { it > 0 }?.let { recur.until = DateTime(it).toDate() }
}
val repeatFrom = recurrence.repeatFrom()
db.execSQL("UPDATE `tasks` SET `repeat_from` = $repeatFrom, `recurrence` = '$recur' WHERE `_id` = $id")
connection.execSQL("UPDATE `tasks` SET `repeat_from` = $repeatFrom, `recurrence` = '$recur' WHERE `_id` = $id")
}
}
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `importance` INTEGER NOT NULL, `dueDate` INTEGER NOT NULL, `hideUntil` INTEGER NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `completed` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `notes` TEXT, `estimatedSeconds` INTEGER NOT NULL, `elapsedSeconds` INTEGER NOT NULL, `timerStart` INTEGER NOT NULL, `notificationFlags` INTEGER NOT NULL, `lastNotified` INTEGER NOT NULL, `recurrence` TEXT, `repeat_from` INTEGER NOT NULL DEFAULT 0, `calendarUri` TEXT, `remoteId` TEXT, `collapsed` INTEGER NOT NULL, `parent` INTEGER NOT NULL)")
db.execSQL("INSERT INTO `_new_tasks` (`parent`,`notes`,`timerStart`,`estimatedSeconds`,`importance`,`created`,`collapsed`,`dueDate`,`completed`,`title`,`hideUntil`,`remoteId`,`recurrence`,`deleted`,`notificationFlags`,`calendarUri`,`modified`,`_id`,`lastNotified`,`elapsedSeconds`,`repeat_from`) SELECT `parent`,`notes`,`timerStart`,`estimatedSeconds`,`importance`,`created`,`collapsed`,`dueDate`,`completed`,`title`,`hideUntil`,`remoteId`,`recurrence`,`deleted`,`notificationFlags`,`calendarUri`,`modified`,`_id`,`lastNotified`,`elapsedSeconds`,`repeat_from` FROM `tasks`")
db.execSQL("DROP TABLE `tasks`")
db.execSQL("ALTER TABLE `_new_tasks` RENAME TO `tasks`")
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `t_rid` ON `tasks` (`remoteId`)")
db.execSQL("CREATE INDEX IF NOT EXISTS `active_and_visible` ON `tasks` (`completed`, `deleted`, `hideUntil`)")
connection.execSQL("CREATE TABLE IF NOT EXISTS `_new_tasks` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `importance` INTEGER NOT NULL, `dueDate` INTEGER NOT NULL, `hideUntil` INTEGER NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `completed` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `notes` TEXT, `estimatedSeconds` INTEGER NOT NULL, `elapsedSeconds` INTEGER NOT NULL, `timerStart` INTEGER NOT NULL, `notificationFlags` INTEGER NOT NULL, `lastNotified` INTEGER NOT NULL, `recurrence` TEXT, `repeat_from` INTEGER NOT NULL DEFAULT 0, `calendarUri` TEXT, `remoteId` TEXT, `collapsed` INTEGER NOT NULL, `parent` INTEGER NOT NULL)")
connection.execSQL("INSERT INTO `_new_tasks` (`parent`,`notes`,`timerStart`,`estimatedSeconds`,`importance`,`created`,`collapsed`,`dueDate`,`completed`,`title`,`hideUntil`,`remoteId`,`recurrence`,`deleted`,`notificationFlags`,`calendarUri`,`modified`,`_id`,`lastNotified`,`elapsedSeconds`,`repeat_from`) SELECT `parent`,`notes`,`timerStart`,`estimatedSeconds`,`importance`,`created`,`collapsed`,`dueDate`,`completed`,`title`,`hideUntil`,`remoteId`,`recurrence`,`deleted`,`notificationFlags`,`calendarUri`,`modified`,`_id`,`lastNotified`,`elapsedSeconds`,`repeat_from` FROM `tasks`")
connection.execSQL("DROP TABLE `tasks`")
connection.execSQL("ALTER TABLE `_new_tasks` RENAME TO `tasks`")
connection.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `t_rid` ON `tasks` (`remoteId`)")
connection.execSQL("CREATE INDEX IF NOT EXISTS `active_and_visible` ON `tasks` (`completed`, `deleted`, `hideUntil`)")
}
}
private val MIGRATION_85_86 = object : Migration(85, 86) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("CREATE TABLE IF NOT EXISTS `attachment_file` (`file_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_uuid` TEXT NOT NULL, `filename` TEXT NOT NULL, `uri` TEXT NOT NULL)")
db.execSQL("INSERT INTO `attachment_file` (`file_id`, `uri`,`filename`,`file_id`,`file_uuid`) SELECT `_id`, `path`,`name`,`_id`,`remoteId` FROM `task_attachments`")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("CREATE TABLE IF NOT EXISTS `attachment_file` (`file_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_uuid` TEXT NOT NULL, `filename` TEXT NOT NULL, `uri` TEXT NOT NULL)")
connection.execSQL("INSERT INTO `attachment_file` (`file_id`, `uri`,`filename`,`file_id`,`file_uuid`) SELECT `_id`, `path`,`name`,`_id`,`remoteId` FROM `task_attachments`")
db.execSQL("CREATE TABLE IF NOT EXISTS `attachment` (`attachment_id` INTEGER PRIMARY KEY AUTOINCREMENT, `task` INTEGER NOT NULL, `file` INTEGER NOT NULL, `file_uuid` TEXT NOT NULL, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`file`) REFERENCES `attachment_file`(`file_id`) ON UPDATE NO ACTION ON DELETE CASCADE)")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_attachment_task` ON `attachment` (`task`)")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_attachment_file` ON `attachment` (`file`)")
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_attachment_task_file` ON `attachment` (`task`, `file`)")
connection.execSQL("CREATE TABLE IF NOT EXISTS `attachment` (`attachment_id` INTEGER PRIMARY KEY AUTOINCREMENT, `task` INTEGER NOT NULL, `file` INTEGER NOT NULL, `file_uuid` TEXT NOT NULL, FOREIGN KEY(`task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`file`) REFERENCES `attachment_file`(`file_id`) ON UPDATE NO ACTION ON DELETE CASCADE)")
connection.execSQL("CREATE INDEX IF NOT EXISTS `index_attachment_task` ON `attachment` (`task`)")
connection.execSQL("CREATE INDEX IF NOT EXISTS `index_attachment_file` ON `attachment` (`file`)")
connection.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_attachment_task_file` ON `attachment` (`task`, `file`)")
db.execSQL(
connection.execSQL(
"INSERT INTO `attachment` (`task`, `file`, `file_uuid`) SELECT `tasks`.`_id`, `task_attachments`.`_id`, `task_attachments`.`remoteId` FROM `task_attachments` JOIN `tasks` ON `tasks`.`remoteId` = `task_attachments`.`task_id`"
)
db.execSQL("DROP TABLE `task_attachments`")
connection.execSQL("DROP TABLE `task_attachments`")
}
}
private val MIGRATION_86_87 = object : Migration(86, 87) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `tasks` ADD COLUMN `read_only` INTEGER NOT NULL DEFAULT 0")
db.execSQL("UPDATE `tasks` SET `read_only` = 1 WHERE `_id` IN (SELECT `cd_task` FROM `caldav_tasks` INNER JOIN `caldav_lists` ON `caldav_tasks`.`cd_calendar` = `caldav_lists`.`cdl_uuid` WHERE `cdl_access` = $ACCESS_READ_ONLY)")
override fun migrate(connection: SQLiteConnection) {
connection.execSQL("ALTER TABLE `tasks` ADD COLUMN `read_only` INTEGER NOT NULL DEFAULT 0")
connection.execSQL("UPDATE `tasks` SET `read_only` = 1 WHERE `_id` IN (SELECT `cd_task` FROM `caldav_tasks` INNER JOIN `caldav_lists` ON `caldav_tasks`.`cd_calendar` = `caldav_lists`.`cdl_uuid` WHERE `cdl_access` = $ACCESS_READ_ONLY)")
}
}
private fun migration_87_88(context: Context) = object : Migration(87, 88) {
override fun migrate(db: SupportSQLiteDatabase) {
override fun migrate(connection: SQLiteConnection) {
val prefs = Preferences(context)
val defaultList = prefs.getStringValue(R.string.p_default_list)?.split(":")
if (
(defaultList?.size == 2) &&
(defaultList[0].toIntOrNull()?.equals(DefaultFilterProvider.TYPE_GOOGLE_TASKS) == true)
) {
db.query("SELECT `gtl_remote_id` FROM `google_task_lists` WHERE `gtl_id` = '${defaultList[1]}'").use { cursor ->
if (cursor.moveToFirst()) {
cursor.getStringOrNull(0)?.let { uuid ->
connection.prepare("SELECT `gtl_remote_id` FROM `google_task_lists` WHERE `gtl_id` = '${defaultList[1]}'").use { cursor ->
if (cursor.step()) {
if (!cursor.isNull(0)) {
val uuid = cursor.getText(0)
prefs.setString(R.string.p_default_list, "${DefaultFilterProvider.TYPE_GOOGLE_TASKS}:$uuid")
}
}
}
}
// migrate google task accounts and lists to caldav table
db.execSQL("ALTER TABLE `caldav_lists` ADD COLUMN `cdl_last_sync` INTEGER NOT NULL DEFAULT 0")
db.execSQL("INSERT INTO `caldav_accounts` (`cda_account_type`, `cda_server_type`, `cda_uuid`, `cda_name`, `cda_username`, `cda_collapsed`) SELECT $TYPE_GOOGLE_TASKS, $SERVER_UNKNOWN, `gta_account`, `gta_account`, `gta_account`, `gta_collapsed` FROM `google_task_accounts`")
db.execSQL("INSERT INTO `caldav_lists` (`cdl_account`, `cdl_uuid`, `cdl_name`, `cdl_color`, `cdl_icon`, `cdl_order`, `cdl_access`, `cdl_last_sync`) SELECT `gtl_account`, `gtl_remote_id`, `gtl_title`, `gtl_color`, `gtl_icon`, `gtl_remote_order`, $ACCESS_OWNER, `gtl_last_sync` FROM `google_task_lists`")
db.execSQL("DROP TABLE `google_task_accounts`")
db.execSQL("DROP TABLE `google_task_lists`")
connection.execSQL("ALTER TABLE `caldav_lists` ADD COLUMN `cdl_last_sync` INTEGER NOT NULL DEFAULT 0")
connection.execSQL("INSERT INTO `caldav_accounts` (`cda_account_type`, `cda_server_type`, `cda_uuid`, `cda_name`, `cda_username`, `cda_collapsed`) SELECT $TYPE_GOOGLE_TASKS, $SERVER_UNKNOWN, `gta_account`, `gta_account`, `gta_account`, `gta_collapsed` FROM `google_task_accounts`")
connection.execSQL("INSERT INTO `caldav_lists` (`cdl_account`, `cdl_uuid`, `cdl_name`, `cdl_color`, `cdl_icon`, `cdl_order`, `cdl_access`, `cdl_last_sync`) SELECT `gtl_account`, `gtl_remote_id`, `gtl_title`, `gtl_color`, `gtl_icon`, `gtl_remote_order`, $ACCESS_OWNER, `gtl_last_sync` FROM `google_task_lists`")
connection.execSQL("DROP TABLE `google_task_accounts`")
connection.execSQL("DROP TABLE `google_task_lists`")
// move cd_order to task table
db.execSQL("ALTER TABLE `tasks` ADD COLUMN `order` INTEGER")
db.execSQL("ALTER TABLE `caldav_tasks` RENAME TO `caldav-temp`")
db.execSQL("CREATE TABLE IF NOT EXISTS `caldav_tasks` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_remote_parent` TEXT, `gt_moved` INTEGER NOT NULL, `gt_remote_order` INTEGER NOT NULL, FOREIGN KEY(`cd_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE)")
db.execSQL("DROP INDEX `index_caldav_tasks_cd_task`")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_caldav_tasks_cd_task` ON `caldav_tasks` (`cd_task`)")
db.execSQL("INSERT INTO `caldav_tasks` (`cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_remote_parent`, `gt_moved`, `gt_remote_order`) SELECT `cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_remote_parent`, 0, 0 FROM `caldav-temp`")
db.execSQL("DROP TABLE `caldav-temp`")
db.execSQL("INSERT INTO `caldav_tasks` (`cd_task`, `cd_calendar`, `cd_remote_id`, `cd_last_sync`, `cd_deleted`, `cd_remote_parent`, `gt_moved`, `gt_remote_order`) SELECT `gt_task`, `gt_list_id`, `gt_remote_id`, `gt_last_sync`, `gt_deleted`, `gt_remote_parent`, 0, 0 FROM google_tasks")
db.execSQL("DROP TABLE `google_tasks`")
connection.execSQL("ALTER TABLE `tasks` ADD COLUMN `order` INTEGER")
connection.execSQL("ALTER TABLE `caldav_tasks` RENAME TO `caldav-temp`")
connection.execSQL("CREATE TABLE IF NOT EXISTS `caldav_tasks` (`cd_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `cd_task` INTEGER NOT NULL, `cd_calendar` TEXT, `cd_object` TEXT, `cd_remote_id` TEXT, `cd_etag` TEXT, `cd_last_sync` INTEGER NOT NULL, `cd_deleted` INTEGER NOT NULL, `cd_remote_parent` TEXT, `gt_moved` INTEGER NOT NULL, `gt_remote_order` INTEGER NOT NULL, FOREIGN KEY(`cd_task`) REFERENCES `tasks`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE)")
connection.execSQL("DROP INDEX `index_caldav_tasks_cd_task`")
connection.execSQL("CREATE INDEX IF NOT EXISTS `index_caldav_tasks_cd_task` ON `caldav_tasks` (`cd_task`)")
connection.execSQL("INSERT INTO `caldav_tasks` (`cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_remote_parent`, `gt_moved`, `gt_remote_order`) SELECT `cd_id`, `cd_task`, `cd_calendar`, `cd_object`, `cd_remote_id`, `cd_etag`, `cd_last_sync`, `cd_deleted`, `cd_remote_parent`, 0, 0 FROM `caldav-temp`")
connection.execSQL("DROP TABLE `caldav-temp`")
connection.execSQL("INSERT INTO `caldav_tasks` (`cd_task`, `cd_calendar`, `cd_remote_id`, `cd_last_sync`, `cd_deleted`, `cd_remote_parent`, `gt_moved`, `gt_remote_order`) SELECT `gt_task`, `gt_list_id`, `gt_remote_id`, `gt_last_sync`, `gt_deleted`, `gt_remote_parent`, 0, 0 FROM google_tasks")
connection.execSQL("DROP TABLE `google_tasks`")
}
}
@ -672,7 +675,7 @@ object Migrations {
)
private fun noop(from: Int, to: Int): Migration = object : Migration(from, to) {
override fun migrate(db: SupportSQLiteDatabase) {}
override fun migrate(connection: SQLiteConnection) {}
}
fun String?.repeatFrom() = if (this?.contains("FROM=COMPLETION") == true) {

@ -18,7 +18,7 @@ import org.tasks.billing.BillingClientImpl
import org.tasks.billing.Inventory
import org.tasks.data.dao.AlarmDao
import org.tasks.data.dao.CaldavDao
import org.tasks.data.dao.ContentProviderDao
import org.tasks.data.dao.Astrid2ContentProviderDao
import org.tasks.data.dao.DeletionDao
import org.tasks.data.dao.FilterDao
import org.tasks.data.dao.GoogleTaskDao
@ -106,7 +106,7 @@ class ApplicationModule {
@Provides
@Singleton
fun getContentProviderDao(db: Database): ContentProviderDao = db.contentProviderDao()
fun getContentProviderDao(db: Database): Astrid2ContentProviderDao = db.contentProviderDao()
@Provides
@Singleton

@ -2,7 +2,7 @@ package org.tasks.injection
import android.content.Context
import androidx.room.Room
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -37,8 +37,8 @@ internal class ProductionModule {
context = context,
name = databaseFile.absolutePath
)
.setDriver(BundledSQLiteDriver())
.addMigrations(*Migrations.migrations(context, fileStorage))
.openHelperFactory(FrameworkSQLiteOpenHelperFactory())
if (!BuildConfig.DEBUG || !preferences.getBoolean(R.string.p_crash_main_queries, false)) {
builder.allowMainThreadQueries()
}

@ -38,10 +38,12 @@ class TasksContentProvider : ContentProvider() {
URI_TODO_AGENDA -> {
hilt.firebase.logEvent(R.string.event_todoagenda)
hilt.contentProviderDao.rawQuery(
SupportSQLiteQueryBuilder
.builder(TODO_AGENDA_TABLES)
.selection(selection, selectionArgs)
.create())
SupportSQLiteQueryBuilder
.builder(TODO_AGENDA_TABLES)
.selection(selection, selectionArgs)
.create()
.sql
)
}
URI_TASKS -> hilt.contentProviderDao.getTasks()
URI_LISTS -> hilt.contentProviderDao.getLists()

@ -0,0 +1,20 @@
package org.tasks.data
import androidx.room.RoomDatabase
import androidx.room.TransactionScope
import androidx.room.Transactor
import androidx.room.useReaderConnection
import androidx.room.useWriterConnection
import androidx.sqlite.SQLiteStatement
suspend fun <T> RoomDatabase.withTransaction(block: suspend TransactionScope<T>.() -> T): T =
useWriterConnection { transactor ->
transactor.withTransaction(Transactor.SQLiteTransactionType.DEFERRED) {
block()
}
}
suspend fun <T> RoomDatabase.rawQuery(query: String, block: (SQLiteStatement) -> T): T =
useReaderConnection { transactor -> transactor.usePrepared(query) { block(it) } }
suspend fun RoomDatabase.inTransaction(): Boolean = useReaderConnection { it.inTransaction() }

@ -0,0 +1,173 @@
package org.tasks.data
import androidx.room.util.getColumnIndex
import androidx.room.util.getColumnIndexOrThrow
import androidx.sqlite.SQLiteStatement
import org.tasks.data.entity.CaldavTask
import org.tasks.data.entity.Geofence
import org.tasks.data.entity.Place
import org.tasks.data.entity.Task
/*
room kmp doesn't support raw query yet 😢
https://issuetracker.google.com/issues/330586815
*/
fun SQLiteStatement.getTasks(): List<TaskContainer> {
val result = mutableListOf<TaskContainer>()
val _cursorIndexOfAccountType: Int = getColumnIndex(this, "accountType")
val _cursorIndexOfParentComplete: Int = getColumnIndex(this, "parentComplete")
val _cursorIndexOfTagsString: Int = getColumnIndex(this, "tags")
val _cursorIndexOfChildren: Int = getColumnIndex(this, "children")
val _cursorIndexOfSortGroup: Int = getColumnIndex(this, "sortGroup")
val _cursorIndexOfPrimarySort: Int = getColumnIndex(this, "primarySort")
val _cursorIndexOfSecondarySort: Int = getColumnIndex(this, "secondarySort")
val _cursorIndexOfIndent: Int = getColumnIndex(this, "indent")
val _cursorIndexOfId: Int = getColumnIndexOrThrow(this, "_id")
val _cursorIndexOfTitle: Int = getColumnIndexOrThrow(this, "title")
val _cursorIndexOfPriority: Int = getColumnIndexOrThrow(this, "importance")
val _cursorIndexOfDueDate: Int = getColumnIndexOrThrow(this, "dueDate")
val _cursorIndexOfHideUntil: Int = getColumnIndexOrThrow(this, "hideUntil")
val _cursorIndexOfCreationDate: Int = getColumnIndexOrThrow(this, "created")
val _cursorIndexOfModificationDate: Int = getColumnIndexOrThrow(this, "modified")
val _cursorIndexOfCompletionDate: Int = getColumnIndexOrThrow(this, "completed")
val _cursorIndexOfDeletionDate: Int = getColumnIndexOrThrow(this, "deleted")
val _cursorIndexOfNotes: Int = getColumnIndexOrThrow(this, "notes")
val _cursorIndexOfEstimatedSeconds: Int = getColumnIndexOrThrow(this, "estimatedSeconds")
val _cursorIndexOfElapsedSeconds: Int = getColumnIndexOrThrow(this, "elapsedSeconds")
val _cursorIndexOfTimerStart: Int = getColumnIndexOrThrow(this, "timerStart")
val _cursorIndexOfRingFlags: Int = getColumnIndexOrThrow(this, "notificationFlags")
val _cursorIndexOfReminderLast: Int = getColumnIndexOrThrow(this, "lastNotified")
val _cursorIndexOfRecurrence: Int = getColumnIndexOrThrow(this, "recurrence")
val _cursorIndexOfRepeatFrom: Int = getColumnIndexOrThrow(this, "repeat_from")
val _cursorIndexOfCalendarURI: Int = getColumnIndexOrThrow(this, "calendarUri")
val _cursorIndexOfRemoteId: Int = getColumnIndexOrThrow(this, "remoteId")
val _cursorIndexOfIsCollapsed: Int = getColumnIndexOrThrow(this, "collapsed")
val _cursorIndexOfParent: Int = getColumnIndexOrThrow(this, "parent")
val _cursorIndexOfOrder: Int = getColumnIndexOrThrow(this, "order")
val _cursorIndexOfReadOnly: Int = getColumnIndexOrThrow(this, "read_only")
val _cursorIndexOfId_1: Int = getColumnIndex(this, "cd_id")
val _cursorIndexOfTask: Int = getColumnIndex(this, "cd_task")
val _cursorIndexOfCalendar: Int = getColumnIndex(this, "cd_calendar")
val _cursorIndexOfRemoteId_1: Int = getColumnIndex(this, "cd_remote_id")
val _cursorIndexOfObj: Int = getColumnIndex(this, "cd_object")
val _cursorIndexOfEtag: Int = getColumnIndex(this, "cd_etag")
val _cursorIndexOfLastSync: Int = getColumnIndex(this, "cd_last_sync")
val _cursorIndexOfDeleted: Int = getColumnIndex(this, "cd_deleted")
val _cursorIndexOfRemoteParent: Int = getColumnIndex(this, "cd_remote_parent")
val _cursorIndexOfIsMoved: Int = getColumnIndex(this, "gt_moved")
val _cursorIndexOfRemoteOrder: Int = getColumnIndex(this, "gt_remote_order")
val _cursorIndexOfId_2: Int = getColumnIndex(this, "geofence_id")
val _cursorIndexOfTask_1: Int = getColumnIndex(this, "task")
val _cursorIndexOfPlace: Int = getColumnIndex(this, "place")
val _cursorIndexOfIsArrival: Int = getColumnIndex(this, "arrival")
val _cursorIndexOfIsDeparture: Int = getColumnIndex(this, "departure")
val _cursorIndexOfId_3: Int = getColumnIndex(this, "place_id")
val _cursorIndexOfUid: Int = getColumnIndex(this, "uid")
val _cursorIndexOfName: Int = getColumnIndex(this, "name")
val _cursorIndexOfAddress: Int = getColumnIndex(this, "address")
val _cursorIndexOfPhone: Int = getColumnIndex(this, "phone")
val _cursorIndexOfUrl: Int = getColumnIndex(this, "url")
val _cursorIndexOfLatitude: Int = getColumnIndex(this, "latitude")
val _cursorIndexOfLongitude: Int = getColumnIndex(this, "longitude")
val _cursorIndexOfColor: Int = getColumnIndex(this, "place_color")
val _cursorIndexOfIcon: Int = getColumnIndex(this, "place_icon")
val _cursorIndexOfOrder_1: Int = getColumnIndex(this, "place_order")
val _cursorIndexOfRadius: Int = getColumnIndex(this, "radius")
while (step()) {
val task = Task(
id = getLong(_cursorIndexOfId),
title = getTextOrNull(_cursorIndexOfTitle),
priority = getInt(_cursorIndexOfPriority),
dueDate = getLong(_cursorIndexOfDueDate),
hideUntil = getLong(_cursorIndexOfHideUntil),
creationDate = getLong(_cursorIndexOfCreationDate),
modificationDate = getLong(_cursorIndexOfModificationDate),
completionDate = getLong(_cursorIndexOfCompletionDate),
deletionDate = getLong(_cursorIndexOfDeletionDate),
notes = getTextOrNull(_cursorIndexOfNotes),
estimatedSeconds = getInt(_cursorIndexOfEstimatedSeconds),
elapsedSeconds = getInt(_cursorIndexOfElapsedSeconds),
timerStart = getLong(_cursorIndexOfTimerStart),
ringFlags = getInt(_cursorIndexOfRingFlags),
reminderLast = getLong(_cursorIndexOfReminderLast),
recurrence = getTextOrNull(_cursorIndexOfRecurrence),
repeatFrom = getInt(_cursorIndexOfRepeatFrom),
calendarURI = getTextOrNull(_cursorIndexOfCalendarURI),
remoteId = getTextOrNull(_cursorIndexOfRemoteId),
isCollapsed = getBoolean(_cursorIndexOfIsCollapsed),
parent = getLong(_cursorIndexOfParent),
order = getLongOrNull(_cursorIndexOfOrder),
readOnly = getBoolean(_cursorIndexOfReadOnly),
)
val caldavTask = getLongOrNull(_cursorIndexOfId_1)?.takeIf { it > 0 }?.let {
CaldavTask(
id = it,
task = getLong(_cursorIndexOfTask),
calendar = getTextOrNull(_cursorIndexOfCalendar),
remoteId = getTextOrNull(_cursorIndexOfRemoteId_1),
obj = getTextOrNull(_cursorIndexOfObj),
etag = getTextOrNull(_cursorIndexOfEtag),
lastSync = getLong(_cursorIndexOfLastSync),
deleted = getLong(_cursorIndexOfDeleted),
remoteParent = getTextOrNull(_cursorIndexOfRemoteParent),
isMoved = getBoolean(_cursorIndexOfIsMoved),
remoteOrder = getLong(_cursorIndexOfRemoteOrder),
)
}
val accountType = getInt(_cursorIndexOfAccountType)
val geofence = getLongOrNull(_cursorIndexOfId_2)?.takeIf { it > 0 }?.let {
Geofence(
id = it,
task = getLong(_cursorIndexOfTask_1),
place = getTextOrNull(_cursorIndexOfPlace),
isArrival = getBoolean(_cursorIndexOfIsArrival),
isDeparture = getBoolean(_cursorIndexOfIsDeparture),
)
}
val place = getLongOrNull(_cursorIndexOfId_3)?.takeIf { it > 0 }?.let {
Place(
id = it,
uid = getTextOrNull(_cursorIndexOfUid),
name = getTextOrNull(_cursorIndexOfName),
address = getTextOrNull(_cursorIndexOfAddress),
phone = getTextOrNull(_cursorIndexOfPhone),
url = getTextOrNull(_cursorIndexOfUrl),
latitude = getDouble(_cursorIndexOfLatitude),
longitude = getDouble(_cursorIndexOfLongitude),
color = getInt(_cursorIndexOfColor),
icon = getInt(_cursorIndexOfIcon),
order = getInt(_cursorIndexOfOrder_1),
radius = getInt(_cursorIndexOfRadius),
)
}
result.add(
TaskContainer(
task = task,
caldavTask = caldavTask,
accountType = accountType,
location = if (geofence != null && place != null) {
Location(geofence, place)
} else {
null
},
tagsString = getTextOrNull(_cursorIndexOfTagsString),
indent = getIntOrNull(_cursorIndexOfIndent) ?: 0,
sortGroup = getLongOrNull(_cursorIndexOfSortGroup),
children = getIntOrNull(_cursorIndexOfChildren) ?: 0,
primarySort = getLongOrNull(_cursorIndexOfPrimarySort) ?: 0,
secondarySort = getLongOrNull(_cursorIndexOfSecondarySort) ?: 0,
parentComplete = getBoolean(_cursorIndexOfParentComplete),
)
)
}
return result
}
private fun SQLiteStatement.getTextOrNull(index: Int): String? =
if (index == -1 || isNull(index)) null else this.getText(index)
private fun SQLiteStatement.getLongOrNull(index: Int): Long? =
if (index == -1 || isNull(index)) null else this.getLong(index)
private fun SQLiteStatement.getIntOrNull(index: Int): Int? =
if (index == -1 || isNull(index)) null else this.getInt(index)

@ -1,15 +1,12 @@
package org.tasks.data.dao
import android.database.Cursor
import androidx.room.Dao
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SupportSQLiteQuery
import org.tasks.data.entity.TagData
import org.tasks.data.entity.Task
@Dao
interface ContentProviderDao {
interface Astrid2ContentProviderDao {
@Query("SELECT name FROM tags WHERE task = :taskId ORDER BY UPPER(name) ASC")
suspend fun getTagNames(taskId: Long): List<String>
@ -30,16 +27,4 @@ interface ContentProviderDao {
@Query("SELECT * FROM tagdata WHERE name IS NOT NULL AND name != '' ORDER BY UPPER(name) ASC")
suspend fun tagDataOrderedByName(): List<TagData>
@Query("SELECT * FROM tasks")
fun getTasks(): Cursor
@Query("""
SELECT caldav_lists.*, caldav_accounts.cda_name
FROM caldav_lists
INNER JOIN caldav_accounts ON cdl_account = cda_uuid""")
fun getLists(): Cursor
@RawQuery
fun rawQuery(query: SupportSQLiteQuery): Cursor
}
}

@ -3,10 +3,8 @@ package org.tasks.data.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.RawQuery
import androidx.room.Update
import androidx.room.withTransaction
import androidx.sqlite.db.SimpleSQLiteQuery
import androidx.room.execSQL
import co.touchlab.kermit.Logger
import org.tasks.data.BuildConfig
import org.tasks.data.TaskContainer
@ -16,8 +14,11 @@ import org.tasks.data.db.SuspendDbUtils.chunkedMap
import org.tasks.data.db.SuspendDbUtils.eachChunk
import org.tasks.data.entity.Alarm
import org.tasks.data.entity.Task
import org.tasks.data.getTasks
import org.tasks.data.rawQuery
import org.tasks.data.sql.Criterion
import org.tasks.data.sql.Functions
import org.tasks.data.withTransaction
import org.tasks.time.DateTimeUtils2
private const val MAX_TIME = 9999999999999
@ -109,28 +110,25 @@ FROM (
abstract suspend fun clearCompletedCalendarEvents(): Int
open suspend fun fetchTasks(callback: suspend () -> List<String>): List<TaskContainer> =
database.withTransaction {
val start = if (BuildConfig.DEBUG) DateTimeUtils2.currentTimeMillis() else 0
val queries = callback()
val last = queries.size - 1
for (i in 0 until last) {
query(SimpleSQLiteQuery(queries[i]))
}
val result = fetchTasks(SimpleSQLiteQuery(queries[last]))
Logger.v("TaskDao") {
"${DateTimeUtils2.currentTimeMillis() - start}ms: ${queries.joinToString(";\n")}"
}
result
database.withTransaction {
val start = if (BuildConfig.DEBUG) DateTimeUtils2.currentTimeMillis() else 0
val queries = callback()
val last = queries.size - 1
for (i in 0 until last) {
execSQL(queries[i])
}
val result = usePrepared(queries[last]) { it.getTasks() }
Logger.v("TaskDao") {
"${DateTimeUtils2.currentTimeMillis() - start}ms: ${queries.joinToString(";\n")}"
}
result
}
@RawQuery
internal abstract suspend fun query(query: SimpleSQLiteQuery): Int
@RawQuery
abstract suspend fun fetchTasks(query: SimpleSQLiteQuery): List<TaskContainer>
suspend fun fetchTasks(query: String): List<TaskContainer> =
database.rawQuery(query) { it.getTasks() }
@RawQuery
abstract suspend fun countRaw(query: SimpleSQLiteQuery): Int
suspend fun countRaw(query: String): Int =
database.rawQuery(query) { if (it.step()) it.getInt(0) else 0 }
suspend fun touch(ids: List<Long>, now: Long = DateTimeUtils2.currentTimeMillis()) =
ids.eachChunk { internalTouch(it, now) }

@ -11,7 +11,7 @@ import org.tasks.data.entity.CaldavAccount
import org.tasks.data.entity.CaldavCalendar
import org.tasks.data.dao.CaldavDao
import org.tasks.data.entity.CaldavTask
import org.tasks.data.dao.ContentProviderDao
import org.tasks.data.dao.Astrid2ContentProviderDao
import org.tasks.data.dao.DeletionDao
import org.tasks.data.entity.Filter
import org.tasks.data.dao.FilterDao
@ -78,7 +78,7 @@ abstract class Database : RoomDatabase() {
abstract fun taskDao(): TaskDao
abstract fun caldavDao(): CaldavDao
abstract fun deletionDao(): DeletionDao
abstract fun contentProviderDao(): ContentProviderDao
abstract fun contentProviderDao(): Astrid2ContentProviderDao
abstract fun upgraderDao(): UpgraderDao
abstract fun principalDao(): PrincipalDao

@ -234,13 +234,15 @@
+| | | \--- androidx.sqlite:sqlite-android:2.5.0-alpha02
+| | | +--- androidx.annotation:annotation:1.8.0 (*)
+| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | \--- androidx.sqlite:sqlite-framework:2.5.0-alpha02 (c)
+| | | +--- androidx.sqlite:sqlite-framework:2.5.0-alpha02 (c)
+| | | \--- androidx.sqlite:sqlite-bundled:2.5.0-alpha02 (c)
+| | +--- androidx.sqlite:sqlite-framework:2.5.0-alpha02
+| | | \--- androidx.sqlite:sqlite-framework-android:2.5.0-alpha02
+| | | +--- androidx.annotation:annotation:1.8.0 (*)
+| | | +--- androidx.sqlite:sqlite:2.5.0-alpha02 (*)
+| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | \--- androidx.sqlite:sqlite:2.5.0-alpha02 (c)
+| | | +--- androidx.sqlite:sqlite:2.5.0-alpha02 (c)
+| | | \--- androidx.sqlite:sqlite-bundled:2.5.0-alpha02 (c)
+| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | +--- org.jetbrains.kotlinx:atomicfu:0.17.0
+| | | \--- org.jetbrains.kotlinx:atomicfu-jvm:0.17.0
@ -603,6 +605,12 @@
++--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.0 (*)
++--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0 (*)
++--- androidx.room:room-runtime:2.7.0-alpha02 (*)
++--- androidx.sqlite:sqlite-bundled:2.5.0-alpha02
+| \--- androidx.sqlite:sqlite-bundled-android:2.5.0-alpha02
+| +--- androidx.sqlite:sqlite:2.5.0-alpha02 (*)
+| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| +--- androidx.sqlite:sqlite:2.5.0-alpha02 (c)
+| \--- androidx.sqlite:sqlite-framework:2.5.0-alpha02 (c)
++--- androidx.appcompat:appcompat:1.6.1 (*)
++--- io.noties.markwon:core:4.6.2
+| +--- androidx.annotation:annotation:1.1.0 -> 1.8.0 (*)

@ -594,13 +594,15 @@
+| | | \--- androidx.sqlite:sqlite-android:2.5.0-alpha02
+| | | +--- androidx.annotation:annotation:1.8.0 (*)
+| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | \--- androidx.sqlite:sqlite-framework:2.5.0-alpha02 (c)
+| | | +--- androidx.sqlite:sqlite-framework:2.5.0-alpha02 (c)
+| | | \--- androidx.sqlite:sqlite-bundled:2.5.0-alpha02 (c)
+| | +--- androidx.sqlite:sqlite-framework:2.5.0-alpha02
+| | | \--- androidx.sqlite:sqlite-framework-android:2.5.0-alpha02
+| | | +--- androidx.annotation:annotation:1.8.0 (*)
+| | | +--- androidx.sqlite:sqlite:2.5.0-alpha02 (*)
+| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | | \--- androidx.sqlite:sqlite:2.5.0-alpha02 (c)
+| | | +--- androidx.sqlite:sqlite:2.5.0-alpha02 (c)
+| | | \--- androidx.sqlite:sqlite-bundled:2.5.0-alpha02 (c)
+| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| | +--- org.jetbrains.kotlinx:atomicfu:0.17.0
+| | | \--- org.jetbrains.kotlinx:atomicfu-jvm:0.17.0
@ -832,6 +834,12 @@
++--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.0 (*)
++--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0 (*)
++--- androidx.room:room-runtime:2.7.0-alpha02 (*)
++--- androidx.sqlite:sqlite-bundled:2.5.0-alpha02
+| \--- androidx.sqlite:sqlite-bundled-android:2.5.0-alpha02
+| +--- androidx.sqlite:sqlite:2.5.0-alpha02 (*)
+| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.0 (*)
+| +--- androidx.sqlite:sqlite:2.5.0-alpha02 (c)
+| \--- androidx.sqlite:sqlite-framework:2.5.0-alpha02 (c)
++--- androidx.appcompat:appcompat:1.6.1 (*)
++--- io.noties.markwon:core:4.6.2
+| +--- androidx.annotation:annotation:1.1.0 -> 1.8.0 (*)

@ -83,6 +83,7 @@ androidx-preference = { module = "androidx.preference:preference", version.ref =
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
androidx-room = { module = "androidx.room:room-runtime", version.ref = "room" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room"}
androidx-sqlite = { module = "androidx.sqlite:sqlite-bundled", version = "2.5.0-alpha02" }
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swiperefreshlayout" }
androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test" }
androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidx-test" }

Loading…
Cancel
Save