refactor(persistence): improve Markdown formula and category handling

Update persistence logic for formulas and categories.

- Formulas targeting `_Measure` no longer include the category suffix in
  Markdown.
- `_Measure` items are now excluded from the category section in Markdown
  to avoid duplication with the formulas section.
- Improved Markdown parsing to correctly handle formulas without an
  explicit category suffix, defaulting them to `_Measure` .
- Added logic to skip virtual index and dimension categories during
  persistence.

Co-Authored-By: fiddlerwoaroof/git-smart-commit (unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q5_K_XL)
This commit is contained in:
Edward Langley
2026-04-09 14:24:39 -07:00
parent 7fea5f67ed
commit c701534053

View File

@ -205,16 +205,38 @@ pub fn format_md(model: &Model) -> String {
if !model.formulas().is_empty() {
w!(out, "\n## Formulas");
for f in model.formulas() {
w!(out, "- {} [{}]", f.raw, f.target_category);
if f.target_category == "_Measure" {
w!(out, "- {}", f.raw);
} else {
w!(out, "- {} [{}]", f.raw, f.target_category);
}
}
}
// ── Categories (items comma-separated on one line) ───────────────
// Collect formula targets so we can exclude them from _Measure items
let formula_targets: std::collections::HashSet<&str> = model
.formulas()
.iter()
.filter(|f| f.target_category == "_Measure")
.map(|f| f.target.as_str())
.collect();
for cat in model.categories.values() {
use crate::model::category::CategoryKind;
// Skip _Index and _Dim — they are fully virtual, never persisted
if matches!(cat.kind, CategoryKind::VirtualIndex | CategoryKind::VirtualDim) {
continue;
}
w!(out, "\n## Category: {}", cat.name);
let mut bare: Vec<String> = Vec::new();
let mut grouped: Vec<String> = Vec::new();
for item in cat.items.values() {
// For _Measure, skip items that are formula targets
// (they'll be recreated from the ## Formulas section)
if cat.kind == CategoryKind::VirtualMeasure && formula_targets.contains(item.name.as_str()) {
continue;
}
match &item.group {
Some(g) => grouped.push(format!("{}[{}]", quote_name(&item.name), quote_name(g))),
None => bare.push(quote_name(&item.name)),
@ -372,8 +394,13 @@ pub fn parse_md(text: &str) -> Result<Model> {
raw[..i].to_string(),
raw[i + 2..raw.len() - 1].to_string(),
));
continue;
}
}
// No [Category] suffix — default to _Measure
if !raw.is_empty() && raw.contains('=') {
formulas.push((raw, "_Measure".to_string()));
}
}
}
}