Skip to content

Commit

Permalink
Focused statement option and some query info improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
lmd59 committed Jan 29, 2025
1 parent 076086a commit 9e7aea5
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 15 deletions.
13 changes: 12 additions & 1 deletion src/calculation/Calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,18 @@ export async function calculateQueryInfo(
const parameters = { 'Measurement Period': new Interval(startCql, endCql) };
// get the retrieves for every statement in the root library
const withErrors: GracefulError[] = [];
const allRetrieves = rootLib.library.statements.def.flatMap(statement => {

let statements = rootLib.library.statements.def;
if (options.focusedStatement) {
const focalStatement = rootLib.library.statements.def.find(s => s.name === options.focusedStatement);
// if focal statement isn't found, warn and stick with the default
if (focalStatement) {
statements = [focalStatement];
} else {
console.warn(`Focused statement \"${options.focusedStatement}\" not found in root library.`);
}
}
const allRetrieves = statements.flatMap(statement => {
if (statement.expression && statement.name != 'Patient') {
const retrievesOutput = RetrievesHelper.findRetrieves(rootLib, elmJSONs, statement.expression);
withErrors.push(...retrievesOutput.withErrors);
Expand Down
8 changes: 7 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ program
'Path to a file that fqm-execution will write the calculation results to (default: output.json)'
)
.option('--root-lib-ref <root-lib-ref>', 'Reference to the root library', undefined)
.option(
'--focused-statement <statement name>',
'To specify the name of the statement that should be focused on for query info calculation',
undefined
)
.parse(process.argv);

function parseBundle(filePath: string): fhir4.Bundle {
Expand Down Expand Up @@ -202,7 +207,8 @@ const calcOptions: CalculationOptions = {
useValueSetCaching: program.cacheValuesets,
verboseCalculationResults: !program.slim,
trustMetaProfile: program.trustMetaProfile,
rootLibRef: program.rootLibRef
rootLibRef: program.rootLibRef,
focusedStatement: program.focusedStatement
};

// Override the measurement period start/end in the options only if the user specified them
Expand Down
36 changes: 23 additions & 13 deletions src/helpers/elm/QueryFilterParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ export async function parseQueryInfo(
queryInfo.fromExternalClause = true;
}
}
// If this query's source is a reference to an expression that is a query then we should parse it and include
// the filters from it.
if (query.source[0].expression.type === 'ExpressionRef') {
const exprRef = query.source[0].expression as ELMExpressionRef;
// If this query's source is a reference to an expression that is a query (or function acting on a query)
// then we should parse it and include the filters from it.
if (query.source[0].expression.type === 'ExpressionRef' || query.source[0].expression.type == 'FunctionRef') {
const exprRef = query.source[0].expression as ELMExpressionRef | ELMFunctionRef;
let queryLib: ELM | null = library;
if (exprRef.libraryName) {
queryLib = findLibraryReference(library, allELM, exprRef.libraryName);
Expand Down Expand Up @@ -517,31 +517,37 @@ export async function interpretOr(
export function interpretFunctionRef(functionRef: ELMFunctionRef, library: ELM): any {
if (functionRef.libraryName) {
const libraryId = findLibraryReferenceId(library, functionRef.libraryName);

// from fhir helpers or MAT Global or fhir common
// from fhir helpers or MAT Global or fhir common or qicore common
if (
libraryId === 'FHIRHelpers' ||
libraryId === 'MATGlobalCommonFunctions' ||
libraryId === 'FHIRCommon' ||
libraryId === 'MATGlobalCommonFunctionsFHIR4'
libraryId === 'MATGlobalCommonFunctionsFHIR4' ||
libraryId === 'QICoreCommon'
) {
switch (functionRef.name) {
case 'ToString':
case 'ToConcept':
case 'ToInterval':
case 'toInterval':
case 'ToDateTime':
case 'Normalize Interval':
case 'Latest':
case 'ToQuantity':
// Act as pass through for all of the above
if (functionRef.operand[0].type == 'Property') {
if (functionRef.operand[0].type === 'Property') {
return functionRef.operand[0] as ELMProperty;
} else if (
functionRef.operand[0].type === 'As' &&
(functionRef.operand[0] as ELMAs).operand.type == 'Property'
) {
return (functionRef.operand[0] as ELMAs).operand as ELMProperty;
} else if (functionRef.operand[0].type === 'As') {
const asExp = functionRef.operand[0] as ELMAs;
if (asExp.operand.type === 'Property') {
return asExp.operand as ELMProperty;
}
// interpret inner function ref
if (asExp.operand.type === 'FunctionRef') {
return interpretFunctionRef(asExp.operand as ELMFunctionRef, library);
}
}

break;
default:
break;
Expand Down Expand Up @@ -834,6 +840,10 @@ export async function interpretIn(
propRef = interpretFunctionRef(inExpr.operand[0] as ELMFunctionRef, library);
} else if (inExpr.operand[0].type == 'Property') {
propRef = inExpr.operand[0] as ELMProperty;
// Extra check for for property pass through (i.e. alias.property.value, grab what's inside the .value)
if (propRef.path === 'value' && !propRef.scope && propRef.source && propRef.source?.type === 'Property') {
propRef = propRef.source as ELMProperty;
}
} else if (inExpr.operand[0].type == 'End' || inExpr.operand[0].type == 'Start') {
const startOrEnd = inExpr.operand[0] as ELMUnaryExpression;
const suffix = startOrEnd.type === 'End' ? '.end' : '.start';
Expand Down
2 changes: 2 additions & 0 deletions src/types/Calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export interface CalculationOptions {
disableHTMLOrdering?: boolean;
/** Builds and returns HTML at the statement level */
buildStatementLevelHTML?: boolean;
/** The name of the statement to focus all results on for a queryInfo calculation. Will be ignored for other calculation types */
focusedStatement?: string;
}

/**
Expand Down

0 comments on commit 9e7aea5

Please sign in to comment.