From 4a997fe63fcfcfe0173a981823fe9f8de825d714 Mon Sep 17 00:00:00 2001 From: U1 <56990620+CHNHJF@users.noreply.github.com> Date: Tue, 15 Sep 2026 14:29:34 +0800 Subject: [PATCH] feat(sidebar): match table comments in local table search --- .../src/lib/sidebar/sidebarSearchTree.ts | 9 ++- .../sidebarLocalTableSearchComment.test.ts | 60 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 packages/app-tests/sidebarLocalTableSearchComment.test.ts diff --git a/apps/desktop/src/lib/sidebar/sidebarSearchTree.ts b/apps/desktop/src/lib/sidebar/sidebarSearchTree.ts index b3aa2a331e..9660bef72c 100644 --- a/apps/desktop/src/lib/sidebar/sidebarSearchTree.ts +++ b/apps/desktop/src/lib/sidebar/sidebarSearchTree.ts @@ -84,15 +84,18 @@ export function filterLocallySearchedTables(nodes: TreeNode[], options: { enable const indexed = options.indexedResults[node.id]; // matchSidebarLabel compares case-insensitively internally and needs the // ORIGINAL label (and entry name) so camelCase boundaries stay detectable. + // Table comments participate in matching, mirroring the global sidebar + // search and the backend's name-or-comment metadata filter. + const entryMatches = (name: string, comment?: string | null) => !!matchSidebarLabel(name, query) || (!!comment && !!matchSidebarLabel(comment, query)); const matchingChildren = indexed === null - ? children.filter((child) => localTableSearchChildTypes.has(child.type) && !!matchSidebarLabel(child.label, query)) + ? children.filter((child) => localTableSearchChildTypes.has(child.type) && entryMatches(child.label, child.comment)) : indexed ? reuseLiveSidebarTreeNodes( - buildSidebarIndexedTableNodes({ parentNodeId: node.id, nodeType: node.type, connectionId: node.connectionId || "", database: node.database || "", schema: node.schema, catalog: node.catalog, entries: indexed.filter((entry) => !!matchSidebarLabel(entry.name, query)) }), + buildSidebarIndexedTableNodes({ parentNodeId: node.id, nodeType: node.type, connectionId: node.connectionId || "", database: node.database || "", schema: node.schema, catalog: node.catalog, entries: indexed.filter((entry) => entryMatches(entry.name, entry.comment)) }), children, ) - : children.filter((child) => localTableSearchChildTypes.has(child.type) && !!matchSidebarLabel(child.label, query)); + : children.filter((child) => localTableSearchChildTypes.has(child.type) && entryMatches(child.label, child.comment)); return { ...node, children: matchingChildren }; }); } diff --git a/packages/app-tests/sidebarLocalTableSearchComment.test.ts b/packages/app-tests/sidebarLocalTableSearchComment.test.ts new file mode 100644 index 0000000000..5c1a854e2f --- /dev/null +++ b/packages/app-tests/sidebarLocalTableSearchComment.test.ts @@ -0,0 +1,60 @@ +// Regression test for t8y2/dbx #9094. +// +// Local-mode sidebar table search only matched table names, even though the +// persisted search index, the global sidebar search, and the backend's +// metadata filter all treat the table comment as searchable text. A user +// searching "订单" against a database whose tables are all pinyin/English +// names with Chinese comments found nothing. filterLocallySearchedTables must +// match name OR comment across all three branches: the indexed branch, the +// indexed === null fallback (index not built yet), and the no-index branch. +import { describe, expect, it } from "vitest"; +import { filterLocallySearchedTables } from "../../apps/desktop/src/lib/sidebar/sidebarSearchTree.ts"; +import type { TableInfo, TreeNode } from "@/types/database"; + +const tables: TableInfo[] = [ + { name: "t_order", table_type: "TABLE", comment: "订单主表" }, + { name: "t_customer", table_type: "TABLE", comment: null }, +]; + +function schemaNode(children: TreeNode[]): TreeNode { + return { id: "conn:db", label: "db", type: "schema", connectionId: "conn", database: "db", children }; +} + +function liveChildren(): TreeNode[] { + return tables.map((table) => ({ + id: `conn:db:${table.name}`, + label: table.name, + type: "table" as const, + connectionId: "conn", + database: "db", + comment: table.comment ?? undefined, + })); +} + +function project(nodes: TreeNode[], indexed: Record) { + return filterLocallySearchedTables(nodes, { enabled: true, queries: { "conn:db": "订单" }, indexedResults: indexed })[0].children!; +} + +describe("sidebar local table search matches table comments (#9094)", () => { + it("matches by comment on the indexed branch", () => { + const children = project([schemaNode(liveChildren())], { "conn:db": tables }); + expect(children.map((node) => node.label)).toEqual(["t_order"]); + }); + + it("matches by comment on the indexed === null fallback branch", () => { + const children = project([schemaNode(liveChildren())], { "conn:db": null }); + expect(children.map((node) => node.label)).toEqual(["t_order"]); + }); + + it("matches by comment on the no-index branch", () => { + const children = project([schemaNode(liveChildren())], {}); + expect(children.map((node) => node.label)).toEqual(["t_order"]); + }); + + it("still matches by name and keeps name-only tables for name queries", () => { + for (const indexed of [{ "conn:db": tables }, { "conn:db": null }, {}]) { + const children = filterLocallySearchedTables([schemaNode(liveChildren())], { enabled: true, queries: { "conn:db": "customer" }, indexedResults: indexed })[0].children!; + expect(children.map((node) => node.label)).toEqual(["t_customer"]); + } + }); +});