feat(sidebar): show table metadata group counts
This commit is contained in:
1 parent
c834421c49
commit
72faf4887b
4 files changed
+191
-11
No files matched your search
@@ -149,6 +149,68 @@ describe("connectionStore Xugu table child metadata", () => {
|
||||
expect(subpartitions.isExpanded).toBe(true);
|
||||
});
|
||||
|
||||
it("records exact counts for every successfully loaded table metadata group", async () => {
|
||||
const getColumns = vi.fn().mockResolvedValue([
|
||||
{ name: "ORDER_ID", data_type: "INT", is_nullable: false, column_default: null, is_primary_key: true, extra: null },
|
||||
{ name: "CUSTOMER_ID", data_type: "INT", is_nullable: false, column_default: null, is_primary_key: false, extra: null },
|
||||
]);
|
||||
const listIndexes = vi.fn().mockResolvedValue([{ name: "IDX_CUSTOMER", columns: ["CUSTOMER_ID"], unique: false }]);
|
||||
const listForeignKeys = vi.fn().mockResolvedValue([{ name: "FK_CUSTOMER", column: "CUSTOMER_ID", ref_table: "CUSTOMERS", ref_column: "ID" }]);
|
||||
const listTriggers = vi.fn().mockResolvedValue([{ name: "TR_AUDIT", timing: "BEFORE", event: "INSERT" }]);
|
||||
const listConstraints = vi.fn().mockResolvedValue([{ name: "PK_SHOP_ORDERS", constraint_type: "PRIMARY KEY", valid: true }]);
|
||||
const listPartitions = vi.fn().mockResolvedValue([]);
|
||||
const listSubpartitions = vi.fn().mockResolvedValue([]);
|
||||
const { store, tableId } = await setup("xugu", {
|
||||
getColumns,
|
||||
listIndexes,
|
||||
listForeignKeys,
|
||||
listTriggers,
|
||||
listConstraints,
|
||||
listPartitions,
|
||||
listSubpartitions,
|
||||
});
|
||||
|
||||
expect(getColumns).not.toHaveBeenCalled();
|
||||
expect(listIndexes).not.toHaveBeenCalled();
|
||||
expect(listForeignKeys).not.toHaveBeenCalled();
|
||||
expect(listTriggers).not.toHaveBeenCalled();
|
||||
expect(listConstraints).not.toHaveBeenCalled();
|
||||
expect(listPartitions).not.toHaveBeenCalled();
|
||||
expect(listSubpartitions).not.toHaveBeenCalled();
|
||||
|
||||
const groupTypes = ["group-columns", "group-indexes", "group-fkeys", "group-triggers", "group-constraints", "group-table-partitions", "group-table-subpartitions"] as const;
|
||||
for (const groupType of groupTypes) {
|
||||
const group = findNode(store.treeNodes, tableId)?.children?.find((node) => node.type === groupType);
|
||||
if (!group) throw new Error(`Missing ${groupType}`);
|
||||
await store.loadTreeNodeChildren(group);
|
||||
}
|
||||
|
||||
expect(findNode(store.treeNodes, tableId)?.children?.map((node) => [node.type, node.objectCount])).toEqual([
|
||||
["group-columns", 2],
|
||||
["group-constraints", 1],
|
||||
["group-fkeys", 1],
|
||||
["group-triggers", 1],
|
||||
["group-indexes", 1],
|
||||
["group-table-partitions", 0],
|
||||
["group-table-subpartitions", 0],
|
||||
]);
|
||||
});
|
||||
|
||||
it("counts the normalized foreign key nodes for a composite foreign key", async () => {
|
||||
const listForeignKeys = vi.fn().mockResolvedValue([
|
||||
{ name: "FK_ORDER_CUSTOMER", column: "CUSTOMER_TENANT_ID", ref_table: "CUSTOMERS", ref_column: "TENANT_ID" },
|
||||
{ name: "FK_ORDER_CUSTOMER", column: "CUSTOMER_ID", ref_table: "CUSTOMERS", ref_column: "ID" },
|
||||
]);
|
||||
const { config, store, tableId } = await setup("mysql", { listForeignKeys });
|
||||
const foreignKeys = findNode(store.treeNodes, `${tableId}:__fkeys`)!;
|
||||
|
||||
await store.loadTreeNodeChildren(foreignKeys);
|
||||
|
||||
expect(listForeignKeys).toHaveBeenCalledWith(config.id, "SHOP_DEMO", "SYSDBA", "SHOP_ORDERS", undefined);
|
||||
expect(foreignKeys.children).toHaveLength(1);
|
||||
expect(foreignKeys.objectCount).toBe(1);
|
||||
});
|
||||
|
||||
it("keeps a rejected Xugu metadata group collapsed and clears its loading state", async () => {
|
||||
const listPartitions = vi.fn().mockRejectedValue(new Error("metadata denied"));
|
||||
const { store, tableId } = await setup("xugu", { listPartitions });
|
||||
@@ -159,6 +221,7 @@ describe("connectionStore Xugu table child metadata", () => {
|
||||
expect(partitions.isLoading).toBe(false);
|
||||
expect(partitions.isExpanded).toBe(false);
|
||||
expect(partitions.children).toEqual([]);
|
||||
expect(partitions.objectCount).toBeUndefined();
|
||||
});
|
||||
|
||||
it("shows Xugu trigger level and status without changing other database labels", async () => {
|
||||
|
||||
@@ -1683,6 +1683,11 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
syncConfirmedEmptyTreeNodeId(parent);
|
||||
}
|
||||
|
||||
function setLoadedTableMetadataChildren(parent: TreeNode, children: TreeNode[]) {
|
||||
setChildren(parent, children);
|
||||
parent.objectCount = parent.children!.length;
|
||||
}
|
||||
|
||||
function removePinnedTreeNodes(nodes: readonly TreeNode[], canonicalize: PinnedTreeNodeIdentityCanonicalizer = (identity) => identity, legacyKeys: readonly string[] = []): boolean {
|
||||
const nextPinnedOrder = removePinnedTreeNodesFromOrder(pinnedTreeNodeOrder.value, nodes, canonicalize, legacyKeys);
|
||||
if (nextPinnedOrder.length === pinnedTreeNodeOrder.value.length && nextPinnedOrder.every((key, index) => key === pinnedTreeNodeOrder.value[index])) return false;
|
||||
@@ -6405,7 +6410,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const fields = await listMongoCompletionFields(connectionId, database, table);
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(
|
||||
setLoadedTableMetadataChildren(
|
||||
targetNode,
|
||||
fields.map((field) => {
|
||||
const column = {
|
||||
@@ -6436,7 +6441,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
if (!targetNode) return;
|
||||
const connConfig = getConfig(connectionId);
|
||||
const isGaussdbM = effectiveDatabaseTypeForConnection(connConfig) === "gaussdb" && connConfig?.driver_profile?.toLowerCase() === "gaussdb-m";
|
||||
setChildren(
|
||||
setLoadedTableMetadataChildren(
|
||||
targetNode,
|
||||
columns.map((col) => ({
|
||||
id: `${parentId}:${col.name}`,
|
||||
@@ -6471,7 +6476,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
if (!metadataCapabilities.indexes || isMongoView) {
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(targetNode, []);
|
||||
setLoadedTableMetadataChildren(targetNode, []);
|
||||
targetNode.isExpanded = true;
|
||||
return;
|
||||
}
|
||||
@@ -6480,7 +6485,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
const mongoCollectionKind = effectiveDbType === "mongodb" && targetNode.type === "group-indexes" ? mongoCollectionKindFromNode(targetNode) : undefined;
|
||||
setChildren(
|
||||
setLoadedTableMetadataChildren(
|
||||
targetNode,
|
||||
indexes.map((idx) => ({
|
||||
id: `${parentId}:${idx.name}`,
|
||||
@@ -6513,7 +6518,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
if (!metadataCapabilities.foreignKeys) {
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(targetNode, []);
|
||||
setLoadedTableMetadataChildren(targetNode, []);
|
||||
targetNode.isExpanded = true;
|
||||
return;
|
||||
}
|
||||
@@ -6525,7 +6530,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
indexCompletionForeignKeys(connectionId, database, table, schema, sqlCompletionForeignKeys(fkeys));
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(
|
||||
setLoadedTableMetadataChildren(
|
||||
targetNode,
|
||||
fkeys.map((fk) => ({
|
||||
id: `${parentId}:${fk.name}`,
|
||||
@@ -6558,7 +6563,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
if (!metadataCapabilities.triggers) {
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(targetNode, []);
|
||||
setLoadedTableMetadataChildren(targetNode, []);
|
||||
targetNode.isExpanded = true;
|
||||
return;
|
||||
}
|
||||
@@ -6567,7 +6572,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
const isXugu = effectiveDatabaseTypeForConnection(getConfig(connectionId)) === "xugu";
|
||||
setChildren(
|
||||
setLoadedTableMetadataChildren(
|
||||
targetNode,
|
||||
triggers.map((tr) => {
|
||||
const xuguDetails = isXugu ? [tr.timing, tr.event, tr.level, tr.enabled === false ? i18n.global.t("objects.disabled") : null, tr.valid === false ? i18n.global.t("objects.invalid") : null].filter(Boolean).join(" · ") : `${tr.timing} ${tr.event}`;
|
||||
@@ -6604,7 +6609,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const constraints = await api.listConstraints(connectionId, database, metadataQuerySchema(connectionId, database, schema), table, catalog);
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(
|
||||
setLoadedTableMetadataChildren(
|
||||
targetNode,
|
||||
constraints.map((constraint) => ({
|
||||
id: `${parentId}:${constraint.name}`,
|
||||
@@ -6635,7 +6640,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const partitions = await api.listPartitions(connectionId, database, metadataQuerySchema(connectionId, database, schema), table, catalog);
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(
|
||||
setLoadedTableMetadataChildren(
|
||||
targetNode,
|
||||
partitions.map((partition) => ({
|
||||
id: `${parentId}:${partition.name}`,
|
||||
@@ -6666,7 +6671,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const partitions = await api.listSubpartitions(connectionId, database, metadataQuerySchema(connectionId, database, schema), table, catalog);
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(
|
||||
setLoadedTableMetadataChildren(
|
||||
targetNode,
|
||||
partitions.map((partition) => ({
|
||||
id: `${parentId}:${partition.name}`,
|
||||
|
||||
Reference in new issue
Block a user