Convert MentionTable to kotlin.

This commit is contained in:
Greyson Parrelli 2024-04-05 15:57:24 -04:00
parent 791dc2724f
commit 9bd4e9524c
2 changed files with 174 additions and 176 deletions

View file

@ -1,176 +0,0 @@
package org.thoughtcrime.securesms.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.signal.core.util.CursorUtil;
import org.signal.core.util.SqlUtil;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class MentionTable extends DatabaseTable implements RecipientIdDatabaseReference, ThreadIdDatabaseReference {
public static final String TABLE_NAME = "mention";
private static final String ID = "_id";
static final String THREAD_ID = "thread_id";
public static final String MESSAGE_ID = "message_id";
static final String RECIPIENT_ID = "recipient_id";
private static final String RANGE_START = "range_start";
private static final String RANGE_LENGTH = "range_length";
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
THREAD_ID + " INTEGER, " +
MESSAGE_ID + " INTEGER, " +
RECIPIENT_ID + " INTEGER, " +
RANGE_START + " INTEGER, " +
RANGE_LENGTH + " INTEGER)";
public static final String[] CREATE_INDEXES = new String[] {
"CREATE INDEX IF NOT EXISTS mention_message_id_index ON " + TABLE_NAME + " (" + MESSAGE_ID + ");",
"CREATE INDEX IF NOT EXISTS mention_recipient_id_thread_id_index ON " + TABLE_NAME + " (" + RECIPIENT_ID + ", " + THREAD_ID + ");"
};
public MentionTable(@NonNull Context context, @NonNull SignalDatabase databaseHelper) {
super(context, databaseHelper);
}
public void insert(long threadId, long messageId, @NonNull Collection<Mention> mentions) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
db.beginTransaction();
try {
for (Mention mention : mentions) {
ContentValues values = new ContentValues();
values.put(THREAD_ID, threadId);
values.put(MESSAGE_ID, messageId);
values.put(RECIPIENT_ID, mention.getRecipientId().toLong());
values.put(RANGE_START, mention.getStart());
values.put(RANGE_LENGTH, mention.getLength());
db.insert(TABLE_NAME, null, values);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
public @NonNull List<Mention> getMentionsForMessage(long messageId) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
List<Mention> mentions = new LinkedList<>();
try (Cursor cursor = db.query(TABLE_NAME, null, MESSAGE_ID + " = ?", SqlUtil.buildArgs(messageId), null, null, null)) {
while (cursor != null && cursor.moveToNext()) {
mentions.add(new Mention(RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID)),
CursorUtil.requireInt(cursor, RANGE_START),
CursorUtil.requireInt(cursor, RANGE_LENGTH)));
}
}
return mentions;
}
public @NonNull Map<Long, List<Mention>> getMentionsForMessages(@NonNull Collection<Long> messageIds) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String ids = TextUtils.join(",", messageIds);
try (Cursor cursor = db.query(TABLE_NAME, null, MESSAGE_ID + " IN (" + ids + ")", null, null, null, null)) {
return readMentions(cursor);
}
}
public @NonNull Map<Long, List<Mention>> getMentionsContainingRecipients(@NonNull Collection<RecipientId> recipientIds, long limit) {
return getMentionsContainingRecipients(recipientIds, -1, limit);
}
public @NonNull Map<Long, List<Mention>> getMentionsContainingRecipients(@NonNull Collection<RecipientId> recipientIds, long threadId, long limit) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String ids = TextUtils.join(",", Stream.of(recipientIds).map(RecipientId::serialize).toList());
String where = " WHERE " + RECIPIENT_ID + " IN (" + ids + ")";
if (threadId != -1) {
where += " AND " + THREAD_ID + " = " + threadId;
}
String subSelect = "SELECT DISTINCT " + MESSAGE_ID +
" FROM " + TABLE_NAME +
where +
" ORDER BY " + ID + " DESC" +
" LIMIT " + limit;
String query = "SELECT *" +
" FROM " + TABLE_NAME +
" WHERE " + MESSAGE_ID +
" IN (" + subSelect + ")";
try (Cursor cursor = db.rawQuery(query, null)) {
return readMentions(cursor);
}
}
void deleteMentionsForMessage(long messageId) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
String where = MESSAGE_ID + " = ?";
db.delete(TABLE_NAME, where, SqlUtil.buildArgs(messageId));
}
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 + " WHERE " + ThreadTable.ACTIVE + " = 1)";
db.delete(TABLE_NAME, where, null);
}
void deleteAllMentions() {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
db.delete(TABLE_NAME, null, null);
}
private @NonNull Map<Long, List<Mention>> readMentions(@Nullable Cursor cursor) {
Map<Long, List<Mention>> mentions = new HashMap<>();
while (cursor != null && cursor.moveToNext()) {
long messageId = CursorUtil.requireLong(cursor, MESSAGE_ID);
List<Mention> messageMentions = mentions.get(messageId);
if (messageMentions == null) {
messageMentions = new LinkedList<>();
mentions.put(messageId, messageMentions);
}
messageMentions.add(new Mention(RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID)),
CursorUtil.requireInt(cursor, RANGE_START),
CursorUtil.requireInt(cursor, RANGE_LENGTH)));
}
return mentions;
}
@Override
public void remapRecipient(@NonNull RecipientId fromId, @NonNull RecipientId toId) {
ContentValues values = new ContentValues();
values.put(RECIPIENT_ID, toId.serialize());
getWritableDatabase().update(TABLE_NAME, values, RECIPIENT_ID + " = ?", SqlUtil.buildArgs(fromId));
}
@Override
public void remapThread(long fromId, long toId) {
ContentValues values = new ContentValues();
values.put(MentionTable.THREAD_ID, toId);
getWritableDatabase().update(TABLE_NAME, values, THREAD_ID + " = ?", SqlUtil.buildArgs(fromId));
}
}

