Started working on Cache Database
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'io.realm.kotlin'
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -46,6 +47,9 @@ dependencies {
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||
implementation 'com.google.code.gson:gson:2.9.0'
|
||||
|
||||
// Realm
|
||||
implementation 'io.realm.kotlin:library-base:1.10.0'
|
||||
|
||||
// https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core
|
||||
implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.7.3', ext: 'pom'
|
||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package net.buzzert.kordophone.backend.db
|
||||
|
||||
import io.realm.kotlin.Realm
|
||||
import io.realm.kotlin.RealmConfiguration
|
||||
import net.buzzert.kordophone.backend.db.model.Conversation
|
||||
import net.buzzert.kordophone.backend.db.model.toDatabaseConversation
|
||||
import net.buzzert.kordophone.backend.model.Conversation as ModelConversation
|
||||
|
||||
internal class CachedChatDatabase (private val realmConfig: RealmConfiguration) {
|
||||
companion object {
|
||||
private val schema = setOf(Conversation::class)
|
||||
|
||||
fun liveDatabase(): CachedChatDatabase {
|
||||
return CachedChatDatabase(
|
||||
RealmConfiguration.Builder(schema = schema)
|
||||
.name("chat-cache")
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
fun testDatabase(): CachedChatDatabase {
|
||||
return CachedChatDatabase(
|
||||
RealmConfiguration.Builder(schema = schema)
|
||||
.name("chat-cache-test")
|
||||
.inMemory()
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val realm = Realm.open(realmConfig)
|
||||
|
||||
fun writeConversations(conversations: List<ModelConversation>) {
|
||||
val dbConversations = conversations.map { it.toDatabaseConversation() }
|
||||
realm.writeBlocking {
|
||||
dbConversations.forEach {
|
||||
copyToRealm(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchConversations(): List<ModelConversation> {
|
||||
val items = realm.query(Conversation::class).find()
|
||||
return items.map { it.toConversation() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package net.buzzert.kordophone.backend.db.model
|
||||
|
||||
import io.realm.kotlin.Realm
|
||||
import io.realm.kotlin.ext.realmListOf
|
||||
import io.realm.kotlin.ext.toRealmList
|
||||
import io.realm.kotlin.types.RealmInstant
|
||||
import io.realm.kotlin.types.RealmList
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
import net.buzzert.kordophone.backend.model.GUID
|
||||
import org.mongodb.kbson.ObjectId
|
||||
import java.time.Instant
|
||||
import net.buzzert.kordophone.backend.model.Conversation as ModelConversation
|
||||
import java.util.Date
|
||||
|
||||
open class Conversation(
|
||||
@PrimaryKey
|
||||
var _id: String,
|
||||
|
||||
var displayName: String?,
|
||||
var participants: RealmList<String>,
|
||||
var date: RealmInstant,
|
||||
var unreadCount: Int,
|
||||
var lastMessagePreview: String,
|
||||
var guid: GUID,
|
||||
|
||||
// TODO: Not sure how to do this yet...
|
||||
// var messages: RealmList<Message>,
|
||||
): RealmObject
|
||||
{
|
||||
constructor(): this(
|
||||
_id = ObjectId().toString(),
|
||||
displayName = null,
|
||||
participants = realmListOf(),
|
||||
date = RealmInstant.now(),
|
||||
unreadCount = 0,
|
||||
lastMessagePreview = "",
|
||||
guid = "",
|
||||
)
|
||||
|
||||
fun toConversation(): ModelConversation {
|
||||
return ModelConversation(
|
||||
displayName = displayName,
|
||||
participants = participants!!.toList(),
|
||||
date = Date.from(date.toInstant()),
|
||||
unreadCount = unreadCount,
|
||||
guid = guid,
|
||||
lastMessagePreview = lastMessagePreview
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun ModelConversation.toDatabaseConversation(): Conversation {
|
||||
val from = this
|
||||
return Conversation().apply {
|
||||
displayName = from.displayName
|
||||
participants = from.participants.toRealmList()
|
||||
date = from.date.toInstant().toRealmInstant()
|
||||
unreadCount = from.unreadCount
|
||||
lastMessagePreview = from.lastMessagePreview
|
||||
guid = from.guid
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package net.buzzert.kordophone.backend.db.model
|
||||
|
||||
import io.realm.kotlin.types.RealmInstant
|
||||
import java.time.Instant
|
||||
|
||||
// Copied from Realm's documentation
|
||||
// https://www.mongodb.com/docs/realm/sdk/kotlin/realm-database/schemas/supported-types/
|
||||
|
||||
fun RealmInstant.toInstant(): Instant {
|
||||
val sec: Long = this.epochSeconds
|
||||
// The value always lies in the range `-999_999_999..999_999_999`.
|
||||
// minus for timestamps before epoch, positive for after
|
||||
val nano: Int = this.nanosecondsOfSecond
|
||||
return if (sec >= 0) { // For positive timestamps, conversion can happen directly
|
||||
Instant.ofEpochSecond(sec, nano.toLong())
|
||||
} else {
|
||||
// For negative timestamps, RealmInstant starts from the higher value with negative
|
||||
// nanoseconds, while Instant starts from the lower value with positive nanoseconds
|
||||
// TODO This probably breaks at edge cases like MIN/MAX
|
||||
Instant.ofEpochSecond(sec - 1, 1_000_000 + nano.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
fun Instant.toRealmInstant(): RealmInstant {
|
||||
val sec: Long = this.epochSecond
|
||||
// The value is always positive and lies in the range `0..999_999_999`.
|
||||
val nano: Int = this.nano
|
||||
|
||||
return if (sec >= 0) { // For positive timestamps, conversion can happen directly
|
||||
RealmInstant.from(sec, nano)
|
||||
} else {
|
||||
// For negative timestamps, RealmInstant starts from the higher value with negative
|
||||
// nanoseconds, while Instant starts from the lower value with positive nanoseconds
|
||||
// TODO This probably breaks at edge cases like MIN/MAX
|
||||
RealmInstant.from(sec + 1, -1_000_000 + nano)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.buzzert.kordophone.backend.db.model
|
||||
|
||||
import android.view.Display.Mode
|
||||
import io.realm.kotlin.Realm
|
||||
import io.realm.kotlin.types.RealmInstant
|
||||
import io.realm.kotlin.types.RealmObject
|
||||
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||
import net.buzzert.kordophone.backend.model.GUID
|
||||
import org.mongodb.kbson.ObjectId
|
||||
import net.buzzert.kordophone.backend.model.Message as ModelMessage
|
||||
import java.util.Date
|
||||
|
||||
open class Message (
|
||||
@PrimaryKey
|
||||
var _id: String,
|
||||
|
||||
var text: String,
|
||||
var guid: GUID,
|
||||
var sender: String?,
|
||||
var date: RealmInstant,
|
||||
): RealmObject
|
||||
{
|
||||
constructor(): this(
|
||||
_id = ObjectId().toString(),
|
||||
text = "",
|
||||
guid = "",
|
||||
sender = null,
|
||||
date = RealmInstant.now(),
|
||||
)
|
||||
|
||||
fun toMessage(): ModelMessage {
|
||||
return ModelMessage(
|
||||
text = text,
|
||||
guid = guid,
|
||||
sender = sender,
|
||||
date = Date.from(date.toInstant()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun ModelMessage.toDatabaseMessage(): Message {
|
||||
val from = this
|
||||
return Message().apply {
|
||||
text = from.text
|
||||
guid = from.guid
|
||||
sender = from.sender
|
||||
date = from.date.toInstant().toRealmInstant()
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ data class Conversation(
|
||||
val date: Date,
|
||||
|
||||
@SerializedName("participantDisplayNames")
|
||||
val participants: List<String>?,
|
||||
val participants: List<String>,
|
||||
|
||||
@SerializedName("displayName")
|
||||
val displayName: String?,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package net.buzzert.kordophone.backend
|
||||
|
||||
import net.buzzert.kordophone.backend.db.CachedChatDatabase
|
||||
import net.buzzert.kordophone.backend.model.Conversation
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import java.util.Date
|
||||
|
||||
class DatabaseTests {
|
||||
@Test
|
||||
fun testCreateRetrieve() {
|
||||
val db = CachedChatDatabase.testDatabase()
|
||||
|
||||
val conversation = Conversation(
|
||||
date = Date(),
|
||||
participants = listOf("james@magahern.com"),
|
||||
displayName = "Test",
|
||||
unreadCount = 1,
|
||||
lastMessagePreview = "Hello!",
|
||||
guid = "1234",
|
||||
)
|
||||
|
||||
db.writeConversations(listOf(conversation))
|
||||
|
||||
val readBackConversations = db.fetchConversations()
|
||||
assertEquals(readBackConversations.count(), 1)
|
||||
|
||||
val readConversation = readBackConversations[0]
|
||||
assertEquals(readConversation, conversation)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user