Skip to content

Commit

Permalink
WIP - only add row context filters if filter is present
Browse files Browse the repository at this point in the history
  • Loading branch information
luciano-fiandesio committed Dec 30, 2024
1 parent 142b508 commit 5c4dba5
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 202 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@

public class CTEContext {
private final Map<String, CteDefinitionWithOffset> cteDefinitions = new LinkedHashMap<>();
@Getter private final Map<String, String> rowContextReferences = new HashMap<>();

public CteDefinitionWithOffset getDefinitionByItemUid(String itemUid) {
return cteDefinitions.get(itemUid);
Expand All @@ -48,7 +47,7 @@ public CteDefinitionWithOffset getDefinitionByItemUid(String itemUid) {
public void addCTE(ProgramStage programStage, QueryItem item, String cteDefinition, int offset) {
cteDefinitions.put(
item.getItem().getUid(),
new CteDefinitionWithOffset(programStage.getUid(), cteDefinition, offset));
new CteDefinitionWithOffset(programStage.getUid(), item.getItemId(), cteDefinition, offset));
}

public void addCTE(
Expand All @@ -59,7 +58,18 @@ public void addCTE(
boolean isRowContext) {
cteDefinitions.put(
item.getItem().getUid(),
new CteDefinitionWithOffset(programStage.getUid(), cteDefinition, offset, isRowContext));
new CteDefinitionWithOffset(programStage.getUid(), item.getItemId(), cteDefinition, offset, isRowContext));
}

public void addExistsCTE(
ProgramStage programStage,
QueryItem item,
String cteDefinition) {
var cteDef = new CteDefinitionWithOffset(programStage.getUid(), item.getItemId(), cteDefinition, -999, false)
.setExists(true);
cteDefinitions.put(
programStage.getUid(),
cteDef);
}

/**
Expand All @@ -68,7 +78,7 @@ public void addCTE(
* @param programIndicator The program indicator
* @param cteDefinition The CTE definition (the SQL query)
*/
public void addCTE(ProgramIndicator programIndicator, String cteDefinition) {
public void addProgramIndicatorCTE(ProgramIndicator programIndicator, String cteDefinition) {
cteDefinitions.put(
programIndicator.getUid(),
new CteDefinitionWithOffset(programIndicator.getUid(), cteDefinition));
Expand All @@ -78,17 +88,6 @@ public void addCTEFilter(String name, String ctedefinition) {
cteDefinitions.put(name, new CteDefinitionWithOffset(name, ctedefinition, true));
}

/**
* Adds a mapping between a row context column and the CTE name that it references.
*
* @param alias The alias of the row context column, for instance "EPEcjy3FWmI.lJTx9EZ1dk1"
* @param cteName The name of the CTE that the row context column references, for instance
* "ps_epecjy3fwmi_ljtx9ez1dk1"
*/
public void addRowContextColumnMapping(String alias, String cteName) {
rowContextReferences.put(alias, cteName);
}

public String getCTEDefinition() {
if (cteDefinitions.isEmpty()) {
return "";
Expand Down Expand Up @@ -121,6 +120,8 @@ public boolean containsCteFilter(String cteFilterName) {

@Getter
public static class CteDefinitionWithOffset {
// Query item id
private String itemId;
// The program stage uid
private final String programStageUid;
// The program indicator uid
Expand All @@ -137,20 +138,29 @@ public static class CteDefinitionWithOffset {
private boolean isProgramIndicator = false;
// Whether the CTE is a filter
private boolean isFilter = false;
// Whether the CTE is a exists, used for checking if the enrollment exists
private boolean isExists = false;

private static final String PS_PREFIX = "ps";
private static final String PI_PREFIX = "pi";

public CteDefinitionWithOffset(String programStageUid, String cteDefinition, int offset) {
public CteDefinitionWithOffset setExists(boolean exists) {
this.isExists = exists;
return this;
}

public CteDefinitionWithOffset(String programStageUid, String queryItemId, String cteDefinition, int offset) {
this.programStageUid = programStageUid;
this.itemId = queryItemId;
this.cteDefinition = cteDefinition;
this.offset = offset;
this.alias = new RandomStringGenerator.Builder().withinRange('a', 'z').build().generate(5);

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Builder.build
should be avoided because it has been deprecated.
this.isRowContext = false;
}

public CteDefinitionWithOffset(
String programStageUid, String cteDefinition, int offset, boolean isRowContext) {
this(programStageUid, cteDefinition, offset);
String programStageUid, String queryItemId, String cteDefinition, int offset, boolean isRowContext) {
this(programStageUid, queryItemId, cteDefinition, offset);
this.isRowContext = isRowContext;
}

Expand Down Expand Up @@ -180,17 +190,25 @@ public CteDefinitionWithOffset(String cteFilterName, String cteDefinition, boole
* @return the name of the CTE
*/
public String asCteName(String uid) {
if (isExists) {
return uid.toLowerCase();
}
if (isProgramIndicator) {
return "%s_%s".formatted(PI_PREFIX, programIndicatorUid.toLowerCase());
}
if (isFilter) {
return "%s".formatted(uid.toLowerCase());
return uid.toLowerCase();
}

return "%s_%s_%s".formatted(PS_PREFIX, programStageUid.toLowerCase(), uid.toLowerCase());
}

public boolean isProgramStage() {
return !isFilter && !isProgramIndicator;
return !isFilter && !isProgramIndicator && !isExists;
}

public boolean isExists() {
return isExists;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,41 +27,50 @@
*/
package org.hisp.dhis.analytics.common;

import org.hisp.dhis.analytics.common.CTEContext.CteDefinitionWithOffset;
import org.hisp.dhis.analytics.event.EventQueryParams;
import org.hisp.dhis.common.QueryItem;
import org.hisp.dhis.db.sql.SqlBuilder;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hisp.dhis.db.sql.SqlBuilder;
import java.util.Set;

public class RowContextUtils {

public static List<String> getRowContextColumns(CTEContext cteContext, SqlBuilder sqlBuilder) {
List<String> columns = new ArrayList<>();
Map<String, String> rowCtxRefs = cteContext.getRowContextReferences();
for (String aliases : rowCtxRefs.keySet()) {
columns.add(getStatusColumn(aliases, rowCtxRefs.get(aliases), sqlBuilder));
columns.add(getExistsColumn(aliases, rowCtxRefs.get(aliases), sqlBuilder));
}
/**
* Get where clauses for row context items
* @param cteContext CTE context
* @param params Event query parameters
* @param sqlBuilder SQL builder
* @return List of where clauses
*/
public static List<String> getRowContextWhereClauses(CTEContext cteContext, EventQueryParams params, SqlBuilder sqlBuilder) {
List<String> whereClauses = new ArrayList<>();
Set<String> ctxNames = cteContext.getCTENames();

return columns;
}
List<String> filters = getItemsWithFilters(params);

public static List<String> getRowContextWhereClauses(CTEContext cteContext) {
List<String> whereClauses = new ArrayList<>();
Map<String, String> rowCtxRefs = cteContext.getRowContextReferences();
for (String alias : rowCtxRefs.values()) {
whereClauses.add("%s.value is null".formatted(alias));
// whereClauses.add("%s.exists_flag = true".formatted(alias));
}
return whereClauses;
}
for (String ctxName : ctxNames) {
CteDefinitionWithOffset cteDef = cteContext.getDefinitionByItemUid(ctxName);
// only add where clause for row context items with filters
if (cteDef.isRowContext() && filters.contains(cteDef.getItemId())) {
whereClauses.add("%s.%s IS NULL".formatted(cteDef.getAlias(),
sqlBuilder.quote(cteDef.getItemId())));
}
// only add where clause for "exists" row context items with filters
if (cteDef.isExists() && filters.contains(cteDef.getItemId())) {
whereClauses.add("ee.enrollment IS NOT NULL");
}
}

private static String getExistsColumn(
String aliases, String cteReference, SqlBuilder sqlBuilder) {
return "coalesce(%s.exists_flag, false) as %s"
.formatted(cteReference, sqlBuilder.quote(aliases + ".status.exists"));
}
return whereClauses;
}

private static String getStatusColumn(String alias, String cteReference, SqlBuilder sqlBuilder) {
return "%s_status.status as %s".formatted(cteReference, sqlBuilder.quote(alias));
}
private static List<String> getItemsWithFilters(EventQueryParams params) {
return params.getItems().stream()
.filter(QueryItem::hasFilter)
.map(QueryItem::getItemId)
.toList();
}
}
Loading

0 comments on commit 5c4dba5

Please sign in to comment.