Files
dbx/apps/desktop/src/lib/table/objectSourceLoad.ts
T
Yy-702 e749bdd42c feat(oracle): Ctrl/Cmd+click 打开存储过程源码
* feat(oracle): open procedure source via Ctrl/Cmd+click in SQL editor

Allow navigating from SQL identifiers to routine source like DataGrip/DBeaver.
Call sites open immediately without a global ALL_OBJECTS scan, and query-tab
views wrap bare Oracle ALL_SOURCE as CREATE OR REPLACE for editable DDL.

Close #5290

* fix(oracle): harden Ctrl/Cmd+click navigation identity model

Address review feedback on routine navigation correctness:
- Distinguish relation column lists (INSERT INTO t(...)) from routine calls
- Resolve schema.routine vs package.member before optimistic open
- Preserve quoted mixed-case identities for Oracle ALL_SOURCE lookup
- Try exact then uppercase name candidates in the Oracle Go agent
2026-08-05 23:57:50 +08:00

79 lines
3.1 KiB
TypeScript

import type { DatabaseType, ObjectSource, ObjectSourceKind } from "@/types/database";
export type GetObjectSourceFn = (connectionId: string, database: string, schema: string, name: string, objectType: ObjectSourceKind, signature?: string, relationName?: string) => Promise<ObjectSource>;
export type BuildEditableObjectSourceFn = (input: { databaseType: DatabaseType; objectType: ObjectSourceKind; schema?: string; name: string; source: string }) => Promise<string>;
/**
* Load object source, retrying common routine type mismatches.
* Optimistic Ctrl/Cmd+click often assumes PROCEDURE; Oracle functions and package bodies need a second try.
*/
export async function loadObjectSourceWithRoutineFallback(
getObjectSource: GetObjectSourceFn,
connectionId: string,
database: string,
schema: string,
name: string,
objectType: ObjectSourceKind,
signature?: string,
relationName?: string,
): Promise<{ source: ObjectSource; objectType: ObjectSourceKind }> {
const primary = await getObjectSource(connectionId, database, schema, name, objectType, signature, relationName);
if (primary.source?.trim()) {
return { source: primary, objectType };
}
const fallbacks: ObjectSourceKind[] = objectType === "PROCEDURE" ? ["FUNCTION"] : objectType === "FUNCTION" ? ["PROCEDURE"] : objectType === "PACKAGE" ? ["PACKAGE_BODY"] : objectType === "PACKAGE_BODY" ? ["PACKAGE"] : [];
for (const fallbackType of fallbacks) {
try {
const alternate = await getObjectSource(connectionId, database, schema, name, fallbackType, signature, relationName);
if (alternate.source?.trim()) {
return { source: alternate, objectType: fallbackType };
}
} catch {
// Keep trying remaining fallbacks; surface the primary empty/error state if none succeed.
}
}
return { source: primary, objectType };
}
/**
* Load raw object source then convert it to the editable editor form.
*
* For Oracle, bare `ALL_SOURCE` text like `procedure name is ...` becomes
* `CREATE OR REPLACE procedure name is ...` so the query tab shows deployable DDL
* (same wrapping ObjectSourceDialog already applies).
*/
export async function loadEditableObjectSourceForEditor(
getObjectSource: GetObjectSourceFn,
buildEditableObjectSource: BuildEditableObjectSourceFn,
options: {
connectionId: string;
database: string;
schema: string;
name: string;
objectType: ObjectSourceKind;
databaseType: DatabaseType;
signature?: string;
relationName?: string;
},
): Promise<{ raw: ObjectSource; editableSource: string; objectType: ObjectSourceKind }> {
const { source: raw, objectType: resolvedType } = await loadObjectSourceWithRoutineFallback(getObjectSource, options.connectionId, options.database, options.schema, options.name, options.objectType, options.signature, options.relationName);
const editableSource = await buildEditableObjectSource({
databaseType: options.databaseType,
objectType: resolvedType,
schema: options.schema,
name: options.name,
source: raw.source,
});
return {
raw,
editableSource: editableSource.trim() ? editableSource : raw.source,
objectType: resolvedType,
};
}