fix: 优化 WHERE 字段补全排序
This commit is contained in:
parent
32f865ff52
commit
e3ec2228d3
|
|
@ -1356,7 +1356,8 @@ async function provideSqlCompletions(currentState: import("@codemirror/state").E
|
|||
scheduleCompletionMetadataRefresh(completionContext);
|
||||
if (!explicit) return localResult;
|
||||
}
|
||||
if (!explicit) {
|
||||
const shouldResolveAsyncColumnCompletion = completionContext.suggestColumns && completionContext.referencedTables.length > 0 && completionContext.prefix.length > 0;
|
||||
if (!explicit && !shouldResolveAsyncColumnCompletion) {
|
||||
scheduleCompletionMetadataRefresh(completionContext);
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,17 @@ describe("sqlCompletion scoped context classification", () => {
|
|||
expect(context.suggestColumns).toBe(true);
|
||||
});
|
||||
|
||||
it("classifies unqualified WHERE field input as column context", () => {
|
||||
const sql = "SELECT * FROM A1User WHERE userc";
|
||||
const context = getSqlCompletionContext(sql, sql.length);
|
||||
|
||||
expect(context.contextKind).toBe("column");
|
||||
expect(context.prefix).toBe("userc");
|
||||
expect(context.referencedTables).toEqual(expect.arrayContaining([expect.objectContaining({ name: "A1User" })]));
|
||||
expect(context.suggestColumns).toBe(true);
|
||||
expect(context.suggestRoutines).toBe(false);
|
||||
});
|
||||
|
||||
it("classifies CALL routine contexts", () => {
|
||||
const sql = "CALL usp_";
|
||||
const context = getSqlCompletionContext(sql, sql.length);
|
||||
|
|
|
|||
|
|
@ -1174,7 +1174,8 @@ class SqlCompletionProvider {
|
|||
return dedupeAndSort(buildMongoCompletionItemsFromContext({ mode: "root", prefix: context.prefix, from: 0 }).map(mongoCompletionItemToSqlCompletionItem));
|
||||
}
|
||||
|
||||
if (!context.exclusiveTableSuggestions && !context.exclusiveColumnSuggestions && !context.exclusiveRoutineSuggestions) {
|
||||
const preferReferencedColumns = hasMatchingReferencedColumnPrefix(context, this.input.columnsByTable);
|
||||
if (!preferReferencedColumns && !context.exclusiveTableSuggestions && !context.exclusiveColumnSuggestions && !context.exclusiveRoutineSuggestions) {
|
||||
const snippets = this.databaseType === "manticoresearch" ? [...(this.input.snippets ?? DEFAULT_SQL_SNIPPETS), ...MANTICORESEARCH_SQL_SNIPPETS] : (this.input.snippets ?? DEFAULT_SQL_SNIPPETS);
|
||||
this.items.push(...buildSnippetItems(context.prefix, snippets, this.input.keywordCase));
|
||||
this.items.push(...buildFunctionSnippetItems(context.prefix, getFunctionDescriptions(this.t), this.databaseType));
|
||||
|
|
@ -2786,6 +2787,8 @@ function buildColumnItems(context: SqlCompletionContext, columnsByTable: Map<str
|
|||
const qualifiedTarget = qualifiedTableTargetFromContext(context);
|
||||
const relatedTables = context.referencedTables.filter((table) => referencedTableMatchesColumnQualifier(table, q, qLower, qualifiedTarget));
|
||||
relevantCols = allColumns.filter((column) => relatedTables.some((table) => columnMatchesReferencedTable(column, table)) || (!!qualifiedTarget && columnMatchesQualifiedTable(column, qualifiedTarget)));
|
||||
} else if (context.referencedTables.length > 0) {
|
||||
relevantCols = allColumns.filter((column) => context.referencedTables.some((table) => columnMatchesReferencedTable(column, table)));
|
||||
}
|
||||
|
||||
// Count name frequencies to detect duplicates across tables
|
||||
|
|
@ -2833,6 +2836,21 @@ function buildColumnItems(context: SqlCompletionContext, columnsByTable: Map<str
|
|||
.sort(compareCompletionItems);
|
||||
}
|
||||
|
||||
function hasMatchingReferencedColumnPrefix(context: SqlCompletionContext, columnsByTable: Map<string, SqlCompletionColumn[]>): boolean {
|
||||
if (!context.suggestColumns || !context.prefix || context.referencedTables.length === 0) return false;
|
||||
|
||||
for (const [key, cols] of columnsByTable.entries()) {
|
||||
for (const column of cols) {
|
||||
if (!matchesPrefix(column.name, context.prefix)) continue;
|
||||
if (context.referencedTables.some((table) => columnMatchesReferencedTable({ ...column, key }, table))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function qualifiedTableTargetFromContext(context: SqlCompletionContext): { schema: string; table: string } | null {
|
||||
const parts = context.qualifierParts ?? context.qualifier?.split(".").filter(Boolean) ?? [];
|
||||
if (parts.length < 2) return null;
|
||||
|
|
|
|||
|
|
@ -836,6 +836,65 @@ test("suggests stored procedures after CALL", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("prioritizes referenced table columns in WHERE field input", () => {
|
||||
const sql = "select * from A1User WHERE userc";
|
||||
const items = buildSqlCompletionItems(sql, sql.length, {
|
||||
tables: [{ name: "A1User", schema: "dbo", type: "table" }],
|
||||
objects: [
|
||||
{ name: "P1UserCodeGenerate", schema: "dbo", type: "procedure" },
|
||||
{ name: "F22UserAccUnit", schema: "dbo", type: "function" },
|
||||
],
|
||||
columnsByTable: new Map([
|
||||
[
|
||||
"dbo.A1User",
|
||||
[
|
||||
{ name: "UserCode", table: "A1User", schema: "dbo", dataType: "varchar" },
|
||||
{ name: "UserName", table: "A1User", schema: "dbo", dataType: "varchar" },
|
||||
],
|
||||
],
|
||||
[
|
||||
"dbo.OtherUserTable",
|
||||
[
|
||||
{ name: "UserCheck", table: "OtherUserTable", schema: "dbo", dataType: "varchar" },
|
||||
],
|
||||
],
|
||||
]),
|
||||
databaseType: "sqlserver",
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
items.map((item) => [item.label, item.type]),
|
||||
[["UserCode", "column"]],
|
||||
);
|
||||
});
|
||||
|
||||
test("keeps snippets below matching WHERE field columns", () => {
|
||||
const sql = "select * from demo_2000_tables.t_0001 WHERE i";
|
||||
const items = buildSqlCompletionItems(sql, sql.length, {
|
||||
tables: [{ name: "t_0001", schema: "demo_2000_tables", type: "table" }],
|
||||
columnsByTable: new Map([
|
||||
[
|
||||
"demo_2000_tables.t_0001",
|
||||
[
|
||||
{ name: "id", table: "t_0001", schema: "demo_2000_tables", dataType: "int", comment: "注释test" },
|
||||
{ name: "image_url", table: "t_0001", schema: "demo_2000_tables", dataType: "varchar(512)", comment: "xixixi" },
|
||||
{ name: "image_mime", table: "t_0001", schema: "demo_2000_tables", dataType: "varchar(64)", comment: "hahaha" },
|
||||
],
|
||||
],
|
||||
]),
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
items.slice(0, 3).map((item) => [item.label, item.type]),
|
||||
[
|
||||
["id", "column"],
|
||||
["image_url", "column"],
|
||||
["image_mime", "column"],
|
||||
],
|
||||
);
|
||||
assert.equal(items.some((item) => item.type === "snippet" && item.label === "insert into"), false);
|
||||
});
|
||||
|
||||
test("suggests user functions and triggers with fuzzy matching", () => {
|
||||
const sql = "select fun";
|
||||
const items = buildSqlCompletionItems(sql, sql.length, {
|
||||
|
|
|
|||
Loading…
Reference in New Issue