fix(presto): optimize metadata completion
This commit is contained in:
1 parent
f5f6bc0b43
commit
95e3cb6571
9 files changed
+528
-37
No files matched your search
@@ -156,6 +156,8 @@ const completionTranslations = computed(() => ({
|
||||
functionDescriptions: Object.fromEntries(SQL_FUNCTION_NAMES.map((name) => [name, t(`editor.completion.functionDescriptions.${name}`)])) as Record<string, string>,
|
||||
}));
|
||||
const MAX_COMPLETION_TABLES = 200;
|
||||
const PRESTO_ON_DEMAND_TABLE_COMPLETION_MIN_PREFIX = 2;
|
||||
const PRESTO_ON_DEMAND_TABLE_COMPLETION_LIMIT = 20;
|
||||
const MAX_JOIN_FK_PREFETCH_TABLES = 24;
|
||||
const MAX_SEMANTIC_DIAGNOSTIC_COLUMN_TABLES = 4;
|
||||
const liveFontSize = ref(settingsStore.editorSettings.fontSize);
|
||||
@@ -717,6 +719,12 @@ function usesOnDemandOnlyCompletionColumns(): boolean {
|
||||
return usesOnDemandOnlyEditorColumnMetadata(props.databaseType);
|
||||
}
|
||||
|
||||
function allowsOnDemandQualifiedTableCompletion(prefix: string): boolean {
|
||||
if (!usesLocalOnlyCompletionMetadata()) return false;
|
||||
if (props.databaseType !== "prestosql" && props.databaseType !== "trino") return false;
|
||||
return prefix.trim().length >= PRESTO_ON_DEMAND_TABLE_COMPLETION_MIN_PREFIX;
|
||||
}
|
||||
|
||||
function completionMetadataTarget(table: { name: string; schema?: string | null }): { database: string; schema?: string } | null {
|
||||
if (props.database == null) return null;
|
||||
if (supportsDatabaseQualifierCompletion() && table.schema) {
|
||||
@@ -1814,9 +1822,12 @@ async function performAsyncCompletionWithResult(epoch: number, completionContext
|
||||
// If qualifier didn't match any table names, try it as a schema name
|
||||
let qualifierIsSchema = false;
|
||||
if (completionContext.qualifier && !qualifierDatabase && !isReferencedTableQualifier(completionContext) && tables.length === 0 && (completionContext.suggestTables || completionContext.exclusiveColumnSuggestions)) {
|
||||
const schemaTables = localOnlyMetadata
|
||||
? connectionStore.lookupLocalCompletionTables(props.connectionId!, props.database!, completionContext.prefix, MAX_COMPLETION_TABLES, completionContext.qualifier)
|
||||
: await listCompletionTablesWithLatencyBudget(props.connectionId!, props.database!, completionContext.prefix, MAX_COMPLETION_TABLES, completionContext.qualifier);
|
||||
let schemaTables = connectionStore.lookupLocalCompletionTables(props.connectionId!, props.database!, completionContext.prefix, MAX_COMPLETION_TABLES, completionContext.qualifier);
|
||||
if (!localOnlyMetadata) {
|
||||
schemaTables = await listCompletionTablesWithLatencyBudget(props.connectionId!, props.database!, completionContext.prefix, MAX_COMPLETION_TABLES, completionContext.qualifier);
|
||||
} else if (schemaTables.length === 0 && allowsOnDemandQualifiedTableCompletion(completionContext.prefix)) {
|
||||
schemaTables = await listCompletionTablesWithLatencyBudget(props.connectionId!, props.database!, completionContext.prefix, PRESTO_ON_DEMAND_TABLE_COMPLETION_LIMIT, completionContext.qualifier);
|
||||
}
|
||||
if (schemaTables.length > 0) {
|
||||
tables = schemaTables;
|
||||
qualifierIsSchema = true;
|
||||
@@ -1868,7 +1879,8 @@ async function performAsyncCompletionWithResult(epoch: number, completionContext
|
||||
}
|
||||
}
|
||||
|
||||
const shouldFetchColumnsForCompletion = !onDemandOnlyColumns || completionContext.suggestColumns || completionContext.exclusiveColumnSuggestions || !!completionContext.insertTable;
|
||||
const isTableNameCompletionContext = completionContext.suggestTables || completionContext.exclusiveTableSuggestions;
|
||||
const shouldFetchColumnsForCompletion = !onDemandOnlyColumns || ((completionContext.suggestColumns || completionContext.exclusiveColumnSuggestions) && !isTableNameCompletionContext) || !!completionContext.insertTable;
|
||||
if (shouldFetchColumnsForCompletion) {
|
||||
await Promise.all(
|
||||
refs.map(async (refTable) => {
|
||||
|
||||
@@ -35,7 +35,7 @@ describe("prestoSqlBuiltinDriver", () => {
|
||||
expect(row.version).toBe("350");
|
||||
expect(row.installed).toBe(false);
|
||||
expect(row.installed_version).toBeNull();
|
||||
expect(row.jre).toBe("");
|
||||
expect(row.jre).toBe("21");
|
||||
});
|
||||
|
||||
it("marks PrestoSQL installed when its Maven coordinate is present", () => {
|
||||
|
||||
@@ -180,6 +180,17 @@ 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("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);
|
||||
|
||||
expect(context.qualifier).toBe("dws_game_sdk_base");
|
||||
expect(context.prefix).toBe("di");
|
||||
expect(context.suggestTables).toBe(true);
|
||||
expect(context.exclusiveTableSuggestions).toBe(true);
|
||||
expect(context.suggestColumns).toBe(true);
|
||||
});
|
||||
|
||||
it("exposes CTEs as table-like referenced tables", () => {
|
||||
const sql = "WITH recent_orders(id, total) AS (SELECT id, total FROM orders) SELECT * FROM recent_orders ro WHERE ro.";
|
||||
const context = getSqlCompletionContext(sql, sql.length);
|
||||
|
||||
@@ -24,8 +24,8 @@ export function prestoSqlBuiltinDriverRow(bundles: JdbcMavenBundleInfo[]): Agent
|
||||
installed: Boolean(installedBundle),
|
||||
installed_version: installedBundle ? PRESTOSQL_JDBC_DRIVER_VERSION : null,
|
||||
update_available: false,
|
||||
requires_java_runtime: false,
|
||||
jre: "",
|
||||
requires_java_runtime: true,
|
||||
jre: "21",
|
||||
jre_installed: true,
|
||||
};
|
||||
}
|
||||
@@ -83,4 +83,33 @@ describe("connectionStore completion assistant", () => {
|
||||
expect(listTables).toHaveBeenCalledWith("pg-1", "app", "public", "acc", 20);
|
||||
expect(tables).toEqual([{ name: "accounts", schema: "public", type: "table" }]);
|
||||
});
|
||||
|
||||
it("keeps schema-qualified local table completion scoped to the selected schema", async () => {
|
||||
const completionAssistantSearch = vi.fn().mockRejectedValue(new Error("assistant unavailable"));
|
||||
const listTables = vi.fn(async (_connectionId: string, _database: string, schema: string, filter: string) => {
|
||||
if (schema === "dim_game_base" && filter === "dim") {
|
||||
return [{ name: "dim_game", table_type: "BASE TABLE", comment: null }];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
vi.doMock("@/lib/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/api", () => ({
|
||||
checkConnectionHealth: vi.fn().mockResolvedValue(undefined),
|
||||
completionAssistantSearch,
|
||||
listSchemas: vi.fn().mockResolvedValue(["dim_game_base", "dws_game_sdk_base"]),
|
||||
listTables,
|
||||
}));
|
||||
|
||||
const { useConnectionStore } = await import("@/stores/connectionStore");
|
||||
const store = useConnectionStore();
|
||||
store.connections = [postgresConnection()];
|
||||
store.connectedIds.add("pg-1");
|
||||
|
||||
const dimTables = await store.listCompletionTables("pg-1", "app", "dim", 20, "dim_game_base");
|
||||
const dwsTables = store.lookupLocalCompletionTables("pg-1", "app", "d", 20, "dws_game_sdk_base");
|
||||
|
||||
expect(dimTables).toEqual([{ name: "dim_game", schema: "dim_game_base", type: "table" }]);
|
||||
expect(dwsTables).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -2966,7 +2966,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
function lookupLocalCompletionTables(connectionId: string, database: string, filter = "", limit?: number, schema?: string): SqlCompletionTable[] {
|
||||
const allScopes = [...completionTableIndex.entries()].filter(([key]) => key.startsWith(`${connectionId}:${database}:`)).map(([, entry]) => entry);
|
||||
const preferred = schema ? completionTableIndex.get(completionScopeKey(connectionId, database, schema)) : undefined;
|
||||
const scopes = preferred ? [preferred, ...allScopes.filter((entry) => entry !== preferred)] : allScopes;
|
||||
const scopes = schema ? (preferred ? [preferred] : []) : allScopes;
|
||||
const treeTables = completionTablesFromTree(treeNodes.value, connectionId, database, schema);
|
||||
const ranked = scopes
|
||||
.flatMap((entry) => entry?.tables ?? [])
|
||||
@@ -2980,7 +2980,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
function lookupLocalCompletionObjects(connectionId: string, database: string, filter = "", limit?: number, schema?: string): SqlCompletionObject[] {
|
||||
const allScopes = [...completionObjectIndex.entries()].filter(([key]) => key.startsWith(`${connectionId}:${database}:`)).map(([, entry]) => entry);
|
||||
const preferred = schema ? completionObjectIndex.get(completionScopeKey(connectionId, database, schema)) : undefined;
|
||||
const scopes = preferred ? [preferred, ...allScopes.filter((entry) => entry !== preferred)] : allScopes;
|
||||
const scopes = schema ? (preferred ? [preferred] : []) : allScopes;
|
||||
const ranked = scopes
|
||||
.flatMap((entry) => entry?.objects ?? [])
|
||||
.map((object) => ({ object, score: objectMatchScore(object, filter, schema) }))
|
||||
|
||||
Reference in new issue
Block a user