Skip to content

Commit

Permalink
Check for all questionnaire response items (incl nested ones) to find…
Browse files Browse the repository at this point in the history
… correct link id (#195)

# Check for all questionnaire response items (incl nested ones) to find
correct link id

## ♻️ Current situation & Problem
*Link any open issues or pull requests (PRs) related to this PR. Please
ensure that all non-trivial PRs are first tracked and discussed in an
existing GitHub issue or discussion.*


## ⚙️ Release Notes 
*Add a bullet point list summary of the feature and possible migration
guides if this is a breaking change so this section can be added to the
release notes.*
*Include code snippets that provide examples of the feature implemented
or links to the documentation if it appends or changes the public
interface.*


## 📚 Documentation
*Please ensure that you properly document any additions in conformance
to [Spezi Documentation
Guide](https://github.com/StanfordSpezi/.github/blob/main/DOCUMENTATIONGUIDE.md).*
*You can use this section to describe your solution, but we encourage
contributors to document your reasoning and changes using in-line
documentation.*


## ✅ Testing
*Please ensure that the PR meets the testing requirements set by CodeCov
and that new functionality is appropriately tested.*
*This section describes important information about the tests and why
some elements might not be testable.*


### Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md):
- [ ] I agree to follow the [Code of
Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md).
  • Loading branch information
pauljohanneskraft authored Jan 15, 2025
1 parent 111c3d7 commit 38658b1
Showing 1 changed file with 102 additions and 34 deletions.
136 changes: 102 additions & 34 deletions functions/models/src/fhir/fhirQuestionnaireResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,37 +20,76 @@ import { optionalish } from '../helpers/optionalish.js'
import { SchemaConverter } from '../helpers/schemaConverter.js'
import { type SymptomQuestionnaireResponse } from '../types/symptomQuestionnaireResponse.js'

export const fhirQuestionnaireResponseItemConverter = new Lazy(
() =>
new SchemaConverter({
schema: z.object({
answer: optionalish(
z
.object({
valueCoding: optionalish(
z.lazy(() => fhirCodingConverter.value.schema),
),
})
.array(),
),
linkId: optionalish(z.string()),
}),
encode: (object) => ({
answer:
object.answer?.flatMap((value) => ({
valueCoding:
value.valueCoding ?
fhirCodingConverter.value.encode(value.valueCoding)
: null,
})) ?? null,
linkId: object.linkId ?? null,
}),
}),
)
const fhirQuestionnaireResponseItemBaseConverter = new SchemaConverter({
schema: z.object({
answer: optionalish(
z
.object({
valueCoding: optionalish(
z.lazy(() => fhirCodingConverter.value.schema),
),
})
.array(),
),
linkId: optionalish(z.string()),
}),
encode: (object) => ({
answer:
object.answer?.flatMap((value) => ({
valueCoding:
value.valueCoding ?
fhirCodingConverter.value.encode(value.valueCoding)
: null,
})) ?? null,
linkId: object.linkId ?? null,
}),
})

export interface FHIRQuestionnaireResponseItemValue
extends z.input<
typeof fhirQuestionnaireResponseItemBaseConverter.value.schema
> {
item?:
| Array<z.input<typeof fhirQuestionnaireResponseItemConverter.value.schema>>
| null
| undefined
}

export type FHIRQuestionnaireResponseItem = z.output<
typeof fhirQuestionnaireResponseItemConverter.value.schema
>
export const fhirQuestionnaireResponseItemConverter = (() => {
const fhirQuestionnaireResponseItemSchema: z.ZodType<
FHIRQuestionnaireResponseItem,
z.ZodTypeDef,
FHIRQuestionnaireResponseItemValue
> = fhirQuestionnaireResponseItemBaseConverter.value.schema.extend({
item: optionalish(
z.array(z.lazy(() => fhirQuestionnaireResponseItemSchema)),
),
})

function fhirQuestionnaireResponseItemEncode(
object: z.output<typeof fhirQuestionnaireResponseItemSchema>,
): z.input<typeof fhirQuestionnaireResponseItemSchema> {
return {
...fhirQuestionnaireResponseItemBaseConverter.value.encode(object),
item:
object.item ?
object.item.map(fhirQuestionnaireResponseItemConverter.value.encode)
: null,
}
}

return new SchemaConverter({
schema: fhirQuestionnaireResponseItemSchema,
encode: fhirQuestionnaireResponseItemEncode,
})
})()

export interface FHIRQuestionnaireResponseItem
extends z.output<
typeof fhirQuestionnaireResponseItemBaseConverter.value.schema
> {
item?: FHIRQuestionnaireResponseItem[]
}

export const fhirQuestionnaireResponseConverter = new Lazy(
() =>
Expand Down Expand Up @@ -274,12 +313,41 @@ export class FHIRQuestionnaireResponse extends FHIRResource {
// Methods

numericSingleAnswerForLink(linkId: string): number {
const answers =
this.item?.find((item) => item.linkId === linkId)?.answer ?? []
for (const item of this.item ?? []) {
const answer = this.numericSingleAnswerForNestedItem(linkId, item)
if (answer !== undefined) return answer
}
throw new Error(`No answer found in response for linkId ${linkId}.`)
}

private numericSingleAnswerForNestedItem(
linkId: string,
item: FHIRQuestionnaireResponseItem,
): number | undefined {
if (item.linkId === linkId) {
return this.numericSingleAnswerForItem(linkId, item)
}
for (const child of item.item ?? []) {
const childAnswer = this.numericSingleAnswerForNestedItem(linkId, child)
if (childAnswer !== undefined) return childAnswer
}
return undefined
}

private numericSingleAnswerForItem(
linkId: string,
item: FHIRQuestionnaireResponseItem,
): number {
const answers = item.answer ?? []
if (answers.length !== 1)
throw new Error(`Zero or multiple answers found for linkId ${linkId}.`)
throw new Error(
`Zero or multiple answers found in response item for linkId ${linkId}.`,
)
const code = answers[0].valueCoding?.code
if (!code) throw new Error(`No answer code found for linkId ${linkId}.`)
if (!code)
throw new Error(
`No answer code found in response item for linkId ${linkId}.`,
)
return parseInt(code)
}
}

0 comments on commit 38658b1

Please sign in to comment.