diff --git a/config/log4j2.xml b/config/log4j2.xml index 703ebd50b..cbe297509 100644 --- a/config/log4j2.xml +++ b/config/log4j2.xml @@ -25,11 +25,25 @@ + + + %d [%t] %-5p - %m%n + + + + + + + + + + diff --git a/src/main/gui/net/sf/jailer/ui/ai/AIQueryAssistant.java b/src/main/gui/net/sf/jailer/ui/ai/AIQueryAssistant.java index 6bd42ea41..d79c49eb5 100644 --- a/src/main/gui/net/sf/jailer/ui/ai/AIQueryAssistant.java +++ b/src/main/gui/net/sf/jailer/ui/ai/AIQueryAssistant.java @@ -43,6 +43,7 @@ import net.sf.jailer.datamodel.Column; import net.sf.jailer.datamodel.DataModel; import net.sf.jailer.datamodel.Table; import net.sf.jailer.ui.ai.AIProviderConfig.ProviderType; +import net.sf.jailer.util.SqlUtil; /** * Sends a natural-language question together with the current data-model schema @@ -280,6 +281,7 @@ public class AIQueryAssistant { static String buildSchemaDescription(DataModel dataModel) { List tables = new ArrayList<>(dataModel.getSortedTables()); StringBuilder sb = new StringBuilder(); + StringBuilder fkSb = new StringBuilder(); int count = Math.min(tables.size(), MAX_TABLES); for (int i = 0; i < count; i++) { Table table = tables.get(i); @@ -306,26 +308,69 @@ public class AIQueryAssistant { sb.append(" PK"); } } - sb.append(")"); + sb.append(")\n"); for (Association assoc : table.associations) { if (!assoc.reversed) { - String joinCond = assoc.getUnrestrictedJoinCondition(); - if (joinCond != null) { - String resolved = joinCond - .replace("A.", assoc.source.getName() + ".") - .replace("B.", assoc.destination.getName() + "."); - sb.append(" -- FK: ").append(resolved.trim()); + String fk = buildFkConstraint(assoc); + if (fk != null) { + fkSb.append(fk).append("\n"); } } } - sb.append("\n"); } if (tables.size() > MAX_TABLES) { sb.append("... and ").append(tables.size() - MAX_TABLES).append(" more tables\n"); } + if (fkSb.length() > 0) { + sb.append("\nForeign keys:\n").append(fkSb); + } return sb.toString(); } + + private static String buildFkConstraint(Association assoc) { + String joinCond = assoc.getUnrestrictedJoinCondition(); + if (joinCond == null) return null; + + String srcName = assoc.source.getName(); + String dstName = assoc.destination.getName(); + + String[] parts = joinCond.split("(?i)\\s+and\\s+"); + List srcCols = new ArrayList<>(); + List dstCols = new ArrayList<>(); + + for (String part : parts) { + String[] sides = part.split("\\s*=\\s*", 2); + if (sides.length != 2) return joinFallback(srcName, dstName, joinCond); + + String leftR = SqlUtil.replaceAliases(sides[0].trim(), srcName, dstName); + String rightR = SqlUtil.replaceAliases(sides[1].trim(), srcName, dstName); + + String srcCol = colAfterTable(leftR, srcName); + if (srcCol == null) srcCol = colAfterTable(rightR, srcName); + String dstCol = colAfterTable(leftR, dstName); + if (dstCol == null) dstCol = colAfterTable(rightR, dstName); + + if (srcCol == null || dstCol == null) return joinFallback(srcName, dstName, joinCond); + srcCols.add(srcCol); + dstCols.add(dstCol); + } + + if (srcCols.isEmpty()) return joinFallback(srcName, dstName, joinCond); + return "ALTER TABLE " + srcName + + " ADD FOREIGN KEY (" + String.join(", ", srcCols) + ")" + + " REFERENCES " + dstName + "(" + String.join(", ", dstCols) + ");"; + } + + private static String joinFallback(String srcName, String dstName, String joinCond) { + String resolvedCond = SqlUtil.replaceAliases(joinCond, srcName, dstName); + return "-- SELECT * FROM " + srcName + " JOIN " + dstName + " ON " + resolvedCond.trim() + ";"; + } + + private static String colAfterTable(String expr, String tableName) { + String prefix = tableName + "."; + return expr.startsWith(prefix) ? expr.substring(prefix.length()) : null; + } } // TODO