ADR-0022 stage 8d: schema cache refresh wiring
New `AppEvent::SchemaCacheRefreshed(SchemaCache)` event + App handler that stores it on `app.schema_cache`. Runtime helper `refresh_schema_cache(database, event_tx)` fetches table / column / relationship names via the `list_names_for` worker request (added in stage 7) and posts the assembled cache. Wired into every site that already posts `TablesRefreshed`: - `seed_initial_tables` (initial project load). - Project-switch path in `handle_project_switch`. - `RebuildSucceeded` path. - Post-DDL path (`spawn_command`). - Post-replay path. Result: schema-aware identifier completion (added in 8c) becomes live — Tab on `show data ` offers the actual table names from the current project, `drop column from T: ` (or similar) offers existing columns, etc. The cache stays fresh across DDL and rebuild without per-keystroke worker round-trips (one refresh per schema-mutating action is amortised across many subsequent keystrokes). Best-effort: a failed `list_names_for` for any individual slot kind leaves that field empty in the cache rather than suppressing the whole refresh — partial completion beats no completion. Tests: 738 passing, 0 failing, 1 ignored (unchanged total — this stage is wiring, not new test surface; the synthetic-cache tests from stage 8c remain the regression net for the completion logic itself). Clippy clean.
This commit is contained in:
+10
@@ -356,6 +356,16 @@ impl App {
|
|||||||
self.tables = tables;
|
self.tables = tables;
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
AppEvent::SchemaCacheRefreshed(cache) => {
|
||||||
|
trace!(
|
||||||
|
tables = cache.tables.len(),
|
||||||
|
columns = cache.columns.len(),
|
||||||
|
relationships = cache.relationships.len(),
|
||||||
|
"schema cache refreshed",
|
||||||
|
);
|
||||||
|
self.schema_cache = cache;
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
AppEvent::PersistenceFatal {
|
AppEvent::PersistenceFatal {
|
||||||
operation,
|
operation,
|
||||||
path,
|
path,
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ pub enum AppEvent {
|
|||||||
},
|
},
|
||||||
/// Refreshed list of tables in the database.
|
/// Refreshed list of tables in the database.
|
||||||
TablesRefreshed(Vec<String>),
|
TablesRefreshed(Vec<String>),
|
||||||
|
/// Refreshed schema lookup cache feeding Tab completion
|
||||||
|
/// for identifier slots (ADR-0022 §9 + stage 8d). Runtime
|
||||||
|
/// posts this alongside `TablesRefreshed` after project
|
||||||
|
/// load and after every successful DDL.
|
||||||
|
SchemaCacheRefreshed(crate::completion::SchemaCache),
|
||||||
/// A persistence failure occurred (ADR-0015 §8). The
|
/// A persistence failure occurred (ADR-0015 §8). The
|
||||||
/// application surfaces a fatal banner and exits cleanly so
|
/// application surfaces a fatal banner and exits cleanly so
|
||||||
/// the message remains above the shell prompt.
|
/// the message remains above the shell prompt.
|
||||||
|
|||||||
@@ -466,6 +466,7 @@ async fn handle_project_switch(
|
|||||||
if let Ok(tables) = session.database().list_tables().await {
|
if let Ok(tables) = session.database().list_tables().await {
|
||||||
let _ = event_tx.send(AppEvent::TablesRefreshed(tables)).await;
|
let _ = event_tx.send(AppEvent::TablesRefreshed(tables)).await;
|
||||||
}
|
}
|
||||||
|
refresh_schema_cache(session.database(), event_tx).await;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let _ = event_tx
|
let _ = event_tx
|
||||||
@@ -817,6 +818,36 @@ async fn seed_initial_tables(database: &Database, event_tx: &mpsc::Sender<AppEve
|
|||||||
error!(error = %e, "failed to seed initial table list");
|
error!(error = %e, "failed to seed initial table list");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
refresh_schema_cache(database, event_tx).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch the three identifier lists (tables / columns /
|
||||||
|
/// relationships) and post them as `SchemaCacheRefreshed`
|
||||||
|
/// (ADR-0022 §9 + stage 8d). Always sends an event, even on
|
||||||
|
/// partial failure — best-effort completion is better than
|
||||||
|
/// no completion. Called wherever `TablesRefreshed` is sent
|
||||||
|
/// today; the schema cache lives on the App and feeds Tab
|
||||||
|
/// completion for identifier slots.
|
||||||
|
async fn refresh_schema_cache(
|
||||||
|
database: &Database,
|
||||||
|
event_tx: &mpsc::Sender<AppEvent>,
|
||||||
|
) {
|
||||||
|
use crate::completion::SchemaCache;
|
||||||
|
use crate::dsl::ident_slot::IdentSlot;
|
||||||
|
let mut cache = SchemaCache::default();
|
||||||
|
if let Ok(tables) = database.list_names_for(IdentSlot::TableName).await {
|
||||||
|
cache.tables = tables;
|
||||||
|
}
|
||||||
|
if let Ok(columns) = database.list_names_for(IdentSlot::Column).await {
|
||||||
|
cache.columns = columns;
|
||||||
|
}
|
||||||
|
if let Ok(rels) = database
|
||||||
|
.list_names_for(IdentSlot::RelationshipName)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
cache.relationships = rels;
|
||||||
|
}
|
||||||
|
let _ = event_tx.send(AppEvent::SchemaCacheRefreshed(cache)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read `project.yaml` + `data/` to compute the rebuild
|
/// Read `project.yaml` + `data/` to compute the rebuild
|
||||||
@@ -905,6 +936,7 @@ fn spawn_rebuild(
|
|||||||
if let Ok(tables) = database.list_tables().await {
|
if let Ok(tables) = database.list_tables().await {
|
||||||
let _ = event_tx.send(AppEvent::TablesRefreshed(tables)).await;
|
let _ = event_tx.send(AppEvent::TablesRefreshed(tables)).await;
|
||||||
}
|
}
|
||||||
|
refresh_schema_cache(&database, &event_tx).await;
|
||||||
}
|
}
|
||||||
Err(DbError::PersistenceFatal {
|
Err(DbError::PersistenceFatal {
|
||||||
operation,
|
operation,
|
||||||
@@ -1003,6 +1035,9 @@ fn spawn_dsl_dispatch(
|
|||||||
}
|
}
|
||||||
Err(e) => warn!(error = %e, "post-list_tables failed"),
|
Err(e) => warn!(error = %e, "post-list_tables failed"),
|
||||||
}
|
}
|
||||||
|
// Refresh the schema cache feeding Tab completion
|
||||||
|
// (ADR-0022 §9). Same timing as TablesRefreshed.
|
||||||
|
refresh_schema_cache(&database, &event_tx).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1337,6 +1372,7 @@ fn spawn_replay(
|
|||||||
}
|
}
|
||||||
Err(e) => warn!(error = %e, "post-replay list_tables failed"),
|
Err(e) => warn!(error = %e, "post-replay list_tables failed"),
|
||||||
}
|
}
|
||||||
|
refresh_schema_cache(&database, &event_tx).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user