From bcfc59f600c7bbe8a09036e72b0e8beab1b25c4b Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Tue, 14 Jan 2025 12:17:25 +0100 Subject: [PATCH] update --- functions/src/healthSummary/generate.ts | 2 +- functions/src/models/healthSummaryData.ts | 21 ++- .../databaseHealthSummaryService.test.ts | 1 + .../databaseHealthSummaryService.ts | 4 +- .../healthSummaryService.mock.ts | 177 +++++++----------- .../healthSummary/healthSummaryService.ts | 1 + .../src/services/trigger/triggerService.ts | 2 +- .../src/tests/mocks/healthSummaryData.ts | 4 +- 8 files changed, 89 insertions(+), 123 deletions(-) diff --git a/functions/src/healthSummary/generate.ts b/functions/src/healthSummary/generate.ts index 5d45964d..502cc0cc 100644 --- a/functions/src/healthSummary/generate.ts +++ b/functions/src/healthSummary/generate.ts @@ -341,7 +341,7 @@ class HealthSummaryPdfGenerator extends PdfGenerator { [ this.texts.vitalsSection.bodyWeightTable.rowTitle, this.data.latestBodyWeight?.toFixed(0) ?? '---', - this.data.averageBodyWeight?.toFixed(0) ?? '---', + this.data.lastSevenDayAverageBodyWeight?.toFixed(0) ?? '---', this.data.bodyWeightRange?.toFixed(0) ?? '---', ].map((title) => this.cell(title)), ], diff --git a/functions/src/models/healthSummaryData.ts b/functions/src/models/healthSummaryData.ts index 5c99d869..112b7261 100644 --- a/functions/src/models/healthSummaryData.ts +++ b/functions/src/models/healthSummaryData.ts @@ -7,6 +7,7 @@ // import { + advanceDateByDays, average, UserMedicationRecommendationType, type FHIRAppointment, @@ -40,6 +41,7 @@ export class HealthSummaryData { recommendations: UserMedicationRecommendation[] vitals: HealthSummaryVitals symptomScores: SymptomScore[] + now: Date // Computed Properties - Body Weight @@ -47,7 +49,16 @@ export class HealthSummaryData { return this.vitals.bodyWeight.at(0)?.value ?? null } - get averageBodyWeight(): number | null { + get lastSevenDayAverageBodyWeight(): number | null { + const bodyWeightValues = this.vitals.bodyWeight + .filter( + (observation) => observation.date >= advanceDateByDays(this.now, -7), + ) + .map((observation) => observation.value) + return average(bodyWeightValues) ?? null + } + + get medianBodyWeight(): number | null { return ( average(this.vitals.bodyWeight.map((observation) => observation.value)) ?? null @@ -136,12 +147,12 @@ export class HealthSummaryData { } get weightCategory(): HealthSummaryWeightCategory { - const averageWeight = this.averageBodyWeight + const medianWeight = this.medianBodyWeight const latestWeight = this.latestBodyWeight - if (averageWeight === null || latestWeight === null) + if (medianWeight === null || latestWeight === null) return HealthSummaryWeightCategory.MISSING - return latestWeight - averageWeight > 1 ? + return latestWeight - medianWeight >= 3 ? HealthSummaryWeightCategory.INCREASING : HealthSummaryWeightCategory.STABLE_OR_DECREASING } @@ -156,6 +167,7 @@ export class HealthSummaryData { recommendations: UserMedicationRecommendation[] vitals: HealthSummaryVitals symptomScores: SymptomScore[] + now: Date }) { this.name = input.name this.dateOfBirth = input.dateOfBirth @@ -164,5 +176,6 @@ export class HealthSummaryData { this.recommendations = input.recommendations this.vitals = input.vitals this.symptomScores = input.symptomScores + this.now = input.now } } diff --git a/functions/src/services/healthSummary/databaseHealthSummaryService.test.ts b/functions/src/services/healthSummary/databaseHealthSummaryService.test.ts index 6c96912c..511f1979 100644 --- a/functions/src/services/healthSummary/databaseHealthSummaryService.test.ts +++ b/functions/src/services/healthSummary/databaseHealthSummaryService.test.ts @@ -24,6 +24,7 @@ describe('HealthSummaryService', () => { it('should fetch health summary data', async () => { const actualData = await healthSummaryService.getHealthSummaryData( 'mockUser', + new Date(2024, 2, 2, 12, 30), QuantityUnit.lbs, ) console.log('actualData:', actualData.nextAppointment?.start.toString()) diff --git a/functions/src/services/healthSummary/databaseHealthSummaryService.ts b/functions/src/services/healthSummary/databaseHealthSummaryService.ts index cae802e4..475a3e4d 100644 --- a/functions/src/services/healthSummary/databaseHealthSummaryService.ts +++ b/functions/src/services/healthSummary/databaseHealthSummaryService.ts @@ -35,6 +35,7 @@ export class DefaultHealthSummaryService implements HealthSummaryService { async getHealthSummaryData( userId: string, + date: Date, weightUnit: QuantityUnit, ): Promise { const [ @@ -50,7 +51,7 @@ export class DefaultHealthSummaryService implements HealthSummaryService { this.patientService.getNextAppointment(userId), this.patientService.getMedicationRecommendations(userId), this.patientService.getSymptomScores(userId, { limit: 5 }), - this.getVitals(userId, advanceDateByDays(new Date(), -14), weightUnit), + this.getVitals(userId, advanceDateByDays(date, -14), weightUnit), ]) const clinician = @@ -66,6 +67,7 @@ export class DefaultHealthSummaryService implements HealthSummaryService { recommendations: recommendations.map((doc) => doc.content), vitals: vitals, symptomScores: symptomScores.map((doc) => doc.content), + now: date, }) } diff --git a/functions/src/services/healthSummary/healthSummaryService.mock.ts b/functions/src/services/healthSummary/healthSummaryService.mock.ts index e793dd72..49bf69fd 100644 --- a/functions/src/services/healthSummary/healthSummaryService.mock.ts +++ b/functions/src/services/healthSummary/healthSummaryService.mock.ts @@ -8,6 +8,7 @@ import { advanceDateByDays, + advanceDateBySeconds, FHIRAppointment, FHIRAppointmentStatus, LocalizedText, @@ -25,19 +26,12 @@ import { /* eslint-disable @typescript-eslint/no-unused-vars */ export class MockHealthSummaryService implements HealthSummaryService { - // Properties - - private readonly startDate: Date - - // Constructor - - constructor(startDate: Date = new Date(2024, 2, 2, 12, 30)) { - this.startDate = startDate - } - // Methods - async getHealthSummaryData(userId: string): Promise { + async getHealthSummaryData( + userId: string, + date: Date, + ): Promise { return new HealthSummaryData({ name: 'John Doe', dateOfBirth: new Date('1970-01-02'), @@ -45,8 +39,8 @@ export class MockHealthSummaryService implements HealthSummaryService { nextAppointment: FHIRAppointment.create({ userId, status: FHIRAppointmentStatus.booked, - created: this.startDateAdvancedByDays(-10), - start: this.startDateAdvancedByDays(1), + created: advanceDateByDays(date, -10), + start: advanceDateByDays(date, 1), durationInMinutes: 60, }), recommendations: [ @@ -98,7 +92,7 @@ export class MockHealthSummaryService implements HealthSummaryService { }, }, ], - vitals: await this.getVitals(userId), + vitals: await this.getVitals(date), symptomScores: [ { questionnaireResponseId: '4', @@ -108,7 +102,7 @@ export class MockHealthSummaryService implements HealthSummaryService { qualityOfLifeScore: 20, symptomFrequencyScore: 60, dizzinessScore: 3, - date: this.startDateAdvancedByDays(-9), + date: advanceDateByDays(date, -9), }, { questionnaireResponseId: '3', @@ -118,7 +112,7 @@ export class MockHealthSummaryService implements HealthSummaryService { qualityOfLifeScore: 37, symptomFrequencyScore: 72, dizzinessScore: 2, - date: this.startDateAdvancedByDays(-18), + date: advanceDateByDays(date, -18), }, { questionnaireResponseId: '2', @@ -128,7 +122,7 @@ export class MockHealthSummaryService implements HealthSummaryService { qualityOfLifeScore: 25, symptomFrequencyScore: 60, dizzinessScore: 1, - date: this.startDateAdvancedByDays(-34), + date: advanceDateByDays(date, -34), }, { questionnaireResponseId: '1', @@ -138,123 +132,121 @@ export class MockHealthSummaryService implements HealthSummaryService { qualityOfLifeScore: 60, symptomFrequencyScore: 80, dizzinessScore: 1, - date: this.startDateAdvancedByDays(-49), + date: advanceDateByDays(date, -49), }, ], + now: date, }) } - async getVitals(userId: string): Promise { + // Helpers + + private async getVitals(date: Date): Promise { const [systolicBloodPressure, diastolicBloodPressure] = - await this.getBloodPressureObservations(userId, this.startDate) + await this.getBloodPressureObservations(date) return { systolicBloodPressure: systolicBloodPressure, diastolicBloodPressure: diastolicBloodPressure, - heartRate: await this.getHeartRateObservations(userId, this.startDate), - bodyWeight: await this.getBodyWeightObservations( - userId, - this.startDate, - QuantityUnit.lbs, - ), - dryWeight: await this.getMostRecentDryWeightObservation(userId), + heartRate: await this.getHeartRateObservations(date), + bodyWeight: await this.getBodyWeightObservations(date), + dryWeight: await this.getMostRecentDryWeightObservation(date), } } - async getBloodPressureObservations( - userId: string, - cutoffDate: Date, + private async getBloodPressureObservations( + date: Date, ): Promise<[Observation[], Observation[]]> { return [ [ { - date: this.startDateAdvancedByDays(-1), + date: advanceDateByDays(date, -1), value: 110, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-2), + date: advanceDateByDays(date, -2), value: 114, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-3), + date: advanceDateByDays(date, -3), value: 123, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-4), + date: advanceDateByDays(date, -4), value: 109, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-5), + date: advanceDateByDays(date, -5), value: 105, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-6), + date: advanceDateByDays(date, -6), value: 98, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-7), + date: advanceDateByDays(date, -7), value: 94, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-8), + date: advanceDateByDays(date, -8), value: 104, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-9), + date: advanceDateByDays(date, -9), value: 102, unit: QuantityUnit.mmHg, }, ], [ { - date: this.startDateAdvancedByDays(-1), + date: advanceDateByDays(date, -1), value: 70, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-2), + date: advanceDateByDays(date, -2), value: 82, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-3), + date: advanceDateByDays(date, -3), value: 75, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-4), + date: advanceDateByDays(date, -4), value: 77, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-5), + date: advanceDateByDays(date, -5), value: 72, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-6), + date: advanceDateByDays(date, -6), value: 68, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-7), + date: advanceDateByDays(date, -7), value: 65, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-8), + date: advanceDateByDays(date, -8), value: 72, unit: QuantityUnit.mmHg, }, { - date: this.startDateAdvancedByDays(-9), + date: advanceDateByDays(date, -9), value: 80, unit: QuantityUnit.mmHg, }, @@ -262,156 +254,113 @@ export class MockHealthSummaryService implements HealthSummaryService { ] } - async getHeartRateObservations( - userId: string, - cutoffDate: Date, - ): Promise { + private async getHeartRateObservations(date: Date): Promise { return [ { - date: this.startDateAdvancedByDays(-1), + date: advanceDateByDays(date, -1), value: 79, unit: QuantityUnit.bpm, }, { - date: this.startDateAdvancedByDays(-2), + date: advanceDateByDays(date, -2), value: 62, unit: QuantityUnit.bpm, }, { - date: this.startDateAdvancedByDays(-3), + date: advanceDateByDays(date, -3), value: 77, unit: QuantityUnit.bpm, }, { - date: this.startDateAdvancedByDays(-4), + date: advanceDateByDays(date, -4), value: 63, unit: QuantityUnit.bpm, }, { - date: this.startDateAdvancedByDays(-5), + date: advanceDateByDays(date, -5), value: 61, unit: QuantityUnit.bpm, }, { - date: this.startDateAdvancedByDays(-6), + date: advanceDateByDays(date, -6), value: 70, unit: QuantityUnit.bpm, }, { - date: this.startDateAdvancedByDays(-7), + date: advanceDateByDays(date, -7), value: 67, unit: QuantityUnit.bpm, }, { - date: this.startDateAdvancedByDays(-8), + date: advanceDateByDays(date, -8), value: 80, unit: QuantityUnit.bpm, }, { - date: this.startDateAdvancedByDays(-9), + date: advanceDateByDays(date, -9), value: 65, unit: QuantityUnit.bpm, }, ] } - async getBodyWeightObservations( - userId: string, - cutoffDate: Date, - unit: QuantityUnit, - ): Promise { + private async getBodyWeightObservations(date: Date): Promise { return [ { - date: this.startDateAdvancedByDays(-1), + date: advanceDateByDays(date, -1), value: 269, unit: QuantityUnit.lbs, }, { - date: this.startDateAdvancedByDays(-2), + date: advanceDateByDays(date, -2), value: 267, unit: QuantityUnit.lbs, }, { - date: this.startDateAdvancedByDays(-3), + date: advanceDateByDays(date, -3), value: 267, unit: QuantityUnit.lbs, }, { - date: this.startDateAdvancedByDays(-4), + date: advanceDateByDays(date, -4), value: 265, unit: QuantityUnit.lbs, }, { - date: this.startDateAdvancedByDays(-5), + date: advanceDateByDays(date, -5), value: 268, unit: QuantityUnit.lbs, }, { - date: this.startDateAdvancedByDays(-6), + date: advanceDateByDays(date, -6), value: 268, unit: QuantityUnit.lbs, }, { - date: this.startDateAdvancedByDays(-7), + date: advanceDateByDays(date, -7), value: 266, unit: QuantityUnit.lbs, }, { - date: this.startDateAdvancedByDays(-8), + date: advanceDateByDays(date, -8), value: 266, unit: QuantityUnit.lbs, }, { - date: this.startDateAdvancedByDays(-9), + date: advanceDateByDays(date, -9), value: 267, unit: QuantityUnit.lbs, }, ] } - async getMostRecentDryWeightObservation( - userId: string, + private async getMostRecentDryWeightObservation( + date: Date, ): Promise { return { - date: this.startDateAdvancedByDays(-4), + date: advanceDateByDays(date, -4), value: 267.5, unit: QuantityUnit.lbs, } } - - async getMostRecentCreatinineObservation( - userId: string, - ): Promise { - return { - date: this.startDateAdvancedByDays(-4), - value: 1.1, - unit: QuantityUnit.mg_dL, - } - } - - async getMostRecentPotassiumObservation( - userId: string, - ): Promise { - return { - date: this.startDateAdvancedByDays(-4), - value: 4.2, - unit: QuantityUnit.mEq_L, - } - } - - async getMostRecentEstimatedGlomerularFiltrationRateObservation( - userId: string, - ): Promise { - return { - date: this.startDateAdvancedByDays(-4), - value: 60, - unit: QuantityUnit.mL_min_173m2, - } - } - - // Helpers - - private startDateAdvancedByDays(days: number): Date { - return advanceDateByDays(this.startDate, days) - } } diff --git a/functions/src/services/healthSummary/healthSummaryService.ts b/functions/src/services/healthSummary/healthSummaryService.ts index 0eab74cf..7e52deea 100644 --- a/functions/src/services/healthSummary/healthSummaryService.ts +++ b/functions/src/services/healthSummary/healthSummaryService.ts @@ -12,6 +12,7 @@ import { type HealthSummaryData } from '../../models/healthSummaryData.js' export interface HealthSummaryService { getHealthSummaryData( userId: string, + date: Date, weightUnit: QuantityUnit, ): Promise } diff --git a/functions/src/services/trigger/triggerService.ts b/functions/src/services/trigger/triggerService.ts index 58009c2b..a964bced 100644 --- a/functions/src/services/trigger/triggerService.ts +++ b/functions/src/services/trigger/triggerService.ts @@ -218,7 +218,7 @@ export class TriggerService { logger.debug( `TriggerService.userObservationWritten(${userId}, ${collection}): Most recent body weight is ${mostRecentBodyWeight} compared to a median of ${bodyWeightMedian}`, ) - if (mostRecentBodyWeight - bodyWeightMedian >= 7) { + if (mostRecentBodyWeight - bodyWeightMedian >= 3) { const messageService = this.factory.message() const messageDoc = await messageService.addMessage( userId, diff --git a/functions/src/tests/mocks/healthSummaryData.ts b/functions/src/tests/mocks/healthSummaryData.ts index be976064..f64a9c55 100644 --- a/functions/src/tests/mocks/healthSummaryData.ts +++ b/functions/src/tests/mocks/healthSummaryData.ts @@ -12,6 +12,6 @@ export function mockHealthSummaryData( userId: string, startDate: Date = new Date(2024, 2, 2, 12, 30), ): Promise { - const service = new MockHealthSummaryService(startDate) - return service.getHealthSummaryData(userId) + const service = new MockHealthSummaryService() + return service.getHealthSummaryData(userId, startDate) }