Skip to content

Commit 35ac9c9

Browse files
Fixed some performance issues
LF-3005
1 parent 4efd8b9 commit 35ac9c9

File tree

11 files changed

+109
-79
lines changed

11 files changed

+109
-79
lines changed

fhir-context/dstu2/index.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const updateWithGeneratedData = require('../general-additions');
12
/**
23
* Exports the FHIR model data for DSTU2. This is an internal structure that
34
* will likely evolve as more FHIR specific processing is added.
@@ -24,10 +25,7 @@ const modelInfo = {
2425
path2Type: require('./path2Type.json')
2526
};
2627

27-
// Generate a set of available data types
28-
modelInfo.availableTypes = new Set();
29-
// IE11 probably doesn't support `new Set(iterable)`
30-
Object.keys(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
31-
Object.values(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
28+
// Update with generated data
29+
updateWithGeneratedData(modelInfo)
3230

3331
module.exports = modelInfo;

fhir-context/general-additions.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Update the model with generated data
2+
module.exports = (modelInfo) => {
3+
// Generate a set of available data types
4+
modelInfo.availableTypes = new Set();
5+
// IE11 probably doesn't support `new Set(iterable)`
6+
Object.keys(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
7+
Object.values(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
8+
9+
// Generate a hash map to map paths to data types excluding "BackboneElement" and "Element".
10+
modelInfo.path2TypeWithoutElements = {};
11+
for(let i in modelInfo.path2Type) {
12+
if (modelInfo.path2Type[i] === 'Element' || modelInfo.path2Type[i] === 'BackboneElement') {
13+
continue;
14+
}
15+
modelInfo.path2TypeWithoutElements[i] = modelInfo.path2Type[i];
16+
}
17+
};

fhir-context/r4/index.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const updateWithGeneratedData = require('../general-additions');
2+
13
/**
24
* Exports the FHIR model data for R4. This is an internal structure that
35
* will likely evolve as more FHIR specific processing is added.
@@ -24,10 +26,7 @@ const modelInfo = {
2426
path2Type: require('./path2Type.json')
2527
};
2628

27-
// Generate a set of available data types
28-
modelInfo.availableTypes = new Set();
29-
// IE11 probably doesn't support `new Set(iterable)`
30-
Object.keys(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
31-
Object.values(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
29+
// Update with generated data
30+
updateWithGeneratedData(modelInfo)
3231

3332
module.exports = modelInfo;

fhir-context/r5/index.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const updateWithGeneratedData = require('../general-additions');
12
/**
23
* Exports the FHIR model data for R5. This is an internal structure that
34
* will likely evolve as more FHIR specific processing is added.
@@ -24,10 +25,7 @@ const modelInfo = {
2425
path2Type: require('./path2Type.json')
2526
};
2627

27-
// Generate a set of available data types
28-
modelInfo.availableTypes = new Set();
29-
// IE11 probably doesn't support `new Set(iterable)`
30-
Object.keys(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
31-
Object.values(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
28+
// Update with generated data
29+
updateWithGeneratedData(modelInfo)
3230

3331
module.exports = modelInfo;

fhir-context/stu3/index.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const updateWithGeneratedData = require('../general-additions');
12
/**
23
* Exports the FHIR model data for STU3. This is an internal structure that
34
* will likely evolve as more FHIR specific processing is added.
@@ -24,11 +25,8 @@ const modelInfo = {
2425
path2Type: require('./path2Type.json')
2526
};
2627

27-
// Generate a set of available data types
28-
modelInfo.availableTypes = new Set();
29-
// IE11 probably doesn't support `new Set(iterable)`
30-
Object.keys(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
31-
Object.values(modelInfo.type2Parent).forEach(i => modelInfo.availableTypes.add(i));
28+
// Update with generated data
29+
updateWithGeneratedData(modelInfo)
3230

3331
module.exports = modelInfo;
3432

package-lock.json

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"@babel/eslint-parser": "^7.17.0",
1616
"@babel/preset-env": "^7.16.11",
1717
"babel-loader": "^8.2.3",
18-
"benny": "github:caderek/benny#pull/40",
18+
"benny": "github:caderek/benny#0ad058d3c7ef0b488a8fe9ae3519159fc7f36bb6",
1919
"bestzip": "^2.2.0",
2020
"copy-webpack-plugin": "^6.0.3",
2121
"cypress": "^13.7.2",

src/fhirpath.js

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,36 @@ engine.ExternalConstantTerm = function(ctx, parentData, node) {
251251
var identifier = extConstant.children[0];
252252
var varName = engine.Identifier(ctx, parentData, identifier)[0];
253253

254-
var value = ctx.vars[varName];
255-
if (!(varName in ctx.vars)) {
254+
var value;
255+
// Check the user-defined environment variables first as the user can override
256+
// the "context" variable like we do in unit tests. In this case, the user
257+
// environment variable can replace the system environment variable in "processedVars".
258+
if (varName in ctx.vars) {
259+
// Restore the ResourceNodes for the top-level objects of the environment
260+
// variables. The nested objects will be converted to ResourceNodes
261+
// in the MemberInvocation method.
262+
value = ctx.vars[varName];
263+
if (Array.isArray(value)) {
264+
value = value.map(
265+
i => i?.__path__
266+
? makeResNode(i, i.__path__.path || null, null,
267+
i.__path__.fhirNodeDataType || null)
268+
: i?.resourceType
269+
? makeResNode(i, null, null)
270+
: i );
271+
} else {
272+
value = value?.__path__
273+
? makeResNode(value, value.__path__.path || null, null,
274+
value.__path__.fhirNodeDataType || null)
275+
: value?.resourceType
276+
? makeResNode(value, null, null)
277+
: value;
278+
}
279+
ctx.processedVars[varName] = value;
280+
delete ctx.vars[varName];
281+
} else if (varName in ctx.processedVars) {
282+
value = ctx.processedVars[varName];
283+
} else {
256284
if (ctx.definedVars && varName in ctx.definedVars)
257285
value = ctx.definedVars[varName];
258286
else
@@ -656,27 +684,7 @@ function applyParsedPath(resource, parsedPath, context, model, options) {
656684
// Set up default standard variables, and allow override from the variables.
657685
// However, we'll keep our own copy of dataRoot for internal processing.
658686
let vars = {context: dataRoot, ucum: 'http://unitsofmeasure.org'};
659-
// Restore the ResourceNodes for the top-level objects of the context
660-
// variables. The nested objects will be converted to ResourceNodes
661-
// in the MemberInvocation method.
662-
if (context) {
663-
context = Object.keys(context).reduce((restoredContext, key) => {
664-
if (Array.isArray(context[key])) {
665-
restoredContext[key] = context[key].map(
666-
i => i?.__path__
667-
? makeResNode(i, i.__path__.path || null, null,
668-
i.__path__.fhirNodeDataType || null)
669-
: makeResNode(i, null, null) );
670-
} else {
671-
restoredContext[key] = context[key]?.__path__
672-
? makeResNode(context[key], context[key].__path__.path || null, null,
673-
context[key].__path__.fhirNodeDataType || null)
674-
: makeResNode(context[key], null, null);
675-
}
676-
return restoredContext;
677-
}, {});
678-
}
679-
let ctx = {dataRoot, vars: Object.assign(vars, context), model};
687+
let ctx = {dataRoot, processedVars: vars, vars: context || {}, model};
680688
if (options.traceFn) {
681689
ctx.customTraceFn = options.traceFn;
682690
}

src/misc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ engine.defineVariable = function (x, label, expr) {
5555
// Just in time initialization of definedVars
5656
if (!this.definedVars) this.definedVars = {};
5757

58-
if (Object.keys(this.vars).includes(label)) {
58+
if (label in this.vars || label in this.processedVars) {
5959
throw new Error("Environment Variable %" + label + " already defined");
6060
}
6161

src/types.js

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,23 +1315,26 @@ class ResourceNode {
13151315
* @return {TypeInfo}
13161316
*/
13171317
getTypeInfo() {
1318-
let result;
1319-
1320-
if (TypeInfo.model) {
1321-
if (/^System\.(.*)$/.test(this.fhirNodeDataType)) {
1322-
result = new TypeInfo({namespace: TypeInfo.System, name: RegExp.$1});
1323-
} else if (this.fhirNodeDataType) {
1324-
result = new TypeInfo({
1325-
namespace: TypeInfo.FHIR,
1326-
name: this.fhirNodeDataType
1327-
});
1318+
if (!this.typeInfo) {
1319+
let typeInfo;
1320+
1321+
if (TypeInfo.model) {
1322+
if (/^System\.(.*)$/.test(this.fhirNodeDataType)) {
1323+
typeInfo = new TypeInfo({namespace: TypeInfo.System, name: RegExp.$1});
1324+
} else if (this.fhirNodeDataType) {
1325+
typeInfo = new TypeInfo({
1326+
namespace: TypeInfo.FHIR,
1327+
name: this.fhirNodeDataType
1328+
});
1329+
}
13281330
}
1329-
}
13301331

1331-
return result
1332-
// Resource object properties that are not defined in the model now have
1333-
// System.* data types:
1334-
|| TypeInfo.createByValueInSystemNamespace(this.data);
1332+
this.typeInfo = typeInfo
1333+
// Resource object properties that are not defined in the model now have
1334+
// System.* data types:
1335+
|| TypeInfo.createByValueInSystemNamespace(this.data);
1336+
}
1337+
return this.typeInfo;
13351338
}
13361339

13371340
toJSON() {
@@ -1350,24 +1353,27 @@ class ResourceNode {
13501353
* @return {FP_Type|any}
13511354
*/
13521355
convertData() {
1353-
var data = this.data;
1354-
const cls = TypeInfo.typeToClassWithCheckString[this.path];
1355-
if (cls) {
1356-
data = cls.checkString(data) || data;
1357-
} else if (TypeInfo.isType(this.path, 'Quantity')) {
1358-
if (data?.system === ucumSystemUrl) {
1359-
if (typeof data.value === 'number' && typeof data.code === 'string') {
1360-
if (data.comparator !== undefined)
1361-
throw new Error('Cannot convert a FHIR.Quantity that has a comparator');
1362-
data = new FP_Quantity(
1363-
data.value,
1364-
FP_Quantity.mapUCUMCodeToTimeUnits[data.code] || '\'' + data.code + '\''
1365-
);
1356+
if (!this.convertedData) {
1357+
var data = this.data;
1358+
const cls = TypeInfo.typeToClassWithCheckString[this.path];
1359+
if (cls) {
1360+
data = cls.checkString(data) || data;
1361+
} else if (TypeInfo.isType(this.path, 'Quantity')) {
1362+
if (data?.system === ucumSystemUrl) {
1363+
if (typeof data.value === 'number' && typeof data.code === 'string') {
1364+
if (data.comparator !== undefined)
1365+
throw new Error('Cannot convert a FHIR.Quantity that has a comparator');
1366+
data = new FP_Quantity(
1367+
data.value,
1368+
FP_Quantity.mapUCUMCodeToTimeUnits[data.code] || '\'' + data.code + '\''
1369+
);
1370+
}
13661371
}
13671372
}
1368-
}
13691373

1370-
return data;
1374+
this.convertedData = data;
1375+
}
1376+
return this.convertedData;
13711377
}
13721378

13731379
}

src/utilities.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,11 @@ util.makeChildResNodes = function(parentResNode, childProperty, model) {
162162
}
163163
}
164164

165-
const fhirNodeDataType = model && model.path2Type[childPath] || null;
166-
childPath = fhirNodeDataType === 'BackboneElement' || fhirNodeDataType === 'Element' ? childPath : fhirNodeDataType || childPath;
165+
let fhirNodeDataType = null;
166+
if (model) {
167+
fhirNodeDataType = model.path2Type[childPath] || null;
168+
childPath = model.path2TypeWithoutElements[childPath] || childPath;
169+
}
167170

168171
let result;
169172
if (util.isSome(toAdd) || util.isSome(_toAdd)) {

0 commit comments

Comments
 (0)