mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 05:20:02 +00:00
feat(schema): 增加数据库对象列表缓存
This commit is contained in:
@@ -53,6 +53,11 @@ const SCHEMA_STATEMENTS: &[&str] = &[
|
||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||
settings_json TEXT NOT NULL
|
||||
)",
|
||||
"CREATE TABLE IF NOT EXISTS schema_cache (
|
||||
cache_key TEXT PRIMARY KEY,
|
||||
payload_json TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
)",
|
||||
];
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -444,6 +449,49 @@ impl Storage {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Schema cache
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
impl Storage {
|
||||
pub async fn save_schema_cache(&self, cache_key: &str, payload: &serde_json::Value) -> Result<(), String> {
|
||||
let json = serde_json::to_string(payload).map_err(|e| e.to_string())?;
|
||||
sqlx::query(
|
||||
"INSERT OR REPLACE INTO schema_cache (cache_key, payload_json, updated_at) \
|
||||
VALUES (?, ?, datetime('now'))",
|
||||
)
|
||||
.bind(cache_key)
|
||||
.bind(&json)
|
||||
.execute(&self.db)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn load_schema_cache(&self, cache_key: &str) -> Result<Option<serde_json::Value>, String> {
|
||||
let row: Option<(String,)> = sqlx::query_as("SELECT payload_json FROM schema_cache WHERE cache_key = ?")
|
||||
.bind(cache_key)
|
||||
.fetch_optional(&self.db)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
match row {
|
||||
Some((json,)) => serde_json::from_str(&json).map(Some).map_err(|e| e.to_string()),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete_schema_cache_prefix(&self, prefix: &str) -> Result<(), String> {
|
||||
sqlx::query("DELETE FROM schema_cache WHERE cache_key = ? OR substr(cache_key, 1, ?) = ?")
|
||||
.bind(prefix)
|
||||
.bind(prefix.len() as i64)
|
||||
.bind(prefix)
|
||||
.execute(&self.db)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// JSON migration
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -9,6 +9,7 @@ pub mod query;
|
||||
pub mod query_cancel;
|
||||
pub mod redis_cmd;
|
||||
pub mod schema;
|
||||
pub mod schema_cache;
|
||||
pub mod sql_file;
|
||||
pub mod table_import;
|
||||
pub mod transfer;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
use std::sync::Arc;
|
||||
use tauri::State;
|
||||
|
||||
use dbx_core::connection::AppState;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn save_schema_cache(
|
||||
state: State<'_, Arc<AppState>>,
|
||||
cache_key: String,
|
||||
payload: serde_json::Value,
|
||||
) -> Result<(), String> {
|
||||
state.storage.save_schema_cache(&cache_key, &payload).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn load_schema_cache(
|
||||
state: State<'_, Arc<AppState>>,
|
||||
cache_key: String,
|
||||
) -> Result<Option<serde_json::Value>, String> {
|
||||
state.storage.load_schema_cache(&cache_key).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn delete_schema_cache_prefix(state: State<'_, Arc<AppState>>, prefix: String) -> Result<(), String> {
|
||||
state.storage.delete_schema_cache_prefix(&prefix).await
|
||||
}
|
||||
@@ -81,6 +81,9 @@ pub fn run() {
|
||||
commands::schema::list_foreign_keys,
|
||||
commands::schema::list_triggers,
|
||||
commands::schema::get_table_ddl,
|
||||
commands::schema_cache::save_schema_cache,
|
||||
commands::schema_cache::load_schema_cache,
|
||||
commands::schema_cache::delete_schema_cache_prefix,
|
||||
commands::query::execute_query,
|
||||
commands::query::execute_multi,
|
||||
commands::query::cancel_query,
|
||||
|
||||
@@ -89,6 +89,11 @@ async fn main() {
|
||||
.route("/schema/foreign-keys", get(routes::schema::list_foreign_keys))
|
||||
.route("/schema/triggers", get(routes::schema::list_triggers))
|
||||
.route("/schema/ddl", get(routes::schema::get_ddl))
|
||||
.route(
|
||||
"/schema/cache",
|
||||
post(routes::schema_cache::save_schema_cache).get(routes::schema_cache::load_schema_cache),
|
||||
)
|
||||
.route("/schema/cache-prefix", delete(routes::schema_cache::delete_schema_cache_prefix))
|
||||
// Query
|
||||
.route("/query/execute", post(routes::query::execute_query))
|
||||
.route("/query/execute-multi", post(routes::query::execute_multi))
|
||||
|
||||
@@ -6,6 +6,7 @@ pub mod mongo;
|
||||
pub mod query;
|
||||
pub mod redis;
|
||||
pub mod schema;
|
||||
pub mod schema_cache;
|
||||
pub mod sql_file;
|
||||
pub mod table_import;
|
||||
pub mod transfer;
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::extract::{Query, State};
|
||||
use axum::Json;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::error::AppError;
|
||||
use crate::state::WebState;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SchemaCacheKeyQuery {
|
||||
pub cache_key: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SchemaCachePrefixQuery {
|
||||
pub prefix: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SaveSchemaCacheRequest {
|
||||
pub cache_key: String,
|
||||
pub payload: serde_json::Value,
|
||||
}
|
||||
|
||||
pub async fn save_schema_cache(
|
||||
State(state): State<Arc<WebState>>,
|
||||
Json(body): Json<SaveSchemaCacheRequest>,
|
||||
) -> Result<Json<()>, AppError> {
|
||||
state.app.storage.save_schema_cache(&body.cache_key, &body.payload).await.map_err(AppError)?;
|
||||
Ok(Json(()))
|
||||
}
|
||||
|
||||
pub async fn load_schema_cache(
|
||||
State(state): State<Arc<WebState>>,
|
||||
Query(query): Query<SchemaCacheKeyQuery>,
|
||||
) -> Result<Json<serde_json::Value>, AppError> {
|
||||
let payload = state.app.storage.load_schema_cache(&query.cache_key).await.map_err(AppError)?;
|
||||
Ok(Json(payload.unwrap_or(serde_json::json!(null))))
|
||||
}
|
||||
|
||||
pub async fn delete_schema_cache_prefix(
|
||||
State(state): State<Arc<WebState>>,
|
||||
Query(query): Query<SchemaCachePrefixQuery>,
|
||||
) -> Result<Json<()>, AppError> {
|
||||
state.app.storage.delete_schema_cache_prefix(&query.prefix).await.map_err(AppError)?;
|
||||
Ok(Json(()))
|
||||
}
|
||||
@@ -451,9 +451,9 @@ async function confirmDropTable() {
|
||||
await api.executeQuery(node.connectionId, node.database, buildDropTableSql(), node.schema);
|
||||
toast(t("contextMenu.dropTableSuccess", { name: node.label }), 3000);
|
||||
if (node.schema) {
|
||||
await connectionStore.loadTables(node.connectionId, node.database, node.schema);
|
||||
await connectionStore.loadTables(node.connectionId, node.database, node.schema, { force: true });
|
||||
} else {
|
||||
await connectionStore.loadTables(node.connectionId, node.database);
|
||||
await connectionStore.loadTables(node.connectionId, node.database, undefined, { force: true });
|
||||
}
|
||||
} catch (e: any) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
|
||||
@@ -518,7 +518,7 @@ async function confirmCreateDatabase() {
|
||||
const sql = `CREATE DATABASE ${quoteIdent(name)};`;
|
||||
await api.executeQuery(node.connectionId, "", sql);
|
||||
toast(t("contextMenu.createDatabaseSuccess", { name }), 3000);
|
||||
await connectionStore.loadDatabases(node.connectionId);
|
||||
await connectionStore.loadDatabases(node.connectionId, { force: true });
|
||||
} catch (e: any) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
|
||||
}
|
||||
@@ -535,7 +535,7 @@ async function confirmDropDatabase() {
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
await api.executeQuery(node.connectionId, "", buildDropDatabaseSql());
|
||||
toast(t("contextMenu.dropDatabaseSuccess", { name: node.label }), 3000);
|
||||
await connectionStore.loadDatabases(node.connectionId);
|
||||
await connectionStore.loadDatabases(node.connectionId, { force: true });
|
||||
} catch (e: any) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
|
||||
}
|
||||
@@ -556,7 +556,7 @@ async function confirmCreateSchema() {
|
||||
const sql = `CREATE SCHEMA ${quoteIdent(name)};`;
|
||||
await api.executeQuery(node.connectionId, node.database, sql);
|
||||
toast(t("contextMenu.createSchemaSuccess", { name }), 3000);
|
||||
await connectionStore.loadSchemas(node.connectionId, node.database);
|
||||
await connectionStore.loadSchemas(node.connectionId, node.database, { force: true });
|
||||
} catch (e: any) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
|
||||
}
|
||||
@@ -573,7 +573,7 @@ async function confirmDropSchema() {
|
||||
await connectionStore.ensureConnected(node.connectionId);
|
||||
await api.executeQuery(node.connectionId, node.database, buildDropSchemaSql());
|
||||
toast(t("contextMenu.dropSchemaSuccess", { name: node.label }), 3000);
|
||||
await connectionStore.loadSchemas(node.connectionId, node.database);
|
||||
await connectionStore.loadSchemas(node.connectionId, node.database, { force: true });
|
||||
} catch (e: any) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
|
||||
}
|
||||
@@ -609,9 +609,9 @@ async function confirmDuplicateStructure() {
|
||||
await api.executeQuery(node.connectionId, node.database, sql, node.schema);
|
||||
toast(t("contextMenu.duplicateStructureSuccess", { name: newName }), 3000);
|
||||
if (node.schema) {
|
||||
await connectionStore.loadTables(node.connectionId, node.database, node.schema);
|
||||
await connectionStore.loadTables(node.connectionId, node.database, node.schema, { force: true });
|
||||
} else {
|
||||
await connectionStore.loadTables(node.connectionId, node.database);
|
||||
await connectionStore.loadTables(node.connectionId, node.database, undefined, { force: true });
|
||||
}
|
||||
} catch (e: any) {
|
||||
toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
|
||||
|
||||
@@ -39,6 +39,9 @@ export const loadConnections = forward("loadConnections");
|
||||
|
||||
// Schema
|
||||
export const listDatabases = forward("listDatabases");
|
||||
export const saveSchemaCache = forward("saveSchemaCache");
|
||||
export const loadSchemaCache = forward("loadSchemaCache");
|
||||
export const deleteSchemaCachePrefix = forward("deleteSchemaCachePrefix");
|
||||
export const listSchemas = forward("listSchemas");
|
||||
export const listTables = forward("listTables");
|
||||
export const getColumns = forward("getColumns");
|
||||
|
||||
@@ -96,6 +96,18 @@ export async function listDatabases(connectionId: string): Promise<DatabaseInfo[
|
||||
return get(`/api/schema/databases?${qs({ connection_id: connectionId })}`);
|
||||
}
|
||||
|
||||
export async function saveSchemaCache(cacheKey: string, payload: unknown): Promise<void> {
|
||||
return post("/api/schema/cache", { cacheKey, payload });
|
||||
}
|
||||
|
||||
export async function loadSchemaCache<T = unknown>(cacheKey: string): Promise<T | null> {
|
||||
return get(`/api/schema/cache?${qs({ cache_key: cacheKey })}`);
|
||||
}
|
||||
|
||||
export async function deleteSchemaCachePrefix(prefix: string): Promise<void> {
|
||||
return del(`/api/schema/cache-prefix?${qs({ prefix })}`);
|
||||
}
|
||||
|
||||
export async function listSchemas(connectionId: string, database: string): Promise<string[]> {
|
||||
return get(`/api/schema/schemas?${qs({ connection_id: connectionId, database })}`);
|
||||
}
|
||||
|
||||
@@ -117,6 +117,18 @@ export async function listDatabases(connectionId: string): Promise<DatabaseInfo[
|
||||
return invoke("list_databases", { connectionId });
|
||||
}
|
||||
|
||||
export async function saveSchemaCache(cacheKey: string, payload: unknown): Promise<void> {
|
||||
return invoke("save_schema_cache", { cacheKey, payload });
|
||||
}
|
||||
|
||||
export async function loadSchemaCache<T = unknown>(cacheKey: string): Promise<T | null> {
|
||||
return invoke("load_schema_cache", { cacheKey });
|
||||
}
|
||||
|
||||
export async function deleteSchemaCachePrefix(prefix: string): Promise<void> {
|
||||
return invoke("delete_schema_cache_prefix", { prefix });
|
||||
}
|
||||
|
||||
export async function listTables(connectionId: string, database: string, schema: string): Promise<TableInfo[]> {
|
||||
return invoke("list_tables", { connectionId, database, schema });
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ import { buildDatabaseTreeNodes } from "@/lib/databaseTree";
|
||||
|
||||
const PINNED_TREE_NODES_STORAGE_KEY = "dbx-pinned-tree-nodes";
|
||||
|
||||
interface LoadTreeOptions {
|
||||
force?: boolean;
|
||||
}
|
||||
|
||||
export const useConnectionStore = defineStore("connection", () => {
|
||||
const connections = ref<ConnectionConfig[]>([]);
|
||||
const isDesktop = isTauriRuntime();
|
||||
@@ -38,6 +42,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const treeNodes = ref<TreeNode[]>([]);
|
||||
const pinnedTreeNodeIds = ref<Set<string>>(loadPinnedTreeNodeIds());
|
||||
const connectedIds = ref<Set<string>>(new Set());
|
||||
const loadedTreeNodeChildrenIds = ref<Set<string>>(new Set());
|
||||
const connectionErrors = ref<Record<string, string>>({});
|
||||
const editingConnectionId = ref<string | null>(null);
|
||||
const newConnectionGroupId = ref<string | null>(null);
|
||||
@@ -188,6 +193,38 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
|
||||
function setChildren(parent: TreeNode, children: TreeNode[]) {
|
||||
parent.children = orderPinnedFirst(children.map(pinTreeNode), (node) => !!node.pinned);
|
||||
loadedTreeNodeChildrenIds.value.add(parent.id);
|
||||
}
|
||||
|
||||
function schemaCacheKey(...parts: string[]): string {
|
||||
return parts.map((part) => encodeURIComponent(part)).join(":");
|
||||
}
|
||||
|
||||
async function loadPersistedTreeChildren(node: TreeNode, cacheKey: string): Promise<boolean> {
|
||||
const children = await api.loadSchemaCache<TreeNode[]>(cacheKey).catch(() => null);
|
||||
if (!children) return false;
|
||||
setChildren(node, children);
|
||||
node.isExpanded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
async function savePersistedTreeChildren(cacheKey: string, children: TreeNode[]) {
|
||||
await api.saveSchemaCache(cacheKey, children).catch(() => undefined);
|
||||
}
|
||||
|
||||
function useCachedChildren(node: TreeNode, options?: LoadTreeOptions): boolean {
|
||||
if (options?.force || !loadedTreeNodeChildrenIds.value.has(node.id)) return false;
|
||||
node.isExpanded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function clearLoadedChildrenCache(prefix: string) {
|
||||
for (const id of loadedTreeNodeChildrenIds.value) {
|
||||
if (id === prefix || id.startsWith(`${prefix}:`)) {
|
||||
loadedTreeNodeChildrenIds.value.delete(id);
|
||||
}
|
||||
}
|
||||
api.deleteSchemaCachePrefix(`${schemaCacheKey(prefix)}:`).catch(() => undefined);
|
||||
}
|
||||
|
||||
function findParentNode(nodes: TreeNode[], id: string, parent: TreeNode | null = null): TreeNode | null {
|
||||
@@ -263,6 +300,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
activeConnectionId.value = null;
|
||||
}
|
||||
invalidateCompletionCache(id);
|
||||
clearLoadedChildrenCache(id);
|
||||
}
|
||||
|
||||
async function updateConnection(config: ConnectionConfig) {
|
||||
@@ -276,6 +314,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
rebuildTreeNodes();
|
||||
connectedIds.value.delete(config.id);
|
||||
invalidateCompletionCache(config.id);
|
||||
clearLoadedChildrenCache(config.id);
|
||||
}
|
||||
|
||||
async function setDefaultDatabase(connectionId: string, database: string) {
|
||||
@@ -343,6 +382,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
node.isExpanded = false;
|
||||
node.children = [];
|
||||
}
|
||||
clearLoadedChildrenCache(connectionId);
|
||||
if (activeConnectionId.value === connectionId) {
|
||||
activeConnectionId.value = null;
|
||||
}
|
||||
@@ -368,15 +408,20 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDatabases(connectionId: string) {
|
||||
async function loadDatabases(connectionId: string, options?: LoadTreeOptions) {
|
||||
const node = findNode(treeNodes.value, connectionId);
|
||||
if (!node) return;
|
||||
if (useCachedChildren(node, options)) return;
|
||||
const cacheKey = schemaCacheKey(connectionId, "databases");
|
||||
if (!options?.force && (await loadPersistedTreeChildren(node, cacheKey))) return;
|
||||
|
||||
node.isLoading = true;
|
||||
try {
|
||||
await ensureConnected(connectionId);
|
||||
const databases = await api.listDatabases(connectionId);
|
||||
setChildren(node, buildDatabaseTreeNodes(connectionId, databases));
|
||||
const children = buildDatabaseTreeNodes(connectionId, databases);
|
||||
setChildren(node, children);
|
||||
await savePersistedTreeChildren(cacheKey, children);
|
||||
node.isExpanded = true;
|
||||
} finally {
|
||||
node.isLoading = false;
|
||||
@@ -460,57 +505,63 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSchemas(connectionId: string, database: string) {
|
||||
async function loadSchemas(connectionId: string, database: string, options?: LoadTreeOptions) {
|
||||
const nodeId = `${connectionId}:${database}`;
|
||||
const node = findNode(treeNodes.value, nodeId);
|
||||
if (!node) return;
|
||||
if (useCachedChildren(node, options)) return;
|
||||
const cacheKey = schemaCacheKey(connectionId, database, "schemas");
|
||||
if (!options?.force && (await loadPersistedTreeChildren(node, cacheKey))) return;
|
||||
|
||||
node.isLoading = true;
|
||||
try {
|
||||
await ensureConnected(connectionId);
|
||||
const schemas = await api.listSchemas(connectionId, database);
|
||||
setChildren(
|
||||
node,
|
||||
schemas.map((s) => ({
|
||||
id: `${connectionId}:${database}:${s}`,
|
||||
label: s,
|
||||
type: "schema" as const,
|
||||
connectionId,
|
||||
database,
|
||||
schema: s,
|
||||
isExpanded: false,
|
||||
children: [],
|
||||
})),
|
||||
);
|
||||
const children = schemas.map((s) => ({
|
||||
id: `${connectionId}:${database}:${s}`,
|
||||
label: s,
|
||||
type: "schema" as const,
|
||||
connectionId,
|
||||
database,
|
||||
schema: s,
|
||||
isExpanded: false,
|
||||
children: [],
|
||||
}));
|
||||
setChildren(node, children);
|
||||
await savePersistedTreeChildren(cacheKey, children);
|
||||
node.isExpanded = true;
|
||||
} finally {
|
||||
node.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadTables(connectionId: string, database: string, schema?: string) {
|
||||
async function loadTables(connectionId: string, database: string, schema?: string, options?: LoadTreeOptions) {
|
||||
const nodeId = schema ? `${connectionId}:${database}:${schema}` : `${connectionId}:${database}`;
|
||||
const node = findNode(treeNodes.value, nodeId);
|
||||
if (!node) return;
|
||||
if (useCachedChildren(node, options)) return;
|
||||
const cacheKey = schemaCacheKey(connectionId, database, schema || "", "tables");
|
||||
if (!options?.force && (await loadPersistedTreeChildren(node, cacheKey))) return;
|
||||
|
||||
node.isLoading = true;
|
||||
try {
|
||||
await ensureConnected(connectionId);
|
||||
const querySchema = schema || database;
|
||||
const tables = await api.listTables(connectionId, database, querySchema);
|
||||
const config = getConfig(connectionId);
|
||||
const effectiveSchema = schema || (config?.db_type && isSchemaAware(config.db_type) ? database : undefined);
|
||||
setChildren(
|
||||
node,
|
||||
tables.map((t) => ({
|
||||
id: `${nodeId}:${t.name}`,
|
||||
label: t.name,
|
||||
type: (t.table_type === "VIEW" ? "view" : "table") as "view" | "table",
|
||||
connectionId,
|
||||
database,
|
||||
schema: effectiveSchema,
|
||||
isExpanded: false,
|
||||
children: [],
|
||||
})),
|
||||
);
|
||||
const children = tables.map((t) => ({
|
||||
id: `${nodeId}:${t.name}`,
|
||||
label: t.name,
|
||||
type: (t.table_type === "VIEW" ? "view" : "table") as "view" | "table",
|
||||
connectionId,
|
||||
database,
|
||||
schema: effectiveSchema,
|
||||
isExpanded: false,
|
||||
children: [],
|
||||
}));
|
||||
setChildren(node, children);
|
||||
await savePersistedTreeChildren(cacheKey, children);
|
||||
node.isExpanded = true;
|
||||
} finally {
|
||||
node.isLoading = false;
|
||||
@@ -696,7 +747,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
return ids;
|
||||
}
|
||||
|
||||
async function loadTreeNodeChildren(node: TreeNode) {
|
||||
async function loadTreeNodeChildren(node: TreeNode, options?: LoadTreeOptions) {
|
||||
if (node.type === "connection" && node.connectionId) {
|
||||
const config = getConfig(node.connectionId);
|
||||
if (config?.db_type === "redis") {
|
||||
@@ -704,19 +755,19 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
} else if (config?.db_type === "mongodb" || config?.db_type === "elasticsearch") {
|
||||
await loadMongoDatabases(node.connectionId);
|
||||
} else {
|
||||
await loadDatabases(node.connectionId);
|
||||
await loadDatabases(node.connectionId, options);
|
||||
}
|
||||
} else if (node.type === "mongo-db" && node.connectionId && node.database) {
|
||||
await loadMongoCollections(node.connectionId, node.database);
|
||||
} else if (node.type === "database" && node.connectionId && node.database) {
|
||||
const config = getConfig(node.connectionId);
|
||||
if (config?.db_type && TREE_SCHEMA_TYPES.has(config.db_type)) {
|
||||
await loadSchemas(node.connectionId, node.database);
|
||||
await loadSchemas(node.connectionId, node.database, options);
|
||||
} else {
|
||||
await loadTables(node.connectionId, node.database);
|
||||
await loadTables(node.connectionId, node.database, undefined, options);
|
||||
}
|
||||
} else if (node.type === "schema" && node.connectionId && node.database && node.schema) {
|
||||
await loadTables(node.connectionId, node.database, node.schema);
|
||||
await loadTables(node.connectionId, node.database, node.schema, options);
|
||||
} else if ((node.type === "table" || node.type === "view") && node.connectionId && node.database) {
|
||||
await loadTableGroups(node.connectionId, node.database, node.label, node.schema);
|
||||
} else if (node.type === "group-columns" && node.connectionId && node.database && node.tableName) {
|
||||
@@ -730,12 +781,12 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function restoreExpandedChildren(node: TreeNode, expandedIds: Set<string>) {
|
||||
async function restoreExpandedChildren(node: TreeNode, expandedIds: Set<string>, options?: LoadTreeOptions) {
|
||||
if (!node.children) return;
|
||||
for (const child of node.children) {
|
||||
if (!expandedIds.has(child.id)) continue;
|
||||
await loadTreeNodeChildren(child);
|
||||
await restoreExpandedChildren(child, expandedIds);
|
||||
await loadTreeNodeChildren(child, options);
|
||||
await restoreExpandedChildren(child, expandedIds, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,8 +796,8 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
if (node.type !== "connection-group") {
|
||||
node.children = [];
|
||||
}
|
||||
await loadTreeNodeChildren(node);
|
||||
await restoreExpandedChildren(node, expandedIds);
|
||||
await loadTreeNodeChildren(node, { force: true });
|
||||
await restoreExpandedChildren(node, expandedIds, { force: true });
|
||||
}
|
||||
|
||||
function isSchemaAwareDatabase(connectionId: string): boolean {
|
||||
@@ -874,8 +925,8 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
}
|
||||
if (!expandedIds.has(node.id)) continue;
|
||||
node.children = [];
|
||||
await loadTreeNodeChildren(node);
|
||||
await restoreExpandedChildren(node, expandedIds);
|
||||
await loadTreeNodeChildren(node, { force: true });
|
||||
await restoreExpandedChildren(node, expandedIds, { force: true });
|
||||
}
|
||||
};
|
||||
await refreshExpandedNodes(treeNodes.value);
|
||||
|
||||
Reference in New Issue
Block a user