feat(app): add ResourceEntity, Dao, Repository + DB migration 8→9
Closes #121
This commit is contained in:
parent
6fc37ee203
commit
542fbb0941
7 changed files with 162 additions and 3 deletions
|
|
@ -9,22 +9,25 @@ import de.bollwerk.app.data.db.dao.ItemDao
|
|||
import de.bollwerk.app.data.db.dao.LocationDao
|
||||
import de.bollwerk.app.data.db.dao.MessageDao
|
||||
import de.bollwerk.app.data.db.dao.PendingSyncOpDao
|
||||
import de.bollwerk.app.data.db.dao.ResourceDao
|
||||
import de.bollwerk.app.data.db.dao.SettingsDao
|
||||
import de.bollwerk.app.data.db.entity.CategoryEntity
|
||||
import de.bollwerk.app.data.db.entity.ItemEntity
|
||||
import de.bollwerk.app.data.db.entity.LocationEntity
|
||||
import de.bollwerk.app.data.db.entity.MessageEntity
|
||||
import de.bollwerk.app.data.db.entity.PendingSyncOpEntity
|
||||
import de.bollwerk.app.data.db.entity.ResourceEntity
|
||||
import de.bollwerk.app.data.db.entity.SettingsEntity
|
||||
|
||||
@Database(
|
||||
entities = [CategoryEntity::class, LocationEntity::class, ItemEntity::class, SettingsEntity::class, PendingSyncOpEntity::class, MessageEntity::class],
|
||||
version = 8,
|
||||
entities = [CategoryEntity::class, LocationEntity::class, ItemEntity::class, SettingsEntity::class, PendingSyncOpEntity::class, MessageEntity::class, ResourceEntity::class],
|
||||
version = 9,
|
||||
exportSchema = true,
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 5, to = 6),
|
||||
AutoMigration(from = 6, to = 7),
|
||||
AutoMigration(from = 7, to = 8)
|
||||
AutoMigration(from = 7, to = 8),
|
||||
AutoMigration(from = 8, to = 9)
|
||||
]
|
||||
)
|
||||
@TypeConverters(LocalDateConverter::class)
|
||||
|
|
@ -35,4 +38,5 @@ internal abstract class BollwerkDatabase : RoomDatabase() {
|
|||
abstract fun settingsDao(): SettingsDao
|
||||
abstract fun pendingSyncOpDao(): PendingSyncOpDao
|
||||
abstract fun messageDao(): MessageDao
|
||||
abstract fun resourceDao(): ResourceDao
|
||||
}
|
||||
|
|
|
|||
24
app/src/main/java/de/bollwerk/app/data/db/dao/ResourceDao.kt
Normal file
24
app/src/main/java/de/bollwerk/app/data/db/dao/ResourceDao.kt
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package de.bollwerk.app.data.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import de.bollwerk.app.data.db.entity.ResourceEntity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
internal interface ResourceDao {
|
||||
|
||||
@Query("SELECT * FROM resources")
|
||||
fun getAll(): Flow<List<ResourceEntity>>
|
||||
|
||||
@Query("SELECT * FROM resources WHERE guid = :guid")
|
||||
suspend fun getByGuid(guid: String): ResourceEntity?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertAll(resources: List<ResourceEntity>)
|
||||
|
||||
@Query("DELETE FROM resources")
|
||||
suspend fun deleteAll()
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package de.bollwerk.app.data.db.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "resources")
|
||||
internal data class ResourceEntity(
|
||||
@PrimaryKey val guid: String,
|
||||
@ColumnInfo(name = "title") val title: String,
|
||||
@ColumnInfo(name = "description") val description: String,
|
||||
@ColumnInfo(name = "tags") val tags: String, // JSON array string
|
||||
@ColumnInfo(name = "file_format") val fileFormat: String,
|
||||
@ColumnInfo(name = "mime_type") val mimeType: String,
|
||||
@ColumnInfo(name = "file_size") val fileSize: Long,
|
||||
@ColumnInfo(name = "release_date") val releaseDate: String?,
|
||||
@ColumnInfo(name = "created_at") val createdAt: Long,
|
||||
@ColumnInfo(name = "updated_at") val updatedAt: Long,
|
||||
@ColumnInfo(name = "author") val author: String?,
|
||||
@ColumnInfo(name = "language") val language: String?,
|
||||
@ColumnInfo(name = "edition") val edition: String?,
|
||||
@ColumnInfo(name = "download_url") val downloadUrl: String
|
||||
)
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package de.bollwerk.app.data.repository
|
||||
|
||||
import de.bollwerk.app.data.db.dao.ResourceDao
|
||||
import de.bollwerk.app.data.db.entity.ResourceEntity
|
||||
import de.bollwerk.app.domain.model.SettingsKey.StringKey
|
||||
import de.bollwerk.app.domain.repository.ResourceRepository
|
||||
import de.bollwerk.app.domain.repository.SettingsRepository
|
||||
import de.bollwerk.shared.model.ResourceDto
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.statement.bodyAsBytes
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.builtins.ListSerializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class ResourceRepositoryImpl @Inject constructor(
|
||||
private val dao: ResourceDao,
|
||||
private val httpClient: HttpClient,
|
||||
private val settingsRepository: SettingsRepository
|
||||
) : ResourceRepository {
|
||||
|
||||
override fun getAll(): Flow<List<ResourceDto>> =
|
||||
dao.getAll().map { entities -> entities.map { it.toDto() } }
|
||||
|
||||
override suspend fun refreshFromServer() = withContext(Dispatchers.IO) {
|
||||
val serverUrl = settingsRepository.getString(StringKey.ServerUrl)
|
||||
val token = settingsRepository.getString(StringKey.AuthAccessToken)
|
||||
if (serverUrl.isBlank() || token.isBlank()) return@withContext
|
||||
|
||||
val response = httpClient.get("$serverUrl/api/resources") {
|
||||
header("Authorization", "Bearer $token")
|
||||
}
|
||||
val resources: List<ResourceDto> = response.body()
|
||||
dao.deleteAll()
|
||||
dao.insertAll(resources.map { it.toEntity() })
|
||||
}
|
||||
|
||||
override suspend fun downloadResource(guid: String): ByteArray = withContext(Dispatchers.IO) {
|
||||
val serverUrl = settingsRepository.getString(StringKey.ServerUrl)
|
||||
val token = settingsRepository.getString(StringKey.AuthAccessToken)
|
||||
|
||||
val response = httpClient.get("$serverUrl/api/resources/$guid/download") {
|
||||
header("Authorization", "Bearer $token")
|
||||
}
|
||||
response.bodyAsBytes()
|
||||
}
|
||||
|
||||
private fun ResourceEntity.toDto() = ResourceDto(
|
||||
guid = guid,
|
||||
title = title,
|
||||
description = description,
|
||||
tags = try { Json.decodeFromString<List<String>>(tags) } catch (_: Exception) { emptyList() },
|
||||
fileFormat = fileFormat,
|
||||
mimeType = mimeType,
|
||||
fileSize = fileSize,
|
||||
releaseDate = releaseDate,
|
||||
createdAt = createdAt,
|
||||
updatedAt = updatedAt,
|
||||
author = author,
|
||||
language = language,
|
||||
edition = edition,
|
||||
downloadUrl = downloadUrl
|
||||
)
|
||||
|
||||
private fun ResourceDto.toEntity() = ResourceEntity(
|
||||
guid = guid,
|
||||
title = title,
|
||||
description = description,
|
||||
tags = Json.encodeToString(ListSerializer(String.serializer()), tags),
|
||||
fileFormat = fileFormat,
|
||||
mimeType = mimeType,
|
||||
fileSize = fileSize,
|
||||
releaseDate = releaseDate,
|
||||
createdAt = createdAt,
|
||||
updatedAt = updatedAt,
|
||||
author = author,
|
||||
language = language,
|
||||
edition = edition,
|
||||
downloadUrl = downloadUrl
|
||||
)
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ import de.bollwerk.app.data.db.dao.ItemDao
|
|||
import de.bollwerk.app.data.db.dao.LocationDao
|
||||
import de.bollwerk.app.data.db.dao.MessageDao
|
||||
import de.bollwerk.app.data.db.dao.PendingSyncOpDao
|
||||
import de.bollwerk.app.data.db.dao.ResourceDao
|
||||
import de.bollwerk.app.data.db.dao.SettingsDao
|
||||
import de.bollwerk.app.data.export.DatabaseTransaction
|
||||
import javax.inject.Singleton
|
||||
|
|
@ -67,6 +68,9 @@ internal object DatabaseModule {
|
|||
@Provides
|
||||
fun provideMessageDao(db: BollwerkDatabase): MessageDao = db.messageDao()
|
||||
|
||||
@Provides
|
||||
fun provideResourceDao(db: BollwerkDatabase): ResourceDao = db.resourceDao()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDatabaseTransaction(db: BollwerkDatabase): DatabaseTransaction =
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import de.bollwerk.app.data.repository.CategoryRepositoryImpl
|
|||
import de.bollwerk.app.data.repository.ItemRepositoryImpl
|
||||
import de.bollwerk.app.data.repository.LocationRepositoryImpl
|
||||
import de.bollwerk.app.data.repository.MessageRepositoryImpl
|
||||
import de.bollwerk.app.data.repository.ResourceRepositoryImpl
|
||||
import de.bollwerk.app.data.repository.SettingsRepositoryImpl
|
||||
import de.bollwerk.app.data.repository.UpdateRepositoryImpl
|
||||
import de.bollwerk.app.domain.repository.CategoryRepository
|
||||
|
|
@ -17,6 +18,7 @@ import de.bollwerk.app.domain.repository.ImportExportRepository
|
|||
import de.bollwerk.app.domain.repository.ItemRepository
|
||||
import de.bollwerk.app.domain.repository.LocationRepository
|
||||
import de.bollwerk.app.domain.repository.MessageRepository
|
||||
import de.bollwerk.app.domain.repository.ResourceRepository
|
||||
import de.bollwerk.app.domain.repository.SettingsRepository
|
||||
import de.bollwerk.app.domain.repository.UpdateRepository
|
||||
import de.bollwerk.app.domain.usecase.ApkInstaller
|
||||
|
|
@ -57,4 +59,8 @@ internal abstract class RepositoryModule {
|
|||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindApkInstaller(impl: ApkInstallerImpl): ApkInstaller
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindResourceRepository(impl: ResourceRepositoryImpl): ResourceRepository
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
package de.bollwerk.app.domain.repository
|
||||
|
||||
import de.bollwerk.shared.model.ResourceDto
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
internal interface ResourceRepository {
|
||||
fun getAll(): Flow<List<ResourceDto>>
|
||||
suspend fun refreshFromServer()
|
||||
suspend fun downloadResource(guid: String): ByteArray
|
||||
}
|
||||
Loading…
Reference in a new issue