mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-22 12:08:34 +00:00
Convert MessageTable to kotlin.
This commit is contained in:
@@ -18,7 +18,7 @@ class SmsSettingsRepository(
|
|||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private fun checkInsecureMessageCount(): SmsExportState? {
|
private fun checkInsecureMessageCount(): SmsExportState? {
|
||||||
val totalSmsMmsCount = smsDatabase.insecureMessageCount + mmsDatabase.insecureMessageCount
|
val totalSmsMmsCount = smsDatabase.getInsecureMessageCount() + mmsDatabase.getInsecureMessageCount()
|
||||||
|
|
||||||
return if (totalSmsMmsCount == 0) {
|
return if (totalSmsMmsCount == 0) {
|
||||||
SmsExportState.NO_SMS_MESSAGES_IN_DATABASE
|
SmsExportState.NO_SMS_MESSAGES_IN_DATABASE
|
||||||
@@ -29,7 +29,7 @@ class SmsSettingsRepository(
|
|||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private fun checkUnexportedInsecureMessageCount(): SmsExportState {
|
private fun checkUnexportedInsecureMessageCount(): SmsExportState {
|
||||||
val totalUnexportedCount = smsDatabase.unexportedInsecureMessagesCount + mmsDatabase.unexportedInsecureMessagesCount
|
val totalUnexportedCount = smsDatabase.getUnexportedInsecureMessagesCount() + mmsDatabase.getUnexportedInsecureMessagesCount()
|
||||||
|
|
||||||
return if (totalUnexportedCount > 0) {
|
return if (totalUnexportedCount > 0) {
|
||||||
SmsExportState.HAS_UNEXPORTED_MESSAGES
|
SmsExportState.HAS_UNEXPORTED_MESSAGES
|
||||||
|
|||||||
@@ -1193,7 +1193,6 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||||||
if (message.getScheduledDate() != -1) {
|
if (message.getScheduledDate() != -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MessageRecord messageRecord = MessageTable.readerFor(message, threadId).getCurrent();
|
|
||||||
|
|
||||||
if (getListAdapter() != null) {
|
if (getListAdapter() != null) {
|
||||||
setLastSeen(0);
|
setLastSeen(0);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -128,7 +128,7 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||||||
* Be smart about where you call this.
|
* Be smart about where you call this.
|
||||||
*/
|
*/
|
||||||
fun rebuildIndex(batchSize: Long = 10_000L) {
|
fun rebuildIndex(batchSize: Long = 10_000L) {
|
||||||
val maxId: Long = SignalDatabase.messages.nextId
|
val maxId: Long = SignalDatabase.messages.getNextId()
|
||||||
|
|
||||||
Log.i(TAG, "Re-indexing. Operating on ID's 1-$maxId in steps of $batchSize.")
|
Log.i(TAG, "Re-indexing. Operating on ID's 1-$maxId in steps of $batchSize.")
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class SignalSmsExportReader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getCount(): Int {
|
fun getCount(): Int {
|
||||||
return messageTable.unexportedInsecureMessagesCount
|
return messageTable.getUnexportedInsecureMessagesCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
@@ -51,7 +51,7 @@ class SignalSmsExportReader(
|
|||||||
messageReader = null
|
messageReader = null
|
||||||
|
|
||||||
val refreshedMmsReader = MessageTable.mmsReaderFor(messageTable.getUnexportedInsecureMessages(CURSOR_LIMIT))
|
val refreshedMmsReader = MessageTable.mmsReaderFor(messageTable.getUnexportedInsecureMessages(CURSOR_LIMIT))
|
||||||
if (refreshedMmsReader.count > 0) {
|
if (refreshedMmsReader.getCount() > 0) {
|
||||||
messageReader = refreshedMmsReader
|
messageReader = refreshedMmsReader
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -88,14 +88,14 @@ class SignalSmsExportReader(
|
|||||||
try {
|
try {
|
||||||
return if (messageIterator?.hasNext() == true) {
|
return if (messageIterator?.hasNext() == true) {
|
||||||
record = messageIterator!!.next()
|
record = messageIterator!!.next()
|
||||||
readExportableMmsMessageFromRecord(record, messageReader!!.messageExportStateForCurrentRecord)
|
readExportableMmsMessageFromRecord(record, messageReader!!.getMessageExportStateForCurrentRecord())
|
||||||
} else {
|
} else {
|
||||||
throw NoSuchElementException()
|
throw NoSuchElementException()
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
if (e.cause is JSONException) {
|
if (e.cause is JSONException) {
|
||||||
Log.w(TAG, "Error processing attachment json, skipping message.", e)
|
Log.w(TAG, "Error processing attachment json, skipping message.", e)
|
||||||
return ExportableMessage.Skip(messageReader!!.currentId)
|
return ExportableMessage.Skip(messageReader!!.getCurrentId())
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.w(TAG, "Error processing message: isMms: ${record?.isMms} type: ${record?.type}")
|
Log.w(TAG, "Error processing message: isMms: ${record?.isMms} type: ${record?.type}")
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
package org.thoughtcrime.securesms.mms;
|
|
||||||
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
|
||||||
import org.thoughtcrime.securesms.database.model.Mention;
|
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class QuoteModel {
|
|
||||||
|
|
||||||
private final long id;
|
|
||||||
private final RecipientId author;
|
|
||||||
private final String text;
|
|
||||||
private final boolean missing;
|
|
||||||
private final List<Attachment> attachments;
|
|
||||||
private final List<Mention> mentions;
|
|
||||||
private final Type type;
|
|
||||||
private final BodyRangeList bodyRanges;
|
|
||||||
|
|
||||||
public QuoteModel(long id,
|
|
||||||
@NonNull RecipientId author,
|
|
||||||
String text,
|
|
||||||
boolean missing,
|
|
||||||
@Nullable List<Attachment> attachments,
|
|
||||||
@Nullable List<Mention> mentions,
|
|
||||||
@NonNull Type type,
|
|
||||||
@Nullable BodyRangeList bodyRanges)
|
|
||||||
{
|
|
||||||
this.id = id;
|
|
||||||
this.author = author;
|
|
||||||
this.text = text;
|
|
||||||
this.missing = missing;
|
|
||||||
this.attachments = attachments;
|
|
||||||
this.mentions = mentions != null ? mentions : Collections.emptyList();
|
|
||||||
this.type = type;
|
|
||||||
this.bodyRanges = bodyRanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecipientId getAuthor() {
|
|
||||||
return author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getText() {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOriginalMissing() {
|
|
||||||
return missing;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Attachment> getAttachments() {
|
|
||||||
return attachments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull List<Mention> getMentions() {
|
|
||||||
return mentions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable BodyRangeList getBodyRanges() {
|
|
||||||
return bodyRanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Type {
|
|
||||||
NORMAL(0, SignalServiceDataMessage.Quote.Type.NORMAL),
|
|
||||||
GIFT_BADGE(1, SignalServiceDataMessage.Quote.Type.GIFT_BADGE);
|
|
||||||
|
|
||||||
private final int code;
|
|
||||||
private final SignalServiceDataMessage.Quote.Type dataMessageType;
|
|
||||||
|
|
||||||
Type(int code, @NonNull SignalServiceDataMessage.Quote.Type dataMessageType) {
|
|
||||||
this.code = code;
|
|
||||||
this.dataMessageType = dataMessageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull SignalServiceDataMessage.Quote.Type getDataMessageType() {
|
|
||||||
return dataMessageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Type fromCode(int code) {
|
|
||||||
for (final Type value : values()) {
|
|
||||||
if (value.code == code) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Invalid code: " + code);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Type fromDataMessageType(@NonNull SignalServiceDataMessage.Quote.Type dataMessageType) {
|
|
||||||
for (final Type value : values()) {
|
|
||||||
if (value.dataMessageType == dataMessageType) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NORMAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package org.thoughtcrime.securesms.mms
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.attachments.Attachment
|
||||||
|
import org.thoughtcrime.securesms.database.model.Mention
|
||||||
|
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||||
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
|
||||||
|
|
||||||
|
class QuoteModel(
|
||||||
|
val id: Long,
|
||||||
|
val author: RecipientId,
|
||||||
|
val text: String,
|
||||||
|
val isOriginalMissing: Boolean,
|
||||||
|
val attachments: List<Attachment>,
|
||||||
|
mentions: List<Mention>?,
|
||||||
|
val type: Type,
|
||||||
|
val bodyRanges: BodyRangeList?
|
||||||
|
) {
|
||||||
|
val mentions: List<Mention>
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.mentions = mentions ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Type(val code: Int, val dataMessageType: SignalServiceDataMessage.Quote.Type) {
|
||||||
|
|
||||||
|
NORMAL(0, SignalServiceDataMessage.Quote.Type.NORMAL),
|
||||||
|
GIFT_BADGE(1, SignalServiceDataMessage.Quote.Type.GIFT_BADGE);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun fromCode(code: Int): Type {
|
||||||
|
for (value in values()) {
|
||||||
|
if (value.code == code) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw IllegalArgumentException("Invalid code: $code")
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun fromDataMessageType(dataMessageType: SignalServiceDataMessage.Quote.Type): Type {
|
||||||
|
for (value in values()) {
|
||||||
|
if (value.dataMessageType === dataMessageType) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NORMAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ object NotificationStateProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MessageTable.mmsReaderFor(unreadMessages).use { reader ->
|
MessageTable.mmsReaderFor(unreadMessages).use { reader ->
|
||||||
var record: MessageRecord? = reader.next
|
var record: MessageRecord? = reader.getNext()
|
||||||
while (record != null) {
|
while (record != null) {
|
||||||
val threadRecipient: Recipient? = SignalDatabase.threads.getRecipientForThreadId(record.threadId)
|
val threadRecipient: Recipient? = SignalDatabase.threads.getRecipientForThreadId(record.threadId)
|
||||||
if (threadRecipient != null) {
|
if (threadRecipient != null) {
|
||||||
@@ -73,7 +73,7 @@ object NotificationStateProvider {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
record = reader.next
|
record = reader.getNext()
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
// XXX Weird SQLCipher bug that's being investigated
|
// XXX Weird SQLCipher bug that's being investigated
|
||||||
record = null
|
record = null
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ConversationListTabRepository {
|
|||||||
fun getNumberOfUnseenStories(): Observable<Long> {
|
fun getNumberOfUnseenStories(): Observable<Long> {
|
||||||
return Observable.create<Long> { emitter ->
|
return Observable.create<Long> { emitter ->
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
emitter.onNext(SignalDatabase.messages.unreadStoryThreadRecipientIds.map { Recipient.resolved(it) }.filterNot { it.shouldHideStory() }.size.toLong())
|
emitter.onNext(SignalDatabase.messages.getUnreadStoryThreadRecipientIds().map { Recipient.resolved(it) }.filterNot { it.shouldHideStory() }.size.toLong())
|
||||||
}
|
}
|
||||||
|
|
||||||
val listener = DatabaseObserver.Observer {
|
val listener = DatabaseObserver.Observer {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ open class StoryViewerRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getStories(hiddenStories: Boolean, isOutgoingOnly: Boolean): Single<List<RecipientId>> {
|
fun getStories(hiddenStories: Boolean, isOutgoingOnly: Boolean): Single<List<RecipientId>> {
|
||||||
return Single.create<List<RecipientId>> { emitter ->
|
return Single.create { emitter ->
|
||||||
val myStoriesId = SignalDatabase.recipients.getOrInsertFromDistributionListId(DistributionListId.MY_STORY)
|
val myStoriesId = SignalDatabase.recipients.getOrInsertFromDistributionListId(DistributionListId.MY_STORY)
|
||||||
val myStories = Recipient.resolved(myStoriesId)
|
val myStories = Recipient.resolved(myStoriesId)
|
||||||
val releaseChannelId = SignalStore.releaseChannelValues().releaseChannelRecipientId
|
val releaseChannelId = SignalStore.releaseChannelValues().releaseChannelRecipientId
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class StoryGroupReplyDataSource(private val parentStoryId: Long) : PagedDataSour
|
|||||||
cursor.moveToPosition(start - 1)
|
cursor.moveToPosition(start - 1)
|
||||||
val mmsReader = MessageTable.MmsReader(cursor)
|
val mmsReader = MessageTable.MmsReader(cursor)
|
||||||
while (cursor.moveToNext() && cursor.position < start + length) {
|
while (cursor.moveToNext() && cursor.position < start + length) {
|
||||||
results.add(readRowFromRecord(mmsReader.current as MmsMessageRecord))
|
results.add(readRowFromRecord(mmsReader.getCurrent() as MmsMessageRecord))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.testing
|
|||||||
|
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
|
import androidx.sqlite.db.SupportSQLiteQuery
|
||||||
|
import org.signal.core.util.toAndroidQuery
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import android.database.sqlite.SQLiteDatabase as AndroidSQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase as AndroidSQLiteDatabase
|
||||||
import android.database.sqlite.SQLiteTransactionListener as AndroidSQLiteTransactionListener
|
import android.database.sqlite.SQLiteTransactionListener as AndroidSQLiteTransactionListener
|
||||||
@@ -49,6 +51,11 @@ class ProxySignalSQLiteDatabase(private val database: AndroidSQLiteDatabase) : S
|
|||||||
return database.queryWithFactory(null, distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit)
|
return database.queryWithFactory(null, distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun query(query: SupportSQLiteQuery): Cursor? {
|
||||||
|
val converted = query.toAndroidQuery()
|
||||||
|
return database.rawQuery(converted.where, converted.whereArgs)
|
||||||
|
}
|
||||||
|
|
||||||
override fun query(table: String?, columns: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, groupBy: String?, having: String?, orderBy: String?): Cursor {
|
override fun query(table: String?, columns: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, groupBy: String?, having: String?, orderBy: String?): Cursor {
|
||||||
return database.query(table, columns, selection, selectionArgs, groupBy, having, orderBy)
|
return database.query(table, columns, selection, selectionArgs, groupBy, having, orderBy)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,4 +162,12 @@ inline fun <T> Cursor.firstOrNull(predicate: (T) -> Boolean = { true }, mapper:
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun Cursor.forEach(operation: (Cursor) -> Unit) {
|
||||||
|
use {
|
||||||
|
while (moveToNext()) {
|
||||||
|
operation(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Boolean.toInt(): Int = if (this) 1 else 0
|
fun Boolean.toInt(): Int = if (this) 1 else 0
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ fun SupportSQLiteDatabase.delete(tableName: String): DeleteBuilderPart1 {
|
|||||||
return DeleteBuilderPart1(this, tableName)
|
return DeleteBuilderPart1(this, tableName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun SupportSQLiteDatabase.insertInto(tableName: String): InsertBuilderPart1 {
|
||||||
|
return InsertBuilderPart1(this, tableName)
|
||||||
|
}
|
||||||
|
|
||||||
class SelectBuilderPart1(
|
class SelectBuilderPart1(
|
||||||
private val db: SupportSQLiteDatabase,
|
private val db: SupportSQLiteDatabase,
|
||||||
private val columns: Array<String>
|
private val columns: Array<String>
|
||||||
@@ -117,6 +121,10 @@ class SelectBuilderPart3(
|
|||||||
return SelectBuilderPart4b(db, columns, tableName, where, whereArgs, limit.toString())
|
return SelectBuilderPart4b(db, columns, tableName, where, whereArgs, limit.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun limit(limit: String): SelectBuilderPart4b {
|
||||||
|
return SelectBuilderPart4b(db, columns, tableName, where, whereArgs, limit)
|
||||||
|
}
|
||||||
|
|
||||||
fun run(): Cursor {
|
fun run(): Cursor {
|
||||||
return db.query(
|
return db.query(
|
||||||
SupportSQLiteQueryBuilder
|
SupportSQLiteQueryBuilder
|
||||||
@@ -140,6 +148,10 @@ class SelectBuilderPart4a(
|
|||||||
return SelectBuilderPart5(db, columns, tableName, where, whereArgs, orderBy, limit.toString())
|
return SelectBuilderPart5(db, columns, tableName, where, whereArgs, orderBy, limit.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun limit(limit: String): SelectBuilderPart5 {
|
||||||
|
return SelectBuilderPart5(db, columns, tableName, where, whereArgs, orderBy, limit)
|
||||||
|
}
|
||||||
|
|
||||||
fun run(): Cursor {
|
fun run(): Cursor {
|
||||||
return db.query(
|
return db.query(
|
||||||
SupportSQLiteQueryBuilder
|
SupportSQLiteQueryBuilder
|
||||||
@@ -220,6 +232,10 @@ class UpdateBuilderPart2(
|
|||||||
return UpdateBuilderPart3(db, tableName, values, where, SqlUtil.buildArgs(*whereArgs))
|
return UpdateBuilderPart3(db, tableName, values, where, SqlUtil.buildArgs(*whereArgs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun where(@Language("sql") where: String, whereArgs: Array<String>): UpdateBuilderPart3 {
|
||||||
|
return UpdateBuilderPart3(db, tableName, values, where, whereArgs)
|
||||||
|
}
|
||||||
|
|
||||||
fun run(conflictStrategy: Int = SQLiteDatabase.CONFLICT_NONE): Int {
|
fun run(conflictStrategy: Int = SQLiteDatabase.CONFLICT_NONE): Int {
|
||||||
return db.update(tableName, conflictStrategy, values, null, null)
|
return db.update(tableName, conflictStrategy, values, null, null)
|
||||||
}
|
}
|
||||||
@@ -246,6 +262,10 @@ class DeleteBuilderPart1(
|
|||||||
return DeleteBuilderPart2(db, tableName, where, SqlUtil.buildArgs(*whereArgs))
|
return DeleteBuilderPart2(db, tableName, where, SqlUtil.buildArgs(*whereArgs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun where(@Language("sql") where: String, whereArgs: Array<String>): DeleteBuilderPart2 {
|
||||||
|
return DeleteBuilderPart2(db, tableName, where, whereArgs)
|
||||||
|
}
|
||||||
|
|
||||||
fun run(): Int {
|
fun run(): Int {
|
||||||
return db.delete(tableName, null, null)
|
return db.delete(tableName, null, null)
|
||||||
}
|
}
|
||||||
@@ -271,6 +291,10 @@ class ExistsBuilderPart1(
|
|||||||
return ExistsBuilderPart2(db, tableName, where, SqlUtil.buildArgs(*whereArgs))
|
return ExistsBuilderPart2(db, tableName, where, SqlUtil.buildArgs(*whereArgs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun where(@Language("sql") where: String, whereArgs: Array<String>): ExistsBuilderPart2 {
|
||||||
|
return ExistsBuilderPart2(db, tableName, where, whereArgs)
|
||||||
|
}
|
||||||
|
|
||||||
fun run(): Boolean {
|
fun run(): Boolean {
|
||||||
return db.query("SELECT EXISTS(SELECT 1 FROM $tableName)", null).use { cursor ->
|
return db.query("SELECT EXISTS(SELECT 1 FROM $tableName)", null).use { cursor ->
|
||||||
cursor.moveToFirst() && cursor.getInt(0) == 1
|
cursor.moveToFirst() && cursor.getInt(0) == 1
|
||||||
@@ -290,3 +314,26 @@ class ExistsBuilderPart2(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InsertBuilderPart1(
|
||||||
|
private val db: SupportSQLiteDatabase,
|
||||||
|
private val tableName: String
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun values(values: ContentValues): InsertBuilderPart2 {
|
||||||
|
return InsertBuilderPart2(db, tableName, values)
|
||||||
|
}
|
||||||
|
fun values(vararg values: Pair<String, Any?>): InsertBuilderPart2 {
|
||||||
|
return InsertBuilderPart2(db, tableName, contentValuesOf(*values))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InsertBuilderPart2(
|
||||||
|
private val db: SupportSQLiteDatabase,
|
||||||
|
private val tableName: String,
|
||||||
|
private val values: ContentValues
|
||||||
|
) {
|
||||||
|
fun run(conflictStrategy: Int = SQLiteDatabase.CONFLICT_NONE): Long {
|
||||||
|
return db.insert(tableName, conflictStrategy, values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -244,12 +244,14 @@ object SqlUtil {
|
|||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun buildCollectionQuery(column: String, values: Collection<Any?>, prefix: String = "", maxSize: Int = MAX_QUERY_ARGS): List<Query> {
|
fun buildCollectionQuery(column: String, values: Collection<Any?>, prefix: String = "", maxSize: Int = MAX_QUERY_ARGS): List<Query> {
|
||||||
require(!values.isEmpty()) { "Must have values!" }
|
return if (values.isEmpty()) {
|
||||||
|
emptyList()
|
||||||
return values
|
} else {
|
||||||
|
values
|
||||||
.chunked(maxSize)
|
.chunked(maxSize)
|
||||||
.map { batch -> buildSingleCollectionQuery(column, batch, prefix) }
|
.map { batch -> buildSingleCollectionQuery(column, batch, prefix) }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenient way of making queries in the form: WHERE [column] IN (?, ?, ..., ?)
|
* A convenient way of making queries in the form: WHERE [column] IN (?, ?, ..., ?)
|
||||||
|
|||||||
@@ -38,3 +38,7 @@ fun String.asListContains(item: String): Boolean {
|
|||||||
fun String.toSingleLine(): String {
|
fun String.toSingleLine(): String {
|
||||||
return this.trimIndent().split("\n").joinToString(separator = " ")
|
return this.trimIndent().split("\n").joinToString(separator = " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String?.emptyIfNull(): String {
|
||||||
|
return this ?: ""
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package org.signal.core.util
|
||||||
|
|
||||||
|
import androidx.sqlite.db.SupportSQLiteProgram
|
||||||
|
import androidx.sqlite.db.SupportSQLiteQuery
|
||||||
|
|
||||||
|
fun SupportSQLiteQuery.toAndroidQuery(): SqlUtil.Query {
|
||||||
|
val program = CapturingSqliteProgram(this.argCount)
|
||||||
|
this.bindTo(program)
|
||||||
|
return SqlUtil.Query(this.sql, program.args())
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CapturingSqliteProgram(count: Int) : SupportSQLiteProgram {
|
||||||
|
private val args: Array<String?> = arrayOfNulls(count)
|
||||||
|
|
||||||
|
fun args(): Array<String> {
|
||||||
|
return args.filterNotNull().toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bindNull(index: Int) {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bindLong(index: Int, value: Long) {
|
||||||
|
args[index - 1] = value.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bindDouble(index: Int, value: Double) {
|
||||||
|
args[index - 1] = value.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bindString(index: Int, value: String?) {
|
||||||
|
args[index - 1] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bindBlob(index: Int, value: ByteArray?) {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearBindings() {
|
||||||
|
for (i in args.indices) {
|
||||||
|
args[i] = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@Config(manifest = Config.NONE, application = Application.class)
|
@Config(manifest = Config.NONE, application = Application.class)
|
||||||
@@ -164,9 +165,9 @@ public final class SqlUtilTest {
|
|||||||
assertArrayEquals(new String[] { "1", "2", "3" }, updateQuery.get(0).getWhereArgs());
|
assertArrayEquals(new String[] { "1", "2", "3" }, updateQuery.get(0).getWhereArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
|
||||||
public void buildCollectionQuery_none() {
|
public void buildCollectionQuery_none() {
|
||||||
SqlUtil.buildCollectionQuery("a", Collections.emptyList());
|
List<SqlUtil.Query> results = SqlUtil.buildCollectionQuery("a", Collections.emptyList());
|
||||||
|
assertTrue(results.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user