@@ -262,7 +262,8 @@ engine.ExternalConstantTerm = function(ctx, parentData, node) {
262
262
// Check the user-defined environment variables first as the user can override
263
263
// the "context" variable like we do in unit tests. In this case, the user
264
264
// environment variable can replace the system environment variable in "processedVars".
265
- if ( varName in ctx . vars ) {
265
+ // If the user-defined environment variable has been processed, we don't need to process it again.
266
+ if ( varName in ctx . vars && ! ctx . processedUserVarNames . has ( varName ) ) {
266
267
// Restore the ResourceNodes for the top-level objects of the environment
267
268
// variables. The nested objects will be converted to ResourceNodes
268
269
// in the MemberInvocation method.
@@ -284,7 +285,7 @@ engine.ExternalConstantTerm = function(ctx, parentData, node) {
284
285
: value ;
285
286
}
286
287
ctx . processedVars [ varName ] = value ;
287
- delete ctx . vars [ varName ] ;
288
+ ctx . processedUserVarNames . add ( varName ) ;
288
289
} else if ( varName in ctx . processedVars ) {
289
290
// "processedVars" are variables with ready-to-use values that have already
290
291
// been converted to ResourceNodes if necessary.
@@ -705,7 +706,7 @@ function parse(path) {
705
706
* @param {(object|object[]) } resource - FHIR resource, bundle as js object or array of resources
706
707
* This resource will be modified by this function to add type information.
707
708
* @param {object } parsedPath - a special object created by the parser that describes the structure of a fhirpath expression.
708
- * @param {object } context - a hash of variable name/value pairs.
709
+ * @param {object } envVars - a hash of variable name/value pairs.
709
710
* @param {object } model - The "model" data object specific to a domain, e.g. R4.
710
711
* For example, you could pass in the result of require("fhirpath/fhir-context/r4");
711
712
* @param {object } options - additional options:
@@ -722,26 +723,27 @@ function parse(path) {
722
723
* RESTful API that is used to create %terminologies that implements
723
724
* the Terminology Service API.
724
725
*/
725
- function applyParsedPath ( resource , parsedPath , context , model , options ) {
726
+ function applyParsedPath ( resource , parsedPath , envVars , model , options ) {
726
727
constants . reset ( ) ;
727
728
let dataRoot = util . arraify ( resource ) . map (
728
729
i => i ?. __path__
729
730
? makeResNode ( i , i . __path__ . parentResNode , i . __path__ . path , null ,
730
731
i . __path__ . fhirNodeDataType )
731
- : i ) ;
732
+ : i ?. resourceType
733
+ ? makeResNode ( i , null , null , null )
734
+ : i ) ;
732
735
// doEval takes a "ctx" object, and we store things in that as we parse, so we
733
736
// need to put user-provided variable data in a sub-object, ctx.vars.
734
737
// Set up default standard variables, and allow override from the variables.
735
738
// However, we'll keep our own copy of dataRoot for internal processing.
736
739
let ctx = {
737
740
dataRoot,
738
741
processedVars : {
739
- ucum : 'http://unitsofmeasure.org'
740
- } ,
741
- vars : {
742
- context : dataRoot ,
743
- ...context
742
+ ucum : 'http://unitsofmeasure.org' ,
743
+ context : dataRoot
744
744
} ,
745
+ processedUserVarNames : new Set ( ) ,
746
+ vars : envVars || { } ,
745
747
model
746
748
} ;
747
749
if ( options . traceFn ) {
@@ -843,7 +845,7 @@ function resolveInternalTypes(val) {
843
845
* or object, if fhirData represents the part of the FHIR resource:
844
846
* @param {string } path.base - base path in resource from which fhirData was extracted
845
847
* @param {string } path.expression - FHIRPath expression relative to path.base
846
- * @param {object } [context ] - a hash of variable name/value pairs.
848
+ * @param {object } [envVars ] - a hash of variable name/value pairs.
847
849
* @param {object } [model] - The "model" data object specific to a domain, e.g. R4.
848
850
* For example, you could pass in the result of require("fhirpath/fhir-context/r4");
849
851
* @param {object } [options] - additional options:
@@ -862,8 +864,8 @@ function resolveInternalTypes(val) {
862
864
* RESTful API that is used to create %terminologies that implements
863
865
* the Terminology Service API.
864
866
*/
865
- function evaluate ( fhirData , path , context , model , options ) {
866
- return compile ( path , model , options ) ( fhirData , context ) ;
867
+ function evaluate ( fhirData , path , envVars , model , options ) {
868
+ return compile ( path , model , options ) ( fhirData , envVars ) ;
867
869
}
868
870
869
871
/**
@@ -924,7 +926,7 @@ function compile(path, model, options) {
924
926
925
927
if ( typeof path === 'object' ) {
926
928
const node = parse ( path . expression ) ;
927
- return function ( fhirData , context ) {
929
+ return function ( fhirData , envVars ) {
928
930
if ( path . base ) {
929
931
let basePath = model . pathsDefinedElsewhere [ path . base ] || path . base ;
930
932
const baseFhirNodeDataType = model && model . path2Type [ basePath ] ;
@@ -934,14 +936,14 @@ function compile(path, model, options) {
934
936
}
935
937
// Globally set model before applying parsed FHIRPath expression
936
938
TypeInfo . model = model ;
937
- return applyParsedPath ( fhirData , node , context , model , options ) ;
939
+ return applyParsedPath ( fhirData , node , envVars , model , options ) ;
938
940
} ;
939
941
} else {
940
942
const node = parse ( path ) ;
941
- return function ( fhirData , context ) {
943
+ return function ( fhirData , envVars ) {
942
944
// Globally set model before applying parsed FHIRPath expression
943
945
TypeInfo . model = model ;
944
- return applyParsedPath ( fhirData , node , context , model , options ) ;
946
+ return applyParsedPath ( fhirData , node , envVars , model , options ) ;
945
947
} ;
946
948
}
947
949
}
0 commit comments