Create UnreadCounterDao.kt

Created Dao with UnreadCounterDatabaseModel.kt for persist Unread Counters for Conversations

MAILAND-2250
This commit is contained in:
Davide Farella 2021-08-09 18:08:10 +02:00
parent 74f7ce0177
commit 8c61febcf3
7 changed files with 312 additions and 9 deletions

View File

@ -0,0 +1,191 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonMail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.mailbox.data.local
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import ch.protonmail.android.data.local.MessageDatabase
import ch.protonmail.android.mailbox.data.local.model.UnreadCounterDatabaseModel
import kotlinx.coroutines.flow.first
import me.proton.core.domain.entity.UserId
import me.proton.core.test.android.runBlockingWithTimeout
import org.junit.runner.RunWith
import kotlin.random.Random
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
/**
* Test suite for [UnreadCounterDao]
*/
@RunWith(AndroidJUnit4::class)
class UnreadCounterDaoTest {
// region Test data
private val oneUserId = UserId("one")
private val twoUserId = UserId("two")
private val inboxLabelId = "inbox"
private val sentLabelId = "sent"
private val oneMessagesInboxCounter = UnreadCounterDatabaseModel(
userId = oneUserId,
type = UnreadCounterDatabaseModel.Type.MESSAGES,
labelId = inboxLabelId,
unreadCount = Random.nextInt()
)
private val oneMessagesSendCounter = UnreadCounterDatabaseModel(
userId = oneUserId,
type = UnreadCounterDatabaseModel.Type.MESSAGES,
labelId = sentLabelId,
unreadCount = Random.nextInt()
)
private val oneConversationsInboxCounter = UnreadCounterDatabaseModel(
userId = oneUserId,
type = UnreadCounterDatabaseModel.Type.CONVERSATIONS,
labelId = inboxLabelId,
unreadCount = Random.nextInt()
)
private val twoMessagesInboxCounter = UnreadCounterDatabaseModel(
userId = twoUserId,
type = UnreadCounterDatabaseModel.Type.MESSAGES,
labelId = inboxLabelId,
unreadCount = Random.nextInt()
)
// endregion
private lateinit var database: MessageDatabase
private lateinit var dao: UnreadCounterDao
@BeforeTest
fun setup() {
database = MessageDatabase.buildInMemoryDatabase(ApplicationProvider.getApplicationContext())
dao = database.getUnreadCounterDao()
}
@AfterTest
fun tearDown() {
database.close()
}
@Test
fun canInsertAndRetrieveMessagesCounter() = runBlockingWithTimeout {
// given
val input = oneMessagesInboxCounter
// when
dao.insertOrUpdate(input)
val result = dao.observeMessagesUnreadCounters(input.userId)
.first()
.first()
// then
assertEquals(input, result)
}
@Test
fun canInsertAndRetrieveConversationsCounter() = runBlockingWithTimeout {
// given
val input = oneConversationsInboxCounter
// when
dao.insertOrUpdate(input)
val result = dao.observeConversationsUnreadCounters(input.userId)
.first()
.first()
// then
assertEquals(input, result)
}
@Test
fun insertIfDifferentUserId() = runBlockingWithTimeout {
// given
val first = oneMessagesInboxCounter
val second = twoMessagesInboxCounter
// when
dao.insertOrUpdate(first, second)
val firstResult = dao.observeUnreadCounters(first.userId, first.type)
.first()
.first()
val secondResult = dao.observeUnreadCounters(second.userId, second.type)
.first()
.first()
// then
assertEquals(first, firstResult)
assertEquals(second, secondResult)
}
@Test
fun insertIfDifferentType() = runBlockingWithTimeout {
// given
val first = oneMessagesInboxCounter
val second = oneConversationsInboxCounter
// when
dao.insertOrUpdate(first, second)
val firstResult = dao.observeUnreadCounters(first.userId, first.type)
.first()
.first()
val secondResult = dao.observeUnreadCounters(second.userId, second.type)
.first()
.first()
// then
assertEquals(first, firstResult)
assertEquals(second, secondResult)
}
@Test
fun insertIfDifferentLabelId() = runBlockingWithTimeout {
// given
val first = oneMessagesInboxCounter
val second = oneMessagesSendCounter
// when
dao.insertOrUpdate(first, second)
val result = dao.observeUnreadCounters(first.userId, first.type)
.first()
// then
assertEquals(2, result.size)
assert(first in result)
assert(second in result)
}
@Test
fun updateIfSameUserIdTypeAndLabelId() = runBlockingWithTimeout {
// given
val first = oneMessagesInboxCounter
val second = first.copy(unreadCount = 15)
// when
dao.insertOrUpdate(first)
dao.insertOrUpdate(second)
val result = dao.observeUnreadCounters(first.userId, first.type)
.first()
.first()
// then
assertEquals(second, result)
}
}

View File

