🐛 fix(sidebar): 兜底定位表分支中的视图节点

This commit is contained in:
Syngnat
2026-06-09 18:45:30 +08:00
parent 327a78f1cb
commit c17d867aa6
2 changed files with 161 additions and 0 deletions

View File

@@ -466,6 +466,149 @@ describe('sidebarLocate', () => {
]);
});
it('finds a unique bare view node when metadata supplies schema separately', () => {
const target = resolveSidebarLocateTarget({
tabId: 'stale-view-tab-id',
connectionId: 'conn-1',
dbName: 'SYSDBA',
tableName: 'V_ACCOUNT',
schemaName: 'SYSDBA',
objectGroup: 'views',
}, { groupBySchema: false });
const tree = [
{
key: 'conn-1',
children: [
{
key: 'conn-1-SYSDBA',
dataRef: { id: 'conn-1', dbName: 'SYSDBA' },
children: [
{
key: 'conn-1-SYSDBA-views',
children: [
{
key: 'conn-1-SYSDBA-view-V_ACCOUNT',
type: 'view',
dataRef: {
id: 'conn-1',
dbName: 'SYSDBA',
viewName: 'V_ACCOUNT',
},
},
],
},
],
},
],
},
];
expect(findSidebarNodePathForLocate(tree, target)).toEqual([
'conn-1',
'conn-1-SYSDBA',
'conn-1-SYSDBA-views',
'conn-1-SYSDBA-view-V_ACCOUNT',
]);
});
it('falls back to a table-like node when a view is only present in the tables branch', () => {
const target = resolveSidebarLocateTarget({
tabId: 'stale-view-tab-id',
connectionId: 'conn-1',
dbName: 'SYSDBA',
tableName: 'V_ACCOUNT',
objectGroup: 'views',
}, { groupBySchema: false });
const tree = [
{
key: 'conn-1',
children: [
{
key: 'conn-1-SYSDBA',
dataRef: { id: 'conn-1', dbName: 'SYSDBA' },
children: [
{
key: 'conn-1-SYSDBA-tables',
children: [
{
key: 'conn-1-SYSDBA-V_ACCOUNT',
type: 'table',
dataRef: {
id: 'conn-1',
dbName: 'SYSDBA',
tableName: 'V_ACCOUNT',
},
},
],
},
],
},
],
},
];
expect(findSidebarNodePathForLocate(tree, target)).toEqual([
'conn-1',
'conn-1-SYSDBA',
'conn-1-SYSDBA-tables',
'conn-1-SYSDBA-V_ACCOUNT',
]);
});
it('falls back to a unique schema-qualified table-like node for an unqualified view request', () => {
const target = resolveSidebarLocateTarget({
tabId: 'stale-view-tab-id',
connectionId: 'conn-1',
dbName: 'SYSDBA',
tableName: 'V_ACCOUNT',
objectGroup: 'views',
}, { groupBySchema: true });
const tree = [
{
key: 'conn-1',
children: [
{
key: 'conn-1-SYSDBA',
dataRef: { id: 'conn-1', dbName: 'SYSDBA' },
children: [
{
key: 'conn-1-SYSDBA-schema-SYSDBA',
children: [
{
key: 'conn-1-SYSDBA-schema-SYSDBA-tables',
children: [
{
key: 'conn-1-SYSDBA-SYSDBA.V_ACCOUNT',
type: 'table',
dataRef: {
id: 'conn-1',
dbName: 'SYSDBA',
tableName: 'SYSDBA.V_ACCOUNT',
schemaName: 'SYSDBA',
},
},
],
},
],
},
],
},
],
},
];
expect(findSidebarNodePathForLocate(tree, target)).toEqual([
'conn-1',
'conn-1-SYSDBA',
'conn-1-SYSDBA-schema-SYSDBA',
'conn-1-SYSDBA-schema-SYSDBA-tables',
'conn-1-SYSDBA-SYSDBA.V_ACCOUNT',
]);
});
it('does not guess a schema-qualified view when an unqualified locate request is ambiguous', () => {
const target = resolveSidebarLocateTarget({
tabId: 'conn-1-SYSDBA-view-V_ACCOUNT',

View File

@@ -368,6 +368,10 @@ const hasLocateTargetSchema = (target: SidebarLocateTarget): boolean => {
return Boolean(toTrimmedString(target.schemaName) || splitSidebarQualifiedName(target.tableName).schemaName);
};
const shouldFallbackViewLocateToTableNode = (target: SidebarLocateTarget): boolean => (
target.objectGroup === 'views' || target.objectGroup === 'materializedViews'
);
export const findSidebarNodePathForLocate = (
nodes: SidebarLocateTreeNodeLike[],
target: SidebarLocateTarget,
@@ -378,6 +382,20 @@ export const findSidebarNodePathForLocate = (
const strictPath = findSidebarNodePathForLocateByObject(nodes, target);
if (strictPath) return strictPath;
if (shouldFallbackViewLocateToTableNode(target)) {
const tableLikeTarget = { ...target, objectGroup: 'tables' as const };
const tableLikePaths = collectSidebarNodePathsForLocateByObject(nodes, tableLikeTarget);
if (tableLikePaths.length === 1) return tableLikePaths[0];
if (!hasLocateTargetSchema(target)) {
const relaxedTableLikePaths = collectSidebarNodePathsForLocateByObject(
nodes,
tableLikeTarget,
{ allowUnqualifiedSchemaMatch: true },
);
if (relaxedTableLikePaths.length === 1) return relaxedTableLikePaths[0];
}
}
if (hasLocateTargetSchema(target)) return null;
const relaxedPaths = collectSidebarNodePathsForLocateByObject(nodes, target, { allowUnqualifiedSchemaMatch: true });