use polars::prelude::*;
use crate::error::Result;
use crate::manifest::{Axis, PathSpec};
pub fn level_col(i: usize) -> String {
format!("__lvl{i}")
}
fn split_expr(spec: &PathSpec) -> Expr {
col(spec.column.as_str()).str().split(lit(spec.sep.clone()))
}
pub fn path_depth(spec: &PathSpec, base: &LazyFrame) -> Result<usize> {
let df = base
.clone()
.select([split_expr(spec).list().len().max().alias("_d")])
.collect()?;
let d = df
.column("_d")
.ok()
.and_then(|c| c.get(0).ok())
.and_then(|av| crate::output::av_to_f64(&av.into_static()))
.map(|f| f as usize)
.unwrap_or(0);
Ok(d.max(1))
}
pub fn derived_levels(depth: usize) -> Vec<String> {
(0..depth).map(level_col).collect()
}
pub fn with_level_cols(spec: &PathSpec, lf: LazyFrame, depth: usize) -> LazyFrame {
let parts = split_expr(spec);
let cols: Vec<Expr> = (0..depth)
.map(|i| {
parts
.clone()
.list()
.get(lit(i as i64), true)
.alias(&level_col(i))
})
.collect();
lf.with_columns(cols)
}
pub fn resolved_levels(axis: &Axis, lf: LazyFrame) -> Result<(Vec<String>, LazyFrame)> {
match &axis.path {
Some(spec) => {
let d = path_depth(spec, &lf)?;
let levels = derived_levels(d);
let lf = with_level_cols(spec, lf, d);
Ok((levels, lf))
}
None => Ok((axis.levels.clone(), lf)),
}
}