Skip to content

Commit

Permalink
feat: db caching, store patterns (#83)
Browse files Browse the repository at this point in the history
Co-authored-by: X1nto <[email protected]>
  • Loading branch information
rushiiMachine and X1nto authored Dec 6, 2022
1 parent cfef3b6 commit 417a2ca
Show file tree
Hide file tree
Showing 65 changed files with 1,845 additions and 730 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
.idea
/build
/captures
/local.properties
/local.properties
*.log
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ dependencies {
Dependencies.AndroidxCore(this)
Dependencies.AndroidxPreferences(this)
Dependencies.AndroidxMedia3(this)
Dependencies.AndroidxRoom(this)
Dependencies.Material(this)
Dependencies.Compose(this)
Dependencies.Accompanist(this)
Expand Down
25 changes: 21 additions & 4 deletions app/src/main/java/com/xinto/opencord/OpenCord.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package com.xinto.opencord

import android.app.Application
import com.xinto.opencord.db.database.CacheDatabase
import com.xinto.opencord.di.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import org.koin.android.ext.android.get
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin

class OpenCord : Application() {
val scope = MainScope()

override fun onCreate() {
super.onCreate()
Expand All @@ -16,15 +22,26 @@ class OpenCord : Application() {
gatewayModule,
httpModule,
managerModule,
repositoryModule,
serviceModule,
simpleAstModule,
viewModelModule,
loggerModule,
providerModule,
hcaptchaModule
databaseModule,
storeModule,
hcaptchaModule,
)
}
}

}
scope.launch(Dispatchers.IO) {
val db = get<CacheDatabase>()

db.apply {
messages().clear()
embeds().clear()
attachments().clear()
users().deleteUnusedUsers()
}
}
}
}
20 changes: 20 additions & 0 deletions app/src/main/java/com/xinto/opencord/db/Converters.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.xinto.opencord.db

import androidx.room.TypeConverter
import com.xinto.opencord.rest.dto.ApiEmbedField
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

@Suppress("unused")
class Converters {
@TypeConverter
fun fromEmbedFields(fields: List<ApiEmbedField>?): String? {
return Json.encodeToString(fields ?: return null)
}

@TypeConverter
fun toEmbedFields(fields: String?): List<ApiEmbedField>? {
return Json.decodeFromString(fields ?: return null)
}
}
28 changes: 28 additions & 0 deletions app/src/main/java/com/xinto/opencord/db/dao/AttachmentsDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.xinto.opencord.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.xinto.opencord.db.entity.message.EntityAttachment

@Dao
interface AttachmentsDao {
// --------------- Inserts ---------------
@Insert(
onConflict = OnConflictStrategy.REPLACE,
entity = EntityAttachment::class
)
fun insertAttachments(attachments: List<EntityAttachment>)

// --------------- Deletes ---------------
@Query("DELETE FROM attachments WHERE message_id = :messageId")
fun deleteAttachments(messageId: Long)

@Query("DELETE FROM attachments")
fun clear()

// --------------- Queries ---------------
@Query("SELECT * FROM attachments WHERE id = :messageId")
fun getAttachments(messageId: Long): List<EntityAttachment>
}
41 changes: 41 additions & 0 deletions app/src/main/java/com/xinto/opencord/db/dao/ChannelsDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.xinto.opencord.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.xinto.opencord.db.entity.channel.EntityChannel

@Dao
interface ChannelsDao {
// --------------- Inserts ---------------
@Insert(
onConflict = OnConflictStrategy.REPLACE,
entity = EntityChannel::class,
)
fun insertChannels(channels: List<EntityChannel>)

// --------------- Inserts ---------------
@Query("UPDATE channels SET is_pins_stored = :isStored WHERE id = :channelId")
fun setChannelPinsStored(channelId: Long, isStored: Boolean = true)

// --------------- Deletes ---------------
@Query("DELETE FROM channels WHERE id = :channelId")
fun deleteChannel(channelId: Long)

@Query("DELETE FROM channels WHERE guild_id = :guildId")
fun deleteChannelsByGuild(guildId: Long)

@Query("DELETE FROM channels")
fun clear()

// --------------- Queries ---------------
@Query("SELECT * FROM channels WHERE id = :channelId LIMIT 1")
fun getChannel(channelId: Long): EntityChannel?

@Query("SELECT * FROM channels WHERE guild_id = :guildId")
fun getChannels(guildId: Long): List<EntityChannel>

@Query("SELECT is_pins_stored FROM channels WHERE id = :channelId")
fun isChannelPinsStored(channelId: Long): Boolean?
}
31 changes: 31 additions & 0 deletions app/src/main/java/com/xinto/opencord/db/dao/EmbedsDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.xinto.opencord.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.xinto.opencord.db.entity.message.EntityEmbed

@Dao
interface EmbedsDao {
// --------------- Inserts ---------------
@Insert(
onConflict = OnConflictStrategy.REPLACE,
entity = EntityEmbed::class
)
fun insertEmbeds(embeds: List<EntityEmbed>)

// --------------- Deletes ---------------
@Query("DELETE FROM embeds WHERE message_id = :messageId")
fun deleteEmbeds(messageId: Long)

@Query("DELETE FROM embeds WHERE message_id = :messageId AND embed_index >= :embedCount")
fun deleteTrailingEmbeds(messageId: Long, embedCount: Int)

@Query("DELETE FROM embeds")
fun clear()

// --------------- Queries ---------------
@Query("SELECT * FROM embeds WHERE message_id = :messageId ORDER BY embed_index ASC")
fun getEmbeds(messageId: Long): List<EntityEmbed>
}
31 changes: 31 additions & 0 deletions app/src/main/java/com/xinto/opencord/db/dao/GuildsDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.xinto.opencord.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.xinto.opencord.db.entity.guild.EntityGuild

