Move CursorExtensions to :core:android:common
module
This commit is contained in:
parent
3974688b63
commit
3ed19f0011
18 changed files with 201 additions and 85 deletions
|
@ -1,41 +0,0 @@
|
|||
package com.fsck.k9.helper
|
||||
|
||||
import android.database.Cursor
|
||||
|
||||
fun <T> Cursor.map(block: (Cursor) -> T): List<T> {
|
||||
return List(count) { index ->
|
||||
moveToPosition(index)
|
||||
block(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun Cursor.getStringOrNull(columnName: String): String? {
|
||||
val columnIndex = getColumnIndex(columnName)
|
||||
return if (isNull(columnIndex)) null else getString(columnIndex)
|
||||
}
|
||||
|
||||
fun Cursor.getIntOrNull(columnName: String): Int? {
|
||||
val columnIndex = getColumnIndex(columnName)
|
||||
return if (isNull(columnIndex)) null else getInt(columnIndex)
|
||||
}
|
||||
|
||||
fun Cursor.getLongOrNull(columnName: String): Long? {
|
||||
val columnIndex = getColumnIndex(columnName)
|
||||
return if (isNull(columnIndex)) null else getLong(columnIndex)
|
||||
}
|
||||
|
||||
fun Cursor.getStringOrThrow(columnName: String): String {
|
||||
return getStringOrNull(columnName) ?: error("Column $columnName must not be null")
|
||||
}
|
||||
|
||||
fun Cursor.getIntOrThrow(columnName: String): Int {
|
||||
return getIntOrNull(columnName) ?: error("Column $columnName must not be null")
|
||||
}
|
||||
|
||||
fun Cursor.getLongOrThrow(columnName: String): Long {
|
||||
return getLongOrNull(columnName) ?: error("Column $columnName must not be null")
|
||||
}
|
||||
|
||||
fun Cursor.getBoolean(columnIndex: Int): Boolean {
|
||||
return getString(columnIndex).toBoolean()
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package com.fsck.k9.mailstore
|
||||
|
||||
import android.content.ContentValues
|
||||
import com.fsck.k9.helper.getIntOrThrow
|
||||
import com.fsck.k9.helper.getLongOrThrow
|
||||
import com.fsck.k9.helper.getStringOrNull
|
||||
import com.fsck.k9.helper.getStringOrThrow
|
||||
import app.k9mail.core.android.common.database.getIntOrThrow
|
||||
import app.k9mail.core.android.common.database.getLongOrThrow
|
||||
import app.k9mail.core.android.common.database.getStringOrNull
|
||||
import app.k9mail.core.android.common.database.getStringOrThrow
|
||||
import kotlinx.datetime.Clock
|
||||
|
||||
class OutboxStateRepository(
|
||||
|
|
|
@ -2,10 +2,10 @@ package com.fsck.k9.storage.messages
|
|||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import app.k9mail.core.android.common.database.getIntOrNull
|
||||
import app.k9mail.core.android.common.database.getLongOrNull
|
||||
import app.k9mail.core.android.common.database.getStringOrNull
|
||||
import com.fsck.k9.K9
|
||||
import com.fsck.k9.helper.getIntOrNull
|
||||
import com.fsck.k9.helper.getLongOrNull
|
||||
import com.fsck.k9.helper.getStringOrNull
|
||||
import com.fsck.k9.mailstore.LockableDatabase
|
||||
import java.util.UUID
|
||||
import timber.log.Timber
|
||||
|
|
|
@ -2,8 +2,8 @@ package com.fsck.k9.storage.messages
|
|||
|
||||
import android.database.Cursor
|
||||
import androidx.core.database.getLongOrNull
|
||||
import app.k9mail.core.android.common.database.map
|
||||
import com.fsck.k9.Account.FolderMode
|
||||
import com.fsck.k9.helper.map
|
||||
import com.fsck.k9.mail.FolderClass
|
||||
import com.fsck.k9.mail.FolderType
|
||||
import com.fsck.k9.mailstore.FolderDetailsAccessor
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.fsck.k9.storage.migrations
|
|||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import app.k9mail.core.android.common.database.map
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingAppend
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingDelete
|
||||
|
@ -11,7 +12,6 @@ import com.fsck.k9.controller.MessagingControllerCommands.PendingMoveAndMarkAsRe
|
|||
import com.fsck.k9.controller.MessagingControllerCommands.PendingMoveOrCopy
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingSetFlag
|
||||
import com.fsck.k9.controller.PendingCommandSerializer
|
||||
import com.fsck.k9.helper.map
|
||||
import com.squareup.moshi.Moshi
|
||||
import timber.log.Timber
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ package com.fsck.k9.storage.migrations
|
|||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import app.k9mail.core.android.common.database.map
|
||||
import com.fsck.k9.Account
|
||||
import com.fsck.k9.helper.map
|
||||
import com.fsck.k9.mailstore.MigrationsHelper
|
||||
import com.fsck.k9.preferences.Protocols
|
||||
import timber.log.Timber
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.fsck.k9.storage.migrations
|
|||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import androidx.core.database.getLongOrNull
|
||||
import com.fsck.k9.helper.map
|
||||
import app.k9mail.core.android.common.database.map
|
||||
import com.fsck.k9.mailstore.MigrationsHelper
|
||||
|
||||
private const val EXTRA_HIGHEST_KNOWN_UID = "imapHighestKnownUid"
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.fsck.k9.storage.migrations
|
|||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import androidx.core.database.getStringOrNull
|
||||
import com.fsck.k9.helper.map
|
||||
import app.k9mail.core.android.common.database.map
|
||||
|
||||
/**
|
||||
* Write the address fields to use ASCII 1 instead of ASCII 0 as separator.
|
||||
|
|
|
@ -2,10 +2,10 @@ package com.fsck.k9.storage.messages
|
|||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.fsck.k9.helper.getIntOrNull
|
||||
import com.fsck.k9.helper.getLongOrNull
|
||||
import com.fsck.k9.helper.getStringOrNull
|
||||
import com.fsck.k9.helper.map
|
||||
import app.k9mail.core.android.common.database.getIntOrNull
|
||||
import app.k9mail.core.android.common.database.getLongOrNull
|
||||
import app.k9mail.core.android.common.database.getStringOrNull
|
||||
import app.k9mail.core.android.common.database.map
|
||||
|
||||
fun SQLiteDatabase.createFolder(
|
||||
name: String = "irrelevant",
|
||||
|
|
|
@ -2,9 +2,9 @@ package com.fsck.k9.storage.messages
|
|||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.fsck.k9.helper.getLongOrNull
|
||||
import com.fsck.k9.helper.getStringOrNull
|
||||
import com.fsck.k9.helper.map
|
||||
import app.k9mail.core.android.common.database.getLongOrNull
|
||||
import app.k9mail.core.android.common.database.getStringOrNull
|
||||
import app.k9mail.core.android.common.database.map
|
||||
|
||||
fun SQLiteDatabase.createExtraValue(
|
||||
name: String = "irrelevant",
|
||||
|
|
|
@ -2,10 +2,10 @@ package com.fsck.k9.storage.messages
|
|||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.fsck.k9.helper.getIntOrNull
|
||||
import com.fsck.k9.helper.getLongOrNull
|
||||
import com.fsck.k9.helper.getStringOrNull
|
||||
import com.fsck.k9.helper.map
|
||||
import app.k9mail.core.android.common.database.getIntOrNull
|
||||
import app.k9mail.core.android.common.database.getLongOrNull
|
||||
import app.k9mail.core.android.common.database.getStringOrNull
|
||||
import app.k9mail.core.android.common.database.map
|
||||
import com.fsck.k9.mailstore.DatabasePreviewType
|
||||
import com.fsck.k9.mailstore.LockableDatabase
|
||||
import com.fsck.k9.mailstore.MigrationsHelper
|
||||
|
|
|
@ -3,10 +3,10 @@ package com.fsck.k9.storage.messages
|
|||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.fsck.k9.helper.getIntOrNull
|
||||
import com.fsck.k9.helper.getLongOrNull
|
||||
import com.fsck.k9.helper.getStringOrNull
|
||||
import com.fsck.k9.helper.map
|
||||
import app.k9mail.core.android.common.database.getIntOrNull
|
||||
import app.k9mail.core.android.common.database.getLongOrNull
|
||||
import app.k9mail.core.android.common.database.getStringOrNull
|
||||
import app.k9mail.core.android.common.database.map
|
||||
|
||||
fun SQLiteDatabase.createMessagePart(
|
||||
type: Int = MessagePartType.UNKNOWN,
|
||||
|
|
|
@ -2,8 +2,8 @@ package com.fsck.k9.storage.messages
|
|||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.fsck.k9.helper.getLongOrNull
|
||||
import com.fsck.k9.helper.map
|
||||
import app.k9mail.core.android.common.database.getLongOrNull
|
||||
import app.k9mail.core.android.common.database.map
|
||||
|
||||
fun SQLiteDatabase.createThread(
|
||||
messageId: Long,
|
||||
|
|
|
@ -2,9 +2,9 @@ package com.fsck.k9.storage.notifications
|
|||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import com.fsck.k9.helper.getIntOrNull
|
||||
import com.fsck.k9.helper.getLongOrNull
|
||||
import com.fsck.k9.helper.map
|
||||
import app.k9mail.core.android.common.database.getIntOrNull
|
||||
import app.k9mail.core.android.common.database.getLongOrNull
|
||||
import app.k9mail.core.android.common.database.map
|
||||
|
||||
fun SQLiteDatabase.createNotification(
|
||||
messageId: Long,
|
||||
|
|
|
@ -9,8 +9,8 @@ import android.net.Uri
|
|||
import android.provider.ContactsContract
|
||||
import androidx.core.content.ContextCompat
|
||||
import app.k9mail.core.android.common.database.EmptyCursor
|
||||
import app.k9mail.core.android.common.database.getLongValue
|
||||
import app.k9mail.core.android.common.database.getStringValue
|
||||
import app.k9mail.core.android.common.database.getLongOrThrow
|
||||
import app.k9mail.core.android.common.database.getStringOrNull
|
||||
import app.k9mail.core.common.mail.EmailAddress
|
||||
|
||||
interface ContactDataSource {
|
||||
|
@ -28,13 +28,13 @@ internal class ContentResolverContactDataSource(
|
|||
override fun getContactFor(emailAddress: EmailAddress): Contact? {
|
||||
getCursorFor(emailAddress).use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
val contactId = cursor.getLongValue(ContactsContract.CommonDataKinds.Email._ID)
|
||||
val lookupKey = cursor.getStringValue(ContactsContract.Contacts.LOOKUP_KEY)
|
||||
val contactId = cursor.getLongOrThrow(ContactsContract.CommonDataKinds.Email._ID)
|
||||
val lookupKey = cursor.getStringOrNull(ContactsContract.Contacts.LOOKUP_KEY)
|
||||
val uri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey)
|
||||
|
||||
val name = cursor.getStringValue(ContactsContract.CommonDataKinds.Identity.DISPLAY_NAME)
|
||||
val name = cursor.getStringOrNull(ContactsContract.CommonDataKinds.Identity.DISPLAY_NAME)
|
||||
|
||||
val photoUri = cursor.getStringValue(ContactsContract.CommonDataKinds.Photo.PHOTO_URI)
|
||||
val photoUri = cursor.getStringOrNull(ContactsContract.CommonDataKinds.Photo.PHOTO_URI)
|
||||
?.let { photoUriString -> Uri.parse(photoUriString) }
|
||||
|
||||
return Contact(
|
||||
|
|
|
@ -2,12 +2,36 @@ package app.k9mail.core.android.common.database
|
|||
|
||||
import android.database.Cursor
|
||||
|
||||
fun Cursor.getStringValue(key: String): String? {
|
||||
val columnIndex = getColumnIndex(key)
|
||||
return getString(columnIndex)
|
||||
fun <T> Cursor.map(block: (Cursor) -> T): List<T> {
|
||||
return List(count) { index ->
|
||||
moveToPosition(index)
|
||||
block(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun Cursor.getLongValue(key: String): Long {
|
||||
val columnIndex = getColumnIndex(key)
|
||||
return getLong(columnIndex)
|
||||
fun Cursor.getStringOrNull(columnName: String): String? {
|
||||
val columnIndex = getColumnIndex(columnName)
|
||||
return if (isNull(columnIndex)) null else getString(columnIndex)
|
||||
}
|
||||
|
||||
fun Cursor.getIntOrNull(columnName: String): Int? {
|
||||
val columnIndex = getColumnIndex(columnName)
|
||||
return if (isNull(columnIndex)) null else getInt(columnIndex)
|
||||
}
|
||||
|
||||
fun Cursor.getLongOrNull(columnName: String): Long? {
|
||||
val columnIndex = getColumnIndex(columnName)
|
||||
return if (isNull(columnIndex)) null else getLong(columnIndex)
|
||||
}
|
||||
|
||||
fun Cursor.getStringOrThrow(columnName: String): String {
|
||||
return getStringOrNull(columnName) ?: error("Column $columnName must not be null")
|
||||
}
|
||||
|
||||
fun Cursor.getIntOrThrow(columnName: String): Int {
|
||||
return getIntOrNull(columnName) ?: error("Column $columnName must not be null")
|
||||
}
|
||||
|
||||
fun Cursor.getLongOrThrow(columnName: String): Long {
|
||||
return getLongOrNull(columnName) ?: error("Column $columnName must not be null")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package app.k9mail.core.android.common.database
|
||||
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.hasMessage
|
||||
import assertk.assertions.isEqualTo
|
||||
import assertk.assertions.isFailure
|
||||
import assertk.assertions.isNull
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.ParameterizedRobolectricTestRunner
|
||||
|
||||
data class CursorExtensionsAccessTestData<T : Any>(
|
||||
val name: String,
|
||||
val value: T,
|
||||
val access: (Cursor, String) -> T?,
|
||||
val throwingAccess: (Cursor, String) -> T,
|
||||
) {
|
||||
override fun toString(): String = name
|
||||
}
|
||||
|
||||
@RunWith(ParameterizedRobolectricTestRunner::class)
|
||||
class CursorExtensionsKtAccessTest(data: CursorExtensionsAccessTestData<Any>) {
|
||||
|
||||
private val testValue = data.value
|
||||
private val testAction = data.access
|
||||
private val testThrowingAction = data.throwingAccess
|
||||
|
||||
@Test
|
||||
fun `testAction should return null if column is null`() {
|
||||
val cursor = MatrixCursor(arrayOf("column")).apply {
|
||||
addRow(arrayOf(null))
|
||||
}
|
||||
|
||||
val result = cursor.map { testAction(it, "column") }
|
||||
|
||||
assertThat(result[0]).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `testAction should return value if column is not null`() {
|
||||
val cursor = MatrixCursor(arrayOf("column")).apply {
|
||||
addRow(arrayOf(testValue))
|
||||
}
|
||||
|
||||
val result = cursor.map { testAction(it, "column") }
|
||||
|
||||
assertThat(result[0]).isEqualTo(testValue)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `testThrowingAction should throw if column is null`() {
|
||||
val cursor = MatrixCursor(arrayOf("column")).apply {
|
||||
addRow(arrayOf(null))
|
||||
}
|
||||
|
||||
assertThat {
|
||||
cursor.map { testThrowingAction(it, "column") }
|
||||
}.isFailure().hasMessage("Column column must not be null")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `testThrowingAction should return value if column is not null`() {
|
||||
val cursor = MatrixCursor(arrayOf("column")).apply {
|
||||
addRow(arrayOf(testValue))
|
||||
}
|
||||
|
||||
val result = cursor.map { testThrowingAction(it, "column") }
|
||||
|
||||
assertThat(result[0]).isEqualTo(testValue)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@ParameterizedRobolectricTestRunner.Parameters(name = "{0}")
|
||||
fun data(): Collection<CursorExtensionsAccessTestData<Any>> {
|
||||
return listOf(
|
||||
CursorExtensionsAccessTestData(
|
||||
name = "getString",
|
||||
value = "value",
|
||||
access = { cursor, column -> cursor.getStringOrNull(column) },
|
||||
throwingAccess = { cursor, column -> cursor.getStringOrThrow(column) },
|
||||
),
|
||||
CursorExtensionsAccessTestData(
|
||||
name = "getInt",
|
||||
value = Int.MAX_VALUE,
|
||||
access = { cursor, column -> cursor.getIntOrNull(column) },
|
||||
throwingAccess = { cursor, column -> cursor.getIntOrThrow(column) },
|
||||
),
|
||||
CursorExtensionsAccessTestData(
|
||||
name = "getLong",
|
||||
value = Long.MAX_VALUE,
|
||||
access = { cursor, column -> cursor.getLongOrNull(column) },
|
||||
throwingAccess = { cursor, column -> cursor.getLongOrThrow(column) },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package app.k9mail.core.android.common.database
|
||||
|
||||
import android.database.MatrixCursor
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class CursorExtensionsKtTest {
|
||||
|
||||
@Test
|
||||
fun `map should return an empty list if cursor is empty`() {
|
||||
val cursor = MatrixCursor(arrayOf("column"))
|
||||
|
||||
val result = cursor.map { it.getStringOrNull("column") }
|
||||
|
||||
assertThat(result).isEqualTo(emptyList<String>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `map should return a list of mapped values`() {
|
||||
val cursor = MatrixCursor(arrayOf("column")).apply {
|
||||
addRow(arrayOf("value1"))
|
||||
addRow(arrayOf("value2"))
|
||||
}
|
||||
|
||||
val result = cursor.map { it.getStringOrNull("column") }
|
||||
|
||||
assertThat(result).isEqualTo(listOf("value1", "value2"))
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue