diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index a0ea4b92..6429e351 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 with: - node-version: '12.x' + node-version: '14.x' - run: npm install - run: npm run lint - run: npm run prettier @@ -22,7 +22,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [12] + node-version: [14] steps: - uses: actions/checkout@v1 diff --git a/.gitignore b/.gitignore index a56b10b3..409a8867 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ COVERAGE/ logs/ node_modules/ dist/ -.idea/ \ No newline at end of file +.idea/ +.DS_Store \ No newline at end of file diff --git a/package.json b/package.json index 8128a496..da9cdaf6 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,9 @@ "url": "git+ssh://git@bitbucket.org/asymmetrik/carejourney-cds.git" }, "jest": { + "moduleNameMapper": { + "axios": "axios/dist/node/axios.cjs" + }, "preset": "ts-jest", "testEnvironment": "node", "transform": { @@ -51,10 +54,12 @@ "dependencies": { "@projecttacoma/node-fhir-server-core": "^2.2.8", "@types/fhir": "^0.0.35", + "axios": "^1.2.1", "body-parser": "^1.19.0", "conventional-changelog-cli": "^2.0.34", "cors": "^2.8.5", "express": "^4.17.1", + "fhirpath": "^3.2.0", "lodash": "^4.17.19", "moment": "^2.24.0", "moment-timezone": "^0.5.40", @@ -77,11 +82,13 @@ "@types/uuid": "^9.0.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", + "axios-mock-adapter": "^1.21.2", "eslint": "^8.28.0", "eslint-config-prettier": "^6.10.1", "jest": "^27.4.5", "jest-extended": "^1.2.0", "json-diff": "^0.9.0", + "nock": "^13.2.9", "nodemon": "^2.0.20", "prettier": "^2.0.5", "ts-jest": "^27.1.2", diff --git a/src/fhir/utilities.ts b/src/fhir/utilities.ts index 5d86e9bd..84a978c8 100644 --- a/src/fhir/utilities.ts +++ b/src/fhir/utilities.ts @@ -8,6 +8,7 @@ import { Globals } from '../globals'; import * as path from 'path'; import * as fs from 'fs'; import * as process from 'process'; +import crypto from 'crypto'; const re = /(?:\.([^.]+))?$/; @@ -43,7 +44,7 @@ export class FhirUtilities { let id = ''; if (!resource.id) { // If no resource ID was provided, generate one. - id = uuidv1(); + id = crypto.randomUUID(); } else { id = resource.id; } @@ -77,6 +78,7 @@ export class FhirUtilities { } const Resource = resolveSchema(baseVersion, resource.resourceType); + const fhirResource = new Resource(resource); // Create the resource's metadata @@ -87,7 +89,7 @@ export class FhirUtilities { }); if (collectionString === '') { - return reject(' Unsupported FHIR Resource Type'); + reject(' Unsupported FHIR Resource Type'); } const collection = db.collection(collectionString); @@ -104,7 +106,8 @@ export class FhirUtilities { collection.insert(doc, (err: any) => { if (err) { console.log(' Error with %s.create: ', resource.resourceType, err.message); - return reject(err); + reject(err); + return; } else { console.log(' Successfully added ' + resource.resourceType + ' -- ' + id); } @@ -113,12 +116,13 @@ export class FhirUtilities { const history_collection = db.collection(historyCollectionString); // Insert our patient record to history but don't assign _id - return history_collection.insert(history_doc, (err2: any) => { + history_collection.insert(history_doc, (err2: any) => { if (err2) { console.log(' Error with %sHistory.create: ', resource.resourceType, err2.message); - return reject(err2); + reject(err2); + return; } - return resolve({ id: doc.id, resource_version: doc.meta.versionId }); + resolve({ id: doc.id, resource_version: doc.meta.versionId }); }); }); } diff --git a/src/lib/TingoDatabase.ts b/src/lib/TingoDatabase.ts index 9d0a7e08..3f0cd96a 100644 --- a/src/lib/TingoDatabase.ts +++ b/src/lib/TingoDatabase.ts @@ -19,6 +19,6 @@ export class TingoDatabase extends Database { const tingo = new tingodb(); this.database = new tingo.Db(this.location, {}); this.client = ''; - return resolve(this.database); + resolve(this.database); }); } diff --git a/src/lib/__tests__/fixtures/library.json b/src/lib/__tests__/fixtures/library.json new file mode 100644 index 00000000..ca123617 --- /dev/null +++ b/src/lib/__tests__/fixtures/library.json @@ -0,0 +1,59 @@ +{ + "resourceType": "Library", + "id": "HomeBloodGlucoseMonitorFaceToFace-prepopulation", + "url": "http://hl7.org/fhir/us/davinci-dtr/Library/HomeBloodGlucoseMonitorFaceToFace-prepopulation", + "name": "HomeBloodGlucoseMonitorFaceToFace-prepopulation", + "version": "0.0.1", + "title": "Blood Glucose Monitor Face To Face Prepopulation", + "status": "draft", + "type": { + "coding": [ + { + "code": "logic-library" + } + ] + }, + "relatedArtifact": [ + { + "type": "depends-on", + "resource": "Library/FHIRHelpers-4.0.0" + }, + { + "type": "depends-on", + "resource": "Library/CDS_Connect_Commons_for_FHIRv400" + }, + { + "type": "depends-on", + "resource": "Library/DTRHelpers" + } + ], + "dataRequirement": [ + { + "type": "Condition", + "codeFilter": [ + { + "path": "code", + "valueSet": "http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113762.1.4.1219.35" + } + ] + }, + { + "type": "MedicationValueSet", + "codeFilter": [ + { + "path": "code", + "valueSet": "http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113762.1.4.1219.85" + } + ] + }, + { + "type": "MedicationStatement" + } + ], + "content": [ + { + "contentType": "application/elm+json", + "url": "files/HomeBloodGlucoseMonitor/r4/HomeBloodGlucoseMonitorFaceToFacePrepopulation-0.0.1.cql" + } + ] +} \ No newline at end of file diff --git a/src/lib/__tests__/fixtures/questionnaire.json b/src/lib/__tests__/fixtures/questionnaire.json new file mode 100644 index 00000000..338e199b --- /dev/null +++ b/src/lib/__tests__/fixtures/questionnaire.json @@ -0,0 +1,3527 @@ +{ + "resourceType": "Questionnaire", + "id": "review-of-system", + "meta": { + "profile": [ + "http://hl7.org/fhir/StructureDefinition/cqf-questionnaire", + "http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-questionnaire-r4" + ] + }, + "name": "Review Of System Module", + "status": "draft", + "item": [ + { + "linkId": "ROS", + "code": [ + { + "code": "71406-3", + "display": "Review of Systems", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Review of Systems", + "item": [ + { + "linkId": "ROS.1", + "code": [ + { + "code": "71407-1", + "display": "Constitutional / General", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Constitutional / General", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.1.1", + "code": [ + { + "code": "8943002", + "display": "Weight gain", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Weight gain", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.1.2", + "code": [ + { + "code": "89362005", + "display": "Weight loss", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Weight loss", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.1.3", + "code": [ + { + "code": "44186003", + "display": "Sleeping problems", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Sleeping problems", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.1.4", + "code": [ + { + "code": "84229001", + "display": "Fatigue", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Fatigue", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.1.5", + "code": [ + { + "code": "386725007", + "display": "Fever", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Fever", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.1.6", + "code": [ + { + "code": "43724002", + "display": "Chills", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Chills", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.1.7", + "code": [ + { + "code": "42984000", + "display": "Night sweats", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Night sweats", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.1.8", + "code": [ + { + "code": "52613005", + "display": "Excessive sweating", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Excessive sweating", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.1.9", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.2", + "code": [ + { + "code": "71408-9", + "display": "Eye", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Eye", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.2.1", + "code": [ + { + "code": "24982008", + "display": "Diplopia", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Diplopia", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.2.2", + "code": [ + { + "code": "225582009", + "display": "Glasses", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Glasses", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.2.3", + "code": [ + { + "code": "285049007", + "display": "Contact lenses", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Contact lenses", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "code": [ + { + "code": "75705005", + "display": "Redness", + "system": "http://snomed.info/sct" + } + ], + "linkId": "ROS.2.4", + "type": "choice", + "text": "Redness", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.2.5", + "code": [ + { + "code": "18628002", + "display": "Discharge", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Discharge", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.2.6", + "code": [ + { + "code": "111516008", + "display": "Blurred vision", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Blurred vision", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.2.7", + "code": [ + { + "code": "23986001", + "display": "Glaucoma", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Glaucoma", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.2.8", + "code": [ + { + "code": "193570009", + "display": "Cataracts", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Cataracts", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.2.9", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.3", + "code": [ + { + "code": "71409-7", + "display": "Ear-nose-mouth-throat", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Ear-nose-mouth-throat", + "item": [ + { + "linkId": "ROS.3.1", + "type": "group", + "text": "Nose", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.1.1", + "code": [ + { + "code": "249366005", + "display": "Epistaxis", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Epistaxis", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.1.2", + "code": [ + { + "code": "36971009", + "display": "Frequent sinus infections", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Frequent sinus infections", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.1.3", + "code": [ + { + "code": "64531003", + "display": "Discharge", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Discharge", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.1.4", + "code": [ + { + "code": "736499003", + "display": "Polyps", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Polyps", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "type": "string", + "linkId": "ROS.3.1.5", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.3.2", + "type": "group", + "text": "Ear", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.2.1", + "code": [ + { + "code": "60862001", + "display": "Tinnitus", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Tinnitus", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "type": "choice", + "code": [ + { + "code": "300132001", + "display": "Discharge", + "system": "http://snomed.info/sct" + } + ], + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.2.2", + "text": "Discharge", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "type": "choice", + "code": [ + { + "code": "15188001", + "display": "Hearing loss", + "system": "http://snomed.info/sct" + } + ], + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.2.3", + "text": "Hearing loss", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "type": "string", + "code": [], + "linkId": "ROS.3.2.4", + "text": "Other" + } + ] + }, + { + "type": "group", + "code": [], + "linkId": "ROS.3.3", + "text": "Mouth", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.3.1", + "code": [ + { + "code": "288939007", + "display": "Odynaphagia", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Odynaphagia", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.3.2", + "code": [ + { + "code": "46557008", + "display": "Tooth disorder", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Tooth disorder", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.3.3", + "code": [ + { + "code": "278615005", + "display": "Uses dentures", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Uses dentures", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.3.3.4", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.3.4", + "type": "group", + "text": "Throat", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.3.4.1", + "code": [ + { + "code": "50219008", + "display": "Hoarseness", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Hoarseness", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.3.4.2", + "type": "string", + "text": "Other" + } + ] + } + ] + }, + { + "linkId": "ROS.4", + "code": [ + { + "code": "71410-5", + "display": "Cardiovascular", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Cardiovascular System", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.4.1", + "code": [ + { + "code": "29857009", + "display": "Chest pain", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Chest pain", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.4.2", + "code": [ + { + "code": "80313002", + "display": "Palpitations", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Palpitations", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.4.3", + "code": [ + { + "code": "62744007", + "display": "Orthopnea", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Orthopnea", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.4.4", + "code": [ + { + "code": "88610006", + "display": "Murmur", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Murmur", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.4.5", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.5", + "code": [ + { + "code": "71411-3", + "display": "Respiratory", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Respiratory System", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.5.1", + "code": [ + { + "code": "49727002", + "display": "Cough", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Cough", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.5.2", + "code": [ + { + "code": "66857006", + "display": "Hemoptysis", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Hemoptysis", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.5.3", + "code": [ + { + "code": "267036007", + "display": "Shortness of breath", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Shortness of breath", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.5.4", + "code": [ + { + "code": "248599002", + "display": "Excess sputum production", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Excess sputum production", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.5.5", + "code": [ + { + "code": "56018004", + "display": "Wheezing", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Wheezing", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.5.6", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.6", + "code": [ + { + "code": "71412-1", + "display": "Gastrointestinal System", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Gastrointestinal", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.1", + "code": [ + { + "code": "399122003", + "display": "Swallowing problem", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Swallowing problem", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.2", + "code": [ + { + "code": "21522001", + "display": "Abdominal pain", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Abdominal pain", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.3", + "code": [ + { + "code": "16331000", + "display": "Heartburn", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Heartburn", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.4", + "code": [ + { + "code": "422587007", + "display": "Nausea", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Nausea", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.5", + "code": [ + { + "code": "422400008", + "display": "Vomiting", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Vomiting", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.6", + "code": [ + { + "code": "8765009", + "display": "Hematemesis", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Hematemesis", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.7", + "code": [ + { + "code": "14760008", + "display": "Constipation", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Constipation", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.8", + "code": [ + { + "code": "62315008", + "display": "Diarrhea", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Diarrhea", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.9", + "code": [ + { + "code": "2901004", + "display": "Melena", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Melena", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.10", + "code": [ + { + "code": "405729008", + "display": "Blood in stool", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Blood in stool", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.11", + "code": [ + { + "code": "40845000", + "display": "Ulcer", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Ulcer", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.6.12", + "code": [ + { + "code": "18165001", + "display": "Jaundice", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Jaundice", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.6.13", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.7", + "code": [ + { + "code": "71413-9", + "display": "Genitourinary", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Genitourinary System", + "item": [ + { + "linkId": "ROS.7.1", + "type": "group", + "text": "Urination", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.7.1.1", + "code": [ + { + "code": "162116003", + "display": "Increased frequency", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Increased frequency", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.7.1.2", + "code": [ + { + "code": "75088002", + "display": "Urgency", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Urgency", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.7.1.3", + "code": [ + { + "code": "5972002", + "display": "Hesitancy", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Hesitancy", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.7.1.4", + "code": [ + { + "code": "48340000", + "display": "Incontinence", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Incontinence", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.7.1.5", + "code": [ + { + "code": "49650001", + "display": "Dysuria", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Dysuria", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.7.1.6", + "code": [ + { + "code": "28442001", + "display": "Polyuria", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Polyuria", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.7.1.7", + "code": [ + { + "code": "139394000", + "display": "Nocturia", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Nocturia", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.7.1.8", + "code": [ + { + "code": "34436003", + "display": "Hematuria", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Hematuria", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + } + ] + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.7.2", + "code": [ + { + "code": "247355005", + "display": "Flank pain", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Flank pain", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.7.3", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.8", + "code": [ + { + "code": "71414-7", + "display": "Musculoskeletal", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Musculoskeletal System", + "item": [ + { + "linkId": "ROS.8.1", + "type": "group", + "text": "Joint", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.1.1", + "code": [ + { + "code": "279069000", + "display": "Pain", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Pain", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.1.2", + "code": [ + { + "code": "300887003", + "display": "Swelling", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Swelling", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.1.3", + "code": [ + { + "code": "84445001", + "display": "Stiffness", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Stiffness", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.1.4", + "code": [ + { + "code": "72704001", + "display": "Fracture", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Fracture", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.1.5", + "code": [ + { + "code": "70733008", + "display": "Range of motion limitation", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Range of motion limitation", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.1.6", + "code": [ + { + "code": "417893002", + "display": "Deformity", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Deformity", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + } + ] + }, + { + "linkId": "ROS.8.2", + "type": "group", + "text": "Muscle", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.2.1", + "code": [ + { + "code": "68962001", + "display": "Pain", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Pain", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.2.2", + "code": [ + { + "code": "82470000", + "display": "Fasciculation", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Fasciculation", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.2.3", + "code": [ + { + "code": "88092000", + "display": "Atrophy", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Atrophy", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.2.4", + "code": [ + { + "code": "26544005", + "display": "Weakness", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Weakness", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.8.2.5", + "code": [ + { + "code": "55300003", + "display": "Cramps", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Cramps", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + } + ] + }, + { + "linkId": "ROS.8.3", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.9", + "code": [ + { + "code": "71415-4", + "display": "Skin", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Skin", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.9.1", + "code": [ + { + "code": "399912005", + "display": "Pressure ulcer", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Pressure ulcer", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.9.2", + "code": [ + { + "code": "271807003", + "display": "Rash", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Rash", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.9.7", + "code": [ + { + "code": "43116000", + "display": "Eczema", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Eczema", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.9.8", + "code": [ + { + "code": "418363000", + "display": "Pruritus", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Pruritus", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.9.3", + "code": [ + { + "code": "247493001", + "display": "Splitting nail", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Splitting nail", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.9.4", + "code": [ + { + "code": "89704006", + "display": "Pitting nail", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Pitting nail", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.9.5", + "code": [ + { + "code": "278040002", + "display": "Hair loss", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Hair loss", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.9.6", + "code": [ + { + "code": "271607001", + "display": "Excessive hair growth", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Excessive hair growth", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.9.9", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.10", + "code": [ + { + "code": "71416-2", + "display": "Neurologic System", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Neurological", + "item": [ + { + "type": "choice", + "code": [ + { + "code": "91175000", + "display": "Seizure", + "system": "http://snomed.info/sct" + } + ], + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.1", + "text": "Seizure", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.2", + "code": [ + { + "code": "44077006", + "display": "Numbness", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Numbness", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.3", + "code": [ + { + "code": "62507009", + "display": "Tingling", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Tingling", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.4", + "code": [ + { + "code": "55406008", + "display": "Increased pain to touch", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Increased pain to touch", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.5", + "code": [ + { + "code": "279079003", + "display": "Dysesthesia", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Dysesthesia", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.6", + "code": [ + { + "code": "25064002", + "display": "Headache", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Headache", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.7", + "code": [ + { + "code": "41786007", + "display": "Weakness", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Weakness", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.8", + "code": [ + { + "code": "404640003", + "display": "Dizziness", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Dizziness", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.9", + "code": [ + { + "code": "271594007", + "display": "Fainting", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Fainting", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.10", + "code": [ + { + "code": "44695005", + "display": "Paralysis", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Paralysis", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.11", + "code": [ + { + "code": "26079004", + "display": "Tremors", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Tremors", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.12", + "code": [ + { + "code": "267078001", + "display": "Involuntary movements", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Involuntary movements", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.13", + "code": [ + { + "code": "22631008", + "display": "Unstable gait", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Unstable gait", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.14", + "code": [ + { + "code": "161898004", + "display": "Fall", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Fall", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.15", + "code": [ + { + "code": "386807006", + "display": "Impaired memory", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Impaired memory", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "drop-down", + "display": "Drop down" + } + ], + "text": "Drop down" + } + } + ], + "linkId": "ROS.10.17", + "code": [ + { + "code": "26329005", + "display": "Poor concentration", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Poor concentration", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.10.16", + "code": [ + { + "code": "229683000", + "display": "Speech disorders", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Speech disorders", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.10.18", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.11", + "code": [ + { + "code": "71417-0", + "display": "Psychiatric System", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Psychiatric", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.11.1", + "code": [ + { + "code": "7011001", + "display": "Hallucinations", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Hallucinations", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.11.2", + "code": [ + { + "code": "2073000", + "display": "Delusions", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Delusions", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.11.3", + "code": [ + { + "code": "366979004", + "display": "Depressed mood", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Depressed mood", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.11.4", + "code": [ + { + "code": "48694002", + "display": "Anxiety", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Anxiety", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.11.5", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.12", + "code": [ + { + "code": "71418-8", + "display": "Endocrine", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Endocrine", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.12.1", + "code": [ + { + "code": "69215007", + "display": "Heat intolerance", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Heat intolerance", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.12.2", + "code": [ + { + "code": "80585000", + "display": "Cold intolerance", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Cold intolerance", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.12.3", + "code": [ + { + "code": "3716002", + "display": "Goiter", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Goiter", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.12.4", + "code": [ + { + "code": "80182007", + "display": "Menstrual irregularity", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Menstrual irregularity", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.12.5", + "code": [ + { + "code": "170951000", + "display": "Menopausal symptoms", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Menopausal symptoms", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "type": "group", + "code": [], + "linkId": "ROS.12.6", + "text": "Breast", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.12.6.1", + "code": [ + { + "code": "89164003", + "display": "Mass/tumor", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Mass/tumor", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.12.6.2", + "code": [ + { + "code": "55222007", + "display": "Tenderness", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Tenderness", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.12.6.3", + "code": [ + { + "code": "54302000", + "display": "Nipple discharge", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Nipple discharge", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.12.6.4", + "code": [ + { + "code": "4754008", + "display": "Gynecomastia", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Gynecomastia", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + } + ] + }, + { + "linkId": "ROS.12.7", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.13", + "code": [ + { + "code": "71419-6", + "display": "Hematologic - Lymphatic System", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Hematologic - lymphatic", + "item": [ + { + "linkId": "ROS.13.1", + "type": "group", + "text": "Swollen glands", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.13.1.1", + "code": [ + { + "code": "425061006", + "display": "Neck", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Neck", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.13.1.2", + "code": [ + { + "code": "127189005", + "display": "Axilla", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Axilla", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button", + "display": "Radio Button" + } + ], + "text": "Radio Button" + } + } + ], + "linkId": "ROS.13.1.3", + "code": [ + { + "code": "127199000", + "display": "Groin", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Groin", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + } + ] + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.13.2", + "code": [ + { + "code": "79654002", + "display": "Edema", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Edema", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.13.3", + "code": [ + { + "code": "63491006", + "display": "Claudication", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Claudication", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.13.4", + "code": [ + { + "code": "128060009", + "display": "Varicose veins", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Varicose veins", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.13.5", + "code": [ + { + "code": "64156001", + "display": "Thrombophlebitis", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Thrombophlebitis", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.13.6", + "code": [ + { + "code": "271737000", + "display": "Anemia", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Anemia", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.13.7", + "code": [ + { + "code": "125667009", + "display": "Bruising", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Bruising", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.13.8", + "code": [ + { + "code": "64779008", + "display": "Bleeding disorder", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Bleeding disorder", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.13.9", + "code": [ + { + "code": "95344007", + "display": "Lower extremity ulcer", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Lower extremity ulcer", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.13.10", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.14", + "code": [ + { + "code": "71420-4", + "display": "Allergic/immunologic", + "system": "http://loinc.org" + } + ], + "type": "group", + "text": "Allergic/immunologic", + "item": [ + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.14.1", + "code": [ + { + "code": "247472004", + "display": "Hives", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Hives", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "coding": [ + { + "system": "http://hl7.org/fhir/questionnaire-item-control", + "code": "radio-button" + } + ] + } + } + ], + "linkId": "ROS.14.2", + "code": [ + { + "code": "39579001", + "display": "Anaphylaxis", + "system": "http://snomed.info/sct" + } + ], + "type": "choice", + "text": "Anaphylaxis", + "answerValueSet": "http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked" + }, + { + "linkId": "ROS.14.3", + "type": "string", + "text": "Other" + } + ] + }, + { + "linkId": "ROS.15", + "type": "display", + "text": "A review of systems is an inventory of body systems obtained through a series of questions seeking to identify signs and/or symptoms which the patient may be experiencing or has experienced", + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl", + "valueCodeableConcept": { + "text": "Help-Button", + "coding": [ + { + "code": "help", + "display": "Help-Button", + "system": "http://hl7.org/fhir/questionnaire-item-control" + } + ] + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/lib/__tests__/fixtures/valueSet.json b/src/lib/__tests__/fixtures/valueSet.json new file mode 100644 index 00000000..a1007b07 --- /dev/null +++ b/src/lib/__tests__/fixtures/valueSet.json @@ -0,0 +1 @@ +{"resourceType" : "ValueSet"} \ No newline at end of file diff --git a/src/lib/__tests__/vsac_cache.test.ts b/src/lib/__tests__/vsac_cache.test.ts new file mode 100644 index 00000000..cca862c6 --- /dev/null +++ b/src/lib/__tests__/vsac_cache.test.ts @@ -0,0 +1,149 @@ +import VsacCache from '../vsac_cache'; +import library from './fixtures/library.json'; +import questionnaire from './fixtures/questionnaire.json'; +import valueSet from './fixtures/valueSet.json'; +import fs from 'fs'; +import nock from 'nock'; +import { TingoDatabase } from '../TingoDatabase'; +import { Globals } from '../../globals'; + +describe('VsacCache', () => { + const client = new VsacCache('./tmp', '2c1d55c3-3484-4902-b645-25f3a4974ce6'); + const dbClient = new TingoDatabase({ + location: './tingo_db', + options: '' + }); + dbClient.connect(); + Globals.databaseClient = dbClient.client; + Globals.database = dbClient.database; + + beforeEach(() => { + Globals.database.close(); + fs.rmSync('./tingo_db', { recursive: true, force: true }); + dbClient.connect(); + Globals.databaseClient = dbClient.client; + Globals.database = dbClient.database; + // client.clearCache(); + client.onlyVsac = false; + jest.resetModules(); + }); + + // need to mock the server endpoints to we do not require hitting + // the server for CI testing with someones api credentials + + test('should be able to collect valueset references from Library Resources', async () => { + const valueSets = client.collectLibraryValuesets(library); + expect(valueSets).toEqual( + new Set([ + 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113762.1.4.1219.85', + 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113762.1.4.1219.35' + ]) + ); + }); + + test('should be able to collect valueset references from Questionnaire Resources', async () => { + const valueSets = client.collectQuestionnaireValuesets(questionnaire); + expect(valueSets).toEqual( + new Set(['http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked']) + ); + }); + + test('should be able to cache valuesets in Library Resources', async () => { + const mockRequest = nock('http://cts.nlm.nih.gov/fhir'); + + mockRequest + .get('/ValueSet/2.16.840.1.113762.1.4.1219.85/$expand') + .reply(200, JSON.stringify(valueSet)); + mockRequest + .get('/ValueSet/2.16.840.1.113762.1.4.1219.35/$expand') + .reply(200, JSON.stringify(valueSet)); + + const valueSets = client.collectLibraryValuesets(library); + valueSets.forEach(async vs => { + expect(await client.isCached(vs)).toBeFalsy(); + }); + + try { + await client.cacheLibrary(library); + valueSets.forEach(async vs => { + expect(await client.isCached(vs)).toBeTruthy(); + }); + } finally { + mockRequest.done(); + } + }); + + test('should be able to cache valuesets in Questionnaire Resources', async () => { + const mockRequest = nock('http://terminology.hl7.org/'); + mockRequest.get('/ValueSet/yes-no-unknown-not-asked').reply(200, JSON.stringify(valueSet)); + + const valueSets = client.collectQuestionnaireValuesets(questionnaire); + valueSets.forEach(async vs => { + expect(await client.isCached(vs)).toBeFalsy(); + }); + + try { + await client.cacheQuestionnaireItems(questionnaire); + valueSets.forEach(async vs => { + expect(await client.isCached(vs)).toBeTruthy(); + }); + } finally { + mockRequest.done(); + } + }); + + test.skip('should be not load valuesets already cached unless forced', async () => { + const mockRequest = nock('http://terminology.hl7.org/'); + mockRequest.get('/ValueSet/yes-no-unknown-not-asked').reply(200, JSON.stringify(valueSet)); + try { + const valueSets = client.collectQuestionnaireValuesets(questionnaire); + valueSets.forEach(async vs => { + expect(await client.isCached(vs)).toBeFalsy(); + }); + + const cached = await client.cacheQuestionnaireItems(questionnaire); + + valueSets.forEach(async vs => { + expect(await client.isCached(vs)).toBeTruthy(); + }); + + const vs = valueSets.values().next().value; + let update = await client.downloadAndCacheValueset(vs); + expect(update.get('cached')).toBeFalsy(); + + mockRequest.get('/ValueSet/yes-no-unknown-not-asked').reply(200, JSON.stringify(valueSet)); + update = await client.downloadAndCacheValueset(vs, true); + + expect(update.get('cached')).toBeTruthy(); + } finally { + mockRequest.done(); + } + }); + + test('should be able to handle errors downloading valuesests', async () => { + const mockRequest = nock('http://terminology.hl7.org/'); + mockRequest.get('/ValueSet/yes-no-unknown-not-asked').reply(404, ''); + + const valueSets = client.collectQuestionnaireValuesets(questionnaire); + valueSets.forEach(async vs => { + expect(await client.isCached(vs)).toBeFalsy(); + }); + + try { + const err = await client.downloadAndCacheValueset( + 'http://terminology.hl7.org/ValueSet/yes-no-unknown-not-asked' + ); + expect(err.get('error')).toBeDefined(); + } finally { + mockRequest.done(); + } + }); + + test('Should not attempt tp download non-vsac valuesets if configured to do so', async () => { + client.onlyVsac = true; + const err = await client.downloadAndCacheValueset('http://localhost:9999/vs/1234'); + expect(err.get('error')).toEqual( + 'Cannot download non vsac valuesets: http://localhost:9999/vs/1234' + ); + }); +}); diff --git a/src/lib/vsac_cache.ts b/src/lib/vsac_cache.ts new file mode 100644 index 00000000..0c08252f --- /dev/null +++ b/src/lib/vsac_cache.ts @@ -0,0 +1,257 @@ +import axios from 'axios'; +import fhirpath from 'fhirpath'; +import fs from 'fs'; +import { stringify } from 'querystring'; +import { FhirUtilities } from '../fhir/utilities'; +import { Globals } from '../globals'; +import constants from '../constants'; +class VsacCache { + cacheDir: string; + apiKey: string; + baseUrl: string; + onlyVsac: boolean; + base_version: string; + + constructor( + cacheDir: string, + apiKey: string, + baseUrl = 'http://cts.nlm.nih.gov/fhir/', + onlyVsac = false, + base_version = '4_0_0' + ) { + this.cacheDir = cacheDir; + this.apiKey = apiKey; + this.baseUrl = baseUrl; + this.onlyVsac = onlyVsac; + this.base_version = base_version; + } + + /** + * + * @param library The library to cache valuesets for + * @param forceReload flag to force reaching valuesets already cached + * @returns Map of caching results url: {valueSet, error, cached} + */ + async cacheLibrary(library: any, forceReload = false) { + const valueSets = this.collectLibraryValuesets(library); + return await this.cacheValuesets(valueSets); + } + + /** + * + * @param obj Questionnaire|item object to cache valuesets for + * @param forceReload flag to force reaching valuesets already cached + * @returns Map of caching results url: {valueSet, error, cached} + */ + + async cacheQuestionnaireItems(obj: any, forceReload = false) { + const valueSets = this.collectQuestionnaireValuesets(obj); + return await this.cacheValuesets(valueSets); + } + + /** + * + * @param library The fhir Library to download valuesets from + * @returns a Set that includes all of the valueset urls found in the Library + */ + collectLibraryValuesets(library: any) { + // ensure only unique values + return new Set(fhirpath.evaluate(library, 'Library.dataRequirement.codeFilter.valueSet')); + } + + /** + * + * @param obj the Questionnaire object or item to collect answerValueSet urls from + * @returns a Set that includes all of the valuesets in the passed object. This returns values for sub items as well + */ + collectQuestionnaireValuesets(obj: any) { + const items = obj.item; + let valuesets = new Set(); + items.forEach(async (item: any) => { + if (item.answerValueSet) { + valuesets.add(item.answerValueSet); + } + if (item.item) { + valuesets = new Set([...valuesets, ...this.collectQuestionnaireValuesets(item)]); + } + }); + // ensure only unique values + return valuesets; + } + + /** + * + * @param valueSets The valusets to cache + * @param forceReload flag to force downloading and caching of the valuesets + * @returns a Map with the return values from caching the valuesets. + */ + async cacheValuesets(valueSets: Set | [], forceReload = false) { + const values = Array.from(valueSets); + const results = new Map(); + return await Promise.all( + values.map(async vs => { + return results.set(vs, await this.downloadAndCacheValueset(vs, forceReload)); + }) + ); + } + + /** + * + * @param idOrUrl the Url to download + * @param forceReload flag to force recaching already cached values + * @returns Map that contains results url: {cached, valueSet, error} + */ + async downloadAndCacheValueset(idOrUrl: string, forceReload = false) { + if (forceReload || !(await this.isCached(idOrUrl))) { + const vs = await this.downloadValueset(idOrUrl); + if (vs.get('error')) { + console.log('Error Downloading ', idOrUrl); + console.log(vs.get('error').message); + } else if (vs.get('valueSet')) { + await this.storeValueSet(this.getValuesetId(idOrUrl), vs.get('valueSet')); + vs.set('cached', true); + } + return vs; + } + const ret = new Map(); + ret.set('cached', false); + return ret; + } + + /** + * + * @param idOrUrl the url to download + * @returns Map that contains results url: {valueset, error} + */ + async downloadValueset(idOrUrl: string) { + const retValue = new Map(); + const vsUrl = this.gtValuesetURL(idOrUrl); + const headers: any = { + Accept: 'application/json+fhir' + }; + let isVsac = false; + // this will only add headers to vsac urls + if (vsUrl.startsWith(this.baseUrl)) { + headers['Authorization'] = 'Basic ' + Buffer.from(':' + this.apiKey).toString('base64'); + isVsac = true; + } + // this will try to download valuesets that are not in vsac as well based on the + // connonical url passed in. + let url = vsUrl; + if (vsUrl.startsWith(this.baseUrl)) { + url = url + '/$expand'; + } + // axios cleanup + await process.nextTick(() => { + const v = 1; + }); + if ((this.onlyVsac && isVsac) || !this.onlyVsac) { + try { + console.log('Downloading vs ' + url); + const vs = await axios.get(url, { + headers: headers + }); + retValue.set('valueSet', vs.data); + } catch (error: any) { + retValue.set('error', error); + } + } else { + retValue.set('error', 'Cannot download non vsac valuesets: ' + url); + } + + return retValue; + } + + /** + * + * @param idOrUrl url to test if already cached + * @returns true or false + */ + async isCached(idOrUrl: string) { + const id = this.getValuesetId(idOrUrl); + + // Grab an instance of our DB and collection + const db = Globals.database; + const collection = db.collection(`${constants.COLLECTION.VALUESET}_${this.base_version}`); + // Query our collection for this observation + return await new Promise((resolve, reject) => { + collection.findOne({ id: id }, (err: any, valueSet: any) => { + if (err) { + console.log('Error with ValueSet.searchById: ', err); + reject(err); + } + if (valueSet) { + resolve(valueSet); + } + resolve(null); + }); + }); + } + + /** + * Stores a valueset in the cache. This currently only works for new inserts and will not update + * any resources currently cached. This will be updated with a move to Mongo. + * @param vs the valueset to cache + */ + async storeValueSet(id: string, vs: any) { + if (!vs.id) { + vs.id = id; + } + await new Promise((resolve, reject) => FhirUtilities.store(vs, resolve, reject)); + } + + /** + * + * @param idOrUrl the url to cache + * @returns identifier used to cache the vs + */ + getValuesetId(idOrUrl: string) { + // is this a url or an id + if (idOrUrl.startsWith('http://') || idOrUrl.startsWith('https://')) { + const url = new URL(idOrUrl); + const parts = url.pathname.split('/'); + return parts[parts.length - 1]; + } + return idOrUrl; + } + + /** + * + * @param idOrUrl the url to cache + * @returns identifier used to cache the vs + */ + gtValuesetURL(idOrUrl: string) { + // is this a url or an id + if (idOrUrl.startsWith('http://') || idOrUrl.startsWith('https://')) { + return idOrUrl; + } + let path = `${this.baseUrl}/ValueSet/${idOrUrl}`; + path = path.replace('//', '/'); + return path; + } + /** + * Clear all of the cached valuesets + * This currently does not work since merging and updating to use tingo. Drop collection in tingo is broken + * + */ + clearCache() { + // drop the collection + try { + const db = Globals.database; + const collection = db.collection(`${constants.COLLECTION.VALUESET}_${this.base_version}`); + if (collection) { + collection.drop(console.log); + const history_collection = db.collection( + `${constants.COLLECTION.VALUESET}_${this.base_version}_History` + ); + if (history_collection) { + history_collection.drop(console.log); + } + } + } catch (e) { + console.error(e); + } + } +} + +export default VsacCache;