@Dao
interface GuildsDao {
// --------------- Inserts ---------------
@Insert(
onConflict = OnConflictStrategy.REPLACE,
entity = EntityGuild::class,
)
fun insertGuilds(guilds: List<EntityGuild>)

// --------------- Deletes ---------------
@Query("DELETE FROM guilds WHERE id = :guildId")
fun deleteGuild(guildId: Long)

@Query("DELETE FROM guilds")
fun clear()

// --------------- Queries ---------------
@Query("SELECT * FROM guilds WHERE id = :guildId LIMIT 1")
fun getGuild(guildId: Long): EntityGuild?

@Query("SELECT * FROM guilds WHERE id IN(:guildIds)")
fun getGuilds(guildIds: List<Long>): List<EntityGuild>
}
46 changes: 46 additions & 0 deletions app/src/main/java/com/xinto/opencord/db/dao/MessagesDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.xinto.opencord.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.xinto.opencord.db.entity.message.EntityMessage

@Dao
interface MessagesDao {
// --------------- Inserts ---------------
@Insert(
onConflict = OnConflictStrategy.REPLACE,
entity = EntityMessage::class,
)
fun insertMessages(messages: List<EntityMessage>)

// --------------- Deletes ---------------
@Query("DELETE FROM messages WHERE id = :messageId")
fun deleteMessage(messageId: Long)

@Query("DELETE FROM messages WHERE channel_id = :channelId")
fun deleteByChannel(channelId: Long)

@Query("DELETE FROM messages")
fun clear()

// --------------- Queries ---------------
@Query("SELECT * FROM messages WHERE id = :id LIMIT 1")
fun getMessage(id: Long): EntityMessage?

@Query("SELECT * FROM messages WHERE channel_id = :channelId ORDER BY id DESC LIMIT :limit")
fun getMessagesLast(channelId: Long, limit: Int): List<EntityMessage>

@Query("SELECT * FROM messages WHERE channel_id = :channelId AND id < :beforeId ORDER BY id DESC LIMIT :limit")
fun getMessagesBefore(channelId: Long, limit: Int, beforeId: Long): List<EntityMessage>

@Query("SELECT * FROM messages WHERE channel_id = :channelId AND id > :afterId ORDER BY id ASC LIMIT :limit")
fun getMessagesAfter(channelId: Long, limit: Int, afterId: Long): List<EntityMessage>

@Query("SELECT * FROM messages WHERE channel_id = :channelId AND id >= :aroundId - ROUND(:limit / 2, 0) ORDER BY id ASC LIMIT :limit")
fun getMessagesAround(channelId: Long, limit: Int, aroundId: Long): List<EntityMessage>

@Query("SELECT * FROM messages WHERE pinned = 1 AND channel_id = :channelId")
fun getPinnedMessages(channelId: Long): List<EntityMessage>
}
25 changes: 25 additions & 0 deletions app/src/main/java/com/xinto/opencord/db/dao/UsersDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.xinto.opencord.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.xinto.opencord.db.entity.user.EntityUser

@Dao
interface UsersDao {
// --------------- Inserts ---------------
@Insert(
onConflict = OnConflictStrategy.REPLACE,
entity = EntityUser::class,
)
fun insertUsers(users: List<EntityUser>)

// --------------- Deletes ---------------
@Query("DELETE FROM USERS WHERE id NOT IN(SELECT author_id FROM MESSAGES)")
fun deleteUnusedUsers()

// --------------- Queries ---------------
@Query("SELECT * FROM users WHERE id = :userId LIMIT 1")
fun getUser(userId: Long): EntityUser?
}
37 changes: 37 additions & 0 deletions app/src/main/java/com/xinto/opencord/db/database/CacheDatabase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.xinto.opencord.db.database

import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.xinto.opencord.db.Converters
import com.xinto.opencord.db.dao.*
import com.xinto.opencord.db.entity.channel.EntityChannel
import com.xinto.opencord.db.entity.guild.EntityGuild
import com.xinto.opencord.db.entity.message.EntityAttachment
import com.xinto.opencord.db.entity.message.EntityEmbed
import com.xinto.opencord.db.entity.message.EntityMessage
import com.xinto.opencord.db.entity.user.EntityUser

@Database(
version = 1,
entities = [
EntityChannel::class,
EntityGuild::class,
EntityAttachment::class,
EntityEmbed::class,
EntityMessage::class,
EntityUser::class,
],
exportSchema = false,
)
@TypeConverters(Converters::class)
abstract class CacheDatabase : RoomDatabase() {
abstract fun channels(): ChannelsDao
abstract fun guilds(): GuildsDao

abstract fun messages(): MessagesDao
abstract fun attachments(): AttachmentsDao
abstract fun embeds(): EmbedsDao

abstract fun users(): UsersDao
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.xinto.opencord.db.entity.channel

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey

@Entity(
tableName = "channels",
indices = [
Index(value = ["guild_id"]),
],
)
data class EntityChannel(
// -------- Discord data -------- //
@PrimaryKey
val id: Long,

@ColumnInfo(name = "guild_id")
val guildId: Long,

@ColumnInfo(name = "name")
val name: String,

@ColumnInfo(name = "type")
val type: Int,

@ColumnInfo(name = "position")
val position: Int,

@ColumnInfo(name = "parent_id")
val parentId: Long?,

@ColumnInfo(name = "nsfw")
val nsfw: Boolean,

// -------- DB relational data -------- //
@ColumnInfo(name = "is_pins_stored")
val pinsStored: Boolean,
)
Loading

0 comments on commit 417a2ca

Please sign in to comment.