Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@
"id": "phq9_5"
},
{
"label": "6. Feeling bad about yourself - or that youre a failure or have let yourself or your family down",
"label": "6. Feeling bad about yourself - or that you're a failure or have let yourself or your family down",
"type": "obs",
"questionOptions": {
"rendering": "radio",
Expand Down Expand Up @@ -562,6 +562,9 @@
"max": "27",
"min": "0",
"showDate": "",
"calculate": {
Copy link
Member

@denniskigen denniskigen Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline calculateExpression here is quite long (~1000 chars) and repeats the UUID-to-score mapping 9 times. Could we consider factoring it out into a reusable custom expression helper function in the form engine instead?

We could add a calcPHQ9Score() helper to common-expression-helpers.ts (similar to calcBMI(), calcEDD(), etc) that looks like this:

/**
 * Calculates PHQ-9 (Patient Health Questionnaire-9) depression screening score
 * Supports both PHQ-2 (questions 1-2) and full PHQ-9 (questions 1-9)
 * Handles hidden/conditional questions by treating undefined/null values as 0
 * 
 * @param responses - Variable number of PHQ question responses (concept UUIDs)
 * @returns Total score (0-27 for full PHQ-9, 0-6 for PHQ-2 only)
 * 
 * @example
 * // PHQ-2 negative screen (questions 3-9 hidden)
 * calcPHQ9Score(phq2_1, phq2_2, phq9_3, phq9_4, phq9_5, phq9_6, phq9_7, phq9_8, phq9_9)
 * // Returns: 0 if both answered "Not at all"
 * 
 * @example
 * // Full PHQ-9
 * calcPHQ9Score(phq2_1, phq2_2, phq9_3, phq9_4, phq9_5, phq9_6, phq9_7, phq9_8, phq9_9)
 * // Returns: Sum of all 9 responses (0-27)
 */
calcPHQ9Score = (...responses: (string | null | undefined)[]): number => {
  const scoreMap: Record<string, number> = {
    '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA': 0, // Not at all
    '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA': 1, // Several days
    '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA': 2, // More than half the days
    '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA': 3, // Nearly every day
  };

  return responses.reduce((sum, answer) => {
    return sum + (answer ? (scoreMap[answer] ?? 0) : 0);
  }, 0);
};

And then we could simplify the calculateExpression in this form by leveraging the new expression helper as follows:

  "calculate": {
    "calculateExpression": "calcPHQ9Score(phq2_1, phq2_2, phq9_3, phq9_4, phq9_5, phq9_6, phq9_7, phq9_8, phq9_9)"
  }

Benefits of this approach:

  • Easier to read, test, and maintain
  • Centralizes the UUID mapping logic
  • Follows DRY principle
  • Matches the architectural pattern used elsewhere in the codebase

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@denniskigen thanks for your feedback, are you suggesting that the change (custom expression helper function) should be implemented in the form engine’s codebase, not directly in the form JSON? @samuelmale is this something you can assist us?

Copy link
Member

@denniskigen denniskigen Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: PR merged. Should be available soon.

"calculateExpression": "(phq2_1 === '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 0 : phq2_1 === '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 1 : phq2_1 === '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 2 : phq2_1 === '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 3 : 0) + (phq2_2 === '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 0 : phq2_2 === '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 1 : phq2_2 === '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 2 : phq2_2 === '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 3 : 0) + (phq9_3 === '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 0 : phq9_3 === '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 1 : phq9_3 === '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 2 : phq9_3 === '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 3 : 0) + (phq9_4 === '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 0 : phq9_4 === '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 1 : phq9_4 === '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 2 : phq9_4 === '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 3 : 0) + (phq9_5 === '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 0 : phq9_5 === '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 1 : phq9_5 === '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 2 : phq9_5 === '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 3 : 0) + (phq9_6 === '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 0 : phq9_6 === '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 1 : phq9_6 === '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 2 : phq9_6 === '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 3 : 0) + (phq9_7 === '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 0 : phq9_7 === '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 1 : phq9_7 === '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 2 : phq9_7 === '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 3 : 0) + (phq9_8 === '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 0 : phq9_8 === '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 1 : phq9_8 === '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 2 : phq9_8 === '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 3 : 0) + (phq9_9 === '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 0 : phq9_9 === '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 1 : phq9_9 === '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 2 : phq9_9 === '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ? 3 : 0)"
},
"conceptMappings": [
{
"type": "SNOMED-CT",
Expand All @@ -573,7 +576,13 @@
}
]
},
"id": "phq9Score"
"id": "phq9Score",
"behaviours": [
{
"intent": "*",
"readonly": "true"
}
]
}
]
}
Expand Down Expand Up @@ -630,4 +639,4 @@
"referencedForms": [],
"encounterType": "36db5123-0ad5-41c0-9037-625b46e0ceef",
"encounter": "Mental Health Assessment"
}
}