Skip to content

Commit d8f7a4e

Browse files
committed
Check retrieve stack for alias
1 parent c112e3b commit d8f7a4e

1 file changed

Lines changed: 30 additions & 22 deletions

File tree

src/helpers/DataRequirementHelpers.ts

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ import { SearchParameters } from '../compartment-definition/SearchParameters';
77
import {
88
AnyELMExpression,
99
ELM,
10-
ELMAliasedQuerySource,
1110
ELMFunctionRef,
1211
ELMIdentifier,
13-
ELMLast,
1412
ELMProperty,
1513
ELMQuery,
1614
ELMStatement
@@ -31,7 +29,7 @@ import { DateTime, Interval } from 'cql-execution';
3129
import { parseTimeStringAsUTC } from '../execution/ValueSetHelper';
3230
import * as MeasureBundleHelpers from './MeasureBundleHelpers';
3331
import { findLibraryReference } from './elm/ELMDependencyHelpers';
34-
import { findClauseInExpression, findClauseInLibrary, findNamedClausesInExpression } from './elm/ELMHelpers';
32+
import { findClauseInLibrary, findNamedClausesInExpression } from './elm/ELMHelpers';
3533
const FHIR_QUERY_PATTERN_URL = 'http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/cqfm-fhirQueryPattern';
3634

3735
/**
@@ -467,6 +465,7 @@ function didEncounterDetailedValueFilterErrors(tbd: fhir4.Extension | GracefulEr
467465
function addMustSupport(allRetrieves: DataTypeQuery[], statement: ELMStatement, rootLib: ELM, allELM: ELM[]) {
468466
const propertyExpressions = findPropertyExpressions(statement, [], rootLib, allELM);
469467

468+
// TODO: double check that the property is applicable for the retrieve type before adding is as a mustSupport
470469
propertyExpressions.forEach(prop => {
471470
// find all matches for this property in allRetrieves
472471
const retrieveMatches = findRetrieveMatches(prop, allRetrieves, allELM);
@@ -630,20 +629,20 @@ export function findRetrieveMatches(prop: PropertyTracker, retrieves: DataTypeQu
630629
const matchIdx = prop.stack.findIndex(
631630
s => s.localId === stackMatch.localId && s.libraryName === stackMatch.libraryName
632631
);
632+
const retMatchIdx = retrieve.expressionStack?.findIndex(
633+
s => s.localId === stackMatch.localId && s.libraryName === stackMatch.libraryName
634+
);
633635
if (prop.property.scope) {
634636
// travel the stack looking for nearest queries (limited by stackMatch)
635637
const scopedQuery = findStackScopedQuery(prop.stack.slice(matchIdx), prop.property.scope, allELM);
636638

637639
if (!scopedQuery) return false;
638640
const { query, position, source } = scopedQuery;
639641
// if the query is our stackMatch, stop here, otherwise continue with query source
640-
if (position === 0) {
641-
// confirm alias matches scope (i.e. the retrieve is somewhere within the source expression tree) // TODO: this is not sufficient, multiple retrieves could be defined within the tree of this source, not just the right one
642-
return (
643-
source &&
644-
source.expression.localId &&
645-
!!retrieve.expressionStack?.find(st => st.localId === source.expression.localId)
646-
);
642+
if (position === 0 && 'alias' in source && source.alias && retrieve.expressionStack) {
643+
//TODO: combine this and the if below??? or just get rid of position 0?
644+
// confirm alias matches scope (i.e. follow the alias down the retrieve stack)
645+
return checkRetrieveStackForAlias(retrieve.expressionStack.slice(retMatchIdx), source.alias, allELM);
647646
}
648647
if ('name' in source.expression && source.expression.name) {
649648
// TODO: do we need any further checks here with the highest reference name?
@@ -661,18 +660,6 @@ export function findRetrieveMatches(prop: PropertyTracker, retrieves: DataTypeQu
661660
const stackSlice = prop.stack.slice(matchIdx);
662661
const checkName = checkStackFunctionDefs(stackSlice, prop.property.source.name, allELM);
663662
if (checkName) {
664-
// get highest FunctionRef in the stack
665-
// check that the operand has an AliasRef type expression with a name equal to...
666-
// top alias in the retrieve stack (up to stackMatch) -> BipolarDiagnosis vs QualifyingEncounter
667-
// const funcRefStackEntry = stackSlice.find(se => se.type === 'FunctionRef');
668-
// if (!funcRefStackEntry) return true;
669-
// const aliasExp = (expressionFromStackEntry(funcRefStackEntry, allELM) as ELMFunctionRef).operand.find(
670-
// o => o.type === 'AliasRef'
671-
// );
672-
673-
const retMatchIdx = retrieve.expressionStack?.findIndex(
674-
s => s.localId === stackMatch.localId && s.libraryName === stackMatch.libraryName
675-
);
676663
const retSlice = retrieve.expressionStack?.slice(retMatchIdx);
677664
const topAlias = retSlice
678665
?.map(se => {
@@ -694,6 +681,27 @@ export function findRetrieveMatches(prop: PropertyTracker, retrieves: DataTypeQu
694681
});
695682
}
696683

684+
// traverse down a retrieve stack, checking query sources and traversing expression references all the way to the retrieve
685+
// currently checks first query and whether a with/without invalidates a contained retrieve, TODO: may need further checks down the stack
686+
export function checkRetrieveStackForAlias(stack: ExpressionStackEntry[], alias: string, allELM: ELM[]) {
687+
for (let i = 0; i < stack.length - 1; i++) {
688+
if (stack[i].type === 'Query') {
689+
const query = expressionFromStackEntry(stack[i], allELM) as ELMQuery;
690+
// search source or relationship next stack expression
691+
const sourceMatch = query.source.find(s => s.expression.localId === stack[i + 1].localId);
692+
const relationshipMatch = query.relationship?.find(r => r.localId === stack[i + 1].localId);
693+
const expRefChange =
694+
stack[i + 1].type === 'ExpressionRef' && stack.find(se => se.type === 'With' || se.type === 'Without');
695+
if (sourceMatch) {
696+
return sourceMatch.alias === alias && !expRefChange;
697+
} else if (relationshipMatch) {
698+
return relationshipMatch.alias === alias && !expRefChange;
699+
}
700+
}
701+
}
702+
return true;
703+
}
704+
697705
// traverse from end of the stack to find the nearest query that has alias labeled with the passed scope
698706
export function findStackScopedQuery(stack: ExpressionStackEntry[], scope: string, allELM: ELM[]) {
699707
for (let i = stack.length - 1; i >= 0; i--) {

0 commit comments

Comments
 (0)