Refactor domain models (DomFunktionaer, DomReiter, DomPferd) to align with ZNS conventions: simplify naming, update properties, and enhance parser logic. Adjust related controllers, repository methods, and tests. Update MASTER_ROADMAP with changes to domain models.

This commit is contained in:
2026-04-06 00:00:20 +02:00
parent 1e5fa3d053
commit f50d4deb16
57 changed files with 811 additions and 532 deletions
@@ -2,7 +2,7 @@
package at.mocode.masterdata.infrastructure.persistence
import at.mocode.core.domain.model.LizenzKlasseE
import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.domain.model.SparteE
import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.*
@@ -72,7 +72,7 @@ class ExposedRegulationRepository : RegulationRepository {
private fun ResultRow.toLicenseMatrixEntry() = LicenseMatrixEntry(
licenseId = this[LicenseTable.id],
sparte = SparteE.valueOf(this[LicenseTable.sparte]),
lizenzKlasse = LizenzKlasseE.valueOf(this[LicenseTable.lizenzKlasse]),
lizenzKlasse = ReiterLizenzKlasseE.valueOf(this[LicenseTable.lizenzKlasse]),
maxTurnierklasseCode = this[LicenseTable.maxTurnierklasseCode],
validFrom = this[LicenseTable.validFrom].toKtInstant(),
validTo = this[LicenseTable.validTo]?.toOptionalKtInstant(),
@@ -2,6 +2,7 @@
package at.mocode.masterdata.infrastructure.persistence
import at.mocode.masterdata.infrastructure.persistence.reiter.ReiterTable
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
@@ -2,6 +2,8 @@
package at.mocode.masterdata.infrastructure.persistence
import at.mocode.masterdata.infrastructure.persistence.reiter.ReiterTable
import at.mocode.masterdata.infrastructure.persistence.verein.VereinTable
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
@@ -1,10 +1,9 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
package at.mocode.masterdata.infrastructure.persistence.funktionaer
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.DomFunktionaer
import at.mocode.masterdata.domain.model.Funktionaer
import at.mocode.masterdata.domain.repository.FunktionaerRepository
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.and
@@ -19,24 +18,25 @@ import kotlin.uuid.Uuid
/**
* Exposed-basierte Implementierung des Funktionaer-Repositorys.
*/
class ExposedFunktionaerRepository : FunktionaerRepository {
class FunktionaerExposedRepository : FunktionaerRepository {
private fun rowToDomFunktionaer(row: ResultRow, qualifikationen: List<String> = emptyList()): DomFunktionaer {
return DomFunktionaer(
funktionaerId = row[FunktionaerTable.id],
satzID = row[FunktionaerTable.satzID] ?: "X",
satzNummer = row[FunktionaerTable.satzNummer] ?: 0,
name = row[FunktionaerTable.name],
qualifikationen = qualifikationen,
istAktiv = row[FunktionaerTable.istAktiv],
bemerkungen = row[FunktionaerTable.bemerkungen],
datenQuelle = DatenQuelleE.valueOf(row[FunktionaerTable.datenQuelle]),
createdAt = row[FunktionaerTable.createdAt],
updatedAt = row[FunktionaerTable.updatedAt]
private fun rowToDomFunktionaer(row: ResultRow, qualifikationen: List<String> = emptyList()): Funktionaer {
return Funktionaer(
funktionaerId = row[FunktionaerTable.id],
personId = row[FunktionaerTable.personId],
satzId = row[FunktionaerTable.satzId] ?: "X",
satzNummer = row[FunktionaerTable.satzNummer] ?: 0,
name = row[FunktionaerTable.name],
qualifikationen = qualifikationen,
istAktiv = row[FunktionaerTable.istAktiv],
bemerkungen = row[FunktionaerTable.bemerkungen],
datenQuelle = DatenQuelleE.valueOf(row[FunktionaerTable.datenQuelle]),
createdAt = row[FunktionaerTable.createdAt],
updatedAt = row[FunktionaerTable.updatedAt]
)
}
override suspend fun findById(id: Uuid): DomFunktionaer? = DatabaseFactory.dbQuery {
override suspend fun findById(id: Uuid): Funktionaer? = DatabaseFactory.dbQuery {
val qualifikationen = FunktionaerQualifikationTable
.selectAll().where { FunktionaerQualifikationTable.funktionaerId eq id }
.map { it[FunktionaerQualifikationTable.qualifikation] }
@@ -46,9 +46,9 @@ class ExposedFunktionaerRepository : FunktionaerRepository {
.singleOrNull()
}
override suspend fun findBySatz(satzID: String, satzNummer: Int): DomFunktionaer? = DatabaseFactory.dbQuery {
override suspend fun findBySatz(satzID: String, satzNummer: Int): Funktionaer? = DatabaseFactory.dbQuery {
val row = FunktionaerTable.selectAll()
.where { (FunktionaerTable.satzID eq satzID) and (FunktionaerTable.satzNummer eq satzNummer) }
.where { (FunktionaerTable.satzId eq satzID) and (FunktionaerTable.satzNummer eq satzNummer) }
.singleOrNull() ?: return@dbQuery null
val qualifikationen = FunktionaerQualifikationTable
@@ -58,7 +58,7 @@ class ExposedFunktionaerRepository : FunktionaerRepository {
rowToDomFunktionaer(row, qualifikationen)
}
override suspend fun findAll(limit: Int, offset: Int): List<DomFunktionaer> = DatabaseFactory.dbQuery {
override suspend fun findAll(limit: Int, offset: Int): List<Funktionaer> = DatabaseFactory.dbQuery {
val funktionaere = FunktionaerTable.selectAll()
.limit(limit).offset(offset.toLong())
.toList()
@@ -73,11 +73,12 @@ class ExposedFunktionaerRepository : FunktionaerRepository {
}
}
override suspend fun save(funktionaer: DomFunktionaer): DomFunktionaer = DatabaseFactory.dbQuery {
override suspend fun save(funktionaer: Funktionaer): Funktionaer = DatabaseFactory.dbQuery {
val exists = FunktionaerTable.selectAll().where { FunktionaerTable.id eq funktionaer.funktionaerId }.any()
if (exists) {
FunktionaerTable.update({ FunktionaerTable.id eq funktionaer.funktionaerId }) {
it[satzID] = funktionaer.satzID
it[personId] = funktionaer.personId
it[satzId] = funktionaer.satzId
it[satzNummer] = funktionaer.satzNummer
it[name] = funktionaer.name
it[istAktiv] = funktionaer.istAktiv
@@ -88,7 +89,8 @@ class ExposedFunktionaerRepository : FunktionaerRepository {
} else {
FunktionaerTable.insert {
it[id] = funktionaer.funktionaerId
it[satzID] = funktionaer.satzID
it[personId] = funktionaer.personId
it[satzId] = funktionaer.satzId
it[satzNummer] = funktionaer.satzNummer
it[name] = funktionaer.name
it[istAktiv] = funktionaer.istAktiv
@@ -121,7 +123,7 @@ class ExposedFunktionaerRepository : FunktionaerRepository {
override suspend fun existsBySatz(satzID: String, satzNummer: Int): Boolean = DatabaseFactory.dbQuery {
FunktionaerTable.selectAll()
.where { (FunktionaerTable.satzID eq satzID) and (FunktionaerTable.satzNummer eq satzNummer) }
.where { (FunktionaerTable.satzId eq satzID) and (FunktionaerTable.satzNummer eq satzNummer) }
.any()
}
}
@@ -1,10 +1,11 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
@file:OptIn(ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
package at.mocode.masterdata.infrastructure.persistence.funktionaer
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
import kotlin.uuid.ExperimentalUuidApi
/**
@@ -12,19 +13,42 @@ import org.jetbrains.exposed.v1.datetime.timestamp
*/
object FunktionaerTable : Table("funktionaer") {
val id = uuid("funktionaer_id")
val satzID = varchar("satz_id", 1).nullable()
val personId = uuid("person_id").nullable()
// === ZNS.zip RICHT01.DAT === ANFANG ===
val satzId = varchar("satz_id", 1)
val satzNummer = integer("satz_nummer").nullable()
val name = varchar("name", 200).nullable()
// === ZNS.zip RICHT01.DAT === ENDE ===
// Kontakt
val imageUrl = varchar("image_url", 255).nullable()
val email = varchar("email", 200).nullable()
val telefon = varchar("telefon", 50).nullable()
val website = varchar("website", 255).nullable()
// Adresse
val strasse = varchar("strasse", 200).nullable()
val hausnummer = varchar("hausnummer", 10).nullable()
val plz = varchar("plz", 10).nullable()
val ort = varchar("ort", 100).nullable()
val bundesland = varchar("bundesland", 100).nullable()
// Status & Verwaltung
val istAktiv = bool("ist_aktiv").default(true)
val bemerkungen = text("bemerkungen").nullable()
val datenQuelle = varchar("daten_quelle", 50)
// Audit
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
index("idx_funktionaer_satz", isUnique = true, satzID, satzNummer)
index("idx_funktionaer_satz", isUnique = true, satzId, satzNummer)
}
}
@@ -1,11 +1,11 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
@file:OptIn(ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
package at.mocode.masterdata.infrastructure.persistence.pferd
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.PferdeGeschlechtE
import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.DomPferd
import at.mocode.masterdata.domain.model.Pferd
import at.mocode.masterdata.domain.repository.HorseRepository
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.eq
@@ -14,12 +14,13 @@ import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.selectAll
import org.jetbrains.exposed.v1.jdbc.update
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
class HorseRepositoryImpl : HorseRepository {
class HorseExposedRepository : HorseRepository {
private fun rowToDomPferd(row: ResultRow): DomPferd {
return DomPferd(
private fun rowToPferd(row: ResultRow): Pferd {
return Pferd(
pferdId = row[HorseTable.id],
kopfnummer = row[HorseTable.kopfnummer],
pferdeName = row[HorseTable.pferdeName],
@@ -42,43 +43,43 @@ class HorseRepositoryImpl : HorseRepository {
)
}
override suspend fun findById(id: Uuid): DomPferd? = DatabaseFactory.dbQuery {
override suspend fun findById(id: Uuid): Pferd? = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.id eq id }
.map(::rowToDomPferd)
.map(::rowToPferd)
.singleOrNull()
}
override suspend fun findByLebensnummer(lebensnummer: String): DomPferd? = DatabaseFactory.dbQuery {
override suspend fun findByLebensnummer(lebensnummer: String): Pferd? = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.lebensnummer eq lebensnummer }
.map(::rowToDomPferd)
.map(::rowToPferd)
.singleOrNull()
}
override suspend fun findBySatznummer(satznummer: String): DomPferd? = DatabaseFactory.dbQuery {
override suspend fun findBySatznummer(satznummer: String): Pferd? = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.satznummer eq satznummer }
.map(::rowToDomPferd)
.map(::rowToPferd)
.singleOrNull()
}
override suspend fun findByKopfnummer(kopfnummer: String): List<DomPferd> = DatabaseFactory.dbQuery {
override suspend fun findByKopfnummer(kopfnummer: String): List<Pferd> = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.kopfnummer eq kopfnummer }
.map(::rowToDomPferd)
.map(::rowToPferd)
}
override suspend fun findByName(searchTerm: String, limit: Int): List<DomPferd> = DatabaseFactory.dbQuery {
override suspend fun findByName(searchTerm: String, limit: Int): List<Pferd> = DatabaseFactory.dbQuery {
val pattern = "%$searchTerm%"
HorseTable.selectAll().where { HorseTable.pferdeName like pattern }
.limit(limit)
.map(::rowToDomPferd)
.map(::rowToPferd)
}
override suspend fun findAllActive(limit: Int): List<DomPferd> = DatabaseFactory.dbQuery {
override suspend fun findAllActive(limit: Int): List<Pferd> = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.istAktiv eq true }
.limit(limit)
.map(::rowToDomPferd)
.map(::rowToPferd)
}
override suspend fun save(horse: DomPferd): DomPferd = DatabaseFactory.dbQuery {
override suspend fun save(horse: Pferd): Pferd = DatabaseFactory.dbQuery {
val exists = HorseTable.selectAll().where { HorseTable.id eq horse.pferdId }.any()
if (exists) {
HorseTable.update({ HorseTable.id eq horse.pferdId }) {
@@ -139,11 +140,11 @@ class HorseRepositoryImpl : HorseRepository {
HorseTable.selectAll().where { HorseTable.istAktiv eq true }.count()
}
override suspend fun upsertByLebensnummer(horse: DomPferd): DomPferd = DatabaseFactory.dbQuery {
override suspend fun upsertByLebensnummer(horse: Pferd): Pferd = DatabaseFactory.dbQuery {
val lebensnummer = horse.lebensnummer ?: return@dbQuery save(horse)
val existing = HorseTable.selectAll().where { HorseTable.lebensnummer eq lebensnummer }
.map(::rowToDomPferd)
.map(::rowToPferd)
.singleOrNull()
if (existing != null) {
@@ -173,11 +174,11 @@ class HorseRepositoryImpl : HorseRepository {
}
}
override suspend fun upsertBySatznummer(horse: DomPferd): DomPferd = DatabaseFactory.dbQuery {
override suspend fun upsertBySatznummer(horse: Pferd): Pferd = DatabaseFactory.dbQuery {
val satznummer = horse.satznummer ?: return@dbQuery save(horse)
val existing = HorseTable.selectAll().where { HorseTable.satznummer eq satznummer }
.map(::rowToDomPferd)
.map(::rowToPferd)
.singleOrNull()
if (existing != null) {
@@ -207,28 +208,28 @@ class HorseRepositoryImpl : HorseRepository {
}
}
// Not implemented or needed based on current requirements/DomPferd state
override suspend fun findByChipNummer(chipNummer: String): DomPferd? = null
override suspend fun findByPassNummer(passNummer: String): DomPferd? = null
override suspend fun findByOepsNummer(oepsNummer: String): DomPferd? = null
override suspend fun findByFeiNummer(feiNummer: String): DomPferd? = null
override suspend fun findByOwnerId(ownerId: Uuid, activeOnly: Boolean): List<DomPferd> = emptyList()
override suspend fun findByResponsiblePersonId(responsiblePersonId: Uuid, activeOnly: Boolean): List<DomPferd> =
// Not implemented or needed based on current requirements/Pferd state
override suspend fun findByChipNummer(chipNummer: String): Pferd? = null
override suspend fun findByPassNummer(passNummer: String): Pferd? = null
override suspend fun findByOepsNummer(oepsNummer: String): Pferd? = null
override suspend fun findByFeiNummer(feiNummer: String): Pferd? = null
override suspend fun findByOwnerId(ownerId: Uuid, activeOnly: Boolean): List<Pferd> = emptyList()
override suspend fun findByResponsiblePersonId(responsiblePersonId: Uuid, activeOnly: Boolean): List<Pferd> =
emptyList()
override suspend fun findByGeschlecht(
geschlecht: PferdeGeschlechtE,
activeOnly: Boolean,
limit: Int
): List<DomPferd> = emptyList()
): List<Pferd> = emptyList()
override suspend fun findByRasse(rasse: String, activeOnly: Boolean, limit: Int): List<DomPferd> = emptyList()
override suspend fun findByBirthYear(birthYear: Int, activeOnly: Boolean): List<DomPferd> = emptyList()
override suspend fun findByBirthYearRange(fromYear: Int, toYear: Int, activeOnly: Boolean): List<DomPferd> =
override suspend fun findByRasse(rasse: String, activeOnly: Boolean, limit: Int): List<Pferd> = emptyList()
override suspend fun findByBirthYear(birthYear: Int, activeOnly: Boolean): List<Pferd> = emptyList()
override suspend fun findByBirthYearRange(fromYear: Int, toYear: Int, activeOnly: Boolean): List<Pferd> =
emptyList()
override suspend fun findOepsRegistered(activeOnly: Boolean): List<DomPferd> = emptyList()
override suspend fun findFeiRegistered(activeOnly: Boolean): List<DomPferd> = emptyList()
override suspend fun findOepsRegistered(activeOnly: Boolean): List<Pferd> = emptyList()
override suspend fun findFeiRegistered(activeOnly: Boolean): List<Pferd> = emptyList()
override suspend fun existsByChipNummer(chipNummer: String): Boolean = false
override suspend fun existsByPassNummer(passNummer: String): Boolean = false
override suspend fun existsByOepsNummer(oepsNummer: String): Boolean = false
@@ -1,16 +1,21 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
@file:OptIn(ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
package at.mocode.masterdata.infrastructure.persistence.pferd
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
import kotlin.uuid.ExperimentalUuidApi
/**
* Exposed-Tabellendefinition für die Pferd-Entität basierend auf PFERDE01.DAT.
*/
object HorseTable : Table("horse") {
val id = uuid("horse_id")
val personId = uuid("person_id").nullable()
// === ZNS.zip PFERDE01.DAT === ANFANG ===
val kopfnummer = varchar("kopfnummer", 4).nullable().index()
val pferdeName = varchar("pferde_name", 200).index()
val lebensnummer = varchar("lebensnummer", 50).nullable().index()
@@ -25,9 +30,14 @@ object HorseTable : Table("horse") {
val feiPass = varchar("fei_pass", 50).nullable()
val satznummer = varchar("satznummer", 10).nullable()
// === ZNS.zip PFERDE01.DAT === ENDE ===
// Status & Verwaltung
val istAktiv = bool("ist_aktiv").default(true)
val bemerkungen = text("bemerkungen").nullable()
val datenQuelle = varchar("daten_quelle", 50)
// Audit
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
@@ -1,24 +1,25 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
@file:OptIn(ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
package at.mocode.masterdata.infrastructure.persistence.reiter
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.LizenzKlasseE
import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.DomReiter
import at.mocode.masterdata.domain.model.Reiter
import at.mocode.masterdata.domain.repository.ReiterRepository
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.jdbc.*
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
/**
* Exposed-basierte Implementierung des Reiter-Repositorys.
*/
class ExposedReiterRepository : ReiterRepository {
class ReiterExposedRepository : ReiterRepository {
private fun rowToDomReiter(row: ResultRow): DomReiter {
return DomReiter(
private fun rowToDomReiter(row: ResultRow): Reiter {
return Reiter(
reiterId = row[ReiterTable.id],
personId = row[ReiterTable.personId],
satznummer = row[ReiterTable.satznummer],
@@ -41,7 +42,7 @@ class ExposedReiterRepository : ReiterRepository {
feiId = row[ReiterTable.feiId],
sperrListe = row[ReiterTable.sperrListe],
lizenzInfo = row[ReiterTable.lizenzInfo],
lizenzKlasse = LizenzKlasseE.valueOf(row[ReiterTable.lizenzKlasse]),
lizenzKlasse = ReiterLizenzKlasseE.valueOf(row[ReiterTable.lizenzKlasse]),
istAktiv = row[ReiterTable.istAktiv],
bemerkungen = row[ReiterTable.bemerkungen],
datenQuelle = DatenQuelleE.valueOf(row[ReiterTable.datenQuelle]),
@@ -50,25 +51,25 @@ class ExposedReiterRepository : ReiterRepository {
)
}
override suspend fun findById(id: Uuid): DomReiter? = DatabaseFactory.dbQuery {
override suspend fun findById(id: Uuid): Reiter? = DatabaseFactory.dbQuery {
ReiterTable.selectAll().where { ReiterTable.id eq id }
.map { rowToDomReiter(it) }
.singleOrNull()
}
override suspend fun findBySatznummer(satznummer: String?): DomReiter? = DatabaseFactory.dbQuery {
override suspend fun findBySatznummer(satznummer: String?): Reiter? = DatabaseFactory.dbQuery {
ReiterTable.selectAll().where { ReiterTable.satznummer eq satznummer }
.map { row -> rowToDomReiter(row) }
.singleOrNull()
}
override suspend fun findAll(limit: Int, offset: Int): List<DomReiter> = DatabaseFactory.dbQuery {
override suspend fun findAll(limit: Int, offset: Int): List<Reiter> = DatabaseFactory.dbQuery {
ReiterTable.selectAll()
.limit(limit).offset(offset.toLong())
.map { row -> rowToDomReiter(row) }
}
override suspend fun save(reiter: DomReiter): DomReiter = DatabaseFactory.dbQuery {
override suspend fun save(reiter: Reiter): Reiter = DatabaseFactory.dbQuery {
val exists = ReiterTable.selectAll().where { ReiterTable.id eq reiter.reiterId }.any()
if (exists) {
ReiterTable.update({ ReiterTable.id eq reiter.reiterId }) {
@@ -147,7 +148,7 @@ class ExposedReiterRepository : ReiterRepository {
ReiterTable.selectAll().where { ReiterTable.satznummer eq satznummer }.any()
}
override suspend fun upsertBySatznummer(reiter: DomReiter): DomReiter = DatabaseFactory.dbQuery {
override suspend fun upsertBySatznummer(reiter: Reiter): Reiter = DatabaseFactory.dbQuery {
val existing = findBySatznummer(reiter.satznummer)
if (existing != null) {
@@ -1,19 +1,22 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
@file:OptIn(ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
package at.mocode.masterdata.infrastructure.persistence.reiter
import at.mocode.core.domain.model.LizenzKlasseE
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.date
import org.jetbrains.exposed.v1.datetime.timestamp
import kotlin.uuid.ExperimentalUuidApi
/**
* Exposed-Tabellendefinition für die Reiter-Entität.
*/
object ReiterTable : Table("reiter") {
val id = uuid("reiter_id")
val personId = uuid("person_id")
val personId = uuid("person_id").nullable()
// === ZNS.zip LITENZ01.DAT === ANFANG ===
val satznummer = varchar("satznummer", 10).nullable()
val nachname = varchar("nachname", 100)
val vorname = varchar("vorname", 100)
@@ -34,11 +37,28 @@ object ReiterTable : Table("reiter") {
val feiId = varchar("fei_id", 20).nullable()
val sperrListe = varchar("sperr_liste", 50).nullable()
val lizenzInfo = varchar("lizenz_info", 100).nullable()
val lizenzKlasse = varchar("lizenz_klasse", 50).default(LizenzKlasseE.LIZENZFREI.name)
// === ZNS.zip LITENZ01.DAT === ENDE ===
// Kontakt
val imageUrl = varchar("image_url", 255).nullable()
val email = varchar("email", 200).nullable()
val telefon = varchar("telefon", 50).nullable()
val website = varchar("website", 255).nullable()
// Adresse
val strasse = varchar("strasse", 200).nullable()
val hausnummer = varchar("hausnummer", 10).nullable()
val plz = varchar("plz", 10).nullable()
val ort = varchar("ort", 100).nullable()
val bundesland = varchar("bundesland", 100).nullable()
// Status & Verwaltung
val istAktiv = bool("ist_aktiv").default(true)
val bemerkungen = text("bemerkungen").nullable()
val datenQuelle = varchar("daten_quelle", 50)
// Audit
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
@@ -1,102 +1,113 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
@file:OptIn(ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
package at.mocode.masterdata.infrastructure.persistence.verein
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.DomVerein
import at.mocode.masterdata.domain.model.Verein
import at.mocode.masterdata.domain.repository.VereinRepository
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.core.like
import org.jetbrains.exposed.v1.core.or
import org.jetbrains.exposed.v1.jdbc.*
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
/**
* Exposed-basierte Implementierung des Verein-Repositorys.
*/
class ExposedVereinRepository : VereinRepository {
class VereinExposedRepository : VereinRepository {
private fun rowToDomVerein(row: ResultRow): DomVerein {
return DomVerein(
private fun rowToVereinDomain(row: ResultRow): Verein {
return Verein(
vereinId = row[VereinTable.id],
personId = row[VereinTable.personId],
// === ZNS.zip VEREIN01.DAT === ANFANG ===
vereinsNummer = row[VereinTable.vereinsNummer],
name = row[VereinTable.name],
kurzname = row[VereinTable.kurzname],
bundesland = row[VereinTable.bundesland],
ort = row[VereinTable.ort],
plz = row[VereinTable.plz],
strasse = row[VereinTable.strasse],
vereinName = row[VereinTable.vereinName],
// === ZNS.zip VEREIN01.DAT === ENDE ===
// Kontakt
imageUrl = row[VereinTable.imageUrl],
email = row[VereinTable.email],
telefon = row[VereinTable.telefon],
website = row[VereinTable.website],
oepsRegionNummer = row[VereinTable.oepsRegionNummer],
istVeranstalter = row[VereinTable.istVeranstalter],
// Adresse
strasse = row[VereinTable.strasse],
hausnummer = row[VereinTable.hausnummer],
plz = row[VereinTable.plz],
ort = row[VereinTable.ort],
bundesland = row[VereinTable.bundesland],
// Status & Verwaltung
istAktiv = row[VereinTable.istAktiv],
logoUrl = row[VereinTable.logoUrl],
istVeranstalter = row[VereinTable.istVeranstalter],
bemerkungen = row[VereinTable.bemerkungen],
datenQuelle = DatenQuelleE.valueOf(row[VereinTable.datenQuelle]),
// Audit
createdAt = row[VereinTable.createdAt],
updatedAt = row[VereinTable.updatedAt]
)
}
override suspend fun findById(id: Uuid): DomVerein? = DatabaseFactory.dbQuery {
override suspend fun findById(id: Uuid): Verein? = DatabaseFactory.dbQuery {
VereinTable.selectAll().where { VereinTable.id eq id }
.map(::rowToDomVerein)
.map(::rowToVereinDomain)
.singleOrNull()
}
override suspend fun findByVereinsNummer(vereinsNummer: String): DomVerein? = DatabaseFactory.dbQuery {
override suspend fun findByVereinsNummer(vereinsNummer: String): Verein? = DatabaseFactory.dbQuery {
VereinTable.selectAll().where { VereinTable.vereinsNummer eq vereinsNummer }
.map(::rowToDomVerein)
.map(::rowToVereinDomain)
.singleOrNull()
}
override suspend fun findByName(searchTerm: String, limit: Int): List<DomVerein> = DatabaseFactory.dbQuery {
override suspend fun findByName(searchTerm: String, limit: Int): List<Verein> = DatabaseFactory.dbQuery {
val pattern = "%$searchTerm%"
VereinTable.selectAll().where { (VereinTable.name like pattern) or (VereinTable.kurzname like pattern) }
VereinTable.selectAll().where { VereinTable.vereinName like pattern }
.limit(limit)
.map(::rowToDomVerein)
.map(::rowToVereinDomain)
}
override suspend fun findByBundesland(bundesland: String, activeOnly: Boolean): List<DomVerein> =
override suspend fun findByBundesland(bundesland: String, activeOnly: Boolean): List<Verein> =
DatabaseFactory.dbQuery {
val query = VereinTable.selectAll().where { VereinTable.bundesland eq bundesland }
if (activeOnly) {
query.andWhere { VereinTable.istAktiv eq true }
}
query.map(::rowToDomVerein)
query.map(::rowToVereinDomain)
}
override suspend fun findVeranstalter(activeOnly: Boolean): List<DomVerein> = DatabaseFactory.dbQuery {
override suspend fun findVeranstalter(activeOnly: Boolean): List<Verein> = DatabaseFactory.dbQuery {
val query = VereinTable.selectAll().where { VereinTable.istVeranstalter eq true }
if (activeOnly) {
query.andWhere { VereinTable.istAktiv eq true }
}
query.map(::rowToDomVerein)
query.map(::rowToVereinDomain)
}
override suspend fun findAllActive(limit: Int, offset: Int): List<DomVerein> = DatabaseFactory.dbQuery {
override suspend fun findAllActive(limit: Int, offset: Int): List<Verein> = DatabaseFactory.dbQuery {
VereinTable.selectAll().where { VereinTable.istAktiv eq true }
.limit(limit).offset(offset.toLong())
.map(::rowToDomVerein)
.map(::rowToVereinDomain)
}
override suspend fun findAll(limit: Int, offset: Int): List<DomVerein> = DatabaseFactory.dbQuery {
override suspend fun findAll(limit: Int, offset: Int): List<Verein> = DatabaseFactory.dbQuery {
VereinTable.selectAll()
.limit(limit).offset(offset.toLong())
.map(::rowToDomVerein)
.map(::rowToVereinDomain)
}
override suspend fun save(verein: DomVerein): DomVerein = DatabaseFactory.dbQuery {
override suspend fun save(verein: Verein): Verein = DatabaseFactory.dbQuery {
val exists = VereinTable.selectAll().where { VereinTable.id eq verein.vereinId }.any()
if (exists) {
VereinTable.update({ VereinTable.id eq verein.vereinId }) {
it[vereinsNummer] = verein.vereinsNummer
it[name] = verein.name
it[kurzname] = verein.kurzname
it[vereinName] = verein.vereinName
it[bundesland] = verein.bundesland
it[ort] = verein.ort
it[plz] = verein.plz
@@ -104,10 +115,9 @@ class ExposedVereinRepository : VereinRepository {
it[email] = verein.email
it[telefon] = verein.telefon
it[website] = verein.website
it[oepsRegionNummer] = verein.oepsRegionNummer
it[istVeranstalter] = verein.istVeranstalter
it[istAktiv] = verein.istAktiv
it[logoUrl] = verein.logoUrl
it[imageUrl] = verein.imageUrl
it[bemerkungen] = verein.bemerkungen
it[datenQuelle] = verein.datenQuelle.name
it[updatedAt] = verein.updatedAt
@@ -116,9 +126,9 @@ class ExposedVereinRepository : VereinRepository {
} else {
VereinTable.insert {
it[id] = verein.vereinId
it[personId] = verein.personId
it[vereinsNummer] = verein.vereinsNummer
it[name] = verein.name
it[kurzname] = verein.kurzname
it[vereinName] = verein.vereinName
it[bundesland] = verein.bundesland
it[ort] = verein.ort
it[plz] = verein.plz
@@ -126,10 +136,9 @@ class ExposedVereinRepository : VereinRepository {
it[email] = verein.email
it[telefon] = verein.telefon
it[website] = verein.website
it[oepsRegionNummer] = verein.oepsRegionNummer
it[istVeranstalter] = verein.istVeranstalter
it[istAktiv] = verein.istAktiv
it[logoUrl] = verein.logoUrl
it[imageUrl] = verein.imageUrl
it[bemerkungen] = verein.bemerkungen
it[datenQuelle] = verein.datenQuelle.name
it[createdAt] = verein.createdAt
@@ -151,17 +160,16 @@ class ExposedVereinRepository : VereinRepository {
VereinTable.selectAll().where { VereinTable.vereinsNummer eq vereinsNummer }.any()
}
override suspend fun upsertByVereinsNummer(verein: DomVerein): DomVerein = DatabaseFactory.dbQuery {
override suspend fun upsertByVereinsNummer(verein: Verein): Verein = DatabaseFactory.dbQuery {
val existing = VereinTable.selectAll().where { VereinTable.vereinsNummer eq verein.vereinsNummer }
.map(::rowToDomVerein)
.map(::rowToVereinDomain)
.singleOrNull()
if (existing != null) {
val toUpdate = verein.copy(vereinId = existing.vereinId)
VereinTable.update({ VereinTable.id eq existing.vereinId }) {
it[vereinsNummer] = toUpdate.vereinsNummer
it[name] = toUpdate.name
it[kurzname] = toUpdate.kurzname
it[vereinName] = toUpdate.vereinName
it[bundesland] = toUpdate.bundesland
it[ort] = toUpdate.ort
it[plz] = toUpdate.plz
@@ -169,10 +177,9 @@ class ExposedVereinRepository : VereinRepository {
it[email] = toUpdate.email
it[telefon] = toUpdate.telefon
it[website] = toUpdate.website
it[oepsRegionNummer] = toUpdate.oepsRegionNummer
it[istVeranstalter] = toUpdate.istVeranstalter
it[istAktiv] = toUpdate.istAktiv
it[logoUrl] = toUpdate.logoUrl
it[imageUrl] = toUpdate.imageUrl
it[bemerkungen] = toUpdate.bemerkungen
it[datenQuelle] = toUpdate.datenQuelle.name
it[updatedAt] = toUpdate.updatedAt
@@ -1,32 +1,47 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
@file:OptIn(ExperimentalUuidApi::class)
package at.mocode.masterdata.infrastructure.persistence
package at.mocode.masterdata.infrastructure.persistence.verein
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.datetime.CurrentTimestamp
import org.jetbrains.exposed.v1.datetime.timestamp
import kotlin.uuid.ExperimentalUuidApi
/**
* Exposed-Tabellendefinition für die Verein-Entität.
*/
object VereinTable : Table("verein") {
val id = uuid("verein_id")
val personId = uuid("person_id").nullable()
// === ZNS.zip VEREIN01.DAT === ANFANG ===
val vereinsNummer = varchar("vereins_nummer", 10).uniqueIndex()
val name = varchar("name", 200)
val kurzname = varchar("kurzname", 100).nullable()
val bundesland = varchar("bundesland", 100).nullable()
val ort = varchar("ort", 100).nullable()
val plz = varchar("plz", 10).nullable()
val strasse = varchar("strasse", 200).nullable()
val vereinName = varchar("verein_name", 200)
// === ZNS.zip VEREIN01.DAT === ENDE ===
// Kontakt
val imageUrl = varchar("image_url", 255).nullable()
val email = varchar("email", 200).nullable()
val telefon = varchar("telefon", 50).nullable()
val website = varchar("website", 255).nullable()
val oepsRegionNummer = varchar("oeps_region_nummer", 10).nullable()
val istVeranstalter = bool("ist_veranstalter").default(false)
// Adresse
val strasse = varchar("strasse", 200).nullable()
val hausnummer = varchar("hausnummer", 10).nullable()
val plz = varchar("plz", 10).nullable()
val ort = varchar("ort", 100).nullable()
val bundesland = varchar("bundesland", 100).nullable()
// Status & Verwaltung
val istAktiv = bool("ist_aktiv").default(true)
val logoUrl = varchar("logo_url", 255).nullable()
val istVeranstalter = bool("ist_veranstalter").default(false)
val bemerkungen = text("bemerkungen").nullable()
val datenQuelle = varchar("daten_quelle", 50)
// Audit
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
@@ -2,7 +2,7 @@
package at.mocode.masterdata.infrastructure.persistence
import at.mocode.core.domain.model.LizenzKlasseE
import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.domain.model.SparteE
import at.mocode.masterdata.domain.model.LicenseMatrixEntry
import at.mocode.masterdata.domain.model.TurnierklasseDefinition
@@ -77,7 +77,7 @@ class RegulationSeedVerificationTest {
val oetoMatrix = listOf(
LicenseMatrixEntry(
sparte = SparteE.SPRINGEN,
lizenzKlasse = LizenzKlasseE.R1,
lizenzKlasse = ReiterLizenzKlasseE.R1,
maxTurnierklasseCode = "L",
validFrom = now,
createdAt = now,
@@ -85,7 +85,7 @@ class RegulationSeedVerificationTest {
),
LicenseMatrixEntry(
sparte = SparteE.SPRINGEN,
lizenzKlasse = LizenzKlasseE.R2,
lizenzKlasse = ReiterLizenzKlasseE.R2,
maxTurnierklasseCode = "M",
validFrom = now,
createdAt = now,
@@ -93,12 +93,12 @@ class RegulationSeedVerificationTest {
)
)
val r1Reiter = at.mocode.masterdata.domain.model.DomReiter(
val r1Reiter = at.mocode.masterdata.domain.model.Reiter(
personId = Uuid.random(),
satznummer = "123456",
nachname = "Müller",
vorname = "Hans",
lizenzKlasse = LizenzKlasseE.R1
lizenzKlasse = ReiterLizenzKlasseE.R1
)
val klasseL = TurnierklasseDefinition(