mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Add new active column to ThreadTable.
This commit is contained in:
committed by
Nicholas Tinsley
parent
a65e9c76bc
commit
b0ca66cc1a
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.database
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.thoughtcrime.securesms.conversationlist.model.ConversationFilter
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.testing.SignalDatabaseRule
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import java.util.UUID
|
||||
|
||||
@Suppress("ClassName")
|
||||
class ThreadTableTest_active {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val databaseRule = SignalDatabaseRule()
|
||||
|
||||
private lateinit var recipient: Recipient
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromServiceId(ServiceId.from(UUID.randomUUID())))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenActiveUnarchivedThread_whenIGetUnarchivedConversationList_thenIExpectThread() {
|
||||
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
MmsHelper.insert(recipient = recipient, threadId = threadId)
|
||||
SignalDatabase.threads.update(threadId, false)
|
||||
|
||||
SignalDatabase.threads.getUnarchivedConversationList(
|
||||
ConversationFilter.OFF,
|
||||
false,
|
||||
0,
|
||||
10
|
||||
).use { threads ->
|
||||
assertEquals(1, threads.count)
|
||||
|
||||
val record = ThreadTable.StaticReader(threads, InstrumentationRegistry.getInstrumentation().context).getNext()
|
||||
|
||||
assertNotNull(record)
|
||||
assertEquals(record!!.recipient.id, recipient.id)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenInactiveUnarchivedThread_whenIGetUnarchivedConversationList_thenIExpectNoThread() {
|
||||
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
MmsHelper.insert(recipient = recipient, threadId = threadId)
|
||||
SignalDatabase.threads.update(threadId, false)
|
||||
SignalDatabase.threads.deleteConversation(threadId)
|
||||
|
||||
SignalDatabase.threads.getUnarchivedConversationList(
|
||||
ConversationFilter.OFF,
|
||||
false,
|
||||
0,
|
||||
10
|
||||
).use { threads ->
|
||||
assertEquals(0, threads.count)
|
||||
}
|
||||
|
||||
val threadId2 = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
assertEquals(threadId2, threadId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenActiveArchivedThread_whenIGetUnarchivedConversationList_thenIExpectNoThread() {
|
||||
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
MmsHelper.insert(recipient = recipient, threadId = threadId)
|
||||
SignalDatabase.threads.update(threadId, false)
|
||||
SignalDatabase.threads.setArchived(setOf(threadId), true)
|
||||
|
||||
SignalDatabase.threads.getUnarchivedConversationList(
|
||||
ConversationFilter.OFF,
|
||||
false,
|
||||
0,
|
||||
10
|
||||
).use { threads ->
|
||||
assertEquals(0, threads.count)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenActiveArchivedThread_whenIGetArchivedConversationList_thenIExpectThread() {
|
||||
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
MmsHelper.insert(recipient = recipient, threadId = threadId)
|
||||
SignalDatabase.threads.update(threadId, false)
|
||||
SignalDatabase.threads.setArchived(setOf(threadId), true)
|
||||
|
||||
SignalDatabase.threads.getArchivedConversationList(
|
||||
ConversationFilter.OFF,
|
||||
0,
|
||||
10
|
||||
).use { threads ->
|
||||
assertEquals(1, threads.count)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenInactiveArchivedThread_whenIGetArchivedConversationList_thenIExpectNoThread() {
|
||||
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
MmsHelper.insert(recipient = recipient, threadId = threadId)
|
||||
SignalDatabase.threads.update(threadId, false)
|
||||
SignalDatabase.threads.deleteConversation(threadId)
|
||||
SignalDatabase.threads.setArchived(setOf(threadId), true)
|
||||
|
||||
SignalDatabase.threads.getArchivedConversationList(
|
||||
ConversationFilter.OFF,
|
||||
0,
|
||||
10
|
||||
).use { threads ->
|
||||
assertEquals(0, threads.count)
|
||||
}
|
||||
|
||||
val threadId2 = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
assertEquals(threadId2, threadId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenActiveArchivedThread_whenIDeactivateThread_thenIExpectNoMessages() {
|
||||
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
MmsHelper.insert(recipient = recipient, threadId = threadId)
|
||||
SignalDatabase.threads.update(threadId, false)
|
||||
|
||||
SignalDatabase.messages.getConversation(threadId).use {
|
||||
assertEquals(1, it.count)
|
||||
}
|
||||
|
||||
SignalDatabase.threads.deleteConversation(threadId)
|
||||
|
||||
SignalDatabase.messages.getConversation(threadId).use {
|
||||
assertEquals(0, it.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ class SignalDatabaseRule(
|
||||
|
||||
private fun deleteAllThreads() {
|
||||
if (deleteAllThreadsOnEachRun) {
|
||||
SignalDatabase.messages.deleteAllThreads()
|
||||
SignalDatabase.threads.clearForTests()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
FROM $TABLE_NAME
|
||||
INNER JOIN ${MembershipTable.TABLE_NAME} ON ${MembershipTable.TABLE_NAME}.${MembershipTable.GROUP_ID} = $TABLE_NAME.$GROUP_ID
|
||||
INNER JOIN ${ThreadTable.TABLE_NAME} ON ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} = $TABLE_NAME.$RECIPIENT_ID
|
||||
WHERE $ACTIVE = 1 AND ${MembershipTable.TABLE_NAME}.${MembershipTable.RECIPIENT_ID} IN (${subquery.where})
|
||||
WHERE $TABLE_NAME.$ACTIVE = 1 AND ${MembershipTable.TABLE_NAME}.${MembershipTable.RECIPIENT_ID} IN (${subquery.where})
|
||||
GROUP BY ${MembershipTable.TABLE_NAME}.${MembershipTable.GROUP_ID}
|
||||
ORDER BY $TITLE COLLATE NOCASE ASC
|
||||
"""
|
||||
@@ -407,10 +407,10 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
val queryArgs: Array<String>
|
||||
|
||||
if (includeInactive) {
|
||||
query = "${membershipQuery.where} AND ($ACTIVE = ? OR $TABLE_NAME.$RECIPIENT_ID IN (SELECT ${ThreadTable.RECIPIENT_ID} FROM ${ThreadTable.TABLE_NAME}))"
|
||||
query = "${membershipQuery.where} AND ($TABLE_NAME.$ACTIVE = ? OR $TABLE_NAME.$RECIPIENT_ID IN (SELECT ${ThreadTable.RECIPIENT_ID} FROM ${ThreadTable.TABLE_NAME} WHERE ${ThreadTable.TABLE_NAME}.${ThreadTable.ACTIVE} = 1))"
|
||||
queryArgs = membershipQuery.whereArgs + buildArgs(1)
|
||||
} else {
|
||||
query = "${membershipQuery.where} AND $ACTIVE = ?"
|
||||
query = "${membershipQuery.where} AND $TABLE_NAME.$ACTIVE = ?"
|
||||
queryArgs = membershipQuery.whereArgs + buildArgs(1)
|
||||
}
|
||||
|
||||
@@ -464,10 +464,10 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
val caseInsensitiveQuery = buildCaseInsensitiveGlobPattern(inputQuery)
|
||||
|
||||
if (includeInactive) {
|
||||
query = "$TITLE GLOB ? AND ($ACTIVE = ? OR $TABLE_NAME.$RECIPIENT_ID IN (SELECT ${ThreadTable.RECIPIENT_ID} FROM ${ThreadTable.TABLE_NAME}))"
|
||||
query = "$TITLE GLOB ? AND ($TABLE_NAME.$ACTIVE = ? OR $TABLE_NAME.$RECIPIENT_ID IN (SELECT ${ThreadTable.RECIPIENT_ID} FROM ${ThreadTable.TABLE_NAME} WHERE ${ThreadTable.TABLE_NAME}.${ThreadTable.ACTIVE} = 1))"
|
||||
queryArgs = buildArgs(caseInsensitiveQuery, 1)
|
||||
} else {
|
||||
query = "$TITLE GLOB ? AND $ACTIVE = ?"
|
||||
query = "$TITLE GLOB ? AND $TABLE_NAME.$ACTIVE = ?"
|
||||
queryArgs = buildArgs(caseInsensitiveQuery, 1)
|
||||
}
|
||||
|
||||
@@ -590,7 +590,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
}
|
||||
|
||||
if (!includeInactive) {
|
||||
query += " AND $ACTIVE = ?"
|
||||
query += " AND $TABLE_NAME.$ACTIVE = ?"
|
||||
args = appendArg(args, "1")
|
||||
}
|
||||
|
||||
@@ -1313,7 +1313,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT
|
||||
) AS active_timestamp
|
||||
FROM $TABLE_NAME INNER JOIN ${ThreadTable.TABLE_NAME} ON ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} = $TABLE_NAME.$RECIPIENT_ID
|
||||
WHERE
|
||||
$ACTIVE = 1 AND
|
||||
$TABLE_NAME.$ACTIVE = 1 AND
|
||||
(
|
||||
$SHOW_AS_STORY_STATE = ${ShowAsStoryState.ALWAYS.code} OR
|
||||
(
|
||||
|
||||
@@ -131,7 +131,7 @@ public class MentionTable extends DatabaseTable implements RecipientIdDatabaseRe
|
||||
|
||||
void deleteAbandonedMentions() {
|
||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||
String where = MESSAGE_ID + " NOT IN (SELECT " + MessageTable.ID + " FROM " + MessageTable.TABLE_NAME + ") OR " + THREAD_ID + " NOT IN (SELECT " + ThreadTable.ID + " FROM " + ThreadTable.TABLE_NAME + ")";
|
||||
String where = MESSAGE_ID + " NOT IN (SELECT " + MessageTable.ID + " FROM " + MessageTable.TABLE_NAME + ") OR " + THREAD_ID + " NOT IN (SELECT " + ThreadTable.ID + " FROM " + ThreadTable.TABLE_NAME + " WHERE " + ThreadTable.ACTIVE + " = 1)";
|
||||
|
||||
db.delete(TABLE_NAME, where, null);
|
||||
}
|
||||
|
||||
@@ -3562,7 +3562,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
fun deleteAbandonedMessages(): Int {
|
||||
val deletes = writableDatabase
|
||||
.delete(TABLE_NAME)
|
||||
.where("$THREAD_ID NOT IN (SELECT _id FROM ${ThreadTable.TABLE_NAME})")
|
||||
.where("$THREAD_ID NOT IN (SELECT _id FROM ${ThreadTable.TABLE_NAME} WHERE ${ThreadTable.ACTIVE} = 1)")
|
||||
.run()
|
||||
|
||||
if (deletes > 0) {
|
||||
|
||||
@@ -406,6 +406,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
||||
$TABLE_NAME.$SEEN_INVITE_REMINDER < ${InsightsBannerTier.TIER_TWO.id} AND
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.HAS_SENT} AND
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.DATE} > ? AND
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.ACTIVE} = 1 AND
|
||||
$TABLE_NAME.$HIDDEN = 0
|
||||
ORDER BY ${ThreadTable.TABLE_NAME}.${ThreadTable.DATE} DESC LIMIT 50
|
||||
"""
|
||||
@@ -3344,13 +3345,16 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
||||
return SqlUtil.Query(subquery, SqlUtil.buildArgs(0, 0, query, query, query, query))
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries all contacts without an active thread.
|
||||
*/
|
||||
fun getAllContactsWithoutThreads(inputQuery: String): Cursor {
|
||||
val query = SqlUtil.buildCaseInsensitiveGlobPattern(inputQuery)
|
||||
|
||||
//language=sql
|
||||
val subquery = """
|
||||
SELECT ${SEARCH_PROJECTION.joinToString(", ")} FROM $TABLE_NAME
|
||||
WHERE $BLOCKED = ? AND $HIDDEN = ? AND NOT EXISTS (SELECT 1 FROM ${ThreadTable.TABLE_NAME} WHERE ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} = $TABLE_NAME.$ID LIMIT 1)
|
||||
WHERE $BLOCKED = ? AND $HIDDEN = ? AND NOT EXISTS (SELECT 1 FROM ${ThreadTable.TABLE_NAME} WHERE ${ThreadTable.TABLE_NAME}.${ThreadTable.ACTIVE} = 1 AND ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} = $TABLE_NAME.$ID LIMIT 1)
|
||||
AND (
|
||||
$SORT_NAME GLOB ? OR
|
||||
$USERNAME GLOB ? OR
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.database.MergeCursor
|
||||
import android.net.Uri
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.core.content.contentValuesOf
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import org.json.JSONObject
|
||||
@@ -106,6 +107,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
const val LAST_SCROLLED = "last_scrolled"
|
||||
const val PINNED = "pinned"
|
||||
const val UNREAD_SELF_MENTION_COUNT = "unread_self_mention_count"
|
||||
const val ACTIVE = "active"
|
||||
|
||||
const val MAX_CACHE_SIZE = 1000
|
||||
|
||||
@@ -134,16 +136,18 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
$HAS_SENT INTEGER DEFAULT 0,
|
||||
$LAST_SCROLLED INTEGER DEFAULT 0,
|
||||
$PINNED INTEGER DEFAULT 0,
|
||||
$UNREAD_SELF_MENTION_COUNT INTEGER DEFAULT 0
|
||||
$UNREAD_SELF_MENTION_COUNT INTEGER DEFAULT 0,
|
||||
$ACTIVE INTEGER DEFAULT 0
|
||||
)
|
||||
"""
|
||||
|
||||
@JvmField
|
||||
val CREATE_INDEXS = arrayOf(
|
||||
"CREATE INDEX IF NOT EXISTS thread_recipient_id_index ON $TABLE_NAME ($RECIPIENT_ID);",
|
||||
"CREATE INDEX IF NOT EXISTS archived_count_index ON $TABLE_NAME ($ARCHIVED, $MEANINGFUL_MESSAGES);",
|
||||
"CREATE INDEX IF NOT EXISTS thread_recipient_id_index ON $TABLE_NAME ($RECIPIENT_ID, $ACTIVE);",
|
||||
"CREATE INDEX IF NOT EXISTS archived_count_index ON $TABLE_NAME ($ACTIVE, $ARCHIVED, $MEANINGFUL_MESSAGES, $PINNED);",
|
||||
"CREATE INDEX IF NOT EXISTS thread_pinned_index ON $TABLE_NAME ($PINNED);",
|
||||
"CREATE INDEX IF NOT EXISTS thread_read ON $TABLE_NAME ($READ);"
|
||||
"CREATE INDEX IF NOT EXISTS thread_read ON $TABLE_NAME ($READ);",
|
||||
"CREATE INDEX IF NOT EXISTS thread_active ON $TABLE_NAME ($ACTIVE);"
|
||||
)
|
||||
|
||||
private val THREAD_PROJECTION = arrayOf(
|
||||
@@ -240,7 +244,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
STATUS to status,
|
||||
DELIVERY_RECEIPT_COUNT to deliveryReceiptCount,
|
||||
READ_RECEIPT_COUNT to readReceiptCount,
|
||||
EXPIRES_IN to expiresIn
|
||||
EXPIRES_IN to expiresIn,
|
||||
ACTIVE to 1
|
||||
)
|
||||
|
||||
writableDatabase
|
||||
@@ -873,7 +878,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
return readableDatabase
|
||||
.select("COUNT(*)")
|
||||
.from(TABLE_NAME)
|
||||
.where("$ARCHIVED = 1 AND $MEANINGFUL_MESSAGES != 0 $filterQuery")
|
||||
.where("$ACTIVE = 1 AND $ARCHIVED = 1 AND $MEANINGFUL_MESSAGES != 0 $filterQuery")
|
||||
.run()
|
||||
.use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
@@ -889,7 +894,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
return readableDatabase
|
||||
.select("COUNT(*)")
|
||||
.from(TABLE_NAME)
|
||||
.where("$ARCHIVED = 0 AND $PINNED != 0 $filterQuery")
|
||||
.where("$ACTIVE = 1 AND $ARCHIVED = 0 AND $PINNED != 0 $filterQuery")
|
||||
.run()
|
||||
.use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
@@ -905,7 +910,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
return readableDatabase
|
||||
.select("COUNT(*)")
|
||||
.from(TABLE_NAME)
|
||||
.where("$ARCHIVED = 0 AND ($MEANINGFUL_MESSAGES != 0 OR $PINNED != 0) $filterQuery")
|
||||
.where("$ACTIVE = 1 AND $ARCHIVED = 0 AND ($MEANINGFUL_MESSAGES != 0 OR $PINNED != 0) $filterQuery")
|
||||
.run()
|
||||
.use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
@@ -968,7 +973,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
for (threadId in threadIds) {
|
||||
pinnedCount++
|
||||
db.update(TABLE_NAME)
|
||||
.values(PINNED to pinnedCount)
|
||||
.values(PINNED to pinnedCount, ACTIVE to 1)
|
||||
.where("$ID = ?", threadId)
|
||||
.run()
|
||||
}
|
||||
@@ -1058,9 +1063,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
writableDatabase.withinTransaction { db ->
|
||||
messages.deleteThread(threadId)
|
||||
drafts.clearDrafts(threadId)
|
||||
db.delete(TABLE_NAME)
|
||||
.where("$ID = ?", threadId)
|
||||
.run()
|
||||
db.deactivateThread(threadId)
|
||||
synchronized(threadIdCache) {
|
||||
threadIdCache.remove(recipientIdForThreadId)
|
||||
}
|
||||
@@ -1078,7 +1081,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
val queries: List<SqlUtil.Query> = SqlUtil.buildCollectionQuery(ID, selectedConversations)
|
||||
writableDatabase.withinTransaction { db ->
|
||||
for (query in queries) {
|
||||
db.delete(TABLE_NAME, query.where, query.whereArgs)
|
||||
db.deactivateThread(query)
|
||||
}
|
||||
|
||||
messages.deleteAbandonedMessages()
|
||||
@@ -1100,13 +1103,21 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
ConversationUtil.clearShortcuts(context, recipientIds)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun clearForTests() {
|
||||
writableDatabase.withinTransaction {
|
||||
deleteAllConversations()
|
||||
it.delete(TABLE_NAME).run()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DiscouragedApi")
|
||||
fun deleteAllConversations() {
|
||||
writableDatabase.withinTransaction { db ->
|
||||
messageLog.deleteAll()
|
||||
messages.deleteAllThreads()
|
||||
drafts.clearAllDrafts()
|
||||
db.delete(TABLE_NAME, null, null)
|
||||
db.deactivateThreads()
|
||||
calls.deleteAllCalls()
|
||||
synchronized(threadIdCache) {
|
||||
threadIdCache.clear()
|
||||
@@ -1316,7 +1327,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
|
||||
if (pinnedRecipient != null) {
|
||||
db.update(TABLE_NAME)
|
||||
.values(PINNED to pinnedPosition)
|
||||
.values(PINNED to pinnedPosition, ACTIVE to 1)
|
||||
.where("$RECIPIENT_ID = ?", pinnedRecipient.id)
|
||||
.run()
|
||||
}
|
||||
@@ -1598,6 +1609,48 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
}
|
||||
}
|
||||
|
||||
private fun SQLiteDatabase.deactivateThreads() {
|
||||
deactivateThread(query = null)
|
||||
}
|
||||
|
||||
private fun SQLiteDatabase.deactivateThread(threadId: Long) {
|
||||
deactivateThread(SqlUtil.Query("$ID = ?", SqlUtil.buildArgs(threadId)))
|
||||
}
|
||||
|
||||
private fun SQLiteDatabase.deactivateThread(query: SqlUtil.Query?) {
|
||||
val update = update(TABLE_NAME)
|
||||
.values(
|
||||
DATE to 0,
|
||||
MEANINGFUL_MESSAGES to 0,
|
||||
READ to ReadStatus.READ.serialize(),
|
||||
TYPE to 0,
|
||||
ERROR to 0,
|
||||
SNIPPET to null,
|
||||
SNIPPET_TYPE to 0,
|
||||
SNIPPET_URI to null,
|
||||
SNIPPET_CONTENT_TYPE to null,
|
||||
SNIPPET_EXTRAS to null,
|
||||
UNREAD_COUNT to 0,
|
||||
ARCHIVED to 0,
|
||||
STATUS to 0,
|
||||
DELIVERY_RECEIPT_COUNT to 0,
|
||||
READ_RECEIPT_COUNT to 0,
|
||||
EXPIRES_IN to 0,
|
||||
LAST_SEEN to 0,
|
||||
HAS_SENT to 0,
|
||||
LAST_SCROLLED to 0,
|
||||
PINNED to 0,
|
||||
UNREAD_SELF_MENTION_COUNT to 0,
|
||||
ACTIVE to 0
|
||||
)
|
||||
|
||||
if (query != null) {
|
||||
update.where(query.where, query.whereArgs).run()
|
||||
} else {
|
||||
update.run()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAttachmentUriFor(record: MessageRecord): Uri? {
|
||||
if (!record.isMms || record.isMmsNotification || record.isGroupAction) {
|
||||
return null
|
||||
@@ -1721,7 +1774,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
SELECT group_id, GROUP_CONCAT(${GroupTable.MembershipTable.TABLE_NAME}.${GroupTable.MembershipTable.RECIPIENT_ID}) as ${GroupTable.MEMBER_GROUP_CONCAT}
|
||||
FROM ${GroupTable.MembershipTable.TABLE_NAME}
|
||||
) as MembershipAlias ON MembershipAlias.${GroupTable.MembershipTable.GROUP_ID} = ${GroupTable.TABLE_NAME}.${GroupTable.GROUP_ID}
|
||||
WHERE $where
|
||||
WHERE $TABLE_NAME.$ACTIVE = 1 AND $where
|
||||
ORDER BY $orderBy
|
||||
"""
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V195_GroupMemberFor
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V196_BackCallLinksWithRecipientV2
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V197_DropAvatarColorFromCallLinks
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V198_AddMacDigestColumn
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V199_AddThreadActiveColumn
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
@@ -62,7 +63,7 @@ object SignalDatabaseMigrations {
|
||||
|
||||
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
|
||||
|
||||
const val DATABASE_VERSION = 198
|
||||
const val DATABASE_VERSION = 199
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
@@ -265,6 +266,10 @@ object SignalDatabaseMigrations {
|
||||
if (oldVersion < 198) {
|
||||
V198_AddMacDigestColumn.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
if (oldVersion < 199) {
|
||||
V199_AddThreadActiveColumn.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
|
||||
/**
|
||||
* Adds the ACTIVE column to the THREAD table, and mark all current threads active.
|
||||
*
|
||||
* For performance and maintainability reasons, instead of explicitly deleting thread rows from the
|
||||
* database, we instead want to mark them as inactive and remove any backing data (messages, etc.),
|
||||
* essentially turning them into tombstones, which can be 'resurrected' when a new attempt is made
|
||||
* to chat with whomever the thread is tied to.
|
||||
*/
|
||||
@Suppress("ClassName")
|
||||
object V199_AddThreadActiveColumn : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("ALTER TABLE thread ADD COLUMN active INTEGER DEFAULT 0")
|
||||
db.execSQL("UPDATE thread SET active = 1")
|
||||
|
||||
db.execSQL("DROP INDEX IF EXISTS thread_recipient_id_index")
|
||||
db.execSQL("DROP INDEX IF EXISTS archived_count_index")
|
||||
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS thread_recipient_id_index ON thread (recipient_id, active)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS archived_count_index ON thread (active, archived, meaningful_messages, pinned)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS thread_active ON thread (active)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user