Create UnreadCounterDao.kt
Created Dao with UnreadCounterDatabaseModel.kt for persist Unread Counters for Conversations MAILAND-2250
This commit is contained in:
parent
74f7ce0177
commit
8c61febcf3
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -40,7 +40,7 @@ import dagger.hilt.components.SingletonComponent
|
|||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object DatabaseModule {
|
||||
internal object DatabaseModule {
|
||||
|
||||
@Provides
|
||||
fun provideAttachmentMetadataDao(
|
||||
|
|
|
@ -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>>
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue