Skip to content

Commit

Permalink
update inner query reassignment, addFiltersToDataRequirements, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahmcdougall committed Oct 16, 2023
1 parent 0e7843d commit 7556acc
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 66 deletions.
57 changes: 30 additions & 27 deletions src/gaps/GapsReportBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -614,39 +614,42 @@ export function addFiltersToDataRequirement(
withErrors: GracefulError[]
) {
if (q.queryInfo) {
// TODO: compare q.dataType to the resource type in queryInfo.source
const relevantSource = q.queryInfo.sources.find(source => source.resourceType === q.dataType);
// if a source cannot be found that matches, exit the function
const detailedFilters = flattenFilters(q.queryInfo.filter);
if (relevantSource) {
const detailedFilters = flattenFilters(q.queryInfo.filter);

detailedFilters.forEach(df => {
// TODO: check the alias before doing an explicit casting of the filters
if (df.type === 'equals' || df.type === 'in') {
const cf = generateDetailedCodeFilter(df as EqualsFilter | InFilter, q.dataType);

if (cf !== null) {
dataRequirement.codeFilter?.push(cf);
}
} else if (df.type === 'during') {
detailedFilters.forEach(df => {
// DuringFilter, etc. inherit from attribute filter (and have alias on them)
const dateFilter = generateDetailedDateFilter(df as DuringFilter);
if (dataRequirement.dateFilter) {
dataRequirement.dateFilter.push(dateFilter);
} else {
dataRequirement.dateFilter = [dateFilter];
}
} else {
const valueFilter = generateDetailedValueFilter(df);
if (didEncounterDetailedValueFilterErrors(valueFilter)) {
withErrors.push(valueFilter);
} else if (valueFilter) {
if (dataRequirement.extension) {
dataRequirement.extension.push(valueFilter);
if (relevantSource.alias === (df as AttributeFilter).alias) {
if (df.type === 'equals' || df.type === 'in') {
const cf = generateDetailedCodeFilter(df as EqualsFilter | InFilter, q.dataType);

if (cf !== null) {
dataRequirement.codeFilter?.push(cf);

Check warning on line 629 in src/gaps/GapsReportBuilder.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
}
} else if (df.type === 'during') {
const dateFilter = generateDetailedDateFilter(df as DuringFilter);
if (dataRequirement.dateFilter) {
dataRequirement.dateFilter.push(dateFilter);

Check warning on line 634 in src/gaps/GapsReportBuilder.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
} else {
dataRequirement.dateFilter = [dateFilter];
}

Check warning on line 637 in src/gaps/GapsReportBuilder.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
} else {
dataRequirement.extension = [valueFilter];
const valueFilter = generateDetailedValueFilter(df);
if (didEncounterDetailedValueFilterErrors(valueFilter)) {
withErrors.push(valueFilter);

Check warning on line 641 in src/gaps/GapsReportBuilder.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
} else if (valueFilter) {
if (dataRequirement.extension) {
dataRequirement.extension.push(valueFilter);

Check warning on line 644 in src/gaps/GapsReportBuilder.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
} else {
dataRequirement.extension = [valueFilter];
}

Check warning on line 647 in src/gaps/GapsReportBuilder.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
}

Check warning on line 648 in src/gaps/GapsReportBuilder.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
}
}
}
});
});
}
}
}

Expand Down
58 changes: 19 additions & 39 deletions src/gaps/QueryFilterParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,8 @@ export async function parseQueryInfo(
patient
);

// use sources from inner query
// TODO: should copy over everything from inner query info, but for anything after 1st elem - replace first one, and copy over rest
// query.sources at index 0 = inner query info sources at index 0 (then copy over the rest using splice to copy everything except first and push on)
queryInfo.sources = innerQueryInfo.sources;
// use first source from inner query (only replaces the first source)
queryInfo.sources = [...innerQueryInfo.sources.slice(0, 1), ...queryInfo.sources.slice(1)];

// replace the filters for this query to match the inner source
replaceAliasesInFilters(queryInfo.filter, query.source[0].alias, innerQuery.source[0].alias);
Expand Down Expand Up @@ -226,14 +224,16 @@ function replaceAliasesInFilters(filter: AnyFilter, match: string, replace: stri
}

/**
* Parse information about the sources in a given query.
* Parse information about the sources in a given query. Treat relationships as sources.
*
* @param query The Query expression to parse.
* @param query The Query to parse. The query source can consist of aliased query sources or relationship clauses.
* @returns Information about each source. This is usually an array of one.
*/
function parseSources(query: ELMQuery): SourceInfo[] {
const sources: SourceInfo[] = [];
query.source.forEach(source => {
const querySources = [...query.source, ...query.relationship];

querySources.forEach(source => {
if (source.expression.type == 'Retrieve') {
const sourceInfo: SourceInfo = {
sourceLocalId: source.localId,
Expand All @@ -242,6 +242,7 @@ function parseSources(query: ELMQuery): SourceInfo[] {
resourceType: parseDataType(source.expression as ELMRetrieve)
};
sources.push(sourceInfo);
// use the resultTypeSpecifier as a fallback if the expression is not a Retrieve
} else if (source.expression.resultTypeSpecifier) {
const sourceInfo: SourceInfo = {
sourceLocalId: source.localId,
Expand All @@ -251,19 +252,7 @@ function parseSources(query: ELMQuery): SourceInfo[] {
sources.push(sourceInfo);
}
});
query.relationship.forEach(relationship => {
// TODO: add conditional for parsing on the resultTypeSpecifier and consolidate logic between
// relationship and source
if (relationship.expression.type === 'Retrieve') {
const sourceInfo: SourceInfo = {
sourceLocalId: relationship.localId,
retrieveLocalId: relationship.expression.localId,
alias: relationship.alias,
resourceType: parseDataType(relationship.expression as ELMRetrieve)
};
sources.push(sourceInfo);
}
});

return sources;
}

Expand All @@ -287,24 +276,15 @@ function parseDataType(retrieve: ELMRetrieve): string {
*/
function parseElementType(expression: ELMExpression): string {
const resultTypeSpecifier = expression.resultTypeSpecifier;
// check if the type is ListTypeSpecifier
if (resultTypeSpecifier?.type === 'ListTypeSpecifier') {
const listTypeSpecifier = resultTypeSpecifier as ListTypeSpecifier;
// check if the elementType is of type NamedTypeSpecifier
if (listTypeSpecifier.elementType.type === 'NamedTypeSpecifier') {
const elementType = listTypeSpecifier.elementType as NamedTypeSpecifier;
return elementType.name.replace(/^(\{http:\/\/hl7.org\/fhir\})?/, '');
} else {
// TODO: just don't create the source info if the resource type can't be found, remove this error
throw new Error('ListTypeSpecifier elementType must be of type NamedTypeSpecifier.');
}
} else {
// TODO: don't throw an error, mark as a warning instead
// if something is being defined as alias either from source or relationship but cant figure out the data type,
// want to mark it some way
// short-circuit out instead
throw new Error('Expression resultTypeSpecifier must be of type ListTypeSpecifier.');
if (
resultTypeSpecifier?.type === 'ListTypeSpecifier' &&

Check warning on line 280 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch

Check warning on line 280 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch

Check warning on line 280 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch

Check warning on line 280 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch

Check warning on line 280 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
(resultTypeSpecifier as ListTypeSpecifier).elementType.type === 'NamedTypeSpecifier'

Check warning on line 281 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
) {
const elementType = (resultTypeSpecifier as ListTypeSpecifier).elementType as NamedTypeSpecifier;

Check warning on line 283 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
return elementType.name.replace(/^(\{http:\/\/hl7.org\/fhir\})?/, '');

Check warning on line 284 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
}

Check warning on line 285 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

Check warning on line 285 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
console.warn(`Resource type cannot be found for ELM Expression with localId ${expression.localId}`);

Check warning on line 286 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
return '';

Check warning on line 287 in src/gaps/QueryFilterParser.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
}

/**
Expand Down Expand Up @@ -773,7 +753,7 @@ export function interpretIncludedIn(
parameters: any
): DuringFilter | UnknownFilter {
let propRef: ELMProperty | GracefulError | null = null;
let withError: GracefulError = { message: 'An unknown error occured' };
let withError: GracefulError = { message: 'An unknown error occurred' };
if (includedIn.operand[0].type == 'FunctionRef') {
propRef = interpretFunctionRef(includedIn.operand[0] as ELMFunctionRef, library);
} else if (includedIn.operand[0].type == 'Property') {
Expand Down Expand Up @@ -839,7 +819,7 @@ export async function interpretIn(
parameters: any
): Promise<InFilter | DuringFilter | UnknownFilter> {
let propRef: ELMProperty | GracefulError | null = null;
let withError: GracefulError = { message: 'An unknown error occured' };
let withError: GracefulError = { message: 'An unknown error occurred' };
if (inExpr.operand[0].type == 'FunctionRef') {
propRef = interpretFunctionRef(inExpr.operand[0] as ELMFunctionRef, library);
} else if (inExpr.operand[0].type == 'Property') {
Expand Down

0 comments on commit 7556acc

Please sign in to comment.