use crate::block_manager::schema_manager::field_type::{FieldAggregate, PivotColumn};
use crate::block_manager::schema_manager::schema::Schema;
use crate::controller::status::Status;
use crate::errors::{Error, Result};
pub fn check_pivot_field_conflicts(status: &Status) -> Result<()> {
for (sheet_id, sheet_nav) in status.navigator.sheet_navs.iter() {
for (block_id, place) in sheet_nav.data.blocks.iter() {
let Some(schema_for_check) = status
.block_schema_manager
.schemas
.get(&(*sheet_id, *block_id))
else {
continue;
};
if place.pivot.is_none() {
if let Some(field) = first_field(schema_for_check, |_, pivot| pivot.is_some()) {
return Err(Error::PayloadError(format!(
"block {block_id} is not a pivot, so its field \"{field}\" cannot \
declare a pivot column. Make the block a pivot or drop the \
declaration."
)));
}
continue;
}
let Some(schema) = status
.block_schema_manager
.schemas
.get(&(*sheet_id, *block_id))
else {
continue;
};
if let Some(field) = first_field(schema, |agg, _| agg.is_some()) {
return Err(Error::PayloadError(format!(
"block {block_id} is a pivot, so its field \"{field}\" is a \
column of the pivot and computes from the pivot recipe — \
it cannot also declare its own aggregate. Drop one of the \
two."
)));
}
}
}
Ok(())
}
fn first_field<P>(schema: &Schema, pred: P) -> Option<String>
where
P: Fn(Option<&FieldAggregate>, Option<&PivotColumn>) -> bool,
{
match schema {
Schema::RowSchema(s) => s
.fields
.iter()
.find(|(_, e)| pred(e.aggregate.as_ref(), e.pivot_column.as_ref()))
.map(|(n, _)| n.clone()),
Schema::ColSchema(s) => s
.fields
.iter()
.find(|(_, e)| pred(e.aggregate.as_ref(), e.pivot_column.as_ref()))
.map(|(n, _)| n.clone()),
Schema::RandomSchema(_) => None,
}
}