feat(oracle): expand package members in schema tree
This commit is contained in:
12 files changed
+508
-75
No files matched your search
@@ -178,7 +178,7 @@ describe("connectionStore metadata loading", () => {
|
||||
store.connectedIds = new Set([connection.id]);
|
||||
store.treeNodes = [packageNode];
|
||||
|
||||
await store.loadXuguPackageMembers(packageNode);
|
||||
await store.loadPackageMembers(packageNode);
|
||||
|
||||
expect(completionAssistantSearch).toHaveBeenCalledWith({
|
||||
connection_id: connection.id,
|
||||
@@ -200,6 +200,84 @@ describe("connectionStore metadata loading", () => {
|
||||
expect(packageNode.children?.every((child) => child.parentName === "business_api")).toBe(true);
|
||||
}, 15000);
|
||||
|
||||
it("loads Oracle package overloads through the shared package member path", async () => {
|
||||
const completionAssistantSearch = vi.fn().mockResolvedValue({
|
||||
candidates: [
|
||||
{ name: "CALCULATE", kind: "procedure", signature: "P_VALUE IN NUMBER" },
|
||||
{ name: "CALCULATE", kind: "procedure", signature: "P_VALUE IN VARCHAR2" },
|
||||
{ name: "ITEM_COUNT", kind: "function", data_type: "NUMBER" },
|
||||
],
|
||||
incomplete: false,
|
||||
fallback_used: false,
|
||||
});
|
||||
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/backend/api", () => ({ checkConnectionHealth: vi.fn().mockResolvedValue(undefined), completionAssistantSearch }));
|
||||
|
||||
const { useConnectionStore } = await import("@/stores/connectionStore");
|
||||
const store = useConnectionStore();
|
||||
const connection = oracleConnection();
|
||||
const packageNode: TreeNode = {
|
||||
id: "oracle-1:XE:APP:package:BUSINESS_API",
|
||||
label: "BUSINESS_API",
|
||||
type: "package",
|
||||
connectionId: connection.id,
|
||||
database: "XE",
|
||||
schema: "APP",
|
||||
children: [],
|
||||
isExpanded: false,
|
||||
};
|
||||
store.connections = [connection];
|
||||
store.connectedIds = new Set([connection.id]);
|
||||
store.treeNodes = [packageNode];
|
||||
|
||||
await store.loadPackageMembers(packageNode);
|
||||
|
||||
expect(completionAssistantSearch).toHaveBeenCalledWith({
|
||||
connection_id: connection.id,
|
||||
database: "XE",
|
||||
schema: "APP",
|
||||
object_kinds: ["routine"],
|
||||
mask: "",
|
||||
case_sensitive: true,
|
||||
global_search: false,
|
||||
max_results: 1000,
|
||||
search_in_comments: false,
|
||||
search_in_definitions: false,
|
||||
parent_schema: "APP",
|
||||
parent_name: "BUSINESS_API",
|
||||
match_mode: "prefix",
|
||||
});
|
||||
expect(packageNode.isExpanded).toBe(true);
|
||||
expect(packageNode.children?.map((child) => child.label)).toEqual(["CALCULATE(P_VALUE IN NUMBER)", "CALCULATE(P_VALUE IN VARCHAR2)", "ITEM_COUNT"]);
|
||||
}, 15000);
|
||||
|
||||
it("does not query package members for unsupported databases", async () => {
|
||||
const completionAssistantSearch = vi.fn();
|
||||
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/backend/api", () => ({ checkConnectionHealth: vi.fn().mockResolvedValue(undefined), completionAssistantSearch }));
|
||||
|
||||
const { useConnectionStore } = await import("@/stores/connectionStore");
|
||||
const store = useConnectionStore();
|
||||
const connection = { ...xuguConnection(), id: "dameng-1", db_type: "dameng" } as ConnectionConfig;
|
||||
const packageNode: TreeNode = {
|
||||
id: "dameng-1:APP:package:BUSINESS_API",
|
||||
label: "BUSINESS_API",
|
||||
type: "package",
|
||||
connectionId: connection.id,
|
||||
database: "APP",
|
||||
schema: "APP",
|
||||
children: [],
|
||||
isExpanded: false,
|
||||
};
|
||||
store.connections = [connection];
|
||||
store.connectedIds = new Set([connection.id]);
|
||||
|
||||
await store.loadPackageMembers(packageNode);
|
||||
|
||||
expect(completionAssistantSearch).not.toHaveBeenCalled();
|
||||
expect(packageNode.isExpanded).toBe(false);
|
||||
}, 15000);
|
||||
|
||||
it("loads missing database roots only for connected sidebar search targets", async () => {
|
||||
const checkConnectionHealth = vi.fn().mockResolvedValue(undefined);
|
||||
const listDatabases = vi.fn().mockResolvedValue([{ name: "dajia", comment: null }]);
|
||||
|
||||
@@ -62,7 +62,7 @@ import { mergeSqlObjectNavigationType, sqlObjectNavigationTypeFromTableType } fr
|
||||
import * as api from "@/lib/backend/api";
|
||||
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
|
||||
import { useTunnelProfileStore } from "@/stores/tunnelProfileStore";
|
||||
import { connectionIsDorisFamilyCatalogCapable, isInternalDorisCatalog, isSchemaAware, normalizeSidebarObjectKind, sidebarObjectKindsForDatabase, usesTreeSchemaMode } from "@/lib/database/databaseCapabilities";
|
||||
import { connectionIsDorisFamilyCatalogCapable, isInternalDorisCatalog, isSchemaAware, normalizeSidebarObjectKind, sidebarObjectKindsForDatabase, supportsPackageMemberExpansion, usesTreeSchemaMode } from "@/lib/database/databaseCapabilities";
|
||||
import { connectionObjectTreeNodeSchema, connectionObjectTreeQuerySchema, connectionShouldDiscoverJdbcSchemas, connectionShouldLoadIdentifierQuote, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection, gaussdbIdentifierQuoteOverride } from "@/lib/database/jdbcDialect";
|
||||
import { buildDatabaseTreeNodes, buildDuckDbConnectionTreeNodes, compareSidebarNames, sortSidebarDatabases, sortSidebarNames, shouldIncludeDefaultDatabaseNode } from "@/lib/database/databaseTree";
|
||||
import { buildSqlServerDatabaseTreeNodes } from "@/lib/database/sqlServerTree";
|
||||
@@ -111,7 +111,7 @@ import { appendAgentDriverUpdateHint, hasAgentDriverUpdate, hasInstalledAgentVer
|
||||
import { appendConnectionErrorHints } from "@/lib/connection/connectionErrorHints";
|
||||
import { appendVisibleDatabaseSelection } from "@/lib/connection/connectionVisibleDatabases";
|
||||
import { filterNacosNamespacesForSidebar, normalizeNacosNamespacesForDisplay } from "@/lib/nacos/nacosNamespaceVisibility";
|
||||
import { buildXuguPackageMemberNodes, markXuguPackageNodesExpandable } from "@/lib/sidebar/xuguPackageMembers";
|
||||
import { buildPackageMemberNodes, markPackageNodesExpandable } from "@/lib/sidebar/packageMembers";
|
||||
import { configuredDatabaseProductName, connectionConfigFingerprint, normalizeDatabaseConnectionInfo } from "@/lib/connection/connectionDatabaseInfo";
|
||||
import { createMetadataLoadTrace, logMetadataLoadTrace, MetadataLoadCoordinator, type MetadataLoadTraceLogger } from "@/lib/metadata/metadataLoadCoordinator";
|
||||
import type { MetadataScopeInput } from "@/lib/metadata/metadataLoadScope";
|
||||
@@ -1606,7 +1606,8 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
});
|
||||
const refreshedGroup = grouped.find((group) => group.type === options.node.type);
|
||||
const children = refreshedGroup?.children ?? [];
|
||||
return options.node.connectionId && getConfig(options.node.connectionId)?.db_type === "xugu" ? markXuguPackageNodesExpandable(children) : children;
|
||||
const databaseType = options.node.connectionId ? effectiveDatabaseTypeForConnection(getConfig(options.node.connectionId)) : undefined;
|
||||
return supportsPackageMemberExpansion(databaseType) ? markPackageNodesExpandable(children) : children;
|
||||
}
|
||||
|
||||
function tableInfosToCompletionTables(tables: readonly TableInfo[], schema?: string): SqlCompletionTable[] {
|
||||
@@ -1870,8 +1871,8 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
schema: options.effectiveSchema,
|
||||
objects: supplementalObjects,
|
||||
});
|
||||
if (getConfig(options.connectionId)?.db_type === "xugu") {
|
||||
supplementalChildren = markXuguPackageNodesExpandable(supplementalChildren);
|
||||
if (supportsPackageMemberExpansion(effectiveDatabaseTypeForConnection(getConfig(options.connectionId)))) {
|
||||
supplementalChildren = markPackageNodesExpandable(supplementalChildren);
|
||||
}
|
||||
if (supplementalChildren.length === 0) return;
|
||||
if (isTreeLoadSearchChanged(searchFilter, options.loadOptions)) return;
|
||||
@@ -5618,8 +5619,9 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
});
|
||||
}
|
||||
|
||||
async function loadXuguPackageMembers(node: TreeNode, options?: LoadTreeOptions): Promise<void> {
|
||||
if (node.type !== "package" || !node.connectionId || !node.database || getConfig(node.connectionId)?.db_type !== "xugu") return;
|
||||
async function loadPackageMembers(node: TreeNode, options?: LoadTreeOptions): Promise<void> {
|
||||
if (node.type !== "package" || !node.connectionId || !node.database) return;
|
||||
if (!supportsPackageMemberExpansion(effectiveDatabaseTypeForConnection(getConfig(node.connectionId)))) return;
|
||||
const connectionId = node.connectionId;
|
||||
const database = node.database;
|
||||
const schema = node.schema;
|
||||
@@ -5629,7 +5631,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
try {
|
||||
await runTreeMetadataLoad(
|
||||
{
|
||||
kind: "xugu-package-members",
|
||||
kind: "package-members",
|
||||
connectionId,
|
||||
database,
|
||||
schema,
|
||||
@@ -5656,7 +5658,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
});
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(targetNode, buildXuguPackageMemberNodes(targetNode, response.candidates));
|
||||
setChildren(targetNode, buildPackageMemberNodes(targetNode, response.candidates));
|
||||
targetNode.isExpanded = true;
|
||||
},
|
||||
options,
|
||||
@@ -7280,7 +7282,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
loadTables,
|
||||
loadTableForLocate,
|
||||
loadObjectGroupChildren,
|
||||
loadXuguPackageMembers,
|
||||
loadPackageMembers,
|
||||
loadMoreObjectGroupChildren,
|
||||
loadAllObjectGroupChildren,
|
||||
loadTableGroups,
|
||||
|
||||
Reference in new issue
Block a user