package de.superx.bianalysis.sqlgeneration; import java.sql.Types; import java.util.ArrayList; import java.util.List; import java.util.StringJoiner; import de.superx.bianalysis.FaultyMetadataException; import de.superx.bianalysis.models.Condition; import de.superx.bianalysis.models.CriteriaGroup; public class AttributeGroupQueryBuilder { public final static String DEFAULT_LOGIC_CRITERIA_GROUP = "AND"; public static StringJoiner buildConditionClause(List caseParams, List argTypes, CriteriaGroup group) { StringJoiner joinerConditions = null; if(group.logic != null) { joinerConditions = new StringJoiner(" " + group.logic + " "); } else { joinerConditions = new StringJoiner(" " + DEFAULT_LOGIC_CRITERIA_GROUP + " "); } for (Object obj : group.conditions) { if (Condition.isCondition(obj)) { Condition condition = Condition.fromMap(obj); switch (condition.operator.toUpperCase()) { case "BETWEEN": if (condition.values == null || condition.values.size() != 2) { throw new FaultyMetadataException("BETWEEN requires exactly two values: " + condition.column); } joinerConditions.add(condition.column + " BETWEEN ? AND ?"); caseParams.add(condition.values.get(0)); caseParams.add(condition.values.get(1)); argTypes.add(Integer.valueOf(Types.VARCHAR)); argTypes.add(Integer.valueOf(Types.VARCHAR)); break; case "=", "!=": joinerConditions.add(condition.column + " " + condition.operator + " ?"); caseParams.add(condition.value); argTypes.add(Integer.valueOf(Types.VARCHAR)); break; case "IN", "NOT IN": StringJoiner inJoiner = new StringJoiner(" "); inJoiner.add(condition.column); inJoiner.add(condition.operator + " ("); StringJoiner joiner = new StringJoiner(", "); for (String value : condition.values) { joiner.add("?"); caseParams.add(value); argTypes.add(Integer.valueOf(Types.VARCHAR)); } inJoiner.add(joiner.toString()); joinerConditions.add(inJoiner.toString() + " )"); break; case "<", ">", ">=", "<=": boolean isNumber = true; try { Double.parseDouble(condition.value); } catch (NumberFormatException e) { isNumber = false; } if(isNumber) { String check = "%s ~ E'^-?\\\\d+$' AND %s::int %s ?"; joinerConditions.add(String.format(check, condition.column, condition.column, condition.operator)); caseParams.add(condition.value); argTypes.add(Integer.valueOf(Types.INTEGER)); } else { joinerConditions.add(condition.column + " " + condition.operator + " ?"); caseParams.add(condition.value); argTypes.add(Integer.valueOf(Types.VARCHAR)); } break; default: throw new FaultyMetadataException("Unsupported operator: " + condition.operator); } } else if (CriteriaGroup.isGroup(obj)) { // Recursively handle nested groups CriteriaGroup subGroup = CriteriaGroup.fromMap(obj); StringJoiner subClause = buildConditionClause(caseParams, argTypes, subGroup); joinerConditions.add("(" + subClause + ")"); } } return joinerConditions; } public static SqlQuery buildColumnQuery(List groups, String tableName, boolean isSortOrder, String columnname) { List caseParams = new ArrayList<>(); StringBuilder caseBuilder = new StringBuilder("CASE "); List argTypes = new ArrayList<>(); int sortOrderColumnNumber = 1; for (CriteriaGroup group : groups) { if(group.conditions == null) { continue; } caseBuilder.append("WHEN "); StringJoiner joinerConditions = buildConditionClause(caseParams, argTypes, group); caseBuilder.append(joinerConditions.toString()); caseBuilder.append(" THEN ? "); if(isSortOrder) { caseParams.add(String.valueOf(sortOrderColumnNumber++)); argTypes.add(Integer.valueOf(Types.INTEGER)); } else { caseParams.add(group.caption); argTypes.add(Integer.valueOf(Types.VARCHAR)); } } caseBuilder.append("ELSE ? END"); if(isSortOrder) { caseParams.add(String.valueOf(sortOrderColumnNumber++)); argTypes.add(Integer.valueOf(Types.INTEGER)); } else { String emptyLabel = groups.stream() .filter(p -> p.isElse) .findFirst() .map(p -> p.caption) .orElse("n.v."); caseParams.add(emptyLabel); argTypes.add(Integer.valueOf(Types.VARCHAR)); } String updateSql = "UPDATE %s SET %s = %s" .formatted(tableName, columnname, caseBuilder); Object[] params = caseParams.toArray(); int[] types = argTypes.stream().mapToInt(Integer::intValue).toArray(); return new SqlQuery(updateSql, params, types); } public static SqlQuery buildValidationQuery(String tableName, String colList, List groups) { StringJoiner selectStatements = new StringJoiner(" INTERSECT "); List caseParams = new ArrayList<>(); List argTypes = new ArrayList<>(); for (CriteriaGroup group : groups) { if(group.isElse) { continue; } StringBuilder criteraStmt = new StringBuilder("SELECT " + colList); StringJoiner selectParams = new StringJoiner(", "); criteraStmt.append(selectParams); criteraStmt.append(" FROM "); criteraStmt.append(tableName); criteraStmt.append(" WHERE "); StringJoiner joinerConditions = buildConditionClause(caseParams, argTypes, group); criteraStmt.append(joinerConditions.toString()); selectStatements.add(criteraStmt); } Object[] params = caseParams.toArray(); int[] types = argTypes.stream().mapToInt(Integer::intValue).toArray(); return new SqlQuery(selectStatements.toString(), params, types); } }