Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(): v2.28 #8

Merged
merged 1 commit into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
25 changes: 25 additions & 0 deletions src/calculation_suite/calculations/GAD_2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generalised Anxiety Disorder Assessment (GAD-2)

## Introduction

This easy-to-use self-administered patient questionnaire is used as a screening tool and severity measure for generalised anxiety disorder (GAD).

## Calculation

This is calculated by assigning scores of 0, 1, 2, and 3 to the response categories, respectively, of “not at all”, “several days”, “more than half the days”, and “nearly every day”. GAD-2 total score for the seven items ranges from 0 to 6.

## Interpretation

Scores of 1, 3, and 5 are taken as the cut-off points for mild, moderate and severe anxiety, respectively.

| Score | Symptom Severity |
| ----- | ---------------- |
| 1-2 | Mild |
| 3-4 | Moderate |
| 5-6 | Severe |

A score of 3 points is the preferred cut-off for identifying possible cases and in which further diagnostic evaluation for generalized anxiety disorder is warranted. Using a cut-off of 3 the GAD-2 has a sensitivity of 86% and specificity of 83% for diagnosis generalized anxiety disorder.

## References

[1] Kroenke K, Spitzer RL, Williams JB, Monahan PO, Löwe B. Anxiety disorders in primary care: prevalence, impairment, comorbidity, and detection. Ann Intern Med. 2007;146:317-25.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @flow
export const best_response = {
GAD2_Q01: 0,
GAD2_Q02: 0
}

export const worst_response = {
GAD2_Q01: 3,
GAD2_Q02: 3
}

