From dd07ee87449da29cdcdde131d2d471f573f0bcd6 Mon Sep 17 00:00:00 2001 From: Abigaila Ekiert Date: Mon, 14 Oct 2024 16:39:51 +0200 Subject: [PATCH] add aq_10 --- .../calculations/AQ_10/README.md | 25 +++ .../__testdata__/aq_10_test_responses.ts | 41 +++++ .../calculations/AQ_10/aq_10.test.ts | 132 ++++++++++++++++ .../calculations/AQ_10/aq_10.ts | 64 ++++++++ .../AQ_10/definition/aq_10_inputs.ts | 148 ++++++++++++++++++ .../AQ_10/definition/aq_10_output.ts | 14 ++ .../calculations/AQ_10/definition/index.ts | 2 + .../calculations/calculation_library.ts | 2 + 8 files changed, 428 insertions(+) create mode 100644 src/calculation_suite/calculations/AQ_10/README.md create mode 100644 src/calculation_suite/calculations/AQ_10/__testdata__/aq_10_test_responses.ts create mode 100644 src/calculation_suite/calculations/AQ_10/aq_10.test.ts create mode 100644 src/calculation_suite/calculations/AQ_10/aq_10.ts create mode 100644 src/calculation_suite/calculations/AQ_10/definition/aq_10_inputs.ts create mode 100644 src/calculation_suite/calculations/AQ_10/definition/aq_10_output.ts create mode 100644 src/calculation_suite/calculations/AQ_10/definition/index.ts diff --git a/src/calculation_suite/calculations/AQ_10/README.md b/src/calculation_suite/calculations/AQ_10/README.md new file mode 100644 index 0000000..5e355eb --- /dev/null +++ b/src/calculation_suite/calculations/AQ_10/README.md @@ -0,0 +1,25 @@ +# Autism Spectrum Quotient (AQ) Adolescent Version (AQ-10) + +## Introduction + +A quick referral guide for parents to complete about a teenager aged 12-15 years old with suspected autism who does not have a learning disability + +## Calculation + +Only 1 point can be scored for each question. Possible answers are "Definitely Agree", "Slightly Agree", "Slightly Disagree" and "Definitely Disagree". +Questions 1, 5, 8 and 10 - score 1 point for Definitely or Slightly Agree. +Questions 2, 3, 4, 6, 7 and 9 - score 1 point for Definitely or Slightly Disagree. +AQ-10 total score for the 10 items ranges from 0 to 10. + +## Interpretation + +If the individual scores 6 or above, consider referring them for a specialist diagnostic assessment. + +## Use + +This is the adolescent version of the test recommended in the NICE clinical guideline [CG142](https://www.nice.org.uk/guidance/CG142). + +## References + +[1] Allison C, Auyeung B, and Baron-Cohen S, (2012) Journal of the American Academy of Child and Adolescent Psychiatry 51(2):202-12. +[2] [Autism Research Centre](https://docs.autismresearchcentre.com/tests/AQ10-Adolescent.pdf) diff --git a/src/calculation_suite/calculations/AQ_10/__testdata__/aq_10_test_responses.ts b/src/calculation_suite/calculations/AQ_10/__testdata__/aq_10_test_responses.ts new file mode 100644 index 0000000..a738cb0 --- /dev/null +++ b/src/calculation_suite/calculations/AQ_10/__testdata__/aq_10_test_responses.ts @@ -0,0 +1,41 @@ +export const best_response = { + AQ10_Q01: 0, + AQ10_Q02: 0, + AQ10_Q03: 0, + AQ10_Q04: 0, + AQ10_Q05: 0, + AQ10_Q06: 0, + AQ10_Q07: 0, + AQ10_Q08: 0, + AQ10_Q09: 0, + AQ10_Q10: 0, +} + +export const worst_response = { + AQ10_Q01: 1, + AQ10_Q02: 1, + AQ10_Q03: 1, + AQ10_Q04: 1, + AQ10_Q05: 1, + AQ10_Q06: 1, + AQ10_Q07: 1, + AQ10_Q08: 1, + AQ10_Q09: 1, + AQ10_Q10: 1, +} + +/** + * Expected score: 6 + */ +export const random_response = { + AQ10_Q01: 1, + AQ10_Q02: 0, + AQ10_Q03: 1, + AQ10_Q04: 0, + AQ10_Q05: 0, + AQ10_Q06: 1, + AQ10_Q07: 1, + AQ10_Q08: 1, + AQ10_Q09: 0, + AQ10_Q10: 1, +} diff --git a/src/calculation_suite/calculations/AQ_10/aq_10.test.ts b/src/calculation_suite/calculations/AQ_10/aq_10.test.ts new file mode 100644 index 0000000..3701c1d --- /dev/null +++ b/src/calculation_suite/calculations/AQ_10/aq_10.test.ts @@ -0,0 +1,132 @@ +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__/aq_10_test_responses' +import { AQ10_INPUTS } from './definition' +import { aq_10 } from './aq_10' + +const BEST_SCORE = 0 +const WORST_SCORE = 10 + +const aq_10_calculation = execute_test_calculation(aq_10) + +describe('aq_10', function () { + it('aq_10 calculation function should be available as a calculation', function () { + expect(CALCULATIONS).to.have.property('aq_10') + }) + + describe('basic assumptions', function () { + const outcome = aq_10_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 = ['AQ10_SCORE', 'AQ10_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 = [ + 'AQ10_Q01', + 'AQ10_Q02', + 'AQ10_Q03', + 'AQ10_Q04', + 'AQ10_Q05', + 'AQ10_Q06', + 'AQ10_Q07', + 'AQ10_Q08', + 'AQ10_Q09', + 'AQ10_Q10', + ] + + const configured_input_ids = + get_input_ids_from_calculation_blueprint(AQ10_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(() => + aq_10_calculation({ + AQ10_Q01: -1, + }) + ).to.throw(InvalidInputsError) + }) + }) + + describe('when called with an empty response', function () { + const outcome = aq_10_calculation({}) + + it('should return undefined result and a missing status for the score', function () { + const score = view_result('AQ10_SCORE')(outcome) + const status = view_status('AQ10_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('AQ10_INTERPRETATION')(outcome) + const status = view_status('AQ10_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 = aq_10_calculation(best_response) + + it('should return the best score', function () { + const score = view_result('AQ10_SCORE')(outcome) + + expect(score).to.eql(BEST_SCORE) + }) + }) + + describe('when called with the worst response', function () { + const outcome = aq_10_calculation(worst_response) + + it('should return the worst score', function () { + const score = view_result('AQ10_SCORE')(outcome) + + expect(score).to.eql(WORST_SCORE) + }) + }) + + describe('when called with a random response', function () { + const outcome = aq_10_calculation(random_response) + + it('should return the expected score', function () { + const score = view_result('AQ10_SCORE')(outcome) + const EXPECTED_SCORE = 6 + + expect(score).to.eql(EXPECTED_SCORE) + }) + }) + }) +}) diff --git a/src/calculation_suite/calculations/AQ_10/aq_10.ts b/src/calculation_suite/calculations/AQ_10/aq_10.ts new file mode 100644 index 0000000..0074296 --- /dev/null +++ b/src/calculation_suite/calculations/AQ_10/aq_10.ts @@ -0,0 +1,64 @@ +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 { AQ10_INPUTS, AQ10_OUTPUT } from './definition' + +const calculate_score = ( + inputs_with_answers: Array +): WIPCalculationResultType => { + const valid_inputs = R.compose( + R.filter(is_numeric), + R.map(input => R.view(rawInputValueLens, input)) + )(inputs_with_answers) + + if (valid_inputs.length !== AQ10_INPUTS.length) + return [ + { + id: 'AQ10_SCORE', + score: MISSING_MESSAGE, + }, + { + id: 'AQ10_INTERPRETATION', + score: MISSING_MESSAGE, + }, + ] + + const total_score = R.sum(valid_inputs) + + return [ + { + id: 'AQ10_SCORE', + score: total_score, + }, + { + id: 'AQ10_INTERPRETATION', + score: + 'If the individual scores 6 or above, consider referring them for a specialist diagnostic assessment.', + }, + ] +} + +export const specific_steps_aq_10_calc = [ + calculate_score, + add_raw_values_to_inputs(AQ10_INPUTS), +] + +export const aq_10: CalculationType = create_calculation({ + calculation_name: + 'Autism Spectrum Quotient (AQ) - Adolescent Version - (AQ-10)', + readme_location: __dirname, + calculation_steps: specific_steps_aq_10_calc, + calculation_definition: { + input_definition: AQ10_INPUTS, + output_definition: AQ10_OUTPUT, + }, +}) diff --git a/src/calculation_suite/calculations/AQ_10/definition/aq_10_inputs.ts b/src/calculation_suite/calculations/AQ_10/definition/aq_10_inputs.ts new file mode 100644 index 0000000..a7d7868 --- /dev/null +++ b/src/calculation_suite/calculations/AQ_10/definition/aq_10_inputs.ts @@ -0,0 +1,148 @@ +import type { InputType } from '../../../../types/calculations.types' + +// for questions 1, 5, 8 and 10 +const allowed_answers_1 = [ + { + label: { en: 'Definitely Agree' }, + value: 1, + }, + { + label: { en: 'Slightly Agree' }, + value: 1, + }, + { + label: { + en: 'Slightly Disagree', + }, + value: 0, + }, + { + label: { en: 'Definitely Disagree' }, + value: 0, + }, +] + +// for questions 2, 3, 4, 6, 7 and 9 +const allowed_answers_2 = [ + { + label: { en: 'Definitely Agree' }, + value: 0, + }, + { + label: { en: 'Slightly Agree' }, + value: 0, + }, + { + label: { + en: 'Slightly Disagree', + }, + value: 1, + }, + { + label: { en: 'Definitely Disagree' }, + value: 1, + }, +] + +export const AQ10_INPUTS: Array = [ + { + input_id: 'AQ10_Q01', + input_label: { + en: 'S/he notices patterns in things all the time', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_1, + }, + }, + { + input_id: 'AQ10_Q02', + input_label: { + en: 'S/he usually concentrates more on the whole picture, rather than the small details', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_2, + }, + }, + { + input_id: 'AQ10_Q03', + input_label: { + en: 'In a social group, s/he can easily keep track of several different people`s conversations', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_2, + }, + }, + { + input_id: 'AQ10_Q04', + input_label: { + en: 'If there is an interruption, s/he can switch back to what s/he was doing very quickly', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_2, + }, + }, + { + input_id: 'AQ10_Q05', + input_label: { + en: 'S/he frequently finds that s/he doesn`t know how to keep a conversation going', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_1, + }, + }, + { + input_id: 'AQ10_Q06', + input_label: { + en: 'S/he is good at social chit-chat', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_2, + }, + }, + { + input_id: 'AQ10_Q07', + input_label: { + en: 'When s/he was younger, s/he used to enjoy playing games involving pretending with other children', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_2, + }, + }, + { + input_id: 'AQ10_Q08', + input_label: { + en: 'S/he finds it difficult to imagine what it would be like to be someone else', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_1, + }, + }, + { + input_id: 'AQ10_Q09', + input_label: { + en: 'S/he finds social situations easy', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_2, + }, + }, + { + input_id: 'AQ10_Q10', + input_label: { + en: 'S/he finds it hard to make new friends', + }, + input_type: { + type: 'number', + allowed_answers: allowed_answers_1, + }, + }, +] diff --git a/src/calculation_suite/calculations/AQ_10/definition/aq_10_output.ts b/src/calculation_suite/calculations/AQ_10/definition/aq_10_output.ts new file mode 100644 index 0000000..82772eb --- /dev/null +++ b/src/calculation_suite/calculations/AQ_10/definition/aq_10_output.ts @@ -0,0 +1,14 @@ +import type { CalculationOutputDefinition } from '../../../../types/calculations.types' + +export const AQ10_OUTPUT: CalculationOutputDefinition[] = [ + { + subresult_id: 'AQ10_SCORE', + label: { en: 'AQ-10 Score' }, + type: 'number', + }, + { + subresult_id: 'AQ10_INTERPRETATION', + label: { en: 'AQ-10 Interpretation' }, + type: 'string', + }, +] diff --git a/src/calculation_suite/calculations/AQ_10/definition/index.ts b/src/calculation_suite/calculations/AQ_10/definition/index.ts new file mode 100644 index 0000000..e768c65 --- /dev/null +++ b/src/calculation_suite/calculations/AQ_10/definition/index.ts @@ -0,0 +1,2 @@ +export { AQ10_INPUTS } from './aq_10_inputs' +export { AQ10_OUTPUT } from './aq_10_output' diff --git a/src/calculation_suite/calculations/calculation_library.ts b/src/calculation_suite/calculations/calculation_library.ts index 02a497f..fcbc2b7 100644 --- a/src/calculation_suite/calculations/calculation_library.ts +++ b/src/calculation_suite/calculations/calculation_library.ts @@ -1,6 +1,7 @@ import type { CalculationsLibraryType } from '../../types/calculations.types' import { ten_meter_walk_test } from './10_meter_walk_test/10_meter_walk_test' import { age_calc } from './age_calc/age_calc' +import { aq_10 } from './AQ_10/aq_10' import { asrs } from './asrs/asrs' import { audit } from './audit/audit' import { beck } from './beck/beck' @@ -125,6 +126,7 @@ import { psqi } from './psqi/psqi' export const CALCULATIONS: CalculationsLibraryType = { age_calc, + aq_10, acro, asrs, audit,