feat(xugu): expose public synonyms in an isolated scope

This commit is contained in:
Elias authored and GitHub committed 2026-08-12 18:24:01 +08:00
1 parent ab46f3fc72
commit ea9a27ce11
11 files changed
+678 -39

No files matched your search

@@ -1,6 +1,7 @@
import { createPinia, setActivePinia } from "pinia";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { ConnectionConfig, TreeNode } from "@/types/database";
import { XUGU_PUBLIC_SYNONYM_SCOPE } from "@/lib/sidebar/xuguPublicSynonyms";
function installLocalStorage() {
const data = new Map<string, string>();
@@ -24,6 +25,18 @@ function postgresConnection(): ConnectionConfig {
};
}
function xuguConnection(): ConnectionConfig {
return {
...postgresConnection(),
id: "xugu-1",
name: "Xugu",
db_type: "xugu",
port: 5138,
username: "SYSDBA",
database: "SYSTEM",
};
}
describe("connectionStore default schema", () => {
beforeEach(() => {
vi.resetModules();
@@ -86,4 +99,26 @@ describe("connectionStore default schema", () => {
expect(schemaLabels()).toEqual(["archive", "public"]);
expect(saveConnections).toHaveBeenLastCalledWith([expect.objectContaining({ id: connection.id, default_schema: undefined })]);
});
it("does not persist the synthetic Xugu public-synonym scope as a default schema", async () => {
const saveConnections = vi.fn().mockResolvedValue(undefined);
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
vi.doMock("@/lib/backend/api", () => ({
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
loadSchemaCache: vi.fn().mockResolvedValue(null),
saveConnections,
saveSchemaCache: vi.fn().mockResolvedValue(undefined),
saveSidebarLayout: vi.fn().mockResolvedValue(undefined),
}));
const { useConnectionStore } = await import("@/stores/connectionStore");
const store = useConnectionStore();
const connection = xuguConnection();
store.addEphemeralConnection(connection);
await store.setDefaultSchema(connection.id, XUGU_PUBLIC_SYNONYM_SCOPE);
expect(store.getConfig(connection.id)?.default_schema).toBeUndefined();
expect(saveConnections).not.toHaveBeenCalled();
});
});
+10 -3
View File
@@ -113,6 +113,7 @@ import { appendAgentDriverUpdateHint, hasAgentDriverUpdate, hasInstalledAgentVer
import { appendConnectionErrorHints } from "@/lib/connection/connectionErrorHints";
import { appendVisibleDatabaseSelection } from "@/lib/connection/connectionVisibleDatabases";
import { buildXuguTypeMemberNodes, isXuguTypeMemberContainer } from "@/lib/sidebar/xuguTypeMembers";
import { isXuguPublicSynonymScope, xuguSchemaDisplayName, XUGU_PUBLIC_SYNONYM_SCOPE } from "@/lib/sidebar/xuguPublicSynonyms";
import { filterNacosNamespacesForSidebar, normalizeNacosNamespacesForDisplay } from "@/lib/nacos/nacosNamespaceVisibility";
import { buildPackageMemberNodes, markPackageNodesExpandable } from "@/lib/sidebar/packageMembers";
import { configuredDatabaseProductName, connectionConfigFingerprint, normalizeDatabaseConnectionInfo } from "@/lib/connection/connectionDatabaseInfo";
@@ -2623,7 +2624,7 @@ export const useConnectionStore = defineStore("connection", () => {
async function setDefaultSchema(connectionId: string, schema: string) {
const config = getConfig(connectionId);
const defaultSchema = schema.trim();
if (!config || !defaultSchema || config.default_schema === defaultSchema) return;
if (!config || !defaultSchema || config.default_schema === defaultSchema || (config.db_type === "xugu" && isXuguPublicSynonymScope(defaultSchema))) return;
await updateConnection({
...config,
default_schema: defaultSchema,
@@ -3947,7 +3948,7 @@ export const useConnectionStore = defineStore("connection", () => {
if (useCachedChildren(node, options, load)) return;
const config = getConfig(connectionId);
const showSystemSchemas = config?.show_system_schemas === true;
const cacheVersion = ownerAwareMetadataCacheVersion(config, "schemas-v3");
const cacheVersion = ownerAwareMetadataCacheVersion(config, config?.db_type === "xugu" ? "schemas-v4" : "schemas-v3");
const cacheKey = schemaCacheKey(connectionId, database, cacheVersion, showSystemSchemas ? "show-system" : "hide-system");
if (!options?.force) {
const cached = await loadPersistedTreeChildren(node, cacheKey, load);
@@ -3966,13 +3967,19 @@ export const useConnectionStore = defineStore("connection", () => {
{ showSystemSchemas },
),
);
// The public-synonym scope is a protocol namespace, not a user
// schema. Keep it discoverable even when a visible-schema filter is
// configured, while preserving the raw key for object routing.
if (config?.db_type === "xugu" && schemas.some((schema) => isXuguPublicSynonymScope(schema.name))) {
visibleSchemaNames.add(XUGU_PUBLIC_SYNONYM_SCOPE);
}
const children: TreeNode[] = schemas
.filter((schema) => visibleSchemaNames.has(schema.name))
.map((schema) => {
const s = schema.name;
return {
id: `${connectionId}:${database}:${s}`,
label: s,
label: config?.db_type === "xugu" ? xuguSchemaDisplayName(s) : s,
type: "schema" as const,
connectionId,
database,