feat(shared): add shared module with common DTO models
New Gradle module :shared (pure Kotlin/JVM) containing @Serializable DTO classes for use by both the Android app and future Ktor server. shared/src/main/kotlin/de/krisenvorrat/shared/model/: - InventoryDto: root DTO replacing ExportData (version, categories, locations, items, settings) - CategoryDto, LocationDto, ItemDto, SettingDto: extracted from the former *Export data classes in :app Migration in :app: - ExportData.kt deleted (classes moved to :shared) - ImportExportRepositoryImpl now imports from de.krisenvorrat.shared.model - app/build.gradle.kts adds implementation(project(:shared)) Build config: - libs.versions.toml: added kotlin-jvm plugin entry - build.gradle.kts (root): registered kotlin-jvm plugin - settings.gradle.kts: include(:shared) JSON wire format is unchanged; all 165 existing tests pass. Closes #39
This commit is contained in:
parent
309587bc36
commit
c0c4978ccf
12 changed files with 100 additions and 56 deletions
|
|
@ -71,6 +71,9 @@ dependencies {
|
||||||
// Serialization
|
// Serialization
|
||||||
implementation(libs.kotlinx.serialization.json)
|
implementation(libs.kotlinx.serialization.json)
|
||||||
|
|
||||||
|
// Shared module
|
||||||
|
implementation(project(":shared"))
|
||||||
|
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
testImplementation(libs.kotlinx.coroutines.test)
|
testImplementation(libs.kotlinx.coroutines.test)
|
||||||
testImplementation(libs.mockk)
|
testImplementation(libs.mockk)
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
package de.krisenvorrat.app.data.export
|
|
||||||
|
|
||||||
import kotlinx.serialization.EncodeDefault
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
|
||||||
@Serializable
|
|
||||||
internal data class ExportData(
|
|
||||||
@EncodeDefault(EncodeDefault.Mode.ALWAYS) val version: Int = 1,
|
|
||||||
val categories: List<CategoryExport>,
|
|
||||||
val locations: List<LocationExport>,
|
|
||||||
val items: List<ItemExport>,
|
|
||||||
val settings: List<SettingExport>
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
internal data class CategoryExport(
|
|
||||||
val id: Int,
|
|
||||||
val name: String
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
internal data class LocationExport(
|
|
||||||
val id: Int,
|
|
||||||
val name: String
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
internal data class ItemExport(
|
|
||||||
val id: String,
|
|
||||||
val name: String,
|
|
||||||
val categoryId: Int,
|
|
||||||
val quantity: Double,
|
|
||||||
val unit: String,
|
|
||||||
val unitPrice: Double,
|
|
||||||
val kcalPer100g: Int?,
|
|
||||||
val expiryDate: String?,
|
|
||||||
val locationId: Int,
|
|
||||||
val minStock: Double,
|
|
||||||
val notes: String,
|
|
||||||
val lastUpdated: Long
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
internal data class SettingExport(
|
|
||||||
val key: String,
|
|
||||||
val value: String
|
|
||||||
)
|
|
||||||
|
|
@ -9,6 +9,11 @@ import de.krisenvorrat.app.data.db.entity.ItemEntity
|
||||||
import de.krisenvorrat.app.data.db.entity.LocationEntity
|
import de.krisenvorrat.app.data.db.entity.LocationEntity
|
||||||
import de.krisenvorrat.app.data.db.entity.SettingsEntity
|
import de.krisenvorrat.app.data.db.entity.SettingsEntity
|
||||||
import de.krisenvorrat.app.domain.repository.ImportExportRepository
|
import de.krisenvorrat.app.domain.repository.ImportExportRepository
|
||||||
|
import de.krisenvorrat.shared.model.CategoryDto
|
||||||
|
import de.krisenvorrat.shared.model.InventoryDto
|
||||||
|
import de.krisenvorrat.shared.model.ItemDto
|
||||||
|
import de.krisenvorrat.shared.model.LocationDto
|
||||||
|
import de.krisenvorrat.shared.model.SettingDto
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -37,11 +42,11 @@ internal class ImportExportRepositoryImpl @Inject constructor(
|
||||||
val items = itemDao.getAll().first()
|
val items = itemDao.getAll().first()
|
||||||
val settings = settingsDao.getAll().first()
|
val settings = settingsDao.getAll().first()
|
||||||
|
|
||||||
val exportData = ExportData(
|
val exportData = InventoryDto(
|
||||||
categories = categories.map { CategoryExport(id = it.id, name = it.name) },
|
categories = categories.map { CategoryDto(id = it.id, name = it.name) },
|
||||||
locations = locations.map { LocationExport(id = it.id, name = it.name) },
|
locations = locations.map { LocationDto(id = it.id, name = it.name) },
|
||||||
items = items.map { item ->
|
items = items.map { item ->
|
||||||
ItemExport(
|
ItemDto(
|
||||||
id = item.id,
|
id = item.id,
|
||||||
name = item.name,
|
name = item.name,
|
||||||
categoryId = item.categoryId,
|
categoryId = item.categoryId,
|
||||||
|
|
@ -56,14 +61,14 @@ internal class ImportExportRepositoryImpl @Inject constructor(
|
||||||
lastUpdated = item.lastUpdated
|
lastUpdated = item.lastUpdated
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
settings = settings.map { SettingExport(key = it.key, value = it.value) }
|
settings = settings.map { SettingDto(key = it.key, value = it.value) }
|
||||||
)
|
)
|
||||||
jsonSerializer.encodeToString(ExportData.serializer(), exportData)
|
jsonSerializer.encodeToString(InventoryDto.serializer(), exportData)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun importFromJson(json: String): Result<Unit> = withContext(Dispatchers.IO) {
|
override suspend fun importFromJson(json: String): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val exportData = jsonSerializer.decodeFromString<ExportData>(json)
|
val exportData = jsonSerializer.decodeFromString<InventoryDto>(json)
|
||||||
check(exportData.version == 1) { "Unsupported export format version: ${exportData.version}" }
|
check(exportData.version == 1) { "Unsupported export format version: ${exportData.version}" }
|
||||||
transaction.execute {
|
transaction.execute {
|
||||||
categoryDao.upsertAll(exportData.categories.map { CategoryEntity(id = it.id, name = it.name) })
|
categoryDao.upsertAll(exportData.categories.map { CategoryEntity(id = it.id, name = it.name) })
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application) apply false
|
alias(libs.plugins.android.application) apply false
|
||||||
|
alias(libs.plugins.kotlin.jvm) apply false
|
||||||
alias(libs.plugins.kotlin.android) apply false
|
alias(libs.plugins.kotlin.android) apply false
|
||||||
alias(libs.plugins.kotlin.compose) apply false
|
alias(libs.plugins.kotlin.compose) apply false
|
||||||
alias(libs.plugins.kotlin.serialization) apply false
|
alias(libs.plugins.kotlin.serialization) apply false
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,4 @@ dependencyResolutionManagement {
|
||||||
|
|
||||||
rootProject.name = "krisenvorrat"
|
rootProject.name = "krisenvorrat"
|
||||||
include(":app")
|
include(":app")
|
||||||
|
include(":shared")
|
||||||
|
|
|
||||||
21
shared/build.gradle.kts
Normal file
21
shared/build.gradle.kts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlin.jvm)
|
||||||
|
alias(libs.plugins.kotlin.serialization)
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(libs.kotlinx.serialization.json)
|
||||||
|
|
||||||
|
testImplementation(libs.junit)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package de.krisenvorrat.shared.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CategoryDto(
|
||||||
|
val id: Int,
|
||||||
|
val name: String
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package de.krisenvorrat.shared.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.EncodeDefault
|
||||||
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
|
@Serializable
|
||||||
|
data class InventoryDto(
|
||||||
|
@EncodeDefault(EncodeDefault.Mode.ALWAYS) val version: Int = 1,
|
||||||
|
val categories: List<CategoryDto>,
|
||||||
|
val locations: List<LocationDto>,
|
||||||
|
val items: List<ItemDto>,
|
||||||
|
val settings: List<SettingDto>
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package de.krisenvorrat.shared.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ItemDto(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val categoryId: Int,
|
||||||
|
val quantity: Double,
|
||||||
|
val unit: String,
|
||||||
|
val unitPrice: Double,
|
||||||
|
val kcalPer100g: Int?,
|
||||||
|
val expiryDate: String?,
|
||||||
|
val locationId: Int,
|
||||||
|
val minStock: Double,
|
||||||
|
val notes: String,
|
||||||
|
val lastUpdated: Long
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package de.krisenvorrat.shared.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LocationDto(
|
||||||
|
val id: Int,
|
||||||
|
val name: String
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package de.krisenvorrat.shared.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SettingDto(
|
||||||
|
val key: String,
|
||||||
|
val value: String
|
||||||
|
)
|
||||||
Loading…
Reference in a new issue