View file

@ -0,0 +1,174 @@
package org.thoughtcrime.securesms.database
import android.content.Context
import android.database.Cursor
import org.signal.core.util.delete
import org.signal.core.util.deleteAll
import org.signal.core.util.insertInto
import org.signal.core.util.readToList
import org.signal.core.util.requireInt
import org.signal.core.util.requireLong
import org.signal.core.util.select
import org.signal.core.util.update
import org.signal.core.util.withinTransaction
import org.thoughtcrime.securesms.database.model.Mention
import org.thoughtcrime.securesms.recipients.RecipientId
class MentionTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTable(context, databaseHelper), RecipientIdDatabaseReference, ThreadIdDatabaseReference {
companion object {
const val TABLE_NAME = "mention"
const val ID = "_id"
const val THREAD_ID = "thread_id"
const val MESSAGE_ID = "message_id"
const val RECIPIENT_ID = "recipient_id"
const val RANGE_START = "range_start"
const val RANGE_LENGTH = "range_length"
const val CREATE_TABLE = """
CREATE TABLE $TABLE_NAME(
$ID INTEGER PRIMARY KEY AUTOINCREMENT,
$THREAD_ID INTEGER,
$MESSAGE_ID INTEGER,
$RECIPIENT_ID INTEGER,
$RANGE_START INTEGER,
$RANGE_LENGTH INTEGER
)
"""
val CREATE_INDEXES = arrayOf(
"CREATE INDEX IF NOT EXISTS mention_message_id_index ON $TABLE_NAME ($MESSAGE_ID);",
"CREATE INDEX IF NOT EXISTS mention_recipient_id_thread_id_index ON $TABLE_NAME ($RECIPIENT_ID, $THREAD_ID);"
)
}
fun insert(threadId: Long, messageId: Long, mentions: Collection<Mention>) {
writableDatabase.withinTransaction { db ->
for (mention in mentions) {
db.insertInto(TABLE_NAME)
.values(
THREAD_ID to threadId,
MESSAGE_ID to messageId,
RECIPIENT_ID to mention.recipientId.toLong(),
RANGE_START to mention.start,
RANGE_LENGTH to mention.length
)
.run()
}
}
}
fun getMentionsForMessage(messageId: Long): List<Mention> {
return readableDatabase
.select()
.from(TABLE_NAME)
.where("$MESSAGE_ID = $messageId")
.run()
.readToList { cursor ->
Mention(
RecipientId.from(cursor.requireLong(RECIPIENT_ID)),
cursor.requireInt(RANGE_START),
cursor.requireInt(RANGE_LENGTH)
)
}
}
fun getMentionsForMessages(messageIds: Collection<Long>): Map<Long, List<Mention>> {
val ids = messageIds.joinToString(separator = ",") { it.toString() }
return readableDatabase
.select()
.from(TABLE_NAME)
.where("$MESSAGE_ID IN ($ids)")
.run()
.use { cursor -> readMentions(cursor) }
}
fun getMentionsContainingRecipients(recipientIds: Collection<RecipientId>, limit: Long): Map<Long, List<Mention>> {
return getMentionsContainingRecipients(recipientIds, -1, limit)
}
fun getMentionsContainingRecipients(recipientIds: Collection<RecipientId>, threadId: Long, limit: Long): Map<Long, List<Mention>> {
val ids = recipientIds.joinToString(separator = ",") { it.serialize() }
var where = "$RECIPIENT_ID IN ($ids)"
if (threadId != -1L) {
where += " AND $THREAD_ID = $threadId"
}
return readableDatabase
.select()
.from(TABLE_NAME)
.where(
"""
$MESSAGE_ID IN (
SELECT DISTINCT $MESSAGE_ID
FROM $TABLE_NAME
WHERE $where
ORDER BY $ID DESC LIMIT $limit
)
"""
)
.run()
.use { cursor -> readMentions(cursor) }
}
fun deleteMentionsForMessage(messageId: Long) {
writableDatabase
.delete(TABLE_NAME)
.where("$MESSAGE_ID = $messageId")
.run()
}
fun deleteAbandonedMentions() {
writableDatabase
.delete(TABLE_NAME)
.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
)
"""
)
.run()
}
fun deleteAllMentions() {
writableDatabase.deleteAll(TABLE_NAME)
}
private fun readMentions(cursor: Cursor): Map<Long, List<Mention>> {
return cursor.readToList {
val messageId = it.requireLong(MESSAGE_ID)
val mention = Mention(
RecipientId.from(it.requireLong(RECIPIENT_ID)),
it.requireInt(RANGE_START),
it.requireInt(RANGE_LENGTH)
)
messageId to mention
}.groupBy({ it.first }, { it.second })
}
override fun remapRecipient(fromId: RecipientId, toId: RecipientId) {
writableDatabase
.update(TABLE_NAME)
.values(RECIPIENT_ID to toId.serialize())
.where("$RECIPIENT_ID = ?", fromId)
.run()
}
override fun remapThread(fromId: Long, toId: Long) {
writableDatabase
.update(TABLE_NAME)
.values(THREAD_ID to toId)
.where("$THREAD_ID = $fromId")
.run()
}
}