fix(ai): append generated SQL without duplicates

This commit is contained in:
0xTyson authored and GitHub committed 2026-08-30 12:25:54 +08:00
1 parent 143be57d41
commit 9491ab08df
5 files changed
+83 -12

No files matched your search

@@ -19,14 +19,23 @@ describe("AI Redis console routing", () => {
});
it("keeps the existing SQL editor and execution behavior for non-Redis connections", () => {
expect(aiAssistantSource).toContain('emit("replaceSql", code)');
expect(aiAssistantSource).toContain('emit("appendSql", code)');
expect(aiAssistantSource).toContain('emit("executeSql", code)');
expect(aiAssistantSource).toContain('emit("tempRunSql", code)');
expect(appSource).toContain("const tabId = ensureQueryTab();");
expect(appSource).toContain("buildDeduplicatedAppendedEditorSql(currentSql, sql)");
expect(appSource).toContain('buildAppendedEditorSql(activeTab.value?.sql || "", sql)');
expect(appSource).toContain("const decision = classifyAiSqlExecution(sql, activeConnection.value);");
});
it("deduplicates immediate-run editor writes without skipping execution", () => {
const handler = appSource.match(/function onAiExecuteSql\(sql: string\) \{[\s\S]*?\n\}/)?.[0] ?? "";
expect(handler).toContain("buildDeduplicatedAppendedEditorSql(currentSql, sql)");
expect(handler).toContain("if (appendedSql !== currentSql) queryStore.updateSql(tabId, appendedSql);");
expect(handler).toContain("runAiGeneratedSql(sql);");
expect(handler).not.toContain("buildAppendedEditorSql(");
});
it("uses the console safety path and rejects unavailable command input", () => {
expect(classifyRedisCommandSafety("CONFIG SET requirepass secret")).toBe("blocked");
expect(classifyRedisCommandSafety("FLUSHDB")).toBe("confirm");
+27
View File
@@ -17,3 +17,30 @@ export function buildAppendedEditorSql(currentEditorSql: string, newSql: string)
return `${currentEditorSql}${separator}${newSql}`;
}
/**
* Append AI-generated SQL unless the exact text already exists as a standalone
* editor block. AI appends use a blank line as their block separator, which
* avoids treating a matching fragment inside a larger statement as a duplicate.
*/
export function buildDeduplicatedAppendedEditorSql(currentEditorSql: string, newSql: string): string {
if (!newSql || containsStandaloneSqlBlock(currentEditorSql, newSql)) return currentEditorSql;
return buildAppendedEditorSql(currentEditorSql, newSql);
}
function containsStandaloneSqlBlock(editorSql: string, sql: string): boolean {
let from = 0;
while (from <= editorSql.length - sql.length) {
const index = editorSql.indexOf(sql, from);
if (index < 0) return false;
const before = editorSql.slice(0, index);
const after = editorSql.slice(index + sql.length);
const startsAtBlockBoundary = index === 0 || /(?:\r?\n){2}$/.test(before);
const endsAtBlockBoundary = after.length === 0 || /^(?:\r?\n){2}/.test(after);
if (startsAtBlockBoundary && endsAtBlockBoundary) return true;
from = index + 1;
}
return false;
}