@ -28,7 +28,7 @@ import kotlinx.coroutines.flow.Flow
import me.proton.core.domain.entity.UserId
import javax.inject.Inject
class RoomLabelRepository @Inject constructor(
internal class RoomLabelRepository @Inject constructor(
private val context: Context,
private val messageDatabaseFactory: MessageDatabase.Factory,
private val messageDao: MessageDao

View File

@ -23,33 +23,44 @@ import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import ch.protonmail.android.data.local.model.Attachment
import ch.protonmail.android.data.local.model.AttachmentTypesConverter
import ch.protonmail.android.data.local.model.CommonTypeConverters
import ch.protonmail.android.data.local.model.Label
import ch.protonmail.android.data.local.model.Message
import ch.protonmail.android.data.local.model.MessagesTypesConverter
import ch.protonmail.android.mailbox.data.local.ConversationDao
import ch.protonmail.android.mailbox.data.local.UnreadCounterDao
import ch.protonmail.android.mailbox.data.local.model.ConversationDatabaseModel
import ch.protonmail.android.mailbox.data.local.model.ConversationTypesConverter
import ch.protonmail.android.mailbox.data.local.model.UnreadCounterDatabaseModel
@Database(
entities = [
Attachment::class,
ConversationDatabaseModel::class,
Message::class,
Label::class,
ConversationDatabaseModel::class
UnreadCounterDatabaseModel::class
],
version = 10
)
@TypeConverters(
value = [
MessagesTypesConverter::class,
CommonTypeConverters::class,
AttachmentTypesConverter::class,
MessagesTypesConverter::class,
ConversationTypesConverter::class
]
)
abstract class MessageDatabase : RoomDatabase() {
internal abstract class MessageDatabase : RoomDatabase() {
abstract fun getDao(): MessageDao
@Deprecated("Use getMessageDao", ReplaceWith("getMessageDao()"))
fun getDao(): MessageDao =
getMessageDao()
abstract fun getMessageDao(): MessageDao
abstract fun getConversationDao(): ConversationDao
abstract fun getUnreadCounterDao(): UnreadCounterDao
companion object Factory : DatabaseFactory<MessageDatabase>(
MessageDatabase::class,

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
* This file is part of ProtonMail.
*
* ProtonMail is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonMail is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
package ch.protonmail.android.data.local.model
import androidx.room.TypeConverter
import me.proton.core.domain.entity.UserId
class CommonTypeConverters {
@TypeConverter
fun toUserId(userId: String) = UserId(userId)
@TypeConverter
fun fromUserId(userId: UserId) = userId.id
}

View File

@ -40,7 +40,7 @@ import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
internal object DatabaseModule {
@Provides
fun provideAttachmentMetadataDao(

View File

@ -19,5 +19,35 @@
package ch.protonmail.android.mailbox.data.local
class UnreadCounterDao {
import androidx.room.Dao
import androidx.room.Query
import ch.protonmail.android.mailbox.data.local.model.UnreadCounterDatabaseModel
import ch.protonmail.android.mailbox.data.local.model.UnreadCounterDatabaseModel.Companion.COLUMN_TYPE
import ch.protonmail.android.mailbox.data.local.model.UnreadCounterDatabaseModel.Companion.COLUMN_USER_ID
import ch.protonmail.android.mailbox.data.local.model.UnreadCounterDatabaseModel.Companion.TABLE_NAME
import kotlinx.coroutines.flow.Flow
import me.proton.core.data.room.db.BaseDao
import me.proton.core.domain.entity.UserId
@Dao
internal abstract class UnreadCounterDao : BaseDao<UnreadCounterDatabaseModel>() {
fun observeMessagesUnreadCounters(userId: UserId): Flow<List<UnreadCounterDatabaseModel>> =
observeUnreadCounters(userId, UnreadCounterDatabaseModel.Type.MESSAGES)
fun observeConversationsUnreadCounters(userId: UserId): Flow<List<UnreadCounterDatabaseModel>> =
observeUnreadCounters(userId, UnreadCounterDatabaseModel.Type.CONVERSATIONS)
@Query(
"""
SELECT * FROM $TABLE_NAME
WHERE
$COLUMN_USER_ID = :userId AND
$COLUMN_TYPE = :type
"""
)
abstract fun observeUnreadCounters(
userId: UserId,
type: UnreadCounterDatabaseModel.Type
): Flow<List<UnreadCounterDatabaseModel>>
}

View File

@ -19,8 +19,47 @@
package ch.protonmail.android.mailbox.data.local.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import ch.protonmail.android.mailbox.data.local.model.UnreadCounterDatabaseModel.Companion.COLUMN_LABEL_ID
import ch.protonmail.android.mailbox.data.local.model.UnreadCounterDatabaseModel.Companion.COLUMN_TYPE
import ch.protonmail.android.mailbox.data.local.model.UnreadCounterDatabaseModel.Companion.COLUMN_USER_ID
import ch.protonmail.android.mailbox.domain.model.UnreadCounter
import me.proton.core.domain.entity.UserId
@Entity
class UnreadCounterDatabaseModel {
/**
* Database model for [UnreadCounter]
*/
@Entity(
tableName = UnreadCounterDatabaseModel.TABLE_NAME,
primaryKeys = [COLUMN_USER_ID, COLUMN_LABEL_ID, COLUMN_TYPE]
)
internal data class UnreadCounterDatabaseModel(
@ColumnInfo(name = COLUMN_USER_ID)
val userId: UserId,
@ColumnInfo(name = COLUMN_TYPE)
val type: Type,
@ColumnInfo(name = COLUMN_LABEL_ID)
val labelId: String,
@ColumnInfo(name = COLUMN_UNREAD_COUNT)
val unreadCount: Int
) {
enum class Type {
MESSAGES,
CONVERSATIONS
}
companion object {
const val TABLE_NAME = "UnreadCounter"
const val COLUMN_USER_ID = "user_id"
const val COLUMN_TYPE = "type"
const val COLUMN_LABEL_ID = "label_id"
const val COLUMN_UNREAD_COUNT = "unread_count"
}
}