From c7015340537a206798a881305598684b5bdca9ba Mon Sep 17 00:00:00 2001 From: Edward Langley Date: Thu, 9 Apr 2026 14:24:39 -0700 Subject: [PATCH] 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) --- src/persistence/mod.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs index 9add417..c590703 100644 --- a/src/persistence/mod.rs +++ b/src/persistence/mod.rs @@ -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 = Vec::new(); let mut grouped: Vec = 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 { 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())); + } } } }