floe_core/checks/
not_null.rs1use 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}