You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
6.8 KiB
168 lines
6.8 KiB
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<String> caseParams, List<Integer> 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<CriteriaGroup> groups, String tableName, boolean isSortOrder, String columnname) { |
|
List<String> caseParams = new ArrayList<>(); |
|
StringBuilder caseBuilder = new StringBuilder("CASE "); |
|
List<Integer> 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<CriteriaGroup> groups) { |
|
StringJoiner selectStatements = new StringJoiner(" INTERSECT "); |
|
List<String> caseParams = new ArrayList<>(); |
|
List<Integer> 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); |
|
} |
|
|
|
}
|
|
|