Repair missing blueprint effect fields
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
package com.ruoyi.generator.service.front;
|
package com.ruoyi.generator.service.front;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -508,6 +511,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
|||||||
}
|
}
|
||||||
Set<String> actionCodes = new HashSet<String>();
|
Set<String> actionCodes = new HashSet<String>();
|
||||||
Set<String> columnNames = collectColumnNames(response);
|
Set<String> columnNames = collectColumnNames(response);
|
||||||
|
Map<String, Set<String>> columnNamesByTable = collectColumnNamesByTable(response);
|
||||||
int actionIndex = 1;
|
int actionIndex = 1;
|
||||||
for (BusinessActionDesign action : response.getBusinessActions())
|
for (BusinessActionDesign action : response.getBusinessActions())
|
||||||
{
|
{
|
||||||
@@ -524,7 +528,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
|||||||
action.setTransaction(action.getTransaction() == null ? Boolean.TRUE : action.getTransaction());
|
action.setTransaction(action.getTransaction() == null ? Boolean.TRUE : action.getTransaction());
|
||||||
action.setRequestFields(normalizeExistingFieldList(action.getRequestFields(), columnNames));
|
action.setRequestFields(normalizeExistingFieldList(action.getRequestFields(), columnNames));
|
||||||
action.setRules(trimStringList(action.getRules(), 200));
|
action.setRules(trimStringList(action.getRules(), 200));
|
||||||
normalizeBusinessEffects(action, columnNames);
|
normalizeBusinessEffects(action, columnNames, columnNamesByTable);
|
||||||
actionIndex++;
|
actionIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -615,6 +619,32 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
|||||||
return columnNames;
|
return columnNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, Set<String>> collectColumnNamesByTable(DatabaseDesignResponse response)
|
||||||
|
{
|
||||||
|
Map<String, Set<String>> columnNamesByTable = new HashMap<String, Set<String>>();
|
||||||
|
if (response == null || response.getTables() == null)
|
||||||
|
{
|
||||||
|
return columnNamesByTable;
|
||||||
|
}
|
||||||
|
for (DatabaseTableDesign table : response.getTables())
|
||||||
|
{
|
||||||
|
if (table == null || StringUtils.isBlank(table.getTableName()) || table.getColumns() == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Set<String> tableColumnNames = new HashSet<String>();
|
||||||
|
for (DatabaseColumnDesign column : table.getColumns())
|
||||||
|
{
|
||||||
|
if (column != null && StringUtils.isNotBlank(column.getColumnName()))
|
||||||
|
{
|
||||||
|
tableColumnNames.add(column.getColumnName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
columnNamesByTable.put(table.getTableName(), tableColumnNames);
|
||||||
|
}
|
||||||
|
return columnNamesByTable;
|
||||||
|
}
|
||||||
|
|
||||||
private List<String> trimStringList(List<String> values, int maxLength)
|
private List<String> trimStringList(List<String> values, int maxLength)
|
||||||
{
|
{
|
||||||
List<String> normalizedValues = new ArrayList<String>();
|
List<String> normalizedValues = new ArrayList<String>();
|
||||||
@@ -633,13 +663,14 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
|||||||
return normalizedValues;
|
return normalizedValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void normalizeBusinessEffects(BusinessActionDesign action, Set<String> columnNames)
|
private void normalizeBusinessEffects(BusinessActionDesign action, Set<String> columnNames, Map<String, Set<String>> columnNamesByTable)
|
||||||
{
|
{
|
||||||
if (action.getEffects() == null)
|
if (action.getEffects() == null)
|
||||||
{
|
{
|
||||||
action.setEffects(new ArrayList<BusinessActionEffectDesign>());
|
action.setEffects(new ArrayList<BusinessActionEffectDesign>());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
List<BusinessActionEffectDesign> normalizedEffects = new ArrayList<BusinessActionEffectDesign>();
|
||||||
int effectIndex = 1;
|
int effectIndex = 1;
|
||||||
for (BusinessActionEffectDesign effect : action.getEffects())
|
for (BusinessActionEffectDesign effect : action.getEffects())
|
||||||
{
|
{
|
||||||
@@ -649,12 +680,83 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
|||||||
}
|
}
|
||||||
effect.setType(normalizeEffectType(effect.getType(), effectIndex));
|
effect.setType(normalizeEffectType(effect.getType(), effectIndex));
|
||||||
effect.setTargetTable(StringUtils.isBlank(effect.getTargetTable()) ? "" : normalizeDatabaseName(effect.getTargetTable(), "table_" + effectIndex));
|
effect.setTargetTable(StringUtils.isBlank(effect.getTargetTable()) ? "" : normalizeDatabaseName(effect.getTargetTable(), "table_" + effectIndex));
|
||||||
effect.setTargetField(StringUtils.isBlank(effect.getTargetField()) ? "" : normalizeDatabaseName(effect.getTargetField(), "field_" + effectIndex));
|
String rawTargetField = StringUtils.isBlank(effect.getTargetField()) ? "" : normalizeDatabaseName(effect.getTargetField(), "field_" + effectIndex);
|
||||||
|
String targetField = resolveEffectTargetField(rawTargetField, effect.getTargetTable(), columnNamesByTable, columnNames);
|
||||||
|
if ("UPDATE_FIELD".equals(effect.getType()) && (StringUtils.isBlank(effect.getTargetTable()) || StringUtils.isBlank(targetField)))
|
||||||
|
{
|
||||||
|
effectIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
effect.setTargetField(targetField);
|
||||||
effect.setValue(trimToLength(effect.getValue(), 200));
|
effect.setValue(trimToLength(effect.getValue(), 200));
|
||||||
|
if (StringUtils.isNotBlank(rawTargetField) && StringUtils.isNotBlank(targetField) && !rawTargetField.equals(targetField))
|
||||||
|
{
|
||||||
|
effect.setValue(rewriteEffectValue(effect.getValue(), rawTargetField, targetField));
|
||||||
|
}
|
||||||
effect.setConditionFields(normalizeExistingFieldList(effect.getConditionFields(), columnNames));
|
effect.setConditionFields(normalizeExistingFieldList(effect.getConditionFields(), columnNames));
|
||||||
effect.setDescription(trimToLength(effect.getDescription(), 200));
|
effect.setDescription(trimToLength(effect.getDescription(), 200));
|
||||||
|
normalizedEffects.add(effect);
|
||||||
effectIndex++;
|
effectIndex++;
|
||||||
}
|
}
|
||||||
|
action.setEffects(normalizedEffects);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveEffectTargetField(String targetField, String targetTable, Map<String, Set<String>> columnNamesByTable, Set<String> columnNames)
|
||||||
|
{
|
||||||
|
if (StringUtils.isBlank(targetField))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
Set<String> tableColumnNames = columnNamesByTable == null ? null : columnNamesByTable.get(targetTable);
|
||||||
|
if (tableColumnNames != null)
|
||||||
|
{
|
||||||
|
if (tableColumnNames.contains(targetField))
|
||||||
|
{
|
||||||
|
return targetField;
|
||||||
|
}
|
||||||
|
String relatedColumn = findRelatedColumn(targetField, tableColumnNames);
|
||||||
|
if (StringUtils.isNotBlank(relatedColumn))
|
||||||
|
{
|
||||||
|
return relatedColumn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return columnNames != null && columnNames.contains(targetField) ? targetField : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String findRelatedColumn(String targetField, Set<String> tableColumnNames)
|
||||||
|
{
|
||||||
|
if (StringUtils.isBlank(targetField) || tableColumnNames == null)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String[] tokens = targetField.split("_");
|
||||||
|
for (int i = tokens.length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
String token = tokens[i];
|
||||||
|
if (token.length() >= 3 && tableColumnNames.contains(token))
|
||||||
|
{
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String columnName : tableColumnNames)
|
||||||
|
{
|
||||||
|
if (columnName.length() >= 3 && (targetField.endsWith("_" + columnName)
|
||||||
|
|| targetField.startsWith(columnName + "_") || targetField.contains("_" + columnName + "_")))
|
||||||
|
{
|
||||||
|
return columnName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String rewriteEffectValue(String value, String rawTargetField, String targetField)
|
||||||
|
{
|
||||||
|
String normalizedValue = trimToLength(value, 200);
|
||||||
|
if (StringUtils.isBlank(normalizedValue))
|
||||||
|
{
|
||||||
|
return normalizedValue;
|
||||||
|
}
|
||||||
|
return normalizedValue.replaceAll("(?<![A-Za-z0-9_])" + Pattern.quote(rawTargetField) + "(?![A-Za-z0-9_])", targetField);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String normalizeEffectType(String type, int index)
|
private String normalizeEffectType(String type, int index)
|
||||||
|
|||||||
@@ -309,6 +309,24 @@ public class AiGenerateServiceImplTest
|
|||||||
assertFalse(projectCaptor.getValue().getBusinessBlueprint().contains("fine_record_id"));
|
assertFalse(projectCaptor.getValue().getBusinessBlueprint().contains("fine_record_id"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateDatabaseRepairsMissingBusinessEffectTargetField()
|
||||||
|
{
|
||||||
|
when(frontProjectMapper.selectFrontProjectByUserAndId(7L, 10L)).thenReturn(project());
|
||||||
|
when(deepSeekClient.chat(anyString())).thenReturn(responseWithMissingBusinessEffectTargetField());
|
||||||
|
|
||||||
|
DatabaseDesignResponse response = service.generateDatabase(7L, 10L, request());
|
||||||
|
|
||||||
|
BusinessActionEffectDesign effect = response.getBusinessActions().get(0).getEffects().get(0);
|
||||||
|
assertEquals("stock", effect.getTargetField());
|
||||||
|
assertEquals("stock - 1", effect.getValue());
|
||||||
|
|
||||||
|
ArgumentCaptor<FrontProject> projectCaptor = ArgumentCaptor.forClass(FrontProject.class);
|
||||||
|
verify(frontProjectMapper).updateFrontProject(projectCaptor.capture());
|
||||||
|
assertTrue(projectCaptor.getValue().getBusinessBlueprint().contains("\"targetField\":\"stock\""));
|
||||||
|
assertFalse(projectCaptor.getValue().getBusinessBlueprint().contains("available_stock"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void generateDatabaseRejectsBusinessActionReferencingMissingTable()
|
public void generateDatabaseRejectsBusinessActionReferencingMissingTable()
|
||||||
{
|
{
|
||||||
@@ -626,6 +644,27 @@ public class AiGenerateServiceImplTest
|
|||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String responseWithMissingBusinessEffectTargetField()
|
||||||
|
{
|
||||||
|
return "{\n"
|
||||||
|
+ " \"tables\": [\n"
|
||||||
|
+ " {\"tableName\": \"book_info\", \"tableComment\": \"Book info\", \"columns\": [\n"
|
||||||
|
+ " {\"columnName\": \"book_id\", \"columnType\": \"bigint(20)\", \"primaryKey\": true, \"autoIncrement\": true, \"columnComment\": \"Book ID\"},\n"
|
||||||
|
+ " {\"columnName\": \"stock\", \"columnType\": \"int(11)\", \"columnComment\": \"Stock\"}\n"
|
||||||
|
+ " ]},\n"
|
||||||
|
+ " {\"tableName\": \"borrow_record\", \"tableComment\": \"Borrow record\", \"columns\": [\n"
|
||||||
|
+ " {\"columnName\": \"borrow_id\", \"columnType\": \"bigint(20)\", \"primaryKey\": true, \"autoIncrement\": true, \"columnComment\": \"Borrow ID\"},\n"
|
||||||
|
+ " {\"columnName\": \"book_id\", \"columnType\": \"bigint(20)\", \"columnComment\": \"Book ID\"}\n"
|
||||||
|
+ " ]}\n"
|
||||||
|
+ " ],\n"
|
||||||
|
+ " \"businessActions\": [\n"
|
||||||
|
+ " {\"code\": \"borrow_book\", \"name\": \"Borrow Book\", \"ownerTable\": \"borrow_record\", \"method\": \"POST\", \"path\": \"/borrow\", \"requestFields\": [\"book_id\"], \"effects\": [\n"
|
||||||
|
+ " {\"type\": \"UPDATE_FIELD\", \"targetTable\": \"book_info\", \"targetField\": \"available_stock\", \"value\": \"available_stock - 1\", \"conditionFields\": [\"book_id\"], \"description\": \"Decrease available stock\"}\n"
|
||||||
|
+ " ]}\n"
|
||||||
|
+ " ]\n"
|
||||||
|
+ "}";
|
||||||
|
}
|
||||||
|
|
||||||
private String responseWithMissingBusinessActionTable()
|
private String responseWithMissingBusinessActionTable()
|
||||||
{
|
{
|
||||||
return "{\n"
|
return "{\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user