use std::sync::Arc;
use derive_where::derive_where;
use topcoat::{context::Cx, view::*};
use super::{Column, ColumnBase, ColumnWidth};
use crate::{
Lens,
schema::{EmbeddedForm, Schema},
values::FormValues,
};
#[derive_where(Clone, Debug)]
pub struct EmbeddedColumn<M, T> {
lens: Lens<M, T>,
base: ColumnBase,
schema: Arc<Schema>,
}
impl<M, T> EmbeddedColumn<M, T>
where
M: toasty::schema::Model,
T: EmbeddedForm,
{
pub fn new(lens: Lens<M, T>) -> Self {
Self {
base: ColumnBase::new(lens.path(), ColumnWidth::Grow),
schema: Arc::new(T::build_schema(lens.path().clone())),
lens,
}
}
base_builders!();
fn spelled(&self, row: &M) -> (&Schema, FormValues) {
let mut values = FormValues::new();
self.lens
.read(row)
.write_node(self.schema.embedded_root(), &mut values);
(&self.schema, values)
}
}
impl<M, T> Column<M> for EmbeddedColumn<M, T>
where
M: toasty::schema::Model + Send + Sync + 'static,
T: EmbeddedForm + Send + Sync + 'static,
{
base_column_methods!();
fn text(&self, cx: &Cx, row: &M) -> String {
let (schema, values) = self.spelled(row);
schema
.embedded_root()
.shown(&schema.fields, &values)
.into_iter()
.filter_map(|index| {
let field = &schema.fields[index];
let value = values.text(field.name()).unwrap_or_default();
let read = field.read(cx, value)?;
Some(format!("{}: {read}", field.label().localize(cx)))
})
.collect::<Vec<_>>()
.join(", ")
}
fn entry<'a>(&self, cx: &'a Cx, row: &M) -> BoxView<'a> {
let (schema, values) = self.spelled(row);
schema.embedded_root().display(cx, &schema.fields, &values)
}
}
impl<M, T> crate::column::ColumnInternals<M> for EmbeddedColumn<M, T>
where
M: toasty::schema::Model + Send + Sync + 'static,
T: EmbeddedForm + Send + Sync + 'static,
{
base_internals!();
fn misdeclared(&self) -> Option<crate::DeclarationErrorKind> {
if let Some(error) = self.base.binding.misdeclared() {
return Some(error);
}
self.schema.declaration_errors().into_iter().next()
}
}