/* * Copyright 2015 Observational Health Data Sciences and Informatics [OHDSI.org]. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ohdsi.webapi.ircalc; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.ohdsi.webapi.cohortdefinition.CohortExpressionQueryBuilder; import org.ohdsi.webapi.cohortdefinition.CriteriaGroup; import org.ohdsi.webapi.helper.ResourceHelper; import org.ohdsi.webapi.vocabulary.ConceptSetExpressionQueryBuilder; /** * * @author Chris Knoll <cknoll@ohdsi.org> */ public class IRAnalysisQueryBuilder { private final static ConceptSetExpressionQueryBuilder conceptSetQueryBuilder = new ConceptSetExpressionQueryBuilder(); private final static CohortExpressionQueryBuilder cohortExpressionQueryBuilder = new CohortExpressionQueryBuilder(); private final static String PERFORM_ANALYSIS_QUERY_TEMPLATE = ResourceHelper.GetResourceAsString("/resources/incidencerate/sql/performAnalysis.sql"); private final static String STRATA_QUERY_TEMPLATE = ResourceHelper.GetResourceAsString("/resources/incidencerate/sql/strata.sql"); public static class BuildExpressionQueryOptions { @JsonProperty("cdmSchema") public String cdmSchema; @JsonProperty("resultsSchema") public String resultsSchema; } private String getStrataQuery(CriteriaGroup strataCriteria) { String resultSql = STRATA_QUERY_TEMPLATE; String additionalCriteriaQuery = "\nJOIN (\n" + cohortExpressionQueryBuilder.getCriteriaGroupQuery(strataCriteria, "#analysis_events") + ") AC on AC.person_id = pe.person_id AND AC.event_id = pe.event_id"; additionalCriteriaQuery = StringUtils.replace(additionalCriteriaQuery,"@indexId", "" + 0); resultSql = StringUtils.replace(resultSql, "@additionalCriteriaQuery", additionalCriteriaQuery); return resultSql; } public String buildAnalysisQuery(IncidenceRateAnalysis analyisis, BuildExpressionQueryOptions options) { String resultSql = PERFORM_ANALYSIS_QUERY_TEMPLATE; IncidenceRateAnalysisExpression analysisExpression; try { ObjectMapper mapper = new ObjectMapper(); analysisExpression = mapper.readValue(analyisis.getDetails().getExpression(), IncidenceRateAnalysisExpression.class); } catch (Exception e) { throw new RuntimeException(e); } // everything deserialized successfully // target and outcome statements for analysis ArrayList<String> cohortIdStatements = new ArrayList<>(); for (int targetId : analysisExpression.targetIds) { cohortIdStatements.add(String.format("SELECT %d as cohort_id, 0 as is_outcome", targetId)); } for (int outcomeId : analysisExpression.outcomeIds) { cohortIdStatements.add(String.format("SELECT %d as cohort_id, 1 as is_outcome", outcomeId)); } resultSql = StringUtils.replace(resultSql,"@cohortInserts", StringUtils.join(cohortIdStatements,"\nUNION\n")); // apply adjustments String adjustmentExpression = "DATEADD(day,%d,%s)"; String adjustedStart = String.format(adjustmentExpression, analysisExpression.timeAtRisk.start.offset, analysisExpression.timeAtRisk.start.dateField == FieldOffset.DateField.StartDate ? "cohort_start_date" : "cohort_end_date"); resultSql = StringUtils.replace(resultSql,"@adjustedStart", adjustedStart); String adjustedEnd = String.format(adjustmentExpression, analysisExpression.timeAtRisk.end.offset, analysisExpression.timeAtRisk.end.dateField == FieldOffset.DateField.StartDate ? "cohort_start_date" : "cohort_end_date"); resultSql = StringUtils.replace(resultSql,"@adjustedEnd", adjustedEnd); // apply study window WHERE clauses ArrayList<String> studyWindowClauses = new ArrayList<>(); if (analysisExpression.studyWindow != null) { if (analysisExpression.studyWindow.startDate != null && analysisExpression.studyWindow.startDate.length() > 0) studyWindowClauses.add(String.format("t.cohort_start_date >= '%s'", analysisExpression.studyWindow.startDate)); if (analysisExpression.studyWindow.endDate != null && analysisExpression.studyWindow.endDate.length() > 0) studyWindowClauses.add(String.format("t.cohort_start_date <= '%s'", analysisExpression.studyWindow.endDate)); } if (studyWindowClauses.size() > 0) resultSql = StringUtils.replace(resultSql, "@cohortDataFilter", "AND " + StringUtils.join(studyWindowClauses," AND ")); else resultSql = StringUtils.replace(resultSql, "@cohortDataFilter", ""); // add end dates if study window end is defined if (analysisExpression.studyWindow != null && analysisExpression.studyWindow.endDate != null && analysisExpression.studyWindow.endDate.length() > 0) { StringBuilder endDatesQuery = new StringBuilder(String.format("UNION\nselect combos.target_id, combos.outcome_id, t.subject_id, t.cohort_start_date, '%s' as followup_end, 0 as is_case", analysisExpression.studyWindow.endDate)); endDatesQuery.append("\nFROM cteCohortCombos combos"); endDatesQuery.append("\nJOIN cteCohortData t on combos.target_id = t.target_id and combos.outcome_id = t.outcome_id"); resultSql = StringUtils.replace(resultSql, "@EndDateUnions", endDatesQuery.toString()); } else resultSql = StringUtils.replace(resultSql, "@EndDateUnions", ""); String codesetQuery = cohortExpressionQueryBuilder.getCodesetQuery(analysisExpression.conceptSets); resultSql = StringUtils.replace(resultSql, "@codesetQuery", codesetQuery); ArrayList<String> strataInsert = new ArrayList<>(); for (int i = 0; i < analysisExpression.strata.size(); i++) { CriteriaGroup cg = analysisExpression.strata.get(i).expression; String stratumInsert = getStrataQuery(cg); stratumInsert = StringUtils.replace(stratumInsert, "@strata_sequence", "" + i); strataInsert.add(stratumInsert); } resultSql = StringUtils.replace(resultSql,"@strataCohortInserts", StringUtils.join(strataInsert,"\n")); if (options != null) { // replease query parameters with tokens resultSql = StringUtils.replace(resultSql, "@cdm_database_schema", options.cdmSchema); resultSql = StringUtils.replace(resultSql, "@results_database_schema", options.resultsSchema); } resultSql = StringUtils.replace(resultSql, "@analysisId", analyisis.getId().toString()); return resultSql; } }