floe_core/checks/
not_null.rs

1use polars::prelude::DataFrame;
2
3use crate::{ConfigError, FloeResult};
4use super::RowError;
5
6pub fn not_null_errors(
7    df: &DataFrame,
8    required_cols: &[String],
9) -> FloeResult<Vec<Vec<RowError>>> {
10    let mut errors_per_row = vec![Vec::new(); df.height()];
11    if required_cols.is_empty() {
12        return Ok(errors_per_row);
13    }
14
15    let mut null_masks = Vec::with_capacity(required_cols.len());
16    for name in required_cols {
17        let mask = df
18            .column(name)
19            .map_err(|err| {
20                Box::new(ConfigError(format!(
21                    "required column {name} not found: {err}"
22                )))
23            })?
24            .is_null();
25        null_masks.push(mask);
26    }
27
28    for row_idx in 0..df.height() {
29        for (col, mask) in required_cols.iter().zip(null_masks.iter()) {
30            if mask.get(row_idx).unwrap_or(false) {
31                errors_per_row[row_idx].push(RowError::new(
32                    "not_null",
33                    col,
34                    "required value missing",
35                ));
36            }
37        }
38    }
39
40    Ok(errors_per_row)
41}