98 lines
3.1 KiB
TypeScript
98 lines
3.1 KiB
TypeScript
import type { ConnectionConfig, DatabaseInfo, TreeNode } from "@/types/database";
|
|
import { DEFAULT_DATABASE_TREE_LABEL } from "@/lib/sidebar/treeNodeContext";
|
|
|
|
const sidebarNameCollator = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" });
|
|
|
|
export function shouldIncludeDefaultDatabaseNode(connection: Pick<ConnectionConfig, "db_type"> | undefined, databases: DatabaseInfo[]): boolean {
|
|
return connection?.db_type === "mysql" && databases.some((database) => !database.name.trim());
|
|
}
|
|
|
|
export function compareSidebarNames(left: string, right: string): number {
|
|
return sidebarNameCollator.compare(left, right);
|
|
}
|
|
|
|
export function sortSidebarNames(names: readonly string[]): string[] {
|
|
return [...names].sort(compareSidebarNames);
|
|
}
|
|
|
|
export function sortSidebarDatabases(databases: readonly DatabaseInfo[]): DatabaseInfo[] {
|
|
return [...databases].sort((left, right) => sidebarNameCollator.compare(left.name, right.name));
|
|
}
|
|
|
|
export function buildDatabaseTreeNodes(
|
|
connectionId: string,
|
|
databases: DatabaseInfo[],
|
|
// `displayLabel` only rewrites the visible text. `id` and `database` keep the
|
|
// backend-reported name because that value round-trips to the agent — Cloud
|
|
// Spanner reports the full `projects/../instances/../databases/..` resource
|
|
// path and would break URL building if the shortened label were sent back.
|
|
options: { includeDefaultWhenEmpty?: boolean; displayLabel?: (name: string) => string } = {},
|
|
): TreeNode[] {
|
|
const nodes = sortSidebarDatabases(databases).flatMap((db) => {
|
|
const name = db.name;
|
|
if (!name.trim()) return [];
|
|
return [
|
|
{
|
|
id: `${connectionId}:${name}`,
|
|
label: options.displayLabel?.(name) || name,
|
|
type: "database" as const,
|
|
connectionId,
|
|
database: name,
|
|
isExpanded: false,
|
|
children: [],
|
|
},
|
|
];
|
|
});
|
|
|
|
if (nodes.length > 0 || !options.includeDefaultWhenEmpty) return nodes;
|
|
|
|
return [
|
|
{
|
|
id: `${connectionId}:`,
|
|
label: DEFAULT_DATABASE_TREE_LABEL,
|
|
type: "database" as const,
|
|
connectionId,
|
|
database: "",
|
|
isExpanded: false,
|
|
children: [],
|
|
},
|
|
];
|
|
}
|
|
|
|
export function buildDuckDbConnectionTreeNodes(connectionId: string, databases: DatabaseInfo[], primarySchemas: string[]): TreeNode[] {
|
|
const schemaNodes = sortSidebarNames(primarySchemas).flatMap((schema) => {
|
|
const name = schema.trim();
|
|
if (!name) return [];
|
|
return [
|
|
{
|
|
id: `${connectionId}:main:${name}`,
|
|
label: name,
|
|
type: "schema" as const,
|
|
connectionId,
|
|
database: "main",
|
|
schema: name,
|
|
isExpanded: false,
|
|
children: [],
|
|
},
|
|
];
|
|
});
|
|
|
|
const attachedCatalogNodes = sortSidebarDatabases(databases).flatMap((db) => {
|
|
const name = db.name;
|
|
if (!name.trim() || name === "main") return [];
|
|
return [
|
|
{
|
|
id: `${connectionId}:${name}`,
|
|
label: name,
|
|
type: "database" as const,
|
|
connectionId,
|
|
database: name,
|
|
isExpanded: false,
|
|
children: [],
|
|
},
|
|
];
|
|
});
|
|
|
|
return [...schemaNodes, ...attachedCatalogNodes];
|
|
}
|