-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🦍 Big refactor to get the HF phenotype running.
- Loading branch information
Showing
44 changed files
with
1,409 additions
and
971 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
src/main/java/edu/phema/elm_to_omop/translate/CorelatedCriteriaTranslator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package edu.phema.elm_to_omop.translate; | ||
|
||
import edu.phema.elm_to_omop.helper.CirceUtil; | ||
import edu.phema.elm_to_omop.translate.criteria.CriteriaTranslator; | ||
import edu.phema.elm_to_omop.translate.criteria.comparison.ComparisonExpressionTranslator; | ||
import edu.phema.elm_to_omop.translate.criteria.correlation.CorrelatedQueryTranslator; | ||
import edu.phema.elm_to_omop.translate.exception.PhemaNotImplementedException; | ||
import org.hl7.elm.r1.*; | ||
import org.ohdsi.circe.cohortdefinition.CorelatedCriteria; | ||
import org.ohdsi.circe.cohortdefinition.Occurrence; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
* Class responsible for generating CorelatedCriteria [sic]. CorelatedCriteria criteria are used for applying | ||
* restrictions to Circe domain Criteria (e.g. ConditionOccurrence). | ||
* <p> | ||
* These restrictions include: | ||
* <p> | ||
* - start and end window restrictions relative to the index event (the containing Criteria, or the cohort entry event) | ||
* - occurrence count (e.g. EXACTLY 3 procedures, AT_LEAST 1 condition) | ||
* - visit restriction relative to the index event (the containing Criteria, or the cohort entry event) | ||
* <p> | ||
* Confusingly, a Criteria has field called CorelatedCriteria, which is of type CriteriaGroup. | ||
*/ | ||
public class CorelatedCriteriaTranslator { | ||
private static CorelatedCriteria generateCorelatedCriteriaForRetrieve(Retrieve retrieve, PhemaElmaToOmopTranslatorContext context) throws Exception { | ||
Occurrence occurrence = CirceUtil.defaultOccurrence(); | ||
|
||
CorelatedCriteria corelatedCriteria = CirceUtil.defaultCorelatedCriteria(); | ||
corelatedCriteria.occurrence = occurrence; | ||
|
||
corelatedCriteria.criteria = CriteriaTranslator.generateCriteriaForExpression(retrieve, context); | ||
|
||
return corelatedCriteria; | ||
} | ||
|
||
private static CorelatedCriteria generateCorelatedCriteriaForQuery(Query query, PhemaElmaToOmopTranslatorContext context) throws Exception { | ||
List<RelationshipClause> relationships = query.getRelationship(); | ||
|
||
if (relationships == null || relationships.size() == 0) { | ||
// We are dealing with an uncorrelated query | ||
|
||
// We don't currently support where clause filtering | ||
if (query.getWhere() != null) { | ||
throw new PhemaNotImplementedException("Query filtering which Where clause is currently unsupported"); | ||
} | ||
|
||
// Right now we basic just support a simple aliased query like [Condition: "valueset"] C, which is exactly | ||
// the same a simple retrieve, so we evaluate it as such. If there are no relationships, there should only | ||
// be one AliasedSource | ||
return generateCorelatedCriteriaForExpression(query.getSource().get(0).getExpression(), context); | ||
} else if (relationships.size() == 1) { | ||
// We are dealing with a correlated query | ||
return CorrelatedQueryTranslator.generateCorelatedCriteriaForCorrelatedQuery(query, context); | ||
} else { | ||
throw new PhemaNotImplementedException("The translator is currently only able to handle a single relationship for a data element"); | ||
} | ||
} | ||
|
||
/** | ||
* Given an Expression from CQL/ELM, convert it into an OHDSI CorelatedCriteria. | ||
* | ||
* @param expression The ELM expression | ||
* @param context The ELM translation context | ||
* @return The CorelatedCriteria for the expression | ||
* @throws Exception | ||
*/ | ||
public static CorelatedCriteria generateCorelatedCriteriaForExpression(Expression expression, PhemaElmaToOmopTranslatorContext context) throws Exception { | ||
if (expression instanceof Retrieve) { | ||
return generateCorelatedCriteriaForRetrieve((Retrieve) expression, context); | ||
} else if (expression instanceof Exists) { | ||
return generateCorelatedCriteriaForExpression(((Exists) expression).getOperand(), context); | ||
} else if (expression instanceof Query) { | ||
return generateCorelatedCriteriaForQuery((Query) expression, context); | ||
} else if (ComparisonExpressionTranslator.isNumericComparison(expression)) { | ||
return ComparisonExpressionTranslator.generateCorelatedCriteriaForComparison(expression, context); | ||
} else { | ||
// TODO - Need to handle more than simple query types | ||
throw new PhemaNotImplementedException(String.format("Unable to generate CorelatedCriteria for type: %s", expression.getClass().getName())); | ||
} | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
src/main/java/edu/phema/elm_to_omop/translate/CriteriaGroupTranslator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package edu.phema.elm_to_omop.translate; | ||
|
||
import edu.phema.elm_to_omop.helper.CirceUtil; | ||
import edu.phema.elm_to_omop.translate.criteria.demographic.DemographicExpressionTranslator; | ||
import edu.phema.elm_to_omop.translate.exception.PhemaNotImplementedException; | ||
import org.hl7.elm.r1.And; | ||
import org.hl7.elm.r1.BinaryExpression; | ||
import org.hl7.elm.r1.Expression; | ||
import org.hl7.elm.r1.Or; | ||
import org.ohdsi.circe.cohortdefinition.CorelatedCriteria; | ||
import org.ohdsi.circe.cohortdefinition.CriteriaGroup; | ||
import org.ohdsi.circe.cohortdefinition.DemographicCriteria; | ||
|
||
/** | ||
* Class responsible for building CriteriaGroups. CriteriaGroups are used to group a potentially heterogeneous | ||
* collection of CorelatedCriteria, DemographicCriteria, and/or other CriteriaGroups together when you want all or some | ||
* of them to apply. | ||
* <p> | ||
* CriteriaGroups can represent the following types of relationships: | ||
* <p> | ||
* - ALL | ||
* - ANY | ||
* - AT_LEAST x | ||
* - AT_MOST x | ||
* <p> | ||
* where x is some integer. | ||
* <p> | ||
* In CQL, these ideas can be represented using AND and OR statements, or by using the Count aggregate expression. | ||
*/ | ||
public class CriteriaGroupTranslator { | ||
/** | ||
* Generates a Circe CriteriaGroup from a ELM BinaryExpression. Creating "ANY" (OR) and "ALL" (AND) CriteriaGroups | ||
* is how nested boolean logic is implemented. Only these two boolean expressions generated CriteriaGroups. Every | ||
* other type of ELM expression generates a CorelatedCriteria | ||
* | ||
* @param expression The ELM BinaryExpression (must be And or Or) | ||
* @param context The translation context | ||
* @return The created "ANY" or "ALL" CriteriaGroup | ||
* @throws Exception | ||
*/ | ||
private static CriteriaGroup generateCriteriaGroupForBinaryExpression(BinaryExpression expression, PhemaElmaToOmopTranslatorContext context) throws Exception { | ||
CriteriaGroup criteriaGroup = new CriteriaGroup(); | ||
criteriaGroup.type = PhemaElmToOmopTranslator.getInclusionExpressionType(expression).toString(); | ||
|
||
for (Expression operand : expression.getOperand()) { | ||
Expression operandExp = operand; | ||
|
||
if (DemographicExpressionTranslator.isDemographicExpression(operandExp)) { | ||
DemographicCriteria demographicCriteria = DemographicExpressionTranslator.generateDemographicCriteriaForExpression(operandExp); | ||
|
||
criteriaGroup.demographicCriteriaList = CirceUtil.addDemographicCriteria(criteriaGroup.demographicCriteriaList, demographicCriteria); | ||
} else { | ||
// Are we nesting even further? | ||
if (PhemaElmToOmopTranslator.isBooleanExpression(operandExp)) { | ||
criteriaGroup.groups = CirceUtil.addCriteriaGroup(criteriaGroup.groups, generateCriteriaGroupForBinaryExpression((BinaryExpression) operandExp, context)); | ||
} else { | ||
CorelatedCriteria corelatedCriteria = CorelatedCriteriaTranslator.generateCorelatedCriteriaForExpression(operandExp, context); | ||
if (corelatedCriteria == null) { | ||
throw new PhemaNotImplementedException("The translator was unable to process this type of expression"); | ||
} | ||
criteriaGroup.criteriaList = CirceUtil.addCorelatedCriteria(criteriaGroup.criteriaList, corelatedCriteria); | ||
} | ||
} | ||
} | ||
|
||
return criteriaGroup; | ||
} | ||
|
||
/** | ||
* This is the entry point for CriteriaGroup generation. This method will delegate CriteriaGroup generation | ||
* based on the type of expression. An exception will be thrown if we do not support translating the expression | ||
* | ||
* @param expression The ELM expression | ||
* @param context The translation context | ||
* @return The created CriteriaGroup | ||
* @throws Exception | ||
*/ | ||
public static CriteriaGroup generateCriteriaGroupForExpression(Expression expression, PhemaElmaToOmopTranslatorContext context) throws Exception { | ||
Expression expr = PhemaElmToOmopTranslator.invertNot(expression); | ||
|
||
CriteriaGroup criteriaGroup = new CriteriaGroup(); | ||
|
||
if (DemographicExpressionTranslator.isDemographicExpression(expr)) { | ||
DemographicCriteria demographicCriteria = DemographicExpressionTranslator.generateDemographicCriteriaForExpression(expr); | ||
criteriaGroup.demographicCriteriaList = CirceUtil.addDemographicCriteria(criteriaGroup.demographicCriteriaList, demographicCriteria); | ||
} else if (expr instanceof And || expr instanceof Or) { | ||
return generateCriteriaGroupForBinaryExpression((BinaryExpression) expr, context); | ||
} else { | ||
CorelatedCriteria corelatedCriteria = CorelatedCriteriaTranslator.generateCorelatedCriteriaForExpression(expr, context); | ||
criteriaGroup.criteriaList = CirceUtil.addCorelatedCriteria(criteriaGroup.criteriaList, corelatedCriteria); | ||
} | ||
|
||
return criteriaGroup; | ||
} | ||
} |
Oops, something went wrong.