Refactor domain models (DomFunktionaer, DomReiter, DomPferd) for ZNS alignment: update properties, streamline validation logic, and enhance parser to support new format. Adjust controllers and repository methods accordingly.

This commit is contained in:
2026-04-05 08:21:11 +02:00
parent aba7b58dd4
commit a61dda69d1
27 changed files with 1006 additions and 1111 deletions
@@ -10,9 +10,7 @@ import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.DomFunktionaer
import at.mocode.masterdata.domain.repository.FunktionaerRepository
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.core.*
import org.jetbrains.exposed.v1.jdbc.*
import kotlin.uuid.Uuid
@@ -21,16 +19,13 @@ import kotlin.uuid.Uuid
*/
class ExposedFunktionaerRepository : FunktionaerRepository {
private fun rowToDomFunktionaer(row: ResultRow): DomFunktionaer {
private fun rowToDomFunktionaer(row: ResultRow, qualifikationen: List<String> = emptyList()): DomFunktionaer {
return DomFunktionaer(
funktionaerId = row[FunktionaerTable.id],
richterNummer = row[FunktionaerTable.richterNummer],
vorname = row[FunktionaerTable.vorname],
nachname = row[FunktionaerTable.nachname],
geburtsdatum = row[FunktionaerTable.geburtsdatum],
email = row[FunktionaerTable.email],
telefon = row[FunktionaerTable.telefon],
vereinsNummer = row[FunktionaerTable.vereinsNummer],
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]),
@@ -40,101 +35,78 @@ class ExposedFunktionaerRepository : FunktionaerRepository {
}
override suspend fun findById(id: Uuid): DomFunktionaer? = DatabaseFactory.dbQuery {
val qualifikationen = FunktionaerQualifikationTable
.selectAll().where { FunktionaerQualifikationTable.funktionaerId eq id }
.map { it[FunktionaerQualifikationTable.qualifikation] }
FunktionaerTable.selectAll().where { FunktionaerTable.id eq id }
.map(::rowToDomFunktionaer)
.map { rowToDomFunktionaer(it, qualifikationen) }
.singleOrNull()
}
override suspend fun findByRichterNummer(richterNummer: String): DomFunktionaer? = DatabaseFactory.dbQuery {
FunktionaerTable.selectAll().where { FunktionaerTable.richterNummer eq richterNummer }
.map(::rowToDomFunktionaer)
.singleOrNull()
}
override suspend fun findBySatz(satzID: String, satzNummer: Int): DomFunktionaer? = DatabaseFactory.dbQuery {
val row = FunktionaerTable.selectAll()
.where { (FunktionaerTable.satzID eq satzID) and (FunktionaerTable.satzNummer eq satzNummer) }
.singleOrNull() ?: return@dbQuery null
override suspend fun findByName(searchTerm: String, limit: Int): List<DomFunktionaer> = DatabaseFactory.dbQuery {
val pattern = "%$searchTerm%"
FunktionaerTable.selectAll()
.where { (FunktionaerTable.nachname like pattern) or (FunktionaerTable.vorname like pattern) }
.limit(limit)
.map(::rowToDomFunktionaer)
}
val qualifikationen = FunktionaerQualifikationTable
.selectAll().where { FunktionaerQualifikationTable.funktionaerId eq row[FunktionaerTable.id] }
.map { it[FunktionaerQualifikationTable.qualifikation] }
override suspend fun findByRolle(rolle: FunktionaerRolleE, activeOnly: Boolean): List<DomFunktionaer> =
DatabaseFactory.dbQuery {
// Rolle wird aktuell nicht in FunktionaerTable gespeichert.
// Falls benötigt, muss die Tabelle erweitert werden.
emptyList()
}
override suspend fun findByRichterQualifikation(
qualifikation: RichterQualifikationE,
activeOnly: Boolean
): List<DomFunktionaer> = DatabaseFactory.dbQuery {
// Qualifikationen werden aktuell nicht in FunktionaerTable gespeichert.
emptyList()
}
override suspend fun findBySparte(sparte: SparteE, activeOnly: Boolean): List<DomFunktionaer> =
DatabaseFactory.dbQuery {
emptyList()
}
override suspend fun findByVereinsNummer(vereinsNummer: String, activeOnly: Boolean): List<DomFunktionaer> =
DatabaseFactory.dbQuery {
val query = FunktionaerTable.selectAll().where { FunktionaerTable.vereinsNummer eq vereinsNummer }
if (activeOnly) {
query.andWhere { FunktionaerTable.istAktiv eq true }
}
query.map(::rowToDomFunktionaer)
}
override suspend fun findAllActive(limit: Int, offset: Int): List<DomFunktionaer> = DatabaseFactory.dbQuery {
FunktionaerTable.selectAll().where { FunktionaerTable.istAktiv eq true }
.limit(limit).offset(offset.toLong())
.map(::rowToDomFunktionaer)
rowToDomFunktionaer(row, qualifikationen)
}
override suspend fun findAll(limit: Int, offset: Int): List<DomFunktionaer> = DatabaseFactory.dbQuery {
FunktionaerTable.selectAll()
val funktionaere = FunktionaerTable.selectAll()
.limit(limit).offset(offset.toLong())
.map(::rowToDomFunktionaer)
.toList()
val ids = funktionaere.map { it[FunktionaerTable.id] }
val qualisMap = FunktionaerQualifikationTable
.selectAll().where { FunktionaerQualifikationTable.funktionaerId inList ids }
.groupBy({ it[FunktionaerQualifikationTable.funktionaerId] }) { it[FunktionaerQualifikationTable.qualifikation] }
funktionaere.map { row ->
rowToDomFunktionaer(row, qualisMap[row[FunktionaerTable.id]] ?: emptyList())
}
}
override suspend fun save(funktionaer: DomFunktionaer): DomFunktionaer = DatabaseFactory.dbQuery {
val exists = FunktionaerTable.selectAll().where { FunktionaerTable.id eq funktionaer.funktionaerId }.any()
if (exists) {
FunktionaerTable.update({ FunktionaerTable.id eq funktionaer.funktionaerId }) {
it[richterNummer] = funktionaer.richterNummer
it[vorname] = funktionaer.vorname
it[nachname] = funktionaer.nachname
it[geburtsdatum] = funktionaer.geburtsdatum
it[email] = funktionaer.email
it[telefon] = funktionaer.telefon
it[vereinsNummer] = funktionaer.vereinsNummer
it[satzID] = funktionaer.satzID
it[satzNummer] = funktionaer.satzNummer
it[name] = funktionaer.name
it[istAktiv] = funktionaer.istAktiv
it[bemerkungen] = funktionaer.bemerkungen
it[datenQuelle] = funktionaer.datenQuelle.name
it[updatedAt] = funktionaer.updatedAt
}
funktionaer
} else {
FunktionaerTable.insert {
it[id] = funktionaer.funktionaerId
it[richterNummer] = funktionaer.richterNummer
it[vorname] = funktionaer.vorname
it[nachname] = funktionaer.nachname
it[geburtsdatum] = funktionaer.geburtsdatum
it[email] = funktionaer.email
it[telefon] = funktionaer.telefon
it[vereinsNummer] = funktionaer.vereinsNummer
it[satzID] = funktionaer.satzID
it[satzNummer] = funktionaer.satzNummer
it[name] = funktionaer.name
it[istAktiv] = funktionaer.istAktiv
it[bemerkungen] = funktionaer.bemerkungen
it[datenQuelle] = funktionaer.datenQuelle.name
it[createdAt] = funktionaer.createdAt
it[updatedAt] = funktionaer.updatedAt
}
funktionaer
}
// Qualifikationen synchronisieren
FunktionaerQualifikationTable.deleteWhere { funktionaerId eq funktionaer.funktionaerId }
funktionaer.qualifikationen.forEach { quali ->
FunktionaerQualifikationTable.insert {
it[funktionaerId] = funktionaer.funktionaerId
it[qualifikation] = quali
}
}
funktionaer
}
override suspend fun delete(id: Uuid): Boolean = DatabaseFactory.dbQuery {
@@ -145,13 +117,9 @@ class ExposedFunktionaerRepository : FunktionaerRepository {
FunktionaerTable.selectAll().where { FunktionaerTable.istAktiv eq true }.count()
}
override suspend fun countByRichterQualifikation(qualifikation: RichterQualifikationE, activeOnly: Boolean): Long =
DatabaseFactory.dbQuery {
// Aktuell keine Qualifikations-Speicherung
0L
}
override suspend fun existsByRichterNummer(richterNummer: String): Boolean = DatabaseFactory.dbQuery {
FunktionaerTable.selectAll().where { FunktionaerTable.richterNummer eq richterNummer }.any()
override suspend fun existsBySatz(satzID: String, satzNummer: Int): Boolean = DatabaseFactory.dbQuery {
FunktionaerTable.selectAll()
.where { (FunktionaerTable.satzID eq satzID) and (FunktionaerTable.satzNummer eq satzNummer) }
.any()
}
}
@@ -4,14 +4,11 @@ package at.mocode.masterdata.infrastructure.persistence
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.LizenzKlasseE
import at.mocode.core.domain.model.SparteE
import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.DomReiter
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.core.like
import org.jetbrains.exposed.v1.core.or
import org.jetbrains.exposed.v1.jdbc.*
import kotlin.uuid.Uuid
@@ -20,133 +17,55 @@ import kotlin.uuid.Uuid
*/
class ExposedReiterRepository : ReiterRepository {
private fun rowToDomReiter(row: ResultRow, sparten: List<SparteE> = emptyList()): DomReiter {
private fun rowToDomReiter(row: ResultRow): DomReiter {
return DomReiter(
reiterId = row[ReiterTable.id],
personId = row[ReiterTable.personId],
satznummer = row[ReiterTable.satznummer],
nachname = row[ReiterTable.nachname],
vorname = row[ReiterTable.vorname],
geburtsdatum = row[ReiterTable.geburtsdatum],
lizenzNummer = row[ReiterTable.lizenzNummer],
lizenzKlasse = LizenzKlasseE.valueOf(row[ReiterTable.lizenzKlasse]),
lizenzSparten = sparten,
startkartAktiv = row[ReiterTable.startkartAktiv],
startkartSaison = row[ReiterTable.startkartSaison],
feiId = row[ReiterTable.feiId],
nation = row[ReiterTable.nation],
vereinsNummer = row[ReiterTable.vereinsNummer],
bundeslandNummer = row[ReiterTable.bundeslandNummer],
vereinsName = row[ReiterTable.vereinsName],
istGastreiter = row[ReiterTable.istGastreiter],
nation = row[ReiterTable.nation],
reiterLizenz = row[ReiterTable.reiterLizenz],
startkarte = row[ReiterTable.startkarte],
fahrLizenz = row[ReiterTable.fahrLizenz],
altersklasseJgJrU25 = row[ReiterTable.altersklasseJgJrU25],
altersklasseY = row[ReiterTable.altersklasseY],
mitgliedsNummer = row[ReiterTable.mitgliedsNummer],
telefonNummer = row[ReiterTable.telefonNummer],
kader = row[ReiterTable.kader],
lastPayYear = row[ReiterTable.lastPayYear],
geschlecht = row[ReiterTable.geschlecht],
geburtsdatum = row[ReiterTable.geburtsdatum],
feiId = row[ReiterTable.feiId],
sperrListe = row[ReiterTable.sperrListe],
lizenzInfo = row[ReiterTable.lizenzInfo],
lizenzKlasse = LizenzKlasseE.valueOf(row[ReiterTable.lizenzKlasse]),
istAktiv = row[ReiterTable.istAktiv],
bemerkungen = row[ReiterTable.bemerkungen],
datenQuelle = DatenQuelleE.valueOf(row[ReiterTable.datenQuelle]),
createdAt = row[ReiterTable.createdAt],
updatedAt = row[ReiterTable.updatedAt]
)
}
private fun getSpartenForReiter(reiterId: Uuid): List<SparteE> {
return ReiterSparteTable.selectAll().where { ReiterSparteTable.reiterId eq reiterId }
.map { SparteE.valueOf(it[ReiterSparteTable.sparte]) }
}
override suspend fun findById(id: Uuid): DomReiter? = DatabaseFactory.dbQuery {
ReiterTable.selectAll().where { ReiterTable.id eq id }
.map { rowToDomReiter(it, getSpartenForReiter(id)) }
.map { rowToDomReiter(it) }
.singleOrNull()
}
override suspend fun findBySatznummer(satznummer: String): DomReiter? = DatabaseFactory.dbQuery {
override suspend fun findBySatznummer(satznummer: String?): DomReiter? = DatabaseFactory.dbQuery {
ReiterTable.selectAll().where { ReiterTable.satznummer eq satznummer }
.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
.map { row -> rowToDomReiter(row) }
.singleOrNull()
}
override suspend fun findByFeiId(feiId: String): DomReiter? = DatabaseFactory.dbQuery {
ReiterTable.selectAll().where { ReiterTable.feiId eq feiId }
.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
.singleOrNull()
}
override suspend fun findByName(searchTerm: String, limit: Int): List<DomReiter> = DatabaseFactory.dbQuery {
val pattern = "%$searchTerm%"
ReiterTable.selectAll().where { (ReiterTable.nachname like pattern) or (ReiterTable.vorname like pattern) }
.limit(limit)
.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
}
override suspend fun findByVereinsNummer(vereinsNummer: String, activeOnly: Boolean): List<DomReiter> =
DatabaseFactory.dbQuery {
val query = ReiterTable.selectAll().where { ReiterTable.vereinsNummer eq vereinsNummer }
if (activeOnly) {
query.andWhere { ReiterTable.istAktiv eq true }
}
query.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
}
override suspend fun findByLizenzKlasse(lizenzKlasse: LizenzKlasseE, activeOnly: Boolean): List<DomReiter> =
DatabaseFactory.dbQuery {
val query = ReiterTable.selectAll().where { ReiterTable.lizenzKlasse eq lizenzKlasse.name }
if (activeOnly) {
query.andWhere { ReiterTable.istAktiv eq true }
}
query.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
}
override suspend fun findBySparte(sparte: SparteE, activeOnly: Boolean): List<DomReiter> = DatabaseFactory.dbQuery {
val query = (ReiterTable innerJoin ReiterSparteTable)
.selectAll().where { ReiterSparteTable.sparte eq sparte.name }
if (activeOnly) {
query.andWhere { ReiterTable.istAktiv eq true }
}
query.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
}
override suspend fun findGastreiter(activeOnly: Boolean): List<DomReiter> = DatabaseFactory.dbQuery {
val query = ReiterTable.selectAll().where { ReiterTable.istGastreiter eq true }
if (activeOnly) {
query.andWhere { ReiterTable.istAktiv eq true }
}
query.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
}
override suspend fun findAllActive(limit: Int, offset: Int): List<DomReiter> = DatabaseFactory.dbQuery {
ReiterTable.selectAll().where { ReiterTable.istAktiv eq true }
.limit(limit).offset(offset.toLong())
.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
}
override suspend fun findAll(limit: Int, offset: Int): List<DomReiter> = DatabaseFactory.dbQuery {
ReiterTable.selectAll()
.limit(limit).offset(offset.toLong())
.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
.map { row -> rowToDomReiter(row) }
}
override suspend fun save(reiter: DomReiter): DomReiter = DatabaseFactory.dbQuery {
@@ -157,17 +76,26 @@ class ExposedReiterRepository : ReiterRepository {
it[satznummer] = reiter.satznummer
it[nachname] = reiter.nachname
it[vorname] = reiter.vorname
it[geburtsdatum] = reiter.geburtsdatum
it[lizenzNummer] = reiter.lizenzNummer
it[lizenzKlasse] = reiter.lizenzKlasse.name
it[startkartAktiv] = reiter.startkartAktiv
it[startkartSaison] = reiter.startkartSaison
it[feiId] = reiter.feiId
it[nation] = reiter.nation
it[vereinsNummer] = reiter.vereinsNummer
it[bundeslandNummer] = reiter.bundeslandNummer
it[vereinsName] = reiter.vereinsName
it[istGastreiter] = reiter.istGastreiter
it[nation] = reiter.nation
it[reiterLizenz] = reiter.reiterLizenz
it[startkarte] = reiter.startkarte
it[fahrLizenz] = reiter.fahrLizenz
it[altersklasseJgJrU25] = reiter.altersklasseJgJrU25
it[altersklasseY] = reiter.altersklasseY
it[mitgliedsNummer] = reiter.mitgliedsNummer
it[telefonNummer] = reiter.telefonNummer
it[kader] = reiter.kader
it[lastPayYear] = reiter.lastPayYear
it[geschlecht] = reiter.geschlecht
it[geburtsdatum] = reiter.geburtsdatum
it[feiId] = reiter.feiId
it[sperrListe] = reiter.sperrListe
it[lizenzInfo] = reiter.lizenzInfo
it[lizenzKlasse] = reiter.lizenzKlasse.name
it[istAktiv] = reiter.istAktiv
it[bemerkungen] = reiter.bemerkungen
it[datenQuelle] = reiter.datenQuelle.name
it[updatedAt] = reiter.updatedAt
}
@@ -178,33 +106,32 @@ class ExposedReiterRepository : ReiterRepository {
it[satznummer] = reiter.satznummer
it[nachname] = reiter.nachname
it[vorname] = reiter.vorname
it[geburtsdatum] = reiter.geburtsdatum
it[lizenzNummer] = reiter.lizenzNummer
it[lizenzKlasse] = reiter.lizenzKlasse.name
it[startkartAktiv] = reiter.startkartAktiv
it[startkartSaison] = reiter.startkartSaison
it[feiId] = reiter.feiId
it[nation] = reiter.nation
it[vereinsNummer] = reiter.vereinsNummer
it[bundeslandNummer] = reiter.bundeslandNummer
it[vereinsName] = reiter.vereinsName
it[istGastreiter] = reiter.istGastreiter
it[nation] = reiter.nation
it[reiterLizenz] = reiter.reiterLizenz
it[startkarte] = reiter.startkarte
it[fahrLizenz] = reiter.fahrLizenz
it[altersklasseJgJrU25] = reiter.altersklasseJgJrU25
it[altersklasseY] = reiter.altersklasseY
it[mitgliedsNummer] = reiter.mitgliedsNummer
it[telefonNummer] = reiter.telefonNummer
it[kader] = reiter.kader
it[lastPayYear] = reiter.lastPayYear
it[geschlecht] = reiter.geschlecht
it[geburtsdatum] = reiter.geburtsdatum
it[feiId] = reiter.feiId
it[sperrListe] = reiter.sperrListe
it[lizenzInfo] = reiter.lizenzInfo
it[lizenzKlasse] = reiter.lizenzKlasse.name
it[istAktiv] = reiter.istAktiv
it[bemerkungen] = reiter.bemerkungen
it[datenQuelle] = reiter.datenQuelle.name
it[createdAt] = reiter.createdAt
it[updatedAt] = reiter.updatedAt
}
}
// Sparten aktualisieren
ReiterSparteTable.deleteWhere { ReiterSparteTable.reiterId eq reiter.reiterId }
reiter.lizenzSparten.forEach { sparte ->
ReiterSparteTable.insert {
it[ReiterSparteTable.id] = Uuid.random()
it[ReiterSparteTable.reiterId] = reiter.reiterId
it[ReiterSparteTable.sparte] = sparte.name
}
}
reiter
}
@@ -221,12 +148,7 @@ class ExposedReiterRepository : ReiterRepository {
}
override suspend fun upsertBySatznummer(reiter: DomReiter): DomReiter = DatabaseFactory.dbQuery {
val existing = ReiterTable.selectAll().where { ReiterTable.satznummer eq reiter.satznummer }
.map { row ->
val id = row[ReiterTable.id]
rowToDomReiter(row, getSpartenForReiter(id))
}
.singleOrNull()
val existing = findBySatznummer(reiter.satznummer)
if (existing != null) {
val toUpdate = reiter.copy(reiterId = existing.reiterId)
@@ -13,13 +13,9 @@ import org.jetbrains.exposed.v1.datetime.timestamp
*/
object FunktionaerTable : Table("funktionaer") {
val id = uuid("funktionaer_id")
val richterNummer = varchar("richter_nummer", 10).nullable().uniqueIndex()
val vorname = varchar("vorname", 100)
val nachname = varchar("nachname", 100)
val geburtsdatum = date("geburtsdatum").nullable()
val email = varchar("email", 200).nullable()
val telefon = varchar("telefon", 50).nullable()
val vereinsNummer = varchar("vereins_nummer", 10).nullable()
val satzID = varchar("satz_id", 1).nullable()
val satzNummer = integer("satz_nummer").nullable()
val name = varchar("name", 200).nullable()
val istAktiv = bool("ist_aktiv").default(true)
val bemerkungen = text("bemerkungen").nullable()
val datenQuelle = varchar("daten_quelle", 50)
@@ -27,4 +23,18 @@ object FunktionaerTable : Table("funktionaer") {
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
index("idx_funktionaer_satz", isUnique = true, satzID, satzNummer)
}
}
/**
* Exposed-Tabellendefinition für die Qualifikationen eines Funktionärs.
*/
object FunktionaerQualifikationTable : Table("funktionaer_qualifikation") {
val funktionaerId = uuid("funktionaer_id").references(FunktionaerTable.id)
val qualifikation = varchar("qualifikation", 20)
override val primaryKey = PrimaryKey(funktionaerId, qualifikation)
}
@@ -7,36 +7,33 @@ 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.repository.HorseRepository
import org.jetbrains.exposed.v1.core.*
import org.jetbrains.exposed.v1.jdbc.*
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.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.Uuid
/**
* Exposed-basierte Implementierung des Horse-Repositorys.
*/
class HorseRepositoryImpl : HorseRepository {
private fun rowToDomPferd(row: ResultRow): DomPferd {
return DomPferd(
pferdId = row[HorseTable.id],
kopfnummer = row[HorseTable.kopfnummer],
pferdeName = row[HorseTable.pferdeName],
geschlecht = PferdeGeschlechtE.valueOf(row[HorseTable.geschlecht]),
geburtsdatum = row[HorseTable.geburtsdatum],
rasse = row[HorseTable.rasse],
farbe = row[HorseTable.farbe],
besitzerId = row[HorseTable.besitzerId],
verantwortlichePersonId = row[HorseTable.verantwortlichePersonId],
zuechterName = row[HorseTable.zuechterName],
zuchtbuchNummer = row[HorseTable.zuchtbuchNummer],
lebensnummer = row[HorseTable.lebensnummer],
chipNummer = row[HorseTable.chipNummer],
passNummer = row[HorseTable.passNummer],
oepsNummer = row[HorseTable.oepsNummer],
feiNummer = row[HorseTable.feiNummer],
vaterName = row[HorseTable.vaterName],
mutterName = row[HorseTable.mutterName],
mutterVaterName = row[HorseTable.mutterVaterName],
stockmass = row[HorseTable.stockmass],
geschlecht = PferdeGeschlechtE.valueOf(row[HorseTable.geschlecht]),
geburtsjahr = row[HorseTable.geburtsjahr],
farbe = row[HorseTable.farbe],
abstammung = row[HorseTable.abstammung],
vereinNummer = row[HorseTable.vereinNummer],
lastPayYear = row[HorseTable.lastPayYear],
verantwortlichePersonId = row[HorseTable.verantwortlichePersonId],
vater = row[HorseTable.vater],
feiPass = row[HorseTable.feiPass],
satznummer = row[HorseTable.satznummer],
istAktiv = row[HorseTable.istAktiv],
bemerkungen = row[HorseTable.bemerkungen],
datenQuelle = DatenQuelleE.valueOf(row[HorseTable.datenQuelle]),
@@ -57,28 +54,15 @@ class HorseRepositoryImpl : HorseRepository {
.singleOrNull()
}
override suspend fun findByChipNummer(chipNummer: String): DomPferd? = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.chipNummer eq chipNummer }
override suspend fun findBySatznummer(satznummer: String): DomPferd? = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.satznummer eq satznummer }
.map(::rowToDomPferd)
.singleOrNull()
}
override suspend fun findByPassNummer(passNummer: String): DomPferd? = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.passNummer eq passNummer }
override suspend fun findByKopfnummer(kopfnummer: String): List<DomPferd> = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.kopfnummer eq kopfnummer }
.map(::rowToDomPferd)
.singleOrNull()
}
override suspend fun findByOepsNummer(oepsNummer: String): DomPferd? = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.oepsNummer eq oepsNummer }
.map(::rowToDomPferd)
.singleOrNull()
}
override suspend fun findByFeiNummer(feiNummer: String): DomPferd? = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.feiNummer eq feiNummer }
.map(::rowToDomPferd)
.singleOrNull()
}
override suspend fun findByName(searchTerm: String, limit: Int): List<DomPferd> = DatabaseFactory.dbQuery {
@@ -88,113 +72,29 @@ class HorseRepositoryImpl : HorseRepository {
.map(::rowToDomPferd)
}
override suspend fun findByOwnerId(ownerId: Uuid, activeOnly: Boolean): List<DomPferd> = DatabaseFactory.dbQuery {
val query = HorseTable.selectAll().where { HorseTable.besitzerId eq ownerId }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.map(::rowToDomPferd)
}
override suspend fun findByResponsiblePersonId(responsiblePersonId: Uuid, activeOnly: Boolean): List<DomPferd> =
DatabaseFactory.dbQuery {
val query = HorseTable.selectAll().where { HorseTable.verantwortlichePersonId eq responsiblePersonId }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.map(::rowToDomPferd)
}
override suspend fun findByGeschlecht(
geschlecht: PferdeGeschlechtE,
activeOnly: Boolean,
limit: Int
): List<DomPferd> = DatabaseFactory.dbQuery {
val query = HorseTable.selectAll().where { HorseTable.geschlecht eq geschlecht.name }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.limit(limit).map(::rowToDomPferd)
}
override suspend fun findByRasse(rasse: String, activeOnly: Boolean, limit: Int): List<DomPferd> =
DatabaseFactory.dbQuery {
val query = HorseTable.selectAll().where { HorseTable.rasse eq rasse }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.limit(limit).map(::rowToDomPferd)
}
override suspend fun findByBirthYear(birthYear: Int, activeOnly: Boolean): List<DomPferd> = DatabaseFactory.dbQuery {
// In Exposed v1 gibt es kein direktes year() für date Spalten ohne extra Extension.
// Wir suchen im Datumsbereich nach.
val startDate = kotlinx.datetime.LocalDate(birthYear, 1, 1)
val endDate = kotlinx.datetime.LocalDate(birthYear, 12, 31)
val query = HorseTable.selectAll()
.where { (HorseTable.geburtsdatum greaterEq startDate) and (HorseTable.geburtsdatum lessEq endDate) }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.map(::rowToDomPferd)
}
override suspend fun findByBirthYearRange(fromYear: Int, toYear: Int, activeOnly: Boolean): List<DomPferd> =
DatabaseFactory.dbQuery {
val startDate = kotlinx.datetime.LocalDate(fromYear, 1, 1)
val endDate = kotlinx.datetime.LocalDate(toYear, 12, 31)
val query = HorseTable.selectAll()
.where { (HorseTable.geburtsdatum greaterEq startDate) and (HorseTable.geburtsdatum lessEq endDate) }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.map(::rowToDomPferd)
}
override suspend fun findAllActive(limit: Int): List<DomPferd> = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.istAktiv eq true }
.limit(limit)
.map(::rowToDomPferd)
}
override suspend fun findOepsRegistered(activeOnly: Boolean): List<DomPferd> = DatabaseFactory.dbQuery {
val query = HorseTable.selectAll().where { HorseTable.oepsNummer.isNotNull() }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.map(::rowToDomPferd)
}
override suspend fun findFeiRegistered(activeOnly: Boolean): List<DomPferd> = DatabaseFactory.dbQuery {
val query = HorseTable.selectAll().where { HorseTable.feiNummer.isNotNull() }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.map(::rowToDomPferd)
}
override suspend fun save(horse: DomPferd): DomPferd = DatabaseFactory.dbQuery {
val exists = HorseTable.selectAll().where { HorseTable.id eq horse.pferdId }.any()
if (exists) {
HorseTable.update({ HorseTable.id eq horse.pferdId }) {
it[kopfnummer] = horse.kopfnummer
it[pferdeName] = horse.pferdeName
it[geschlecht] = horse.geschlecht.name
it[geburtsdatum] = horse.geburtsdatum
it[rasse] = horse.rasse
it[farbe] = horse.farbe
it[besitzerId] = horse.besitzerId
it[verantwortlichePersonId] = horse.verantwortlichePersonId
it[zuechterName] = horse.zuechterName
it[zuchtbuchNummer] = horse.zuchtbuchNummer
it[lebensnummer] = horse.lebensnummer
it[chipNummer] = horse.chipNummer
it[passNummer] = horse.passNummer
it[oepsNummer] = horse.oepsNummer
it[feiNummer] = horse.feiNummer
it[vaterName] = horse.vaterName
it[mutterName] = horse.mutterName
it[mutterVaterName] = horse.mutterVaterName
it[stockmass] = horse.stockmass
it[geschlecht] = horse.geschlecht.name
it[geburtsjahr] = horse.geburtsjahr
it[farbe] = horse.farbe
it[abstammung] = horse.abstammung
it[vereinNummer] = horse.vereinNummer
it[lastPayYear] = horse.lastPayYear
it[verantwortlichePersonId] = horse.verantwortlichePersonId
it[vater] = horse.vater
it[feiPass] = horse.feiPass
it[satznummer] = horse.satznummer
it[istAktiv] = horse.istAktiv
it[bemerkungen] = horse.bemerkungen
it[datenQuelle] = horse.datenQuelle.name
@@ -204,24 +104,19 @@ class HorseRepositoryImpl : HorseRepository {
} else {
HorseTable.insert {
it[id] = horse.pferdId
it[kopfnummer] = horse.kopfnummer
it[pferdeName] = horse.pferdeName
it[geschlecht] = horse.geschlecht.name
it[geburtsdatum] = horse.geburtsdatum
it[rasse] = horse.rasse
it[farbe] = horse.farbe
it[besitzerId] = horse.besitzerId
it[verantwortlichePersonId] = horse.verantwortlichePersonId
it[zuechterName] = horse.zuechterName
it[zuchtbuchNummer] = horse.zuchtbuchNummer
it[lebensnummer] = horse.lebensnummer
it[chipNummer] = horse.chipNummer
it[passNummer] = horse.passNummer
it[oepsNummer] = horse.oepsNummer
it[feiNummer] = horse.feiNummer
it[vaterName] = horse.vaterName
it[mutterName] = horse.mutterName
it[mutterVaterName] = horse.mutterVaterName
it[stockmass] = horse.stockmass
it[geschlecht] = horse.geschlecht.name
it[geburtsjahr] = horse.geburtsjahr
it[farbe] = horse.farbe
it[abstammung] = horse.abstammung
it[vereinNummer] = horse.vereinNummer
it[lastPayYear] = horse.lastPayYear
it[verantwortlichePersonId] = horse.verantwortlichePersonId
it[vater] = horse.vater
it[feiPass] = horse.feiPass
it[satznummer] = horse.satznummer
it[istAktiv] = horse.istAktiv
it[bemerkungen] = horse.bemerkungen
it[datenQuelle] = horse.datenQuelle.name
@@ -240,50 +135,10 @@ class HorseRepositoryImpl : HorseRepository {
HorseTable.selectAll().where { HorseTable.lebensnummer eq lebensnummer }.any()
}
override suspend fun existsByChipNummer(chipNummer: String): Boolean = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.chipNummer eq chipNummer }.any()
}
override suspend fun existsByPassNummer(passNummer: String): Boolean = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.passNummer eq passNummer }.any()
}
override suspend fun existsByOepsNummer(oepsNummer: String): Boolean = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.oepsNummer eq oepsNummer }.any()
}
override suspend fun existsByFeiNummer(feiNummer: String): Boolean = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.feiNummer eq feiNummer }.any()
}
override suspend fun countActive(): Long = DatabaseFactory.dbQuery {
HorseTable.selectAll().where { HorseTable.istAktiv eq true }.count()
}
override suspend fun countByOwnerId(ownerId: Uuid, activeOnly: Boolean): Long = DatabaseFactory.dbQuery {
val query = HorseTable.selectAll().where { HorseTable.besitzerId eq ownerId }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.count()
}
override suspend fun countOepsRegistered(activeOnly: Boolean): Long = DatabaseFactory.dbQuery {
val query = HorseTable.selectAll().where { HorseTable.oepsNummer.isNotNull() }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.count()
}
override suspend fun countFeiRegistered(activeOnly: Boolean): Long = DatabaseFactory.dbQuery {
val query = HorseTable.selectAll().where { HorseTable.feiNummer.isNotNull() }
if (activeOnly) {
query.andWhere { HorseTable.istAktiv eq true }
}
query.count()
}
override suspend fun upsertByLebensnummer(horse: DomPferd): DomPferd = DatabaseFactory.dbQuery {
val lebensnummer = horse.lebensnummer ?: return@dbQuery save(horse)
@@ -294,24 +149,19 @@ class HorseRepositoryImpl : HorseRepository {
if (existing != null) {
val toUpdate = horse.copy(pferdId = existing.pferdId)
HorseTable.update({ HorseTable.id eq existing.pferdId }) {
it[kopfnummer] = toUpdate.kopfnummer
it[pferdeName] = toUpdate.pferdeName
it[geschlecht] = toUpdate.geschlecht.name
it[geburtsdatum] = toUpdate.geburtsdatum
it[rasse] = toUpdate.rasse
it[farbe] = toUpdate.farbe
it[besitzerId] = toUpdate.besitzerId
it[verantwortlichePersonId] = toUpdate.verantwortlichePersonId
it[zuechterName] = toUpdate.zuechterName
it[zuchtbuchNummer] = toUpdate.zuchtbuchNummer
it[HorseTable.lebensnummer] = toUpdate.lebensnummer
it[chipNummer] = toUpdate.chipNummer
it[passNummer] = toUpdate.passNummer
it[oepsNummer] = toUpdate.oepsNummer
it[feiNummer] = toUpdate.feiNummer
it[vaterName] = toUpdate.vaterName
it[mutterName] = toUpdate.mutterName
it[mutterVaterName] = toUpdate.mutterVaterName
it[stockmass] = toUpdate.stockmass
it[geschlecht] = toUpdate.geschlecht.name
it[geburtsjahr] = toUpdate.geburtsjahr
it[farbe] = toUpdate.farbe
it[abstammung] = toUpdate.abstammung
it[vereinNummer] = toUpdate.vereinNummer
it[lastPayYear] = toUpdate.lastPayYear
it[verantwortlichePersonId] = toUpdate.verantwortlichePersonId
it[vater] = toUpdate.vater
it[feiPass] = toUpdate.feiPass
it[satznummer] = toUpdate.satznummer
it[istAktiv] = toUpdate.istAktiv
it[bemerkungen] = toUpdate.bemerkungen
it[datenQuelle] = toUpdate.datenQuelle.name
@@ -322,4 +172,68 @@ class HorseRepositoryImpl : HorseRepository {
save(horse)
}
}
override suspend fun upsertBySatznummer(horse: DomPferd): DomPferd = DatabaseFactory.dbQuery {
val satznummer = horse.satznummer ?: return@dbQuery save(horse)
val existing = HorseTable.selectAll().where { HorseTable.satznummer eq satznummer }
.map(::rowToDomPferd)
.singleOrNull()
if (existing != null) {
val toUpdate = horse.copy(pferdId = existing.pferdId)
HorseTable.update({ HorseTable.id eq existing.pferdId }) {
it[kopfnummer] = toUpdate.kopfnummer
it[pferdeName] = toUpdate.pferdeName
it[lebensnummer] = toUpdate.lebensnummer
it[geschlecht] = toUpdate.geschlecht.name
it[geburtsjahr] = toUpdate.geburtsjahr
it[farbe] = toUpdate.farbe
it[abstammung] = toUpdate.abstammung
it[vereinNummer] = toUpdate.vereinNummer
it[lastPayYear] = toUpdate.lastPayYear
it[verantwortlichePersonId] = toUpdate.verantwortlichePersonId
it[vater] = toUpdate.vater
it[feiPass] = toUpdate.feiPass
it[HorseTable.satznummer] = toUpdate.satznummer
it[istAktiv] = toUpdate.istAktiv
it[bemerkungen] = toUpdate.bemerkungen
it[datenQuelle] = toUpdate.datenQuelle.name
it[updatedAt] = toUpdate.updatedAt
}
toUpdate
} else {
save(horse)
}
}
// 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> =
emptyList()
override suspend fun findByGeschlecht(
geschlecht: PferdeGeschlechtE,
activeOnly: Boolean,
limit: Int
): List<DomPferd> = 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> =
emptyList()
override suspend fun findOepsRegistered(activeOnly: Boolean): List<DomPferd> = emptyList()
override suspend fun findFeiRegistered(activeOnly: Boolean): List<DomPferd> = 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
override suspend fun existsByFeiNummer(feiNummer: String): Boolean = false
override suspend fun countByOwnerId(ownerId: Uuid, activeOnly: Boolean): Long = 0
override suspend fun countOepsRegistered(activeOnly: Boolean): Long = 0
override suspend fun countFeiRegistered(activeOnly: Boolean): Long = 0
}
@@ -4,32 +4,27 @@ package at.mocode.masterdata.infrastructure.persistence
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
/**
* Exposed-Tabellendefinition für die Pferd-Entität.
* Exposed-Tabellendefinition für die Pferd-Entität basierend auf PFERDE01.DAT.
*/
object HorseTable : Table("horse") {
val id = uuid("horse_id")
val kopfnummer = varchar("kopfnummer", 4).nullable().index()
val pferdeName = varchar("pferde_name", 200).index()
val geschlecht = varchar("geschlecht", 20)
val geburtsdatum = date("geburtsdatum").nullable()
val rasse = varchar("rasse", 100).nullable()
val farbe = varchar("farbe", 100).nullable()
val besitzerId = uuid("besitzer_id").nullable()
val verantwortlichePersonId = uuid("verantwortliche_person_id").nullable()
val zuechterName = varchar("zuechter_name", 200).nullable()
val zuchtbuchNummer = varchar("zuchtbuch_nummer", 50).nullable()
val lebensnummer = varchar("lebensnummer", 50).nullable().index()
val chipNummer = varchar("chip_nummer", 50).nullable()
val passNummer = varchar("pass_nummer", 50).nullable()
val oepsNummer = varchar("oeps_nummer", 50).nullable()
val feiNummer = varchar("fei_nummer", 50).nullable()
val vaterName = varchar("vater_name", 200).nullable()
val mutterName = varchar("mutter_name", 200).nullable()
val mutterVaterName = varchar("mutter_vater_name", 200).nullable()
val stockmass = integer("stockmass").nullable()
val geschlecht = varchar("geschlecht", 20)
val geburtsjahr = integer("geburtsjahr").nullable()
val farbe = varchar("farbe", 100).nullable()
val abstammung = varchar("abstammung", 100).nullable()
val vereinNummer = integer("verein_nummer").nullable()
val lastPayYear = integer("last_pay_year").nullable()
val verantwortlichePersonId = varchar("verantwortliche_person_id", 100).nullable()
val vater = varchar("vater", 200).nullable()
val feiPass = varchar("fei_pass", 50).nullable()
val satznummer = varchar("satznummer", 10).nullable()
val istAktiv = bool("ist_aktiv").default(true)
val bemerkungen = text("bemerkungen").nullable()
val datenQuelle = varchar("daten_quelle", 50)
@@ -37,4 +32,8 @@ object HorseTable : Table("horse") {
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
index("idx_horse_satznummer", isUnique = true, satznummer)
}
}
@@ -2,6 +2,7 @@
package at.mocode.masterdata.infrastructure.persistence
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
@@ -13,20 +14,30 @@ import org.jetbrains.exposed.v1.datetime.timestamp
object ReiterTable : Table("reiter") {
val id = uuid("reiter_id")
val personId = uuid("person_id")
val satznummer = varchar("satznummer", 10).uniqueIndex()
val lizenzNummer = varchar("lizenz_nummer", 20).nullable()
val lizenzKlasse = varchar("lizenz_klasse", 20)
val startkartAktiv = bool("startkart_aktiv").default(false)
val startkartSaison = integer("startkart_saison").nullable()
val feiId = varchar("fei_id", 20).nullable()
val nation = varchar("nation", 3).nullable()
val satznummer = varchar("satznummer", 10).nullable()
val nachname = varchar("nachname", 100)
val vorname = varchar("vorname", 100)
val geburtsdatum = date("geburtsdatum").nullable()
val vereinsNummer = varchar("vereins_nummer", 10).nullable()
val bundeslandNummer = integer("bundesland_nummer").nullable()
val vereinsName = varchar("vereins_name", 200).nullable()
val istGastreiter = bool("ist_gastreiter").default(false)
val nation = varchar("nation", 10).nullable()
val reiterLizenz = varchar("reiter_lizenz", 20).nullable()
val startkarte = varchar("startkarte", 20).nullable()
val fahrLizenz = varchar("fahr_lizenz", 20).nullable()
val altersklasseJgJrU25 = varchar("altersklasse_jg_jr_u25", 10).nullable()
val altersklasseY = varchar("altersklasse_y", 10).nullable()
val mitgliedsNummer = integer("mitglieds_nummer").nullable()
val telefonNummer = varchar("telefon_nummer", 50).nullable()
val kader = varchar("kader", 50).nullable()
val lastPayYear = integer("last_pay_year").nullable()
val geschlecht = varchar("geschlecht", 10).nullable()
val geburtsdatum = date("geburtsdatum").nullable()
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)
val istAktiv = bool("ist_aktiv").default(true)
val bemerkungen = text("bemerkungen").nullable()
val datenQuelle = varchar("daten_quelle", 50)
val createdAt = timestamp("created_at").defaultExpression(CurrentTimestamp)
val updatedAt = timestamp("updated_at").defaultExpression(CurrentTimestamp)
@@ -98,9 +98,7 @@ class RegulationSeedVerificationTest {
satznummer = "123456",
nachname = "Müller",
vorname = "Hans",
lizenzKlasse = LizenzKlasseE.R1,
lizenzSparten = listOf(SparteE.SPRINGEN),
startkartAktiv = true
lizenzKlasse = LizenzKlasseE.R1
)
val klasseL = TurnierklasseDefinition(