fix(sidebar): merge table metadata into object groups

This commit is contained in:
t8y2 2026-06-03 02:48:09 +08:00
parent c6da454864
commit 0fc5a03822
3 changed files with 79 additions and 3 deletions

View File

@ -212,6 +212,43 @@ export function sortDatabaseObjectsByName<T>(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<string, TableTreeEntry>();

View File

@ -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 });

View File

@ -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" },
],
);
});