use std::collections::HashSet;
use crate::{
DeclarationError, DeclarationErrorKind, EditableColumnFault, Site,
column::Editor,
form::RecordForm,
resource::{Mounted, Resource},
schema::fields::Field,
};
pub(super) fn check<R: Resource>(declared: &Mounted<R>, errors: &mut Vec<DeclarationError>) {
let form = &declared.form;
let guarded: HashSet<String> = form
.condition_watchers()
.into_iter()
.filter_map(|(_, guarded)| guarded)
.collect();
for column in declared.table.declared_columns() {
let Some(editor) = column.internals().edits() else {
continue;
};
let name = column.name();
let field = form.fields().find(|field| field.name() == name);
let fault = match field {
_ if !<R::Form as RecordForm>::HAS_FORM => EditableColumnFault::NoForm,
None => EditableColumnFault::Unplaced,
Some(field) if !edits_with(field, editor) => {
EditableColumnFault::OtherControl(editor.control())
}
Some(field)
if editor == Editor::Select
&& !offers(field, &column.internals().edit_options()) =>
{
EditableColumnFault::OtherOptions
}
Some(_) if guarded.contains(name) => EditableColumnFault::Conditional,
Some(field) if field.is_disabled(true) => EditableColumnFault::Disabled,
Some(_) => continue,
};
errors.push(DeclarationError::of::<R>(
Site::Table,
DeclarationErrorKind::EditableColumn {
column: name.to_string(),
fault,
},
));
}
}
fn edits_with(field: &Field, editor: Editor) -> bool {
match editor {
Editor::Toggle => field.is_checkbox(),
Editor::Select => field
.as_choice()
.is_some_and(|choice| !choice.is_relationship() && !choice.is_multiple()),
Editor::Text => field.as_text().is_some_and(|text| text.is_one_line()),
}
}
fn offers(field: &Field, options: &[(String, crate::Text)]) -> bool {
field
.as_choice()
.is_some_and(|choice| choice.static_options() == options)
}