2020-08-05 22:45:52 +02:00
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 ;
2020-08-07 21:18:40 +02:00
import androidx.annotation.Nullable ;
import com.annimon.stream.Stream ;
2020-08-05 22:45:52 +02:00
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 {
2020-08-12 17:12:01 +02:00
static final String TABLE_NAME = "mention" ;
2020-08-05 22:45:52 +02:00
private static final String ID = "_id" ;
2020-08-12 17:12:01 +02:00
static final String THREAD_ID = "thread_id" ;
2020-08-05 22:45:52 +02:00
private static final String MESSAGE_ID = "message_id" ;
2020-08-12 17:12:01 +02:00
static final String RECIPIENT_ID = "recipient_id" ;
2020-08-05 22:45:52 +02:00
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 ) {
2020-08-07 21:18:40 +02:00
SQLiteDatabase db = databaseHelper . getReadableDatabase ( ) ;
String ids = TextUtils . join ( "," , messageIds ) ;
2020-08-05 22:45:52 +02:00
try ( Cursor cursor = db . query ( TABLE_NAME , null , MESSAGE_ID + " IN (" + ids + ")" , null , null , null , null ) ) {
2020-08-07 21:18:40 +02:00
return readMentions ( cursor ) ;
}
}
2020-08-05 22:45:52 +02:00
2020-08-07 21:18:40 +02:00
public @NonNull Map < Long , List < Mention > > getMentionsContainingRecipients ( @NonNull Collection < RecipientId > recipientIds , long limit ) {
return getMentionsContainingRecipients ( recipientIds , - 1 , limit ) ;
}
2020-08-05 22:45:52 +02:00
2020-08-07 21:18:40 +02:00
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 ;
2020-08-05 22:45:52 +02:00
}
2020-08-07 21:18:40 +02:00
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 ) ;
}
}
2020-09-30 20:35:02 +02:00
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 ( ) ;
2020-10-08 15:46:26 +02:00
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 + ")" ;
2020-09-30 20:35:02 +02:00
db . delete ( TABLE_NAME , where , null ) ;
}
void deleteAllMentions ( ) {
SQLiteDatabase db = databaseHelper . getWritableDatabase ( ) ;
db . delete ( TABLE_NAME , null , null ) ;
}
2020-08-07 21:18:40 +02:00
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 ) ) ) ;
}
2020-08-05 22:45:52 +02:00
return mentions ;
}
}