mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-23 07:08:16 +00:00
After an app update (typically >15min since last use), the on-disk schema
tree cache is past its TTL and counts as stale. When "locate in sidebar"
loads the connection's databases, the stale cache is served synchronously
and an async `refreshStaleTreeNode` fires in the background; that refresh
replaces the database node with a fresh one whose tables haven't loaded
yet, evicting the node that locate just populated. By the time
`findNodePathForActiveTab` runs, the target table isn't in the tree, so
locate only reaches the database. After a restart the cache is fresh, no
refresh races, and locate works — matching the report.
Make `ensureTreeLoadedForTab` accept `{ force }` (loads everything via
awaited calls, bypassing the stale-cache fire-and-forget path) and, in
`locateActiveTabInSidebar`, retry once with force when the first
`findNodePath` misses. Fresh-cache locates still succeed on the first
pass and never force (no regression); `refreshStaleTreeNode` is untouched.
Co-authored-by: vrustx <vrustx@vrustxdeMac-mini.local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
vrustx
Claude Opus 4.8
parent
e6062b2b07
commit
094dfb1f06
@@ -230,7 +230,15 @@ async function locateActiveTabInSidebar() {
|
||||
clearSearchScopeFilter();
|
||||
}
|
||||
|
||||
const nodePath = findNodePathForActiveTab(tab, store.treeNodes);
|
||||
let nodePath = findNodePathForActiveTab(tab, store.treeNodes);
|
||||
if (!nodePath) {
|
||||
// The first load may have served a stale schema cache whose async refresh
|
||||
// replaced the database node before its tables finished loading, so the
|
||||
// table isn't in the tree yet. Force a synchronous reload and retry once so
|
||||
// locate reaches the table, not just the database (issue #715).
|
||||
await ensureTreeLoadedForTab(tab, { force: true });
|
||||
nodePath = findNodePathForActiveTab(tab, store.treeNodes);
|
||||
}
|
||||
if (!nodePath) return;
|
||||
|
||||
for (const ancestor of nodePath) {
|
||||
@@ -256,23 +264,30 @@ async function locateActiveTabInSidebar() {
|
||||
await scrollToSidebarNode(match.id);
|
||||
}
|
||||
|
||||
async function ensureTreeLoadedForTab(tab: QueryTab) {
|
||||
async function ensureTreeLoadedForTab(tab: QueryTab, opts?: { force?: boolean }) {
|
||||
const connId = tab.connectionId;
|
||||
if (!connId) return;
|
||||
|
||||
const config = store.getConfig(connId);
|
||||
if (!config) return;
|
||||
|
||||
// When forcing, bypass the cached children check so we reload from the
|
||||
// source. A stale schema cache otherwise serves children and triggers an
|
||||
// async background refresh that can replace nodes mid-flight, leaving the
|
||||
// tree without the target table by the time we search for it (issue #715).
|
||||
const force = opts?.force ?? false;
|
||||
const loadOptions = force ? { force: true } : undefined;
|
||||
|
||||
// Ensure databases are loaded under the connection
|
||||
const connNode = store.treeNodes.find((n) => n.id === connId);
|
||||
if (connNode && (!connNode.children || connNode.children.length === 0)) {
|
||||
if (connNode && (force || !connNode.children || connNode.children.length === 0)) {
|
||||
try {
|
||||
if (config.db_type === "redis") {
|
||||
await store.loadRedisDatabases(connId);
|
||||
} else if (config.db_type === "mongodb" || config.db_type === "elasticsearch") {
|
||||
await store.loadMongoDatabases(connId);
|
||||
} else {
|
||||
await store.loadDatabases(connId);
|
||||
await store.loadDatabases(connId, loadOptions);
|
||||
}
|
||||
} catch {
|
||||
return;
|
||||
@@ -283,23 +298,24 @@ async function ensureTreeLoadedForTab(tab: QueryTab) {
|
||||
|
||||
// Find the database node
|
||||
const dbNode = findDatabaseNode(store.treeNodes, connId, tab.database);
|
||||
if (!dbNode || (dbNode.children && dbNode.children.length > 0)) return;
|
||||
if (!dbNode) return;
|
||||
if (!force && dbNode.children && dbNode.children.length > 0) return;
|
||||
|
||||
// Load database contents
|
||||
try {
|
||||
if (config.db_type === "sqlserver") {
|
||||
await store.loadSqlServerDatabaseObjects(connId, tab.database);
|
||||
await store.loadSqlServerDatabaseObjects(connId, tab.database, loadOptions);
|
||||
} else if (usesTreeSchemaMode(config.db_type) && !connectionUsesDatabaseObjectTreeMode(config)) {
|
||||
await store.loadSchemas(connId, tab.database);
|
||||
await store.loadSchemas(connId, tab.database, loadOptions);
|
||||
// If we have a schema, also load tables under that schema
|
||||
if (tab.schema) {
|
||||
const schemaNode = findSchemaNode(store.treeNodes, connId, tab.database, tab.schema);
|
||||
if (schemaNode && (!schemaNode.children || schemaNode.children.length === 0)) {
|
||||
await store.loadTables(connId, tab.database, tab.schema);
|
||||
if (schemaNode && (force || !schemaNode.children || schemaNode.children.length === 0)) {
|
||||
await store.loadTables(connId, tab.database, tab.schema, loadOptions);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await store.loadTables(connId, tab.database);
|
||||
await store.loadTables(connId, tab.database, undefined, loadOptions);
|
||||
}
|
||||
} catch {
|
||||
// Node just won't have children loaded
|
||||
|
||||
Reference in New Issue
Block a user