From 0fc5a03822305f1fc7489580fe5bbd395b766f35 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Wed, 3 Jun 2026 02:48:09 +0800 Subject: [PATCH] fix(sidebar): merge table metadata into object groups --- apps/desktop/src/lib/tableTree.ts | 37 ++++++++++++++++++++++ apps/desktop/src/stores/connectionStore.ts | 14 ++++++-- packages/app-tests/tableTree.test.ts | 31 +++++++++++++++++- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/lib/tableTree.ts b/apps/desktop/src/lib/tableTree.ts index 531f0ab82..acf0baa12 100644 --- a/apps/desktop/src/lib/tableTree.ts +++ b/apps/desktop/src/lib/tableTree.ts @@ -212,6 +212,43 @@ export function sortDatabaseObjectsByName(items: readonly T[], getName: (item return [...items].sort((left, right) => databaseObjectNameCollator.compare(getName(left), getName(right))); } +export function mergeTableInfosIntoObjects( + objects: readonly ObjectInfo[], + tables: readonly TableInfo[], + schema?: string, +): ObjectInfo[] { + const merged = [...objects]; + const seen = new Set( + merged.map((obj) => { + const name = normalizeDatabaseObjectName(obj.name); + const objectSchema = obj.schema ? normalizeDatabaseObjectName(obj.schema) : schema || ""; + return `${normalizeObjectType(obj.object_type)}\0${objectSchema.toLowerCase()}\0${name.toLowerCase()}`; + }), + ); + + for (const table of tables) { + const objectType = normalizeObjectType(table.table_type); + if (objectType !== "TABLE" && objectType !== "VIEW") continue; + const name = normalizeDatabaseObjectName(table.name); + if (!name) continue; + const key = `${objectType}\0${(schema || "").toLowerCase()}\0${name.toLowerCase()}`; + if (seen.has(key)) continue; + seen.add(key); + merged.push({ + name, + object_type: objectType, + schema, + comment: table.comment, + created_at: undefined, + updated_at: undefined, + parent_schema: table.parent_schema, + parent_name: table.parent_name, + }); + } + + return merged; +} + function buildPartitionTree(entries: TableTreeEntry[], connectionId: string, database: string): TreeNode[] { const orderedEntries = sortDatabaseObjectsByName(entries, (entry) => entry.node.label); const byKey = new Map(); diff --git a/apps/desktop/src/stores/connectionStore.ts b/apps/desktop/src/stores/connectionStore.ts index 8434bc0bb..a9cba9774 100644 --- a/apps/desktop/src/stores/connectionStore.ts +++ b/apps/desktop/src/stores/connectionStore.ts @@ -35,6 +35,7 @@ import { buildGroupedObjectTreeNodes, buildTableTreeNodes, expandCachedObjectBrowserNodes, + mergeTableInfosIntoObjects, objectGroupRefreshParentId, tablePartitionGroups, } from "@/lib/tableTree"; @@ -1060,8 +1061,17 @@ export const useConnectionStore = defineStore("connection", () => { children = buildTableTreeNodes({ nodeId, connectionId, database, schema: effectiveSchema, tables }); } else { try { - const objects = await api.listObjects(connectionId, database, querySchema); - children = buildGroupedObjectTreeNodes({ nodeId, connectionId, database, schema: effectiveSchema, objects }); + const [objects, tables] = await Promise.all([ + api.listObjects(connectionId, database, querySchema), + api.listTables(connectionId, database, querySchema), + ]); + children = buildGroupedObjectTreeNodes({ + nodeId, + connectionId, + database, + schema: effectiveSchema, + objects: mergeTableInfosIntoObjects(objects, tables, effectiveSchema), + }); } catch { const tables = await api.listTables(connectionId, database, querySchema); children = buildTableTreeNodes({ nodeId, connectionId, database, schema: effectiveSchema, tables }); diff --git a/packages/app-tests/tableTree.test.ts b/packages/app-tests/tableTree.test.ts index 994cf4fdc..3c148040a 100644 --- a/packages/app-tests/tableTree.test.ts +++ b/packages/app-tests/tableTree.test.ts @@ -1,6 +1,10 @@ import test from "node:test"; import assert from "node:assert/strict"; -import { buildGroupedObjectTreeNodes, buildTableTreeNodes } from "../../apps/desktop/src/lib/tableTree.ts"; +import { + buildGroupedObjectTreeNodes, + buildTableTreeNodes, + mergeTableInfosIntoObjects, +} from "../../apps/desktop/src/lib/tableTree.ts"; import type { ObjectInfo, TableInfo, TreeNode } from "../../apps/desktop/src/types/database.ts"; function table(name: string, parent?: string): TableInfo { @@ -164,3 +168,28 @@ test("buildGroupedObjectTreeNodes groups Oracle packages and package bodies", () ], ); }); + +test("mergeTableInfosIntoObjects restores views missing from object metadata", () => { + const merged = mergeTableInfosIntoObjects( + [object("orders")], + [ + table("orders"), + { + name: "active_orders", + table_type: "VIEW", + comment: "current orders", + parent_schema: null, + parent_name: null, + }, + ], + "public", + ); + + assert.deepEqual( + merged.map((item) => ({ name: item.name, type: item.object_type, schema: item.schema, comment: item.comment })), + [ + { name: "orders", type: "TABLE", schema: "public", comment: null }, + { name: "active_orders", type: "VIEW", schema: "public", comment: "current orders" }, + ], + ); +});