feat(grid): allow drilling into formula cells
When drilling into a cell that is the target of a formula, the resulting record set was empty because the formula target coordinate itself does not exist in the raw data. This change strips the '_Measure' coordinate from the drill key if the value is a known formula target, allowing the underlying data records that feed the formula to be discovered. Co-Authored-By: fiddlerwoaroof/git-smart-commit (gemma-4-31B-it-UD-Q4_K_XL.gguf)
This commit is contained in:
@ -111,6 +111,57 @@ mod tests {
|
|||||||
"Expected TogglePruneEmpty, got: {dbg}"
|
"Expected TogglePruneEmpty, got: {dbg}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Drilling into a formula cell (e.g. Profit = Revenue - Cost) should
|
||||||
|
/// return the underlying data records, not an empty result set. The
|
||||||
|
/// formula target coordinate is stripped from the drill key so that
|
||||||
|
/// matching_cells finds the raw data backing the formula.
|
||||||
|
#[test]
|
||||||
|
fn drill_into_formula_cell_returns_data_records() {
|
||||||
|
use crate::formula::parse_formula;
|
||||||
|
use crate::model::Model;
|
||||||
|
use crate::model::cell::{CellKey, CellValue};
|
||||||
|
|
||||||
|
let mut m = Model::new("Test");
|
||||||
|
m.add_category("Region").unwrap();
|
||||||
|
m.category_mut("Region").unwrap().add_item("East");
|
||||||
|
m.category_mut("_Measure").unwrap().add_item("Revenue");
|
||||||
|
m.category_mut("_Measure").unwrap().add_item("Cost");
|
||||||
|
m.set_cell(
|
||||||
|
CellKey::new(vec![
|
||||||
|
("_Measure".into(), "Revenue".into()),
|
||||||
|
("Region".into(), "East".into()),
|
||||||
|
]),
|
||||||
|
CellValue::Number(1000.0),
|
||||||
|
);
|
||||||
|
m.set_cell(
|
||||||
|
CellKey::new(vec![
|
||||||
|
("_Measure".into(), "Cost".into()),
|
||||||
|
("Region".into(), "East".into()),
|
||||||
|
]),
|
||||||
|
CellValue::Number(600.0),
|
||||||
|
);
|
||||||
|
m.add_formula(parse_formula("Profit = Revenue - Cost", "_Measure").unwrap());
|
||||||
|
|
||||||
|
let layout = make_layout(&m);
|
||||||
|
let reg = make_registry();
|
||||||
|
let ctx = make_ctx(&m, &layout, ®);
|
||||||
|
|
||||||
|
// Drill into the Profit/East cell — a formula-derived cell
|
||||||
|
let key = CellKey::new(vec![
|
||||||
|
("_Measure".into(), "Profit".into()),
|
||||||
|
("Region".into(), "East".into()),
|
||||||
|
]);
|
||||||
|
let cmd = DrillIntoCell { key };
|
||||||
|
let effects = cmd.execute(&ctx);
|
||||||
|
let dbg = effects_debug(&effects);
|
||||||
|
|
||||||
|
// Should find underlying data records, not "0 rows"
|
||||||
|
assert!(
|
||||||
|
!dbg.contains("0 rows"),
|
||||||
|
"Drill into formula cell should find data records, got: {dbg}"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Grid operations ─────────────────────────────────────────────────────
|
// ── Grid operations ─────────────────────────────────────────────────────
|
||||||
@ -233,9 +284,27 @@ impl Cmd for DrillIntoCell {
|
|||||||
let drill_name = "_Drill".to_string();
|
let drill_name = "_Drill".to_string();
|
||||||
let mut effects: Vec<Box<dyn Effect>> = Vec::new();
|
let mut effects: Vec<Box<dyn Effect>> = Vec::new();
|
||||||
|
|
||||||
|
// If drilling into a formula cell, strip the formula target from the
|
||||||
|
// key so matching_cells finds the underlying raw data records instead
|
||||||
|
// of returning nothing.
|
||||||
|
let drill_key = if let Some(measure_val) = self.key.get("_Measure") {
|
||||||
|
let is_formula_target = ctx
|
||||||
|
.model
|
||||||
|
.formulas()
|
||||||
|
.iter()
|
||||||
|
.any(|f| f.target_category == "_Measure" && f.target == measure_val);
|
||||||
|
if is_formula_target {
|
||||||
|
self.key.without("_Measure")
|
||||||
|
} else {
|
||||||
|
self.key.clone()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.key.clone()
|
||||||
|
};
|
||||||
|
|
||||||
// Capture the records snapshot NOW (before we switch views).
|
// Capture the records snapshot NOW (before we switch views).
|
||||||
let records: Vec<(crate::model::cell::CellKey, crate::model::cell::CellValue)> =
|
let records: Vec<(crate::model::cell::CellKey, crate::model::cell::CellValue)> =
|
||||||
if self.key.0.is_empty() {
|
if drill_key.0.is_empty() {
|
||||||
ctx.model
|
ctx.model
|
||||||
.data
|
.data
|
||||||
.iter_cells()
|
.iter_cells()
|
||||||
@ -244,7 +313,7 @@ impl Cmd for DrillIntoCell {
|
|||||||
} else {
|
} else {
|
||||||
ctx.model
|
ctx.model
|
||||||
.data
|
.data
|
||||||
.matching_cells(&self.key.0)
|
.matching_cells(&drill_key.0)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| (k, v.clone()))
|
.map(|(k, v)| (k, v.clone()))
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
Reference in New Issue
Block a user