fix(completion): include PostgreSQL function parameters

This commit is contained in:
zipg authored and GitHub committed 2026-07-28 21:25:30 +08:00
1 parent a0d4a31467
commit 89c69ebe65
11 files changed
+166 -7

No files matched your search

@@ -3187,9 +3187,9 @@ function isTableNameCompletionContext(completionContext: ReturnType<typeof getSq
function mergeCompletionObjects(existing: SqlCompletionObject[], incoming: SqlCompletionObject[]) {
const merged = [...existing];
const indexes = new Map(existing.map((object, index) => [`${object.type}:${object.schema ?? ""}:${object.name}:${object.parentName ?? ""}`.toLowerCase(), index]));
const indexes = new Map(existing.map((object, index) => [completionObjectIdentityKey(object), index]));
for (const object of incoming) {
const key = `${object.type}:${object.schema ?? ""}:${object.name}:${object.parentName ?? ""}`.toLowerCase();
const key = completionObjectIdentityKey(object);
const index = indexes.get(key);
if (index == null) {
indexes.set(key, merged.length);
@@ -3201,6 +3201,10 @@ function mergeCompletionObjects(existing: SqlCompletionObject[], incoming: SqlCo
return merged;
}
function completionObjectIdentityKey(object: SqlCompletionObject): string {
return `${object.type}:${object.schema ?? ""}:${object.name}:${object.parentName ?? ""}:${object.signature?.trim() ?? ""}`.toLowerCase();
}
function completionObjectsDiffer(existing: SqlCompletionObject[], incoming: SqlCompletionObject[]): boolean {
if (existing.length !== incoming.length) return true;
return existing.some((object, index) => {
+50 -3
View File
@@ -3024,17 +3024,19 @@ function buildObjectItems(context: SqlCompletionContext, objects: SqlCompletionO
? quoteSqlIdentifier(object.name, dialect)
: (object.applyName ?? (object.schema && !objectInCurrentSchema ? `${quoteSqlIdentifier(object.schema, dialect)}.${quoteSqlIdentifier(object.name, dialect)}` : quoteSqlIdentifier(object.name, dialect)));
const locationDetail = object.type === "trigger" && object.parentName ? `trigger on ${object.parentName}` : object.parentName ? `${object.type} in ${object.parentName}` : object.schema ? `${object.type} in ${object.schema}` : object.type;
const detail = object.dataType ? `${locationDetail} [${object.dataType}]` : locationDetail;
const signature = object.signature?.trim();
const detail = [locationDetail, signature ? `(${signature})` : undefined, object.dataType ? `[${object.dataType}]` : undefined].filter(Boolean).join(" ");
const schemaBoost = onlyFunctions ? Math.min(object.boost ?? 0, 1000) : (object.boost ?? 0);
const typeBoost = routineTypeBoost(object.type, prioritizeOracleFunctions && !onlyFunctions);
const baseDedupeKey = object.applyName || (databaseType === "oracle" && object.schema) ? applyName : undefined;
return {
label: object.name,
type: "function" as const,
detail,
info: buildRoutineInfo(object),
apply: object.type === "trigger" || object.type === "package" ? applyName : `${applyName}()`,
apply: object.type === "trigger" || object.type === "package" ? applyName : buildRoutineApply(applyName, object.signature),
boost: computeBoost(object.name, context.prefix) + typeBoost + schemaBoost,
dedupeKey: object.applyName || (databaseType === "oracle" && object.schema) ? applyName : undefined,
dedupeKey: signature ? `${baseDedupeKey ?? object.name}(${signature})` : baseDedupeKey,
// Preserve exact routine matches before the capped candidate list is truncated.
exactMatch: !!context.prefix && object.name.toLowerCase() === context.prefix.toLowerCase(),
};
@@ -3043,6 +3045,51 @@ function buildObjectItems(context: SqlCompletionContext, objects: SqlCompletionO
.slice(0, MAX_TABLE_COMPLETION_ITEMS);
}
function buildRoutineApply(applyName: string, signature?: string): string {
const parameters = splitRoutineSignatureParameters(signature?.trim() ?? "");
if (parameters.length === 0) return `${applyName}()`;
return `${applyName}(${parameters.map((parameter, index) => `\${${index + 1}:${escapeSnippetFieldName(parameter)}}`).join(", ")})`;
}
function splitRoutineSignatureParameters(signature: string): string[] {
if (!signature) return [];
const parameters: string[] = [];
let start = 0;
let parenthesisDepth = 0;
let bracketDepth = 0;
let quoted = false;
for (let index = 0; index < signature.length; index++) {
const char = signature[index];
if (char === '"') {
if (quoted && signature[index + 1] === '"') {
index++;
} else {
quoted = !quoted;
}
continue;
}
if (quoted) continue;
if (char === "(") parenthesisDepth++;
else if (char === ")" && parenthesisDepth > 0) parenthesisDepth--;
else if (char === "[") bracketDepth++;
else if (char === "]" && bracketDepth > 0) bracketDepth--;
else if (char === "," && parenthesisDepth === 0 && bracketDepth === 0) {
const parameter = signature.slice(start, index).trim();
if (parameter) parameters.push(parameter);
start = index + 1;
}
}
const parameter = signature.slice(start).trim();
if (parameter) parameters.push(parameter);
return parameters;
}
function escapeSnippetFieldName(value: string): string {
return value.replace(/[{}]/g, "\\$&");
}
function buildRoutineInfo(object: SqlCompletionObject): string | undefined {
const qualifiedName = object.parentName ? [object.parentSchema ?? object.schema, object.parentName, object.name].filter(Boolean).join(".") : [object.schema, object.name].filter(Boolean).join(".");
const parts = [qualifiedName || object.name, object.signature?.trim(), object.comment?.trim()].filter((part): part is string => !!part);
+2 -1
View File
@@ -5130,6 +5130,7 @@ export const useConnectionStore = defineStore("connection", () => {
parentSchema: candidate.parent_schema ?? undefined,
parentName: candidate.parent_name ?? undefined,
dataType,
signature: candidate.signature ?? undefined,
comment: candidate.comment ?? null,
applyName: completionCandidateApplyName(candidate.name, candidate.schema, preferredSchema),
boost: oracleMetadata ? completionCandidateSchemaBoost(candidate.schema, preferredSchema) : completionRoutineSchemaBoost(candidate.schema, preferredSchema),
@@ -5736,7 +5737,7 @@ export const useConnectionStore = defineStore("connection", () => {
const seen = new Set<string>();
const deduped: SqlCompletionObject[] = [];
for (const object of objects) {
const key = `${object.type}:${object.schema ?? ""}:${object.name}:${object.parentName ?? ""}`.toLowerCase();
const key = `${object.type}:${object.schema ?? ""}:${object.name}:${object.parentName ?? ""}:${object.signature?.trim() ?? ""}`.toLowerCase();
if (seen.has(key)) continue;
seen.add(key);
deduped.push(object);
+1
View File
@@ -106,6 +106,7 @@ export interface CompletionAssistantCandidate {
parent_name?: string | null;
comment?: string | null;
data_type?: string | null;
signature?: string | null;
}
export interface CompletionAssistantResponse {