feat(sqlserver): support linked server browsing
This commit is contained in:
1 parent
fc8ae4b69f
commit
9e75f62dbf
20 files changed
+617
-32
No files matched your search
@@ -102,6 +102,10 @@ export const syncSavedSqlDirectory = forward("syncSavedSqlDirectory");
|
||||
|
||||
// Schema
|
||||
export const listDatabases = forward("listDatabases");
|
||||
export const listSqlServerLinkedServers = forward("listSqlServerLinkedServers");
|
||||
export const listSqlServerLinkedServerCatalogs = forward("listSqlServerLinkedServerCatalogs");
|
||||
export const listSqlServerLinkedServerSchemas = forward("listSqlServerLinkedServerSchemas");
|
||||
export const listSqlServerLinkedServerTables = forward("listSqlServerLinkedServerTables");
|
||||
export const saveSchemaCache = forward("saveSchemaCache");
|
||||
export const loadSchemaCache = forward("loadSchemaCache");
|
||||
export const deleteSchemaCachePrefix = forward("deleteSchemaCachePrefix");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type {
|
||||
ConnectionConfig,
|
||||
DatabaseInfo,
|
||||
LinkedServerInfo,
|
||||
TableInfo,
|
||||
ObjectInfo,
|
||||
ObjectSource,
|
||||
@@ -392,6 +393,22 @@ export async function listDatabases(connectionId: string): Promise<DatabaseInfo[
|
||||
return get(`/api/schema/databases?${qs({ connection_id: connectionId })}`);
|
||||
}
|
||||
|
||||
export async function listSqlServerLinkedServers(connectionId: string): Promise<LinkedServerInfo[]> {
|
||||
return get(`/api/schema/sqlserver/linked-servers?${qs({ connection_id: connectionId })}`);
|
||||
}
|
||||
|
||||
export async function listSqlServerLinkedServerCatalogs(connectionId: string, server: string): Promise<DatabaseInfo[]> {
|
||||
return get(`/api/schema/sqlserver/linked-server-catalogs?${qs({ connection_id: connectionId, server })}`);
|
||||
}
|
||||
|
||||
export async function listSqlServerLinkedServerSchemas(connectionId: string, server: string, catalog: string): Promise<string[]> {
|
||||
return get(`/api/schema/sqlserver/linked-server-schemas?${qs({ connection_id: connectionId, server, catalog })}`);
|
||||
}
|
||||
|
||||
export async function listSqlServerLinkedServerTables(connectionId: string, server: string, catalog: string, schema: string, filter?: string, limit?: number, offset?: number): Promise<TableInfo[]> {
|
||||
return get(`/api/schema/sqlserver/linked-server-tables?${qs({ connection_id: connectionId, server, catalog, schema, filter, limit, offset })}`);
|
||||
}
|
||||
|
||||
export async function saveSchemaCache(cacheKey: string, payload: unknown): Promise<void> {
|
||||
return post("/api/schema/cache", { cacheKey, payload });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import type { TreeNode } from "@/types/database";
|
||||
|
||||
const SQLSERVER_LINKED_SCHEMA_PREFIX = "__dbx_sqlserver_linked__:";
|
||||
|
||||
export interface SqlServerLinkedSchemaRef {
|
||||
server: string;
|
||||
catalog: string;
|
||||
schema: string;
|
||||
}
|
||||
|
||||
export function encodeSqlServerLinkedSchema(ref: SqlServerLinkedSchemaRef): string {
|
||||
return `${SQLSERVER_LINKED_SCHEMA_PREFIX}${[ref.server, ref.catalog, ref.schema].map(encodeURIComponent).join("|")}`;
|
||||
}
|
||||
|
||||
export function parseSqlServerLinkedSchema(schema: string | undefined): SqlServerLinkedSchemaRef | null {
|
||||
if (!schema?.startsWith(SQLSERVER_LINKED_SCHEMA_PREFIX)) return null;
|
||||
const parts = schema.slice(SQLSERVER_LINKED_SCHEMA_PREFIX.length).split("|").map(decodeURIComponent);
|
||||
if (parts.length !== 3 || parts.some((part) => !part.trim())) return null;
|
||||
return { server: parts[0], catalog: parts[1], schema: parts[2] };
|
||||
}
|
||||
|
||||
export function isSqlServerLinkedNode(node: Pick<TreeNode, "linkedServer" | "linkedCatalog" | "linkedSchema" | "schema">): boolean {
|
||||
return !!node.linkedServer || !!node.linkedCatalog || !!node.linkedSchema || !!parseSqlServerLinkedSchema(node.schema);
|
||||
}
|
||||
|
||||
export function sqlServerLinkedTableSchema(node: Pick<TreeNode, "linkedServer" | "linkedCatalog" | "linkedSchema">): string | undefined {
|
||||
if (!node.linkedServer || !node.linkedCatalog || !node.linkedSchema) return undefined;
|
||||
return encodeSqlServerLinkedSchema({
|
||||
server: node.linkedServer,
|
||||
catalog: node.linkedCatalog,
|
||||
schema: node.linkedSchema,
|
||||
});
|
||||
}
|
||||
|
||||
export function quoteSqlServerIdentifier(name: string): string {
|
||||
return `[${name.replace(/\]/g, "]]")}]`;
|
||||
}
|
||||
|
||||
export function sqlServerLinkedTableName(ref: SqlServerLinkedSchemaRef, tableName: string): string {
|
||||
return [ref.server, ref.catalog, ref.schema, tableName].map(quoteSqlServerIdentifier).join(".");
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { DatabaseType } from "../types/database.ts";
|
||||
import { isSchemaAware, usesDatabaseObjectTreeMode } from "./databaseCapabilities.ts";
|
||||
import * as api from "./api.ts";
|
||||
import { parseSqlServerLinkedSchema, sqlServerLinkedTableName } from "./sqlServerLinkedServers.ts";
|
||||
|
||||
export interface BuildTableSelectSqlOptions {
|
||||
databaseType?: DatabaseType;
|
||||
@@ -42,6 +43,10 @@ export function qualifiedTableName(options: Pick<BuildTableSelectSqlOptions, "da
|
||||
return quoteTableIdentifier(databaseType, tableName);
|
||||
}
|
||||
if (isSchemaAware(databaseType) && !usesDatabaseObjectTreeMode(databaseType) && schema) {
|
||||
if (databaseType === "sqlserver") {
|
||||
const linked = parseSqlServerLinkedSchema(schema);
|
||||
if (linked) return sqlServerLinkedTableName(linked, tableName);
|
||||
}
|
||||
return `${quoteTableIdentifier(databaseType, schema)}.${quoteTableIdentifier(databaseType, tableName)}`;
|
||||
}
|
||||
return quoteTableIdentifier(databaseType, tableName);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { listen, type UnlistenFn } from "@tauri-apps/api/event";
|
||||
import type {
|
||||
ConnectionConfig,
|
||||
DatabaseInfo,
|
||||
LinkedServerInfo,
|
||||
TableInfo,
|
||||
ObjectInfo,
|
||||
ObjectSource,
|
||||
@@ -474,6 +475,22 @@ export async function listDatabases(connectionId: string): Promise<DatabaseInfo[
|
||||
return invoke("list_databases", { connectionId });
|
||||
}
|
||||
|
||||
export async function listSqlServerLinkedServers(connectionId: string): Promise<LinkedServerInfo[]> {
|
||||
return invoke("list_sqlserver_linked_servers", { connectionId });
|
||||
}
|
||||
|
||||
export async function listSqlServerLinkedServerCatalogs(connectionId: string, server: string): Promise<DatabaseInfo[]> {
|
||||
return invoke("list_sqlserver_linked_server_catalogs", { connectionId, server });
|
||||
}
|
||||
|
||||
export async function listSqlServerLinkedServerSchemas(connectionId: string, server: string, catalog: string): Promise<string[]> {
|
||||
return invoke("list_sqlserver_linked_server_schemas", { connectionId, server, catalog });
|
||||
}
|
||||
|
||||
export async function listSqlServerLinkedServerTables(connectionId: string, server: string, catalog: string, schema: string, filter?: string, limit?: number, offset?: number): Promise<TableInfo[]> {
|
||||
return invoke("list_sqlserver_linked_server_tables", { connectionId, server, catalog, schema, filter, limit, offset });
|
||||
}
|
||||
|
||||
export async function saveSchemaCache(cacheKey: string, payload: unknown): Promise<void> {
|
||||
return invoke("save_schema_cache", { cacheKey, payload });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user