165 lines
6.6 KiB
Java
165 lines
6.6 KiB
Java
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 net.sqlcipher.database.SQLiteDatabase;
|
|
|
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
|
import org.thoughtcrime.securesms.database.model.Mention;
|
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
|
import org.thoughtcrime.securesms.util.CursorUtil;
|
|
import org.thoughtcrime.securesms.util.SqlUtil;
|
|
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
public class MentionDatabase extends Database {
|
|
|
|
static final String TABLE_NAME = "mention";
|
|
|
|
private static final String ID = "_id";
|
|
static final String THREAD_ID = "thread_id";
|
|
private 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 MentionDatabase(@NonNull Context context, @NonNull SQLCipherOpenHelper databaseHelper) {
|
|
super(context, databaseHelper);
|
|
}
|
|
|
|
public void insert(long threadId, long messageId, @NonNull Collection<Mention> mentions) {
|
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
|
|
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.getReadableDatabase();
|
|
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.getReadableDatabase();
|
|
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.getReadableDatabase();
|
|
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.getWritableDatabase();
|
|
String where = MESSAGE_ID + " = ?";
|
|
|
|
db.delete(TABLE_NAME, where, SqlUtil.buildArgs(messageId));
|
|
}
|
|
|
|
void deleteAbandonedMentions() {
|
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
String where = MESSAGE_ID + " NOT IN (SELECT " + MmsDatabase.ID + " FROM " + MmsDatabase.TABLE_NAME + ") OR " + THREAD_ID + " NOT IN (SELECT " + ThreadDatabase.ID + " FROM " + ThreadDatabase.TABLE_NAME + ")";
|
|
|
|
db.delete(TABLE_NAME, where, null);
|
|
}
|
|
|
|
void deleteAllMentions() {
|
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
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;
|
|
}
|
|
}
|