fix(sqlserver): preserve double-dot completion targets

This commit is contained in:
guoyongchang authored and GitHub committed 2026-07-31 19:33:18 +08:00
1 parent e1052333c1
commit 00927ac435
5 files changed
+115 -12

No files matched your search

@@ -134,6 +134,56 @@ describe("semantic SQL completion candidates", () => {
expect(context.qualifierParts).toEqual(["DatabaseB", "OUT", "orders"]);
expect(items.filter((item) => item.type === "column").map((item) => item.label)).toEqual(["target_marker"]);
});
it("completes SQL Server tables from the database dbo schema after a double dot", () => {
const { context, items } = semanticCompletion(
"SELECT * FROM BarDB..|",
{
tables: [{ name: "orders", database: "BarDB", schema: "dbo", type: "table" }],
},
{ databaseType: "sqlserver", dialect: "sqlserver" },
);
expect(context).toMatchObject({
prefix: "",
qualifier: "BarDB.dbo",
qualifierParts: ["BarDB", "dbo"],
});
expect(items.filter((item) => item.type === "table")).toEqual([expect.objectContaining({ label: "orders", apply: "orders" })]);
});
it("completes SQL Server alias columns from the exact double-dot metadata target", () => {
const columnsByTable = new Map<string, SqlCompletionColumn[]>([
["FooDB.dbo.orders", [{ name: "wrong_database", table: "orders", schema: "dbo" }]],
["BarDB.sales.orders", [{ name: "wrong_schema", table: "orders", schema: "sales" }]],
["BarDB.dbo.orders", [{ name: "target_marker", table: "orders", schema: "dbo" }]],
]);
const { model, context, items } = semanticCompletion("SELECT * FROM BarDB..orders AS o WHERE o.|", { columnsByTable }, { databaseType: "sqlserver", dialect: "sqlserver" });
expect(model.rowSources).toEqual([
expect.objectContaining({
name: "orders",
qualifierParts: ["BarDB", "dbo"],
alias: "o",
metadataTarget: { database: "BarDB", schema: "dbo", table: "orders" },
}),
]);
expect(context.referencedTables).toEqual([expect.objectContaining({ name: "orders", database: "BarDB", schema: "dbo", alias: "o" })]);
expect(items.filter((item) => item.type === "column").map((item) => item.label)).toEqual(["target_marker"]);
});
it("completes unqualified SQL Server columns from the exact double-dot metadata target", () => {
const columnsByTable = new Map<string, SqlCompletionColumn[]>([
["FooDB.dbo.orders", [{ name: "wrong_database", table: "orders", schema: "dbo" }]],
["BarDB.sales.orders", [{ name: "wrong_schema", table: "orders", schema: "sales" }]],
["BarDB.dbo.orders", [{ name: "target_marker", table: "orders", schema: "dbo" }]],
]);
const { context, items } = semanticCompletion("SELECT * FROM BarDB..orders WHERE tar|", { columnsByTable }, { databaseType: "sqlserver", dialect: "sqlserver" });
expect(context.referencedTables).toEqual([expect.objectContaining({ name: "orders", database: "BarDB", schema: "dbo" })]);
expect(items.filter((item) => item.type === "column").map((item) => item.label)).toEqual(["target_marker"]);
});
it.each([
["MySQL ORDER BY", "SELECT * FROM t LIMIT 100 or|", "mysql", "mysql", "ORDER BY"],
["PostgreSQL ON CONFLICT", "INSERT INTO t VALUES (1) on|", "postgres", "postgres", "ON CONFLICT"],
@@ -440,6 +440,13 @@ describe("sqlCompletion scoped context classification", () => {
expect(context.referencedTables).toEqual(expect.arrayContaining([expect.objectContaining({ schema: "dbo", name: "Users", alias: "u" }), expect.objectContaining({ name: "Orders", alias: "o" })]));
});
it("preserves SQL Server database and omitted schema in legacy table references", () => {
const sql = "SELECT * FROM BarDB..orders AS o WHERE o.";
const context = getSqlCompletionContext(sql, sql.length, { databaseType: "sqlserver" });
expect(context.referencedTables).toEqual([expect.objectContaining({ database: "BarDB", schema: "dbo", name: "orders", alias: "o" })]);
});
it("treats schema-qualified table prefixes in FROM as table completion input", () => {
const sql = "SELECT * FROM dws_game_sdk_base.di";
const context = getSqlCompletionContext(sql, sql.length);
@@ -82,6 +82,38 @@ describe("sqlCompletionLookupTarget", () => {
});
});
it("routes a SQL Server double-dot qualifier to the database's dbo schema", () => {
const sql = "select * from BarDB..ord";
const completionContext = getSqlCompletionContext(sql, sql.length, { databaseType: "sqlserver" });
expect(completionContext).toMatchObject({
prefix: "ord",
qualifier: "BarDB.dbo",
qualifierParts: ["BarDB", "dbo"],
});
expect(
resolveSqlCompletionTableLookupTarget({
currentDatabase: "FooDB",
currentSchema: "sales",
supportsDatabaseQualifier: false,
supportsDatabaseSchemaQualifier: true,
knownDatabases: ["FooDB", "BarDB"],
completionContext,
}),
).toEqual({
database: "BarDB",
schema: "dbo",
filter: "ord",
qualifierDatabase: "BarDB",
});
});
it.each(["postgres", "trino", "prestosql"] as const)("does not apply SQL Server double-dot semantics to %s", (databaseType) => {
const sql = "select * from BarDB..ord";
expect(getSqlCompletionContext(sql, sql.length, { databaseType }).qualifierParts).toBeUndefined();
});
it("keeps PostgreSQL schema completion in the current database", () => {
const target = resolveSqlCompletionTableLookupTarget({
currentDatabase: "app",