/**
* Expected score: 3
*/
export const random_response = {
GAD2_Q01: 3,
GAD2_Q02: 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// @flow
import type { InputType } from '../../../../types/calculations.types'

export const GAD2_INPUTS: Array<InputType> = [
{
input_id: 'GAD2_Q01',
input_label: {
en: 'Over the last two weeks, how often have you been bothered by feeling nervous, anxious, or on edge?',
nl: 'Hoe vaak hebt u in de afgelopen 2 weken last gehad van uzelf zenuwachtig, angstig of gespannen te voelen?'
},
input_type: {
type: 'number',
allowed_answers: [
{
label: { en: 'Not at all', nl: 'Helemaal niet' },
value: 0
},
{
label: { en: 'Several days', nl: 'Meerdere dagen' },
value: 1
},
{
label: {
en: 'More than half the days',
nl: 'Meer dan de helft van de dagen'
},
value: 2
},
{
label: { en: 'Nearly every day', nl: 'Bijna elke dag' },
value: 3
}
]
}
},
{
input_id: 'GAD2_Q02',
input_label: {
en: 'Over the last two weeks, how often have you been bothered by not being able to stop or control worrying?',
nl: 'Hoe vaak hebt u in de afgelopen 2 weken last gehad van niet in staat te zijn om te stoppen met piekeren of om controle te krijgen over het piekeren?'
},
input_type: {
type: 'number',
allowed_answers: [
{
label: { en: 'Not at all', nl: 'Helemaal niet' },
value: 0
},
{
label: { en: 'Several days', nl: 'Meerdere dagen' },
value: 1
},
{
label: {
en: 'More than half the days',
nl: 'Meer dan de helft van de dagen'
},
value: 2
},
{
label: { en: 'Nearly every day', nl: 'Bijna elke dag' },
value: 3
}
]
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @flow

type AnxietySeverityType =
| 'No anxiety'
| 'Mild anxiety'
| 'Moderate anxiety'
| 'Severe anxiety'

export const GAD2_INTERPRETATION_TABLE: Record<string, AnxietySeverityType> = {
'0': 'No anxiety',
'1': 'Mild anxiety',
'2': 'Mild anxiety',
'3': 'Moderate anxiety',
'4': 'Moderate anxiety',
'5': 'Severe anxiety',
'6': 'Severe anxiety',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// @flow

import type { CalculationOutputDefinition } from '../../../../types/calculations.types'

export const GAD2_OUTPUT: CalculationOutputDefinition[] = [
{
subresult_id: 'GAD2_SCORE',
label: { en: 'GAD-2 Score' },
type: 'number'
},
{
subresult_id: 'GAD2_INTERPRETATION',
label: { en: 'GAD-2 Interpretation' },
type: 'string'
}
]
4 changes: 4 additions & 0 deletions src/calculation_suite/calculations/GAD_2/definition/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// @flow
export { GAD2_INPUTS } from './gad_2_inputs'
export { GAD2_OUTPUT } from './gad_2_output'
export { GAD2_INTERPRETATION_TABLE } from './gad_2_interpretation'
140 changes: 140 additions & 0 deletions src/calculation_suite/calculations/GAD_2/gad_2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// @flow
import { expect } from 'chai'

import { InvalidInputsError } from '../../errors'
import { execute_test_calculation } from '../../helper_functions/execute_test_calculation'
import { get_result_ids_from_calculation_output } from '../../helper_functions/get_result_ids_from_calculation_output'
import { view_result } from '../../helper_functions/view_result'
import { view_status } from '../../helper_functions/view_status'
import { MISSING_STATUS } from '../../PARAMETERS'
import { CALCULATIONS } from '../calculation_library'
import { get_input_ids_from_calculation_blueprint } from '../shared_functions'
import {
best_response,
random_response,
worst_response,
} from './__testdata__/gad_2_test_responses'
import { GAD2_INPUTS } from './definition'
import { gad_2 } from './gad_2'

const BEST_SCORE = 0
const WORST_SCORE = 6

const gad_2_calculation = execute_test_calculation(gad_2)

describe('gad_2', function () {
it('gad_2 calculation function should be available as a calculation', function () {
expect(CALCULATIONS).to.have.property('gad_2')
})

describe('basic assumptions', function () {
const outcome = gad_2_calculation(best_response)

it('should return 2 calculation results', function () {
expect(outcome).to.have.length(2)
})

it('should have the expected calculation result ids', function () {
const EXPECTED_CALCULATION_ID = ['GAD2_SCORE', 'GAD2_INTERPRETATION']

const configured_calculation_id =
get_result_ids_from_calculation_output(outcome)

expect(configured_calculation_id).to.eql(EXPECTED_CALCULATION_ID)
})
})

describe('validation', function () {
describe('the score includes the correct input fields', function () {
it('should have all the expected input ids configured', function () {
const EXPECTED_INPUT_IDS = ['GAD2_Q01', 'GAD2_Q02']

const configured_input_ids =
get_input_ids_from_calculation_blueprint(GAD2_INPUTS)

expect(EXPECTED_INPUT_IDS).to.eql(configured_input_ids)
})
})

describe('when an answer is not not one of the allowed answers', function () {
it('should throw an InvalidInputsError', function () {
expect(() =>
gad_2_calculation({
GAD2_Q01: -1,
})
).to.throw(InvalidInputsError)
})
})

describe('when called with an empty response', function () {
const outcome = gad_2_calculation({})

it('should return undefined result and a missing status for the score', function () {
const score = view_result('GAD2_SCORE')(outcome)
const status = view_status('GAD2_SCORE')(outcome)

expect(score).to.eql(undefined)
expect(status).to.eql(MISSING_STATUS)
})

it('should return undefined result and a missing status for the interpretation', function () {
const score = view_result('GAD2_INTERPRETATION')(outcome)
const status = view_status('GAD2_INTERPRETATION')(outcome)

expect(score).to.eql(undefined)
expect(status).to.eql(MISSING_STATUS)
})
})
})

describe('score calculation', function () {
describe('when called with the best response', function () {
const outcome = gad_2_calculation(best_response)

it('should return the best score', function () {
const score = view_result('GAD2_SCORE')(outcome)

expect(score).to.eql(BEST_SCORE)
})

it('should return the "No anxiety" interpretation', function () {
const score = view_result('GAD2_INTERPRETATION')(outcome)

expect(score).to.eql('No anxiety')
})
})

describe('when called with the worst response', function () {
const outcome = gad_2_calculation(worst_response)

it('should return the worst score', function () {
const score = view_result('GAD2_SCORE')(outcome)

expect(score).to.eql(WORST_SCORE)
})

it('should return the "severe anxiety" interpretation', function () {
const score = view_result('GAD2_INTERPRETATION')(outcome)

expect(score).to.eql('Severe anxiety')
})
})

describe('when called with a random response', function () {
const outcome = gad_2_calculation(random_response)

it('should return the expected score', function () {
const score = view_result('GAD2_SCORE')(outcome)
const EXPECTED_SCORE = 3

expect(score).to.eql(EXPECTED_SCORE)
})

it('should return the "Mild anxiety" interpretation', function () {
const score = view_result('GAD2_INTERPRETATION')(outcome)

expect(score).to.eql('Moderate anxiety')
})
})
})
})
67 changes: 67 additions & 0 deletions src/calculation_suite/calculations/GAD_2/gad_2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// @flow
import R from 'ramda'

import type {
CalculationType,
InputType,
WIPCalculationResultType
} from '../../../types/calculations.types'
import { rawInputValueLens } from '../../helper_functions/calculation_variants/api/input/lenses'
import { add_raw_values_to_inputs } from '../../helper_functions/calculation_variants/simple_calculation'
import { create_calculation } from '../../helper_functions/create_calculation'
import { MISSING_MESSAGE } from '../../PARAMETERS'
import { is_numeric } from '../shared_functions'
import {
GAD2_INPUTS,
GAD2_INTERPRETATION_TABLE,
GAD2_OUTPUT
} from './definition'

const calculate_score = (
inputs_with_answers: Array<InputType>
): WIPCalculationResultType => {
const valid_inputs = R.compose(
R.filter(is_numeric),
R.map((input) => R.view(rawInputValueLens, input))
)(inputs_with_answers)

if (valid_inputs.length !== GAD2_INPUTS.length)
return [
{
id: 'GAD2_SCORE',
score: MISSING_MESSAGE
},
{
id: 'GAD2_INTERPRETATION',
score: MISSING_MESSAGE
}
]

const total_score = R.sum(valid_inputs)

return [
{
id: 'GAD2_SCORE',
score: total_score
},
{
id: 'GAD2_INTERPRETATION',
score: GAD2_INTERPRETATION_TABLE[total_score.toString()]
}
]
}

export const specific_steps_gad_2_calc = [
calculate_score,
add_raw_values_to_inputs(GAD2_INPUTS)
]

export const gad_2: CalculationType = create_calculation({
calculation_name: 'Generalised Anxiety Disorder Assessment (GAD-2)',
readme_location: __dirname,
calculation_steps: specific_steps_gad_2_calc,
calculation_definition: {
input_definition: GAD2_INPUTS,
output_definition: GAD2_OUTPUT
}
})
Loading
Loading