Skip to content

Commit

Permalink
refactor: use aggregate data extractors
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreaGiulianelli committed May 18, 2023
1 parent 6a2b1f4 commit 0b1ad2e
Showing 1 changed file with 24 additions and 90 deletions.
114 changes: 24 additions & 90 deletions src/main/kotlin/usecase/ReportGenerationUseCase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,7 @@ package usecase

import entity.healthcareuser.HealthcareUser
import entity.healthcareuser.PatientVitalSigns
import entity.healthcareuser.VitalSign
import entity.healthprofessional.HealthProfessionalID
import entity.measurements.AggregateData
import entity.measurements.Humidity
import entity.measurements.LightUnit
import entity.measurements.Luminosity
import entity.measurements.Percentage
import entity.measurements.Presence
import entity.measurements.Temperature
import entity.measurements.TemperatureUnit
import entity.medicaldevice.ImplantableMedicalDevice
import entity.medicaldevice.MedicalTechnologyUsage
import entity.process.SurgicalProcess
Expand All @@ -30,9 +21,11 @@ import entity.report.SurgeryReport
import entity.room.RoomEnvironmentalData
import entity.room.RoomType
import entity.tracking.TrackingInfo
import usecase.aggregation.AggregateRoomEnvironmentalDataExtractor
import usecase.aggregation.AggregateVitalSignsExtractor
import usecase.aggregation.util.CollectionExtensions.takePeriod
import java.time.Instant
import java.util.Date
import kotlin.math.pow

/**
* This use case has the objective of generate the [SurgeryReport] based on the information of the
Expand All @@ -55,106 +48,47 @@ class ReportGenerationUseCase(
private val medicalTechnologyUsage: Set<MedicalTechnologyUsage> = setOf(),
) : UseCase<SurgeryReport> {
override fun execute(): SurgeryReport = SurgeryReport(
surgicalProcess.id,
this.surgicalProcess.id,
Date.from(
surgicalProcess.processStates.first {
this.surgicalProcess.processStates.first {
it.second == SurgicalProcessState.PreSurgery(SurgicalProcessStep.PATIENT_IN_PREPARATION)
}.first,
),
surgicalProcess.description,
surgicalProcess.inChargeHealthProfessional,
surgicalProcess.patientID,
healthcareUser,
this.surgicalProcess.description,
this.surgicalProcess.inChargeHealthProfessional,
this.surgicalProcess.patientID,
this.healthcareUser,
computeAggregateData(),
consumedImplantableMedicalDevices,
medicalTechnologyUsage,
healthProfessionalTrackingInformation,
this.consumedImplantableMedicalDevices,
this.medicalTechnologyUsage,
this.healthProfessionalTrackingInformation,
)

private fun computeAggregateData(): Map<SurgicalProcessState, SurgeryProcessStepAggregateData> {
val stateSorted = this.surgicalProcess.processStates.sortedBy { it.first }
val finalDateIterator = stateSorted.map { it.first }.sorted().iterator()
val finalDateIterator = stateSorted.map { it.first }.iterator()

return stateSorted.associate {
val dateTimeFrom = it.first
return stateSorted.associate { stateEntry ->
val dateTimeFrom = stateEntry.first
val dateTimeTo = if (finalDateIterator.hasNext()) finalDateIterator.next() else null
val vitalSignsInPeriod = this.patientVitalSigns
.takePeriod(dateTimeFrom, dateTimeTo)
.map { pair -> pair.second }
val environmentalDataInPeriod =
this.environmentalData.mapValues { entry ->
entry
.value
.takePeriod(dateTimeFrom, dateTimeTo)
.map { it.second }
}
val environmentalDataInPeriod = this.environmentalData.mapValues { roomDataEntry -> roomDataEntry
.value
.takePeriod(dateTimeFrom, dateTimeTo)
.map { it.second }
}
Pair(
it.second,
stateEntry.second,
SurgeryProcessStepAggregateData(
it.first,
AggregateData(
average = vitalSignsInPeriod.applyAggregationToVitalSigns { this.average() },
variance = vitalSignsInPeriod.applyAggregationToVitalSigns { this.variance() },
maximum = vitalSignsInPeriod.applyAggregationToVitalSigns { this.max() },
minimum = vitalSignsInPeriod.applyAggregationToVitalSigns { this.min() },
),
stateEntry.first,
AggregateVitalSignsExtractor(vitalSignsInPeriod).aggregate(),
environmentalDataInPeriod.mapValues { roomDataEntry ->
with(roomDataEntry.value) {
AggregateData(
average = this.applyAggregationToRoomEnvironmentalData { this.average() },
variance = this.applyAggregationToRoomEnvironmentalData { this.variance() },
maximum = this.applyAggregationToRoomEnvironmentalData { this.max() },
minimum = this.applyAggregationToRoomEnvironmentalData { this.min() },
)
}
AggregateRoomEnvironmentalDataExtractor(roomDataEntry.value).aggregate()
},
),
)
}
}

private fun Collection<RoomEnvironmentalData>.applyAggregationToRoomEnvironmentalData(
operation: Collection<Double>.() -> Double,
): RoomEnvironmentalData = RoomEnvironmentalData(
temperature = Temperature(
this.mapNotNull { it.temperature?.value }.operation(),
TemperatureUnit.CELSIUS,
),
humidity = Humidity(Percentage(this.mapNotNull { it.humidity?.percentage?.value }.operation())),
luminosity = Luminosity(
this.mapNotNull { it.luminosity?.value }.operation(),
LightUnit.LUX,
),
presence = Presence(
this.mapNotNull { it.presence?.presenceDetected }.groupBy { it }.maxBy { it.value.size }.key,
),
)

private fun Collection<PatientVitalSigns>.applyAggregationToVitalSigns(
operation: Collection<Double>.() -> Double,
): PatientVitalSigns = PatientVitalSigns(
heartBeat = VitalSign.HeartBeat(this.mapNotNull { it.heartBeat?.bpm?.toDouble() }.operation().toInt()),
diastolicBloodPressure = VitalSign.DiastolicBloodPressure(
this.mapNotNull { it.diastolicBloodPressure?.pressure?.toDouble() }.operation().toInt(),
),
systolicBloodPressure = VitalSign.SystolicBloodPressure(
this.mapNotNull { it.systolicBloodPressure?.pressure?.toDouble() }.operation().toInt(),
),
respiratoryRate = VitalSign.RespiratoryRate(
this.mapNotNull { it.respiratoryRate?.rate?.toDouble() }.operation().toInt(),
),
saturationPercentage = VitalSign.SaturationPercentage(
Percentage(this.mapNotNull { it.saturationPercentage?.percentage?.value }.operation()),
),
bodyTemperature = VitalSign.BodyTemperature(
Temperature(this.mapNotNull { it.bodyTemperature?.temperature?.value }.average(), TemperatureUnit.CELSIUS),
),
)
private fun <X> Collection<Pair<Instant, X>>.takePeriod(from: Instant, to: Instant? = null) =
this.filter {
(to != null && it.first >= from && it.first <= to) || (to == null && it.first >= from)
}
private fun Collection<Double>.variance(): Double = with(this.average()) {
this@variance.sumOf { (it - this).pow(2) } / this@variance.size
}
}

0 comments on commit 0b1ad2e

Please sign in to comment.