aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/db
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2019-04-21 21:02:55 -0400
committerAllan Wang <me@allanwang.ca>2019-04-21 21:02:55 -0400
commit5002792f2c79a7479c531736a4a9c40c0b1fe116 (patch)
treec4ce594859a1d47d41c62674298ee67c2481fa25 /app/src/main/kotlin/com/pitchedapps/frost/db
parent4739e6f58df1116babac69896764e83db551f583 (diff)
downloadfrost-5002792f2c79a7479c531736a4a9c40c0b1fe116.tar.gz
frost-5002792f2c79a7479c531736a4a9c40c0b1fe116.tar.bz2
frost-5002792f2c79a7479c531736a4a9c40c0b1fe116.zip
Wrap all db calls using our own context
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/db')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/db/CacheDb.kt19
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt15
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/db/DaoUtils.kt28
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/db/GenericDb.kt14
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/db/NotificationDb.kt17
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/db/ThreadDb.kt115
6 files changed, 67 insertions, 141 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/db/CacheDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/db/CacheDb.kt
index 4906f60a..f0dacdc7 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/db/CacheDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/db/CacheDb.kt
@@ -55,23 +55,32 @@ data class CacheEntity(
interface CacheDao {
@Query("SELECT * FROM frost_cache WHERE id = :id AND type = :type")
- suspend fun select(id: Long, type: String): CacheEntity?
+ fun _select(id: Long, type: String): CacheEntity?
@Insert(onConflict = OnConflictStrategy.REPLACE)
- suspend fun insertCache(cache: CacheEntity)
+ fun _insertCache(cache: CacheEntity)
@Query("DELETE FROM frost_cache WHERE id = :id AND type = :type")
- suspend fun delete(id: Long, type: String)
+ fun _delete(id: Long, type: String)
+}
+
+suspend fun CacheDao.select(id: Long, type: String) = dao {
+ _select(id, type)
+}
+
+suspend fun CacheDao.delete(id: Long, type: String) = dao {
+ _delete(id, type)
}
/**
* Returns true if successful, given that there are constraints to the insertion
*/
-suspend fun CacheDao.save(id: Long, type: String, contents: String): Boolean =
+suspend fun CacheDao.save(id: Long, type: String, contents: String): Boolean = dao {
try {
- insertCache(CacheEntity(id, type, System.currentTimeMillis(), contents))
+ _insertCache(CacheEntity(id, type, System.currentTimeMillis(), contents))
true
} catch (e: Exception) {
L.e(e) { "Cache save failed for $type" }
false
}
+}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt
index 5aadbb02..b81ce365 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/db/CookiesDb.kt
@@ -53,21 +53,26 @@ data class CookieEntity(
interface CookieDao {
@Query("SELECT * FROM cookies")
- suspend fun selectAll(): List<CookieEntity>
+ fun _selectAll(): List<CookieEntity>
@Query("SELECT * FROM cookies WHERE cookie_id = :id")
- suspend fun selectById(id: Long): CookieEntity?
+ fun _selectById(id: Long): CookieEntity?
@Insert(onConflict = OnConflictStrategy.REPLACE)
- suspend fun save(cookie: CookieEntity)
+ fun _save(cookie: CookieEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE)
- suspend fun save(cookies: List<CookieEntity>)
+ fun _save(cookies: List<CookieEntity>)
@Query("DELETE FROM cookies WHERE cookie_id = :id")
- suspend fun deleteById(id: Long)
+ fun _deleteById(id: Long)
}
+suspend fun CookieDao.selectAll() = dao { _selectAll() }
+suspend fun CookieDao.selectById(id: Long) = dao { _selectById(id) }
+suspend fun CookieDao.save(cookie: CookieEntity) = dao { _save(cookie) }
+suspend fun CookieDao.save(cookies: List<CookieEntity>) = dao { _save(cookies) }
+suspend fun CookieDao.deleteById(id: Long) = dao { _deleteById(id) }
suspend fun CookieDao.currentCookie() = selectById(Prefs.userId)
@Database(version = CookiesDb.VERSION)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/db/DaoUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/db/DaoUtils.kt
new file mode 100644
index 00000000..c31aa9b7
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/db/DaoUtils.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019 Allan Wang
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.pitchedapps.frost.db
+
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+/**
+ * Wraps dao calls to work with coroutines
+ * Non transactional queries were supposed to be fixed in https://issuetracker.google.com/issues/69474692,
+ * but it still requires dispatch from a non ui thread.
+ * This avoids that constraint
+ */
+suspend inline fun <T> dao(crossinline block: () -> T) = withContext(Dispatchers.IO) { block() }
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/db/GenericDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/db/GenericDb.kt
index 4177ae86..f36c8af9 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/db/GenericDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/db/GenericDb.kt
@@ -43,27 +43,27 @@ data class GenericEntity(
interface GenericDao {
@Query("SELECT contents FROM frost_generic WHERE type = :type")
- suspend fun select(type: String): String?
+ fun _select(type: String): String?
@Insert(onConflict = OnConflictStrategy.REPLACE)
- suspend fun save(entity: GenericEntity)
+ fun _save(entity: GenericEntity)
@Query("DELETE FROM frost_generic WHERE type = :type")
- suspend fun delete(type: String)
+ fun _delete(type: String)
companion object {
const val TYPE_TABS = "generic_tabs"
}
}
-suspend fun GenericDao.saveTabs(tabs: List<FbItem>) {
+suspend fun GenericDao.saveTabs(tabs: List<FbItem>) = dao {
val content = tabs.joinToString(",") { it.name }
- save(GenericEntity(GenericDao.TYPE_TABS, content))
+ _save(GenericEntity(GenericDao.TYPE_TABS, content))
}
-suspend fun GenericDao.getTabs(): List<FbItem> {
+suspend fun GenericDao.getTabs(): List<FbItem> = dao {
val allTabs = FbItem.values.map { it.name to it }.toMap()
- return select(GenericDao.TYPE_TABS)
+ _select(GenericDao.TYPE_TABS)
?.split(",")
?.mapNotNull { allTabs[it] }
?.takeIf { it.isNotEmpty() }
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/db/NotificationDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/db/NotificationDb.kt
index e1f7fc76..8936d682 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/db/NotificationDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/db/NotificationDb.kt
@@ -42,8 +42,6 @@ import com.raizlabs.android.dbflow.kotlinextensions.where
import com.raizlabs.android.dbflow.sql.SQLiteType
import com.raizlabs.android.dbflow.sql.migration.AlterTableMigration
import com.raizlabs.android.dbflow.structure.BaseModel
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
@Entity(
tableName = "notifications",
@@ -120,7 +118,7 @@ interface NotificationDao {
fun _deleteNotifications(userId: Long, type: String)
@Query("DELETE FROM notifications")
- suspend fun deleteAll()
+ fun _deleteAll()
/**
* It is assumed that the notification batch comes from the same user
@@ -134,17 +132,18 @@ interface NotificationDao {
}
}
-suspend fun NotificationDao.selectNotifications(userId: Long, type: String): List<NotificationContent> =
- withContext(Dispatchers.IO) {
- _selectNotifications(userId, type).map { it.toNotifContent() }
- }
+suspend fun NotificationDao.deleteAll() = dao { _deleteAll() }
+
+suspend fun NotificationDao.selectNotifications(userId: Long, type: String): List<NotificationContent> = dao {
+ _selectNotifications(userId, type).map { it.toNotifContent() }
+}
/**
* Returns true if successful, given that there are constraints to the insertion
*/
suspend fun NotificationDao.saveNotifications(type: String, notifs: List<NotificationContent>): Boolean {
if (notifs.isEmpty()) return true
- return withContext(Dispatchers.IO) {
+ return dao {
try {
_saveNotifications(type, notifs)
true
@@ -155,7 +154,7 @@ suspend fun NotificationDao.saveNotifications(type: String, notifs: List<Notific
}
}
-suspend fun NotificationDao.latestEpoch(userId: Long, type: String): Long = withContext(Dispatchers.IO) {
+suspend fun NotificationDao.latestEpoch(userId: Long, type: String): Long = dao {
_selectEpoch(userId, type) ?: lastNotificationTime(userId).let {
when (type) {
NOTIF_CHANNEL_GENERAL -> it.epoch
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/db/ThreadDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/db/ThreadDb.kt
deleted file mode 100644
index d7c91211..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/db/ThreadDb.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2018 Allan Wang
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.pitchedapps.frost.db
-
-import androidx.room.Dao
-import androidx.room.Embedded
-import androidx.room.Entity
-import androidx.room.ForeignKey
-import androidx.room.Index
-import androidx.room.Insert
-import androidx.room.OnConflictStrategy
-import androidx.room.Query
-import androidx.room.Transaction
-import com.pitchedapps.frost.db.CookieModel_Table.cookie
-import com.pitchedapps.frost.facebook.parsers.FrostThread
-import com.pitchedapps.frost.utils.L
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-
-@Entity(
- tableName = "threads",
- primaryKeys = ["thread_id", "userId"],
- foreignKeys = [ForeignKey(
- entity = CookieEntity::class,
- parentColumns = ["cookie_id"],
- childColumns = ["userId"],
- onDelete = ForeignKey.CASCADE
- )],
- indices = [Index("thread_id"), Index("userId")]
-)
-data class ThreadEntity(
- @Embedded(prefix = "thread_")
- val thread: FrostThread,
- val userId: Long
-)
-
-data class ThreadContentEntity(
- @Embedded
- val cookie: CookieEntity,
- @Embedded(prefix = "thread_")
- val thread: FrostThread
-)
-
-@Dao
-interface ThreadDao {
-
- /**
- * Note that notifications are guaranteed to be ordered by descending timestamp
- */
- @Transaction
- @Query("SELECT * FROM cookies INNER JOIN threads ON cookie_id = userId WHERE userId = :userId ORDER BY thread_time DESC")
- fun _selectThreads(userId: Long): List<ThreadContentEntity>
-
- @Query("SELECT thread_time FROM threads WHERE userId = :userId ORDER BY thread_time DESC LIMIT 1")
- fun _selectEpoch(userId: Long): Long?
-
- @Insert(onConflict = OnConflictStrategy.REPLACE)
- fun _insertThreads(notifs: List<ThreadEntity>)
-
- @Query("DELETE FROM threads WHERE userId = :userId ")
- fun _deleteThreads(userId: Long)
-
- @Query("DELETE FROM threads")
- suspend fun deleteAll()
-
- /**
- * It is assumed that the notification batch comes from the same user
- */
- @Transaction
- fun _saveThreads(userId: Long, notifs: List<FrostThread>) {
- val entities = notifs.map { ThreadEntity(it, userId) }
- _deleteThreads(userId)
- _insertThreads(entities)
- }
-}
-
-suspend fun ThreadDao.selectThreads(userId: Long): List<ThreadContentEntity> =
- withContext(Dispatchers.IO) {
- _selectThreads(userId)
- }
-
-/**
- * Returns true if successful, given that there are constraints to the insertion
- */
-suspend fun ThreadDao.saveThreads(userId: Long, threads: List<FrostThread>): Boolean {
- if (threads.isEmpty()) return true
- return withContext(Dispatchers.IO) {
- try {
- _saveThreads(userId, threads)
- true
- } catch (e: Exception) {
- L.e(e) { "Thread save failed" }
- false
- }
- }
-}
-
-suspend fun ThreadDao.latestEpoch(userId: Long, type: String): Long =
- withContext(Dispatchers.IO) {
- _selectEpoch(userId) ?: lastNotificationTime(userId).epochIm
- }