feat(dolt): improve system tables and SQL completion

This commit is contained in:
hanxuanyu authored and GitHub committed 2026-08-14 22:18:28 +08:00
1 parent c5eea21821
commit a574459f8b
30 files changed
+789 -70

No files matched your search

+22 -11
View File
@@ -13,7 +13,7 @@ import { requiresMysqlIdentifierQuote, requiresPostgresIdentifierQuote } from "@
import { identifierMatchScore, matchesIdentifierSearch } from "@/lib/sql/identifierSearch";
import { containsHan, orderedSubsequenceSpan, pinyinFirstLetters } from "@/lib/common/pinyin";
import { quoteTableIdentifier } from "@/lib/table/tableSelectSql";
import { DOLT_SQL_ROUTINES, doltSqlRoutineSignatures, isDoltDriverProfile } from "@/lib/database/doltProfile";
import { driverProfileCompletionObjects, driverProfileCompletionTableMetadata, driverProfileCompletionTables, driverProfileRoutineSignatures } from "@/lib/database/driverProfileExtensions";
export { DEFAULT_SQL_SNIPPETS, resolveSqlSnippetBodyForDatabase } from "@/lib/sql/sqlSnippetTemplates";
@@ -1373,6 +1373,18 @@ class SqlCompletionProvider {
build(): SqlCompletionItem[] {
const { context } = this;
const pendingJoinKeyword = isPendingJoinKeywordContext(context);
const completionTables = [
...this.input.tables.map((table) => {
const metadata = driverProfileCompletionTableMetadata(this.input.driverProfile, table.name);
if (!metadata) return table;
return {
...table,
detail: table.detail ?? metadata.detail,
boost: (table.boost ?? 0) + (metadata.boost ?? 0),
};
}),
...driverProfileCompletionTables(this.input.driverProfile, context),
];
if (this.databaseType === "mongodb") {
return dedupeAndSort(buildMongoCompletionItemsFromContext({ mode: "root", prefix: context.prefix, from: 0 }).map(mongoCompletionItemToSqlCompletionItem));
@@ -1385,7 +1397,7 @@ class SqlCompletionProvider {
this.items.push(...buildSnippetItems(context.prefix, snippets, this.input.keywordCase, this.databaseType));
}
if (!preferReferencedColumns || context.suggestRoutines) {
const functionItems = context.dataTypeContext ? [] : buildFunctionSnippetItems(context.prefix, getFunctionDescriptions(this.t), this.databaseType, this.input.driverProfile, context.openingParenAfterCursor, this.input.keywordCase, this.input.functionCase);
const functionItems = context.dataTypeContext ? [] : buildFunctionSnippetItems(context.prefix, getFunctionDescriptions(this.t), this.databaseType, context.openingParenAfterCursor, this.input.keywordCase, this.input.functionCase);
this.items.push(...(preferReferencedColumns ? functionItems.filter((item) => item.label.toLowerCase().startsWith(context.prefix.toLowerCase())) : functionItems));
if (isOracleLikeDatabase(this.databaseType)) {
this.items.push(...buildOracleSystemValueItems(context.prefix, this.input.keywordCase));
@@ -1443,8 +1455,8 @@ class SqlCompletionProvider {
}
if (!context.exclusiveColumnSuggestions && context.suggestTables) {
this.items.push(...buildForeignKeyRelatedTableItems(context, this.input.tables, this.input.foreignKeysByTable, this.dialect, !!this.input.autoAliasTables && context.autoAliasTableCompletions, this.databaseType, this.input.keywordCase, this.input.currentSchema));
this.items.push(...buildTableItems(context, this.input.tables, this.dialect, !!this.input.autoAliasTables && context.autoAliasTableCompletions, context.referencedTables, this.databaseType, this.input.currentSchema, this.input.keywordCase));
this.items.push(...buildForeignKeyRelatedTableItems(context, completionTables, this.input.foreignKeysByTable, this.dialect, !!this.input.autoAliasTables && context.autoAliasTableCompletions, this.databaseType, this.input.keywordCase, this.input.currentSchema));
this.items.push(...buildTableItems(context, completionTables, this.dialect, !!this.input.autoAliasTables && context.autoAliasTableCompletions, context.referencedTables, this.databaseType, this.input.currentSchema, this.input.keywordCase));
if (this.databaseType === "clickhouse") {
this.items.push(...buildClickHouseFunctionItems(context.prefix, context.openingParenAfterCursor, "table"));
}
@@ -1457,7 +1469,7 @@ class SqlCompletionProvider {
}
if (context.suggestRoutines || context.exclusiveRoutineSuggestions || context.oracleTableFunctionContext) {
const profileObjects = isDoltDriverProfile(this.input.driverProfile) ? DOLT_SQL_ROUTINES : [];
const profileObjects = driverProfileCompletionObjects(this.input.driverProfile, context);
this.items.push(...buildObjectItems(context, [...(this.input.objects ?? []), ...profileObjects], this.dialect, this.databaseType, this.input.currentSchema));
}
@@ -1889,7 +1901,7 @@ export function getSqlFunctionSignatureHelp(sql: string, cursor: number, databas
const observedParameter = countTopLevelCommas(call.groupText);
if (databaseType !== "clickhouse") {
const lookupName = call.name.toUpperCase();
const parameters = activeFunctionSignatures(databaseType, driverProfile).get(lookupName);
const parameters = activeFunctionSignatures(databaseType).get(lookupName) ?? driverProfileRoutineSignatures(driverProfile).get(lookupName);
if (!parameters) return null;
const activeParameter = Math.min(observedParameter, Math.max(0, parameters.length - 1));
const signature = `${lookupName}(${parameters.join(", ")})`;
@@ -4455,14 +4467,13 @@ function buildSnippetItems(prefix: string, snippets: SqlSnippet[], keywordCase?:
});
}
function activeFunctionSignatures(databaseType?: DatabaseType, driverProfile?: string): Map<string, string[]> {
function activeFunctionSignatures(databaseType?: DatabaseType): Map<string, string[]> {
const commonFunctionNames = databaseType === "cloudflare-d1" ? CLOUDFLARE_D1_COMMON_FUNCTION_NAMES : COMMON_SQL_FUNCTION_NAMES;
const signatures = databaseType ? new Map(Array.from(SQL_FUNCTION_SIGNATURES.entries()).filter(([name]) => commonFunctionNames.has(name))) : new Map(SQL_FUNCTION_SIGNATURES);
const databaseSignatures = databaseType ? DATABASE_FUNCTION_SIGNATURES[databaseType] : undefined;
if (databaseSignatures) {
for (const [name, parameters] of databaseSignatures) signatures.set(name, parameters);
}
for (const [name, parameters] of doltSqlRoutineSignatures(driverProfile)) signatures.set(name, parameters);
return signatures;
}
@@ -4504,11 +4515,11 @@ function buildClickHouseFunctionItems(prefix: string, omitOpeningParen: boolean,
});
}
function buildFunctionSnippetItems(prefix: string, functionDescriptions: Map<string, string>, databaseType?: DatabaseType, driverProfile?: string, omitOpeningParen = false, keywordCase?: SqlKeywordCase, functionCase?: SqlKeywordCase): SqlCompletionItem[] {
function buildFunctionSnippetItems(prefix: string, functionDescriptions: Map<string, string>, databaseType?: DatabaseType, omitOpeningParen = false, keywordCase?: SqlKeywordCase, functionCase?: SqlKeywordCase): SqlCompletionItem[] {
if (databaseType === "clickhouse") return buildClickHouseFunctionItems(prefix, omitOpeningParen);
const items: SqlCompletionItem[] = [];
for (const [name, parameters] of activeFunctionSignatures(databaseType, driverProfile).entries()) {
for (const [name, parameters] of activeFunctionSignatures(databaseType).entries()) {
if (!matchesPrefix(name, prefix)) continue;
const functionName = applySqlFunctionCase(name, functionCase);
const paramStr = parameters.length > 0 ? parameters.map((p) => `\${${applyGeneratedSqlTemplateKeywordCase(p, keywordCase)}}`).join(", ") : "";
@@ -4516,7 +4527,7 @@ function buildFunctionSnippetItems(prefix: string, functionDescriptions: Map<str
items.push({
label: functionName,
type: "function" as const,
detail: functionDescriptions.get(name) ?? (isDoltDriverProfile(driverProfile) && name.startsWith("DOLT_") ? "Dolt routine" : "function"),
detail: functionDescriptions.get(name) ?? "function",
apply: mysqlApply ? `${functionName}${applyGeneratedSqlTemplateKeywordCase(mysqlApply.slice(name.length), keywordCase)}` : `${functionName}(${paramStr})`,
boost: computeBoost(name, prefix) + 300,
});