mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 05:10:26 +00:00
fix(sql): correct table introducer keyword completion
This commit is contained in:
@@ -205,6 +205,24 @@ describe("semantic SQL completion candidates", () => {
|
||||
expect(items).toEqual(expect.arrayContaining([expect.objectContaining({ label: expectedKeyword, type: "keyword" })]));
|
||||
});
|
||||
|
||||
it.each([
|
||||
["UPDATE", "update|", "sqlserver"],
|
||||
["FROM", "select * from|", "mysql"],
|
||||
["JOIN", "select * from t1 join|", "mysql"],
|
||||
] as const)("keeps a fully typed table introducer keyword (%s) in the candidate list", (keyword, sql, databaseType) => {
|
||||
const { context, items } = semanticCompletion(sql, {}, { databaseType });
|
||||
|
||||
expect(context.suggestKeywords).toBe(true);
|
||||
expect(items).toEqual(expect.arrayContaining([expect.objectContaining({ label: keyword, type: "keyword" })]));
|
||||
});
|
||||
|
||||
it("offers tables once a table introducer keyword is committed with whitespace", () => {
|
||||
const { context, items } = semanticCompletion("update |", { tables: [{ name: "orders" }] }, { databaseType: "sqlserver" });
|
||||
|
||||
expect(context.exclusiveTableSuggestions).toBe(true);
|
||||
expect(items).toEqual(expect.arrayContaining([expect.objectContaining({ label: "orders", type: "table" })]));
|
||||
});
|
||||
|
||||
it("does not offer keyword continuations for qualified column prefixes", () => {
|
||||
const columnsByTable = new Map<string, SqlCompletionColumn[]>([["t", [{ name: "order_number", table: "t" }]]]);
|
||||
const { context, items } = semanticCompletion("SELECT * FROM t WHERE t.or|", { columnsByTable }, { databaseType: "mysql", dialect: "mysql" });
|
||||
|
||||
@@ -1010,12 +1010,11 @@ function buildCursorIntent(tokens: readonly SqlSemanticToken[], cursor: number,
|
||||
};
|
||||
}
|
||||
|
||||
// Same rule as the unqualified table slot below: the introducer is the word before the
|
||||
// identifier being completed, never the identifier itself (issue #10415).
|
||||
if (
|
||||
trailing.qualifierParts.length > 0 &&
|
||||
(previous === "from" ||
|
||||
previous === "join" ||
|
||||
TABLE_INTRODUCERS.has(previous) ||
|
||||
TABLE_INTRODUCERS.has(wordBeforeReplacement) ||
|
||||
(TABLE_INTRODUCERS.has(wordBeforeReplacement) ||
|
||||
TABLE_INTRODUCERS.has(wordBeforeTrailing) ||
|
||||
(!!targetSource && !targetSource.alias && trailing.replacementRange.start >= targetSource.sourceSpan.start && trailing.replacementRange.start <= targetSource.sourceSpan.end + 1 && TABLE_INTRODUCERS.has(wordBeforePosition(tokens, targetSource.sourceSpan.start))))
|
||||
) {
|
||||
@@ -1027,8 +1026,13 @@ function buildCursorIntent(tokens: readonly SqlSemanticToken[], cursor: number,
|
||||
return { kind: "alias_column", prefix: trailing.prefix, replacementRange: trailing.replacementRange, qualifierParts: trailing.qualifierParts, targetSourceId: targetSource.id, expectedObjectKinds: ["column"], confidence: "high" };
|
||||
}
|
||||
|
||||
if (TABLE_INTRODUCERS.has(previous) || TABLE_INTRODUCERS.has(wordBeforeReplacement) || TABLE_INTRODUCERS.has(wordBeforeTrailing) || previous === "from" || previous === "join" || wordBeforeReplacement === "from" || wordBeforeReplacement === "join" || tableListContinuation) {
|
||||
return { kind: previous === "join" ? "table" : "table", prefix: trailing.prefix, replacementRange: trailing.replacementRange, qualifierParts: trailing.qualifierParts, expectedObjectKinds: ["table", "view"], confidence: "high" };
|
||||
// A table introducer only introduces the slot that follows it, so both checks read
|
||||
// the word before the identifier being completed (wordBeforeTrailing) or before its
|
||||
// whole qualified name (wordBeforeReplacement). `previous` must not be used here: it
|
||||
// is the word at the cursor, so typing `update`/`from`/`join` in full made the
|
||||
// keyword introduce its own slot and dropped its own completion (issue #10415).
|
||||
if (TABLE_INTRODUCERS.has(wordBeforeReplacement) || TABLE_INTRODUCERS.has(wordBeforeTrailing) || tableListContinuation) {
|
||||
return { kind: "table", prefix: trailing.prefix, replacementRange: trailing.replacementRange, qualifierParts: trailing.qualifierParts, expectedObjectKinds: ["table", "view"], confidence: "high" };
|
||||
}
|
||||
|
||||
if (previous === "call" || previous === "exec" || previous === "execute") {
|
||||
|
||||
Reference in New Issue
Block a user