feat(masterdata): add controllers, services, and repositories for Reiter, Horse, and Verein domains
- Introduced entities `ReiterController`, `HorseController`, and `VereinController`, with associated REST routes. - Implemented upsert functionality for `Reiter`, `Horse`, and `Verein` repositories. - Added services for `Altersklasse` calculations and integrated them into the domain layer. - Updated database schema to include `ReiterTable`, `HorseTable`, `VereinTable`, and `FunktionaerTable`. - Refactored `masterdataApiModule` to register new domain controllers. - Adjusted Ktor server and Spring configurations to support new domains. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
parent
c576bbd6af
commit
0c870ba2e3
|
|
@ -1,24 +1,24 @@
|
|||
package at.mocode.masterdata.api
|
||||
|
||||
import at.mocode.masterdata.api.plugins.IdempotencyPlugin
|
||||
import at.mocode.masterdata.api.rest.AltersklasseController
|
||||
import at.mocode.masterdata.api.rest.BundeslandController
|
||||
import at.mocode.masterdata.api.rest.CountryController
|
||||
import at.mocode.masterdata.api.rest.PlatzController
|
||||
import io.ktor.server.application.Application
|
||||
import io.ktor.server.routing.routing
|
||||
import at.mocode.masterdata.api.rest.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
/**
|
||||
* Ktor-Modul für den Masterdata-Bounded-Context.
|
||||
*
|
||||
* - Installiert das IdempotencyPlugin (Header „Idempotency-Key“) global.
|
||||
* - Registriert alle Masterdata-Routen (Country, Bundesland, Altersklasse, Platz).
|
||||
* - Registriert alle Masterdata-Routen (Country, Bundesland, Altersklasse, Platz, Reiter, Horse, Verein).
|
||||
*/
|
||||
fun Application.masterdataApiModule(
|
||||
countryController: CountryController,
|
||||
bundeslandController: BundeslandController,
|
||||
altersklasseController: AltersklasseController,
|
||||
platzController: PlatzController
|
||||
platzController: PlatzController,
|
||||
reiterController: ReiterController,
|
||||
horseController: HorseController,
|
||||
vereinController: VereinController
|
||||
) {
|
||||
// Installiere das Idempotency-Plugin global für alle Routen
|
||||
IdempotencyPlugin.install(this)
|
||||
|
|
@ -29,5 +29,8 @@ fun Application.masterdataApiModule(
|
|||
with(bundeslandController) { registerRoutes() }
|
||||
with(altersklasseController) { registerRoutes() }
|
||||
with(platzController) { registerRoutes() }
|
||||
with(reiterController) { registerRoutes() }
|
||||
with(horseController) { registerRoutes() }
|
||||
with(vereinController) { registerRoutes() }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.masterdata.api.rest
|
||||
|
||||
import at.mocode.core.domain.serialization.InstantSerializer
|
||||
import at.mocode.core.domain.serialization.LocalDateSerializer
|
||||
import at.mocode.masterdata.domain.model.DomPferd
|
||||
import at.mocode.masterdata.domain.repository.HorseRepository
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.time.Instant
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Controller für Pferde-bezogene REST-Endpunkte.
|
||||
*/
|
||||
class HorseController(private val horseRepository: HorseRepository) {
|
||||
|
||||
@Serializable
|
||||
data class HorseDto(
|
||||
val pferdId: String,
|
||||
val pferdeName: String,
|
||||
val geschlecht: String,
|
||||
@Serializable(with = LocalDateSerializer::class)
|
||||
val geburtsdatum: LocalDate? = null,
|
||||
val rasse: String? = null,
|
||||
val lebensnummer: String? = null,
|
||||
val oepsNummer: String? = null,
|
||||
val feiNummer: String? = null,
|
||||
val istAktiv: Boolean,
|
||||
@Serializable(with = InstantSerializer::class)
|
||||
val updatedAt: Instant
|
||||
)
|
||||
|
||||
fun Route.registerRoutes() {
|
||||
route("/horse") {
|
||||
/**
|
||||
* Sucht Pferde nach Name.
|
||||
*/
|
||||
get("/search") {
|
||||
val query = call.request.queryParameters["q"] ?: ""
|
||||
val results = horseRepository.findByName(query)
|
||||
call.respond(results.map { it.toDto() })
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft ein spezifisches Pferd ab.
|
||||
*/
|
||||
get("/{id}") {
|
||||
val idStr = call.parameters["id"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||
val id = try {
|
||||
Uuid.parse(idStr)
|
||||
} catch (e: Exception) {
|
||||
return@get call.respond(HttpStatusCode.BadRequest)
|
||||
}
|
||||
|
||||
val pferd = horseRepository.findById(id)
|
||||
if (pferd != null) {
|
||||
call.respond(pferd.toDto())
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht ein Pferd nach seiner Lebensnummer.
|
||||
*/
|
||||
get("/lebensnummer/{nr}") {
|
||||
val nr = call.parameters["nr"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||
val pferd = horseRepository.findByLebensnummer(nr)
|
||||
if (pferd != null) {
|
||||
call.respond(pferd.toDto())
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun DomPferd.toDto() = HorseDto(
|
||||
pferdId = pferdId.toString(),
|
||||
pferdeName = pferdeName,
|
||||
geschlecht = geschlecht.name,
|
||||
geburtsdatum = geburtsdatum,
|
||||
rasse = rasse,
|
||||
lebensnummer = lebensnummer,
|
||||
oepsNummer = oepsNummer,
|
||||
feiNummer = feiNummer,
|
||||
istAktiv = istAktiv,
|
||||
updatedAt = updatedAt
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.masterdata.api.rest
|
||||
|
||||
import at.mocode.core.domain.serialization.InstantSerializer
|
||||
import at.mocode.core.domain.serialization.LocalDateSerializer
|
||||
import at.mocode.masterdata.domain.model.DomReiter
|
||||
import at.mocode.masterdata.domain.repository.ReiterRepository
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.time.Instant
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Controller für Reiter-bezogene REST-Endpunkte.
|
||||
*/
|
||||
class ReiterController(private val reiterRepository: ReiterRepository) {
|
||||
|
||||
@Serializable
|
||||
data class ReiterDto(
|
||||
val reiterId: String,
|
||||
val satznummer: String,
|
||||
val nachname: String,
|
||||
val vorname: String,
|
||||
@Serializable(with = LocalDateSerializer::class)
|
||||
val geburtsdatum: LocalDate? = null,
|
||||
val lizenzNummer: String? = null,
|
||||
val lizenzKlasse: String,
|
||||
val startkartAktiv: Boolean,
|
||||
val nation: String? = null,
|
||||
val vereinsName: String? = null,
|
||||
@Serializable(with = InstantSerializer::class)
|
||||
val updatedAt: Instant
|
||||
)
|
||||
|
||||
fun Route.registerRoutes() {
|
||||
route("/reiter") {
|
||||
/**
|
||||
* Sucht Reiter nach Name oder Satznummer.
|
||||
*/
|
||||
get("/search") {
|
||||
val query = call.request.queryParameters["q"] ?: ""
|
||||
val results = reiterRepository.findByName(query)
|
||||
call.respond(results.map { it.toDto() })
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft einen spezifischen Reiter ab.
|
||||
*/
|
||||
get("/{id}") {
|
||||
val idStr = call.parameters["id"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||
val id = try {
|
||||
Uuid.parse(idStr)
|
||||
} catch (e: Exception) {
|
||||
return@get call.respond(HttpStatusCode.BadRequest)
|
||||
}
|
||||
|
||||
val reiter = reiterRepository.findById(id)
|
||||
if (reiter != null) {
|
||||
call.respond(reiter.toDto())
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht einen Reiter nach seiner Satznummer.
|
||||
*/
|
||||
get("/satznummer/{nr}") {
|
||||
val nr = call.parameters["nr"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||
val reiter = reiterRepository.findBySatznummer(nr)
|
||||
if (reiter != null) {
|
||||
call.respond(reiter.toDto())
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun DomReiter.toDto() = ReiterDto(
|
||||
reiterId = reiterId.toString(),
|
||||
satznummer = satznummer,
|
||||
nachname = nachname,
|
||||
vorname = vorname,
|
||||
geburtsdatum = geburtsdatum,
|
||||
lizenzNummer = lizenzNummer,
|
||||
lizenzKlasse = lizenzKlasse.name,
|
||||
startkartAktiv = startkartAktiv,
|
||||
nation = nation,
|
||||
vereinsName = vereinsName,
|
||||
updatedAt = updatedAt
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.masterdata.api.rest
|
||||
|
||||
import at.mocode.core.domain.serialization.InstantSerializer
|
||||
import at.mocode.masterdata.domain.model.DomVerein
|
||||
import at.mocode.masterdata.domain.repository.VereinRepository
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Controller für Vereins-bezogene REST-Endpunkte.
|
||||
*/
|
||||
class VereinController(private val vereinRepository: VereinRepository) {
|
||||
|
||||
@Serializable
|
||||
data class VereinDto(
|
||||
val vereinId: String,
|
||||
val vereinsNummer: String,
|
||||
val name: String,
|
||||
val kurzname: String? = null,
|
||||
val bundesland: String,
|
||||
val ort: String? = null,
|
||||
val istVeranstalter: Boolean,
|
||||
val istAktiv: Boolean,
|
||||
@Serializable(with = InstantSerializer::class)
|
||||
val updatedAt: kotlin.time.Instant
|
||||
)
|
||||
|
||||
fun Route.registerRoutes() {
|
||||
route("/verein") {
|
||||
/**
|
||||
* Sucht Vereine nach Name oder Kurzname.
|
||||
*/
|
||||
get("/search") {
|
||||
val query = call.request.queryParameters["q"] ?: ""
|
||||
val results = vereinRepository.findByName(query)
|
||||
call.respond(results.map { it.toDto() })
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft einen spezifischen Verein ab.
|
||||
*/
|
||||
get("/{id}") {
|
||||
val idStr = call.parameters["id"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||
val id = try {
|
||||
Uuid.parse(idStr)
|
||||
} catch (e: Exception) {
|
||||
return@get call.respond(HttpStatusCode.BadRequest)
|
||||
}
|
||||
|
||||
val verein = vereinRepository.findById(id)
|
||||
if (verein != null) {
|
||||
call.respond(verein.toDto())
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht einen Verein nach seiner Vereinsnummer.
|
||||
*/
|
||||
get("/nummer/{nr}") {
|
||||
val nr = call.parameters["nr"] ?: return@get call.respond(HttpStatusCode.BadRequest)
|
||||
val verein = vereinRepository.findByVereinsNummer(nr)
|
||||
if (verein != null) {
|
||||
call.respond(verein.toDto())
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun DomVerein.toDto() = VereinDto(
|
||||
vereinId = vereinId.toString(),
|
||||
vereinsNummer = vereinsNummer,
|
||||
name = name,
|
||||
kurzname = kurzname,
|
||||
bundesland = bundesland ?: "",
|
||||
ort = ort,
|
||||
istVeranstalter = istVeranstalter,
|
||||
istAktiv = istAktiv,
|
||||
updatedAt = updatedAt
|
||||
)
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
package at.mocode.masterdata.domain.repository
|
||||
|
||||
import at.mocode.masterdata.domain.model.DomPferd
|
||||
import at.mocode.core.domain.model.PferdeGeschlechtE
|
||||
import at.mocode.masterdata.domain.model.DomPferd
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
|
|
@ -245,4 +245,10 @@ interface HorseRepository {
|
|||
* @return The count of FEI registered horses
|
||||
*/
|
||||
suspend fun countFeiRegistered(activeOnly: Boolean = true): Long
|
||||
|
||||
/**
|
||||
* Speichert ein Pferd basierend auf der Lebensnummer (Upsert).
|
||||
* Wenn ein Pferd mit der Lebensnummer existiert, wird es aktualisiert, ansonsten neu angelegt.
|
||||
*/
|
||||
suspend fun upsertByLebensnummer(horse: DomPferd): DomPferd
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,4 +86,10 @@ interface ReiterRepository {
|
|||
* Prüft ob ein Reiter mit der gegebenen Satznummer bereits existiert.
|
||||
*/
|
||||
suspend fun existsBySatznummer(satznummer: String): Boolean
|
||||
|
||||
/**
|
||||
* Speichert einen Reiter basierend auf der Satznummer (Upsert).
|
||||
* Wenn ein Reiter mit der Satznummer existiert, wird er aktualisiert, ansonsten neu angelegt.
|
||||
*/
|
||||
suspend fun upsertBySatznummer(reiter: DomReiter): DomReiter
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,4 +69,10 @@ interface VereinRepository {
|
|||
* Prüft ob ein Verein mit der gegebenen Vereinsnummer bereits existiert.
|
||||
*/
|
||||
suspend fun existsByVereinsNummer(vereinsNummer: String): Boolean
|
||||
|
||||
/**
|
||||
* Speichert einen Verein basierend auf der Vereinsnummer (Upsert).
|
||||
* Wenn ein Verein mit der Nummer existiert, wird er aktualisiert, ansonsten neu angelegt.
|
||||
*/
|
||||
suspend fun upsertByVereinsNummer(verein: DomVerein): DomVerein
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
package at.mocode.masterdata.domain.service
|
||||
|
||||
import at.mocode.core.domain.model.SparteE
|
||||
import at.mocode.masterdata.domain.model.AltersklasseDefinition
|
||||
import at.mocode.masterdata.domain.model.DomReiter
|
||||
import kotlinx.datetime.LocalDate
|
||||
|
||||
/**
|
||||
* Service zur Berechnung und Ermittlung von Altersklassen gemäß ÖTO.
|
||||
*/
|
||||
interface AltersklasseRechner {
|
||||
|
||||
/**
|
||||
* Ermittelt das Alter einer Person für ein bestimmtes Jahr gemäß der ÖTO-Stichtagsregel
|
||||
* (Alter am 31.12. des laufenden Kalenderjahres).
|
||||
*
|
||||
* @param geburtsdatum Das Geburtsdatum der Person.
|
||||
* @param referenzJahr Das Kalenderjahr, für das das Alter berechnet werden soll.
|
||||
* @return Das Alter in Jahren.
|
||||
*/
|
||||
fun berechneOetoAlter(geburtsdatum: LocalDate, referenzJahr: Int): Int
|
||||
|
||||
/**
|
||||
* Ermittelt alle zutreffenden Altersklassen für einen Reiter in einem bestimmten Jahr und einer Sparte.
|
||||
*
|
||||
* @param reiter Der Reiter, für den die Altersklasse ermittelt werden soll.
|
||||
* @param referenzJahr Das Kalenderjahr des Turniers.
|
||||
* @param sparte Die Sparte des Bewerbs (optional).
|
||||
* @param verfügbareDefinitionen Die Liste der im System definierten Altersklassen.
|
||||
* @return Eine Liste der zutreffenden Altersklassen-Definitionen.
|
||||
*/
|
||||
fun ermittleAltersklassen(
|
||||
reiter: DomReiter,
|
||||
referenzJahr: Int,
|
||||
sparte: SparteE? = null,
|
||||
verfügbareDefinitionen: List<AltersklasseDefinition>
|
||||
): List<AltersklasseDefinition>
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package at.mocode.masterdata.domain.service
|
||||
|
||||
import at.mocode.core.domain.model.SparteE
|
||||
import at.mocode.masterdata.domain.model.AltersklasseDefinition
|
||||
import at.mocode.masterdata.domain.model.DomReiter
|
||||
import kotlinx.datetime.LocalDate
|
||||
|
||||
/**
|
||||
* Standard-Implementierung des [AltersklasseRechner] gemäß ÖTO.
|
||||
*/
|
||||
class AltersklasseRechnerImpl : AltersklasseRechner {
|
||||
|
||||
override fun berechneOetoAlter(geburtsdatum: LocalDate, referenzJahr: Int): Int {
|
||||
// Gemäß ÖTO: Stichtag für alle Altersklassen ist der 31. Dezember des laufenden Kalenderjahres.
|
||||
// Das bedeutet einfach: ReferenzJahr - GeburtsJahr.
|
||||
return referenzJahr - geburtsdatum.year
|
||||
}
|
||||
|
||||
override fun ermittleAltersklassen(
|
||||
reiter: DomReiter,
|
||||
referenzJahr: Int,
|
||||
sparte: SparteE?,
|
||||
verfügbareDefinitionen: List<AltersklasseDefinition>
|
||||
): List<AltersklasseDefinition> {
|
||||
val geburtsdatum = reiter.geburtsdatum ?: return emptyList()
|
||||
val alter = berechneOetoAlter(geburtsdatum, referenzJahr)
|
||||
|
||||
return verfügbareDefinitionen.filter { def ->
|
||||
if (!def.istAktiv) return@filter false
|
||||
|
||||
// Sparte prüfen (falls in der Definition eine Sparte vorgegeben ist)
|
||||
if (def.sparteFilter != null && sparte != null && def.sparteFilter != sparte) {
|
||||
return@filter false
|
||||
}
|
||||
|
||||
// Alter prüfen
|
||||
val minMatch = def.minAlter == null || alter >= def.minAlter!!
|
||||
val maxMatch = def.maxAlter == null || alter <= def.maxAlter!!
|
||||
|
||||
minMatch && maxMatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -174,4 +174,35 @@ class ExposedReiterRepository : ReiterRepository {
|
|||
override suspend fun existsBySatznummer(satznummer: String): Boolean = DatabaseFactory.dbQuery {
|
||||
ReiterTable.selectAll().where { ReiterTable.satznummer eq satznummer }.any()
|
||||
}
|
||||
|
||||
override suspend fun upsertBySatznummer(reiter: DomReiter): DomReiter = DatabaseFactory.dbQuery {
|
||||
val existing = ReiterTable.selectAll().where { ReiterTable.satznummer eq reiter.satznummer }
|
||||
.map(::rowToDomReiter)
|
||||
.singleOrNull()
|
||||
|
||||
if (existing != null) {
|
||||
val toUpdate = reiter.copy(reiterId = existing.reiterId)
|
||||
ReiterTable.update({ ReiterTable.id eq existing.reiterId }) {
|
||||
it[personId] = toUpdate.personId
|
||||
it[nachname] = toUpdate.nachname
|
||||
it[vorname] = toUpdate.vorname
|
||||
it[geburtsdatum] = toUpdate.geburtsdatum
|
||||
it[lizenzNummer] = toUpdate.lizenzNummer
|
||||
it[lizenzKlasse] = toUpdate.lizenzKlasse.name
|
||||
it[startkartAktiv] = toUpdate.startkartAktiv
|
||||
it[startkartSaison] = toUpdate.startkartSaison
|
||||
it[feiId] = toUpdate.feiId
|
||||
it[nation] = toUpdate.nation
|
||||
it[vereinsNummer] = toUpdate.vereinsNummer
|
||||
it[vereinsName] = toUpdate.vereinsName
|
||||
it[istGastreiter] = toUpdate.istGastreiter
|
||||
it[istAktiv] = toUpdate.istAktiv
|
||||
it[datenQuelle] = toUpdate.datenQuelle.name
|
||||
it[updatedAt] = toUpdate.updatedAt
|
||||
}
|
||||
toUpdate
|
||||
} else {
|
||||
save(reiter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,14 +7,10 @@ import at.mocode.core.utils.database.DatabaseFactory
|
|||
import at.mocode.masterdata.domain.model.DomVerein
|
||||
import at.mocode.masterdata.domain.repository.VereinRepository
|
||||
import org.jetbrains.exposed.v1.core.ResultRow
|
||||
import org.jetbrains.exposed.v1.core.or
|
||||
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 org.jetbrains.exposed.v1.core.eq
|
||||
import org.jetbrains.exposed.v1.core.like
|
||||
import org.jetbrains.exposed.v1.jdbc.andWhere
|
||||
import org.jetbrains.exposed.v1.core.or
|
||||
import org.jetbrains.exposed.v1.jdbc.*
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
|
|
@ -151,4 +147,35 @@ class ExposedVereinRepository : VereinRepository {
|
|||
override suspend fun existsByVereinsNummer(vereinsNummer: String): Boolean = DatabaseFactory.dbQuery {
|
||||
VereinTable.selectAll().where { VereinTable.vereinsNummer eq vereinsNummer }.any()
|
||||
}
|
||||
|
||||
override suspend fun upsertByVereinsNummer(verein: DomVerein): DomVerein = DatabaseFactory.dbQuery {
|
||||
val existing = VereinTable.selectAll().where { VereinTable.vereinsNummer eq verein.vereinsNummer }
|
||||
.map(::rowToDomVerein)
|
||||
.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[bundesland] = toUpdate.bundesland
|
||||
it[ort] = toUpdate.ort
|
||||
it[plz] = toUpdate.plz
|
||||
it[strasse] = toUpdate.strasse
|
||||
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[bemerkungen] = toUpdate.bemerkungen
|
||||
it[datenQuelle] = toUpdate.datenQuelle.name
|
||||
it[updatedAt] = toUpdate.updatedAt
|
||||
}
|
||||
toUpdate
|
||||
} else {
|
||||
save(verein)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,4 +283,43 @@ class HorseRepositoryImpl : HorseRepository {
|
|||
}
|
||||
query.count()
|
||||
}
|
||||
|
||||
override suspend fun upsertByLebensnummer(horse: DomPferd): DomPferd = DatabaseFactory.dbQuery {
|
||||
val lebensnummer = horse.lebensnummer ?: return@dbQuery save(horse)
|
||||
|
||||
val existing = HorseTable.selectAll().where { HorseTable.lebensnummer eq lebensnummer }
|
||||
.map(::rowToDomPferd)
|
||||
.singleOrNull()
|
||||
|
||||
if (existing != null) {
|
||||
val toUpdate = horse.copy(pferdId = existing.pferdId)
|
||||
HorseTable.update({ HorseTable.id eq existing.pferdId }) {
|
||||
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[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[istAktiv] = toUpdate.istAktiv
|
||||
it[bemerkungen] = toUpdate.bemerkungen
|
||||
it[datenQuelle] = toUpdate.datenQuelle.name
|
||||
it[updatedAt] = toUpdate.updatedAt
|
||||
}
|
||||
toUpdate
|
||||
} else {
|
||||
save(horse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
package at.mocode.masterdata.service.config
|
||||
|
||||
import at.mocode.masterdata.api.masterdataApiModule
|
||||
import at.mocode.masterdata.api.rest.AltersklasseController
|
||||
import at.mocode.masterdata.api.rest.BundeslandController
|
||||
import at.mocode.masterdata.api.rest.CountryController
|
||||
import at.mocode.masterdata.api.rest.PlatzController
|
||||
import io.ktor.server.engine.embeddedServer
|
||||
import io.ktor.server.engine.EmbeddedServer
|
||||
import io.ktor.server.netty.Netty
|
||||
import io.ktor.server.netty.NettyApplicationEngine
|
||||
import at.mocode.masterdata.api.rest.*
|
||||
import io.ktor.server.engine.*
|
||||
import io.ktor.server.netty.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.DisposableBean
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
|
@ -33,7 +27,10 @@ class KtorServerConfiguration {
|
|||
countryController: CountryController,
|
||||
bundeslandController: BundeslandController,
|
||||
altersklasseController: AltersklasseController,
|
||||
platzController: PlatzController
|
||||
platzController: PlatzController,
|
||||
reiterController: ReiterController,
|
||||
horseController: HorseController,
|
||||
vereinController: VereinController
|
||||
): EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration> {
|
||||
log.info("Starting Masterdata Ktor server on port {}", port)
|
||||
val engine = embeddedServer(Netty, port = port) {
|
||||
|
|
@ -41,7 +38,10 @@ class KtorServerConfiguration {
|
|||
countryController = countryController,
|
||||
bundeslandController = bundeslandController,
|
||||
altersklasseController = altersklasseController,
|
||||
platzController = platzController
|
||||
platzController = platzController,
|
||||
reiterController = reiterController,
|
||||
horseController = horseController,
|
||||
vereinController = vereinController
|
||||
)
|
||||
}
|
||||
engine.start(wait = false)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package at.mocode.masterdata.service.config
|
||||
|
||||
import at.mocode.masterdata.api.rest.*
|
||||
import at.mocode.masterdata.application.usecase.*
|
||||
import at.mocode.masterdata.domain.repository.*
|
||||
import at.mocode.masterdata.infrastructure.persistence.*
|
||||
import at.mocode.masterdata.api.rest.*
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.Profile
|
||||
|
|
@ -134,6 +134,21 @@ class MasterdataConfiguration {
|
|||
): PlatzController {
|
||||
return PlatzController(getPlatzUseCase, createPlatzUseCase)
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun reiterController(reiterRepository: ReiterRepository): ReiterController {
|
||||
return ReiterController(reiterRepository)
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun horseController(horseRepository: HorseRepository): HorseController {
|
||||
return HorseController(horseRepository)
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun vereinController(vereinRepository: VereinRepository): VereinController {
|
||||
return VereinController(vereinRepository)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
package at.mocode.masterdata.service.config
|
||||
|
||||
|
||||
import at.mocode.masterdata.infrastructure.persistence.AltersklasseTable
|
||||
import at.mocode.masterdata.infrastructure.persistence.BundeslandTable
|
||||
import at.mocode.masterdata.infrastructure.persistence.LandTable
|
||||
import at.mocode.masterdata.infrastructure.persistence.PlatzTable
|
||||
import at.mocode.masterdata.infrastructure.persistence.*
|
||||
import jakarta.annotation.PostConstruct
|
||||
import jakarta.annotation.PreDestroy
|
||||
import org.jetbrains.exposed.v1.jdbc.SchemaUtils
|
||||
|
|
@ -36,7 +33,11 @@ class MasterdataDatabaseConfiguration {
|
|||
LandTable,
|
||||
BundeslandTable,
|
||||
AltersklasseTable,
|
||||
PlatzTable
|
||||
PlatzTable,
|
||||
ReiterTable,
|
||||
HorseTable,
|
||||
VereinTable,
|
||||
FunktionaerTable
|
||||
)
|
||||
log.info("Masterdata database schema initialized successfully")
|
||||
}
|
||||
|
|
@ -72,7 +73,11 @@ class MasterdataTestDatabaseConfiguration {
|
|||
LandTable,
|
||||
BundeslandTable,
|
||||
AltersklasseTable,
|
||||
PlatzTable
|
||||
PlatzTable,
|
||||
ReiterTable,
|
||||
HorseTable,
|
||||
VereinTable,
|
||||
FunktionaerTable
|
||||
)
|
||||
log.info("Test masterdata database schema initialized successfully")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user