cql-exec-fhir
Advanced tools
Comparing version 1.1.0 to 1.1.1
@@ -158,3 +158,3 @@ 'use strict'; | ||
var suffix = parts.length > 1 ? parts.splice(1).join('.') : undefined; | ||
var element = this._typeInfo.findElement(root); | ||
var element = this._typeInfo.findElement(root, true); // true: support explicit choices | ||
if (typeof element === 'undefined') { | ||
@@ -165,35 +165,51 @@ console.error('Failed to locate element for ' + this._typeInfo.name + '.' + root); | ||
var property = root; | ||
var typeSpecifier = element.typeSpecifier; | ||
// Special handling for choices to find the right value in FHIR (e.g., the property might | ||
// be 'value', but in JSON, it's spelled out as 'valueDateTime') | ||
if (typeSpecifier.isChoice) { | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
var choicePropertyName = function choicePropertyName(element, choice) { | ||
return '' + element.name + choice.name[0].toUpperCase() + choice.name.slice(1); | ||
}; | ||
try { | ||
for (var _iterator2 = typeSpecifier.choices[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var choice = _step2.value; | ||
var property = void 0, | ||
typeSpecifier = void 0; | ||
if (root !== element.name && element.typeSpecifier.isChoice) { | ||
// This only happens when the root was explicit (e.g., medicationCodeableConcept) but the | ||
// property is a choice (e.g., medication). In this case we need to find the matchin choice | ||
// and use it. We don't want other choices, even if they're in the data. | ||
property = root; // keep the explicit name | ||
typeSpecifier = element.typeSpecifier.choices.find(function (c) { | ||
return property === choicePropertyName(element, c); | ||
}); | ||
} else { | ||
property = element.name; | ||
typeSpecifier = element.typeSpecifier; | ||
if (typeSpecifier.isChoice) { | ||
// Special handling for choices to find the right value in the FHIR data (e.g., the property | ||
// might be 'value', but in JSON, it's spelled out as 'valueDateTime'). | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
if (choice.isNamed) { | ||
var choiceProperty = '' + property + choice.name[0].toUpperCase() + choice.name.slice(1); | ||
if (this._json[choiceProperty] != null || this._json['_' + choiceProperty] != null) { | ||
property = choiceProperty; | ||
typeSpecifier = choice; | ||
break; | ||
try { | ||
for (var _iterator2 = typeSpecifier.choices[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var choice = _step2.value; | ||
if (choice.isNamed) { | ||
var choiceProperty = choicePropertyName(element, choice); | ||
if (this._json[choiceProperty] != null || this._json['_' + choiceProperty] != null) { | ||
property = choiceProperty; | ||
typeSpecifier = choice; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
@@ -200,0 +216,0 @@ } |
@@ -219,3 +219,18 @@ 'use strict'; | ||
key: 'findElement', | ||
/** | ||
* Finds an element by name, optionally allowing for explicit choice names. If explicit choice names | ||
* are allowed, then if 'medicationCodeableConcept' is passed in, but the real element name is | ||
* 'medication' and it is a choice where 'CodeableConcept' is a valid option type, then it will return | ||
* that. If explicit choice names are not allowed, it will return `undefined`. Technically, explicit | ||
* choicenames won't come up often -- likely only when a ModelInfo uses one as its primaryCodePath or | ||
* primaryDatePath (and even then, some might consider that a bug in the ModelInfo). | ||
* @param {string} el - the name of the element to find | ||
* @param {boolean} allowExplicitChoice - indicates if explicit choice names are allowed | ||
* @return {ClassElement} | ||
*/ | ||
value: function findElement(el) { | ||
var allowExplicitChoice = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; | ||
var element = this._elementsByName.get(el); | ||
@@ -226,2 +241,26 @@ // TODO: Should we add support for when the base type is a System type? | ||
} | ||
if (element == null && allowExplicitChoice) { | ||
// Now go through the name checking possible combinations of name and type for explicit choices | ||
// E.g., medicationCodeableConcept -> medication / CodeableConcept -> medicationCodeable / Concept | ||
for (var i = 0; i < el.length; i++) { | ||
if (/^[A-Z]$/.test(el[i])) { | ||
var name = el.slice(0, i); | ||
var potential = this.findElement(name, false); | ||
if (potential != null && potential.typeSpecifier && potential.typeSpecifier.isChoice) { | ||
var _ret = function () { | ||
var explicitType = el.slice(i); | ||
var typeMatchesChoice = potential.typeSpecifier.choices.find(function (c) { | ||
return c.name === explicitType || c.name === '' + explicitType[0].toLowerCase() + explicitType.slice(1); | ||
}); | ||
if (typeMatchesChoice) { | ||
element = potential; | ||
return 'break'; | ||
} | ||
}(); | ||
if (_ret === 'break') break; | ||
} | ||
} | ||
} | ||
} | ||
return element; | ||
@@ -228,0 +267,0 @@ } |
{ | ||
"name": "cql-exec-fhir", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Provides a FHIR-based data source for use w/ CQL", | ||
@@ -5,0 +5,0 @@ "author": "Chris Moesel <cmoesel@mitre.org>", |
@@ -223,2 +223,18 @@ const cql = require('cql-execution'); | ||
it('should support getting an option of a choice using explicit name', () => { | ||
// This is needed because the ModelInfo indicates MedicationRequest's primaryCodePath as medicationCodeableConcept! | ||
const pt = patientSource.currentPatient(); | ||
const condition = pt.findRecords('MedicationRequest').find(p => p.getId() === 'a87a2346-f826-40db-95ff-0660786460c0'); | ||
const code = condition.getCode('medicationCodeableConcept'); | ||
expect(code).to.deep.equal(new cql.Code('308192', 'http://www.nlm.nih.gov/research/umls/rxnorm', undefined, 'Amoxicillin 500 MG Oral Tablet')); | ||
}); | ||
it('should not return wrong type if explicit choice name was requested but data used different type', () => { | ||
// This is needed because the ModelInfo indicates MedicationRequest's primaryCodePath as medicationCodeableConcept! | ||
const pt = patientSource.currentPatient(); | ||
const condition = pt.findRecords('MedicationRequest').find(p => p.getId() === 'a87a2346-f826-40db-95ff-0660786460c0'); | ||
const code = condition.getCode('medicationReference'); | ||
expect(code).to.be.undefined; | ||
}); | ||
it('should support id and extension on primitives', () => { | ||
@@ -225,0 +241,0 @@ const pt = patientSource.currentPatient(); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
3675797
35192
0