Indexes: add index / drop index, persistence, display (ADR-0025)
Implement ADR-0025 — indexes as a DSL DDL feature. - Grammar: `add index [as <name>] on <T> (<cols>)`, `drop index <name>` / `drop index on <T> (<cols>)`, plus a `--cascade` flag on `drop column`. - db.rs: index operations over the engine's native index catalog (no metadata table). The rebuild-table primitive now captures and recreates indexes, so `change column` and the relationship operations no longer silently drop them. - `drop column` refuses an indexed column unless `--cascade`, which drops the covering indexes and reports each. - Persistence: additive `indexes:` list in `project.yaml` (version unchanged); round-trips through rebuild/export/import. - Display: an `Indexes:` section in the structure view and a nested tables/indexes items panel (S2). Reconciles requirements.md (C3 index portion, S2 satisfied) and CLAUDE.md. 1038 tests passing (+31), clippy clean.
This commit is contained in:
+35
-5
@@ -30,7 +30,7 @@ use crate::app::App;
|
||||
use crate::cli::Args;
|
||||
use crate::db::{
|
||||
AddColumnResult, ChangeColumnTypeResult, DataResult, Database, DbError, DeleteResult,
|
||||
InsertResult, TableDescription, UpdateResult,
|
||||
DropColumnResult, InsertResult, TableDescription, UpdateResult,
|
||||
};
|
||||
use crate::dsl::Command;
|
||||
use crate::event::AppEvent;
|
||||
@@ -863,6 +863,9 @@ async fn build_schema_cache(database: &Database) -> crate::completion::SchemaCac
|
||||
if let Ok(rels) = database.list_names_for(IdentSource::Relationships).await {
|
||||
cache.relationships = rels;
|
||||
}
|
||||
if let Ok(indexes) = database.list_names_for(IdentSource::Indexes).await {
|
||||
cache.indexes = indexes;
|
||||
}
|
||||
// Phase D (ADR-0024 §Phase D): per-table column metadata
|
||||
// with user-facing types. The walker's
|
||||
// `DynamicSubgrammar(column_value_list)` reads this to
|
||||
@@ -872,6 +875,11 @@ async fn build_schema_cache(database: &Database) -> crate::completion::SchemaCac
|
||||
// walker falls back to the schemaless value-literal list.
|
||||
for name in cache.tables.clone() {
|
||||
if let Ok(desc) = database.describe_table(name.clone(), None).await {
|
||||
// Per-table index names for the items panel (S2,
|
||||
// ADR-0025). Captured before `desc.columns` is
|
||||
// consumed below.
|
||||
let index_names: Vec<String> =
|
||||
desc.indexes.iter().map(|i| i.name.clone()).collect();
|
||||
let cols: Vec<TableColumn> = desc
|
||||
.columns
|
||||
.into_iter()
|
||||
@@ -882,7 +890,8 @@ async fn build_schema_cache(database: &Database) -> crate::completion::SchemaCac
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
cache.table_columns.insert(name, cols);
|
||||
cache.table_columns.insert(name.clone(), cols);
|
||||
cache.table_indexes.insert(name, index_names);
|
||||
}
|
||||
}
|
||||
cache
|
||||
@@ -1039,6 +1048,10 @@ fn spawn_dsl_dispatch(
|
||||
command: command.clone(),
|
||||
result,
|
||||
},
|
||||
Ok(CommandOutcome::DropColumn(result)) => AppEvent::DslDropColumnSucceeded {
|
||||
command: command.clone(),
|
||||
result,
|
||||
},
|
||||
Err(DbError::PersistenceFatal {
|
||||
operation,
|
||||
path,
|
||||
@@ -1367,6 +1380,7 @@ enum CommandOutcome {
|
||||
Delete(DeleteResult),
|
||||
ChangeColumn(ChangeColumnTypeResult),
|
||||
AddColumn(AddColumnResult),
|
||||
DropColumn(DropColumnResult),
|
||||
}
|
||||
|
||||
/// Spawn a task that reads a script file and dispatches each
|
||||
@@ -1576,10 +1590,14 @@ async fn execute_command_typed(
|
||||
.add_column(table, column, ty, src)
|
||||
.await
|
||||
.map(CommandOutcome::AddColumn),
|
||||
Command::DropColumn { table, column } => database
|
||||
.drop_column(table, column, src)
|
||||
Command::DropColumn {
|
||||
table,
|
||||
column,
|
||||
cascade,
|
||||
} => database
|
||||
.drop_column(table, column, cascade, src)
|
||||
.await
|
||||
.map(|d| CommandOutcome::Schema(Some(d))),
|
||||
.map(CommandOutcome::DropColumn),
|
||||
Command::RenameColumn { table, old, new } => database
|
||||
.rename_column(table, old, new, src)
|
||||
.await
|
||||
@@ -1620,6 +1638,18 @@ async fn execute_command_typed(
|
||||
.drop_relationship(selector, src)
|
||||
.await
|
||||
.map(CommandOutcome::Schema),
|
||||
Command::AddIndex {
|
||||
name,
|
||||
table,
|
||||
columns,
|
||||
} => database
|
||||
.add_index(name, table, columns, src)
|
||||
.await
|
||||
.map(|d| CommandOutcome::Schema(Some(d))),
|
||||
Command::DropIndex { selector } => database
|
||||
.drop_index(selector, src)
|
||||
.await
|
||||
.map(|d| CommandOutcome::Schema(Some(d))),
|
||||
Command::ShowTable { name } => database
|
||||
.describe_table(name, src)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user