use toasty::stmt::Path;
pub(crate) use crate::toasty_compat::model::{EnumShape, LeafField};
use crate::{
DeclarationErrorKind,
toasty_compat::model::{self, AppSchema, ModelPath},
};
#[derive(Debug, Clone)]
pub(crate) struct Binding {
placeholder: String,
leaf: Result<LeafField, DeclarationErrorKind>,
root: Option<String>,
}
impl Binding {
pub(crate) fn of<M, T>(path: &Path<M, T>) -> Self
where
M: toasty::schema::Model,
{
let path = ModelPath::of(path);
Self {
placeholder: format!("{:?}", path.steps()),
leaf: resolve::<M>(&path),
root: model::root_field::<M>(&path),
}
}
pub(crate) fn refused<M, T>(path: &Path<M, T>, error: DeclarationErrorKind) -> Self {
Self {
placeholder: format!("{:?}", ModelPath::of(path).steps()),
leaf: Err(error),
root: None,
}
}
pub(crate) fn named(name: String, label: crate::Text) -> Self {
Self {
placeholder: String::new(),
leaf: Ok(LeafField {
name,
label,
nullable: true,
unique: false,
unique_with: Vec::new(),
}),
root: None,
}
}
fn leaf(&self) -> Option<&LeafField> {
self.leaf.as_ref().ok()
}
pub(crate) fn name(&self) -> &str {
self.leaf().map_or(&self.placeholder, |leaf| &leaf.name)
}
pub(crate) fn label(&self) -> crate::Text {
self.leaf()
.map_or_else(|| crate::Text::from(""), |leaf| leaf.label.clone())
}
pub(crate) fn nullable(&self) -> bool {
self.leaf().is_none_or(|leaf| leaf.nullable)
}
pub(crate) fn unique(&self) -> bool {
self.leaf().is_some_and(|leaf| leaf.unique)
}
pub(crate) fn unique_with(&self) -> &[Vec<String>] {
self.leaf().map_or(&[], |leaf| &leaf.unique_with)
}
pub(crate) fn reads<M>(&self) -> crate::lens::Reads<M> {
match &self.root {
Some(root) => crate::lens::Reads::nothing().named(root.clone()),
None => crate::lens::Reads::nothing(),
}
}
pub(crate) fn misdeclared(&self) -> Option<DeclarationErrorKind> {
self.leaf.as_ref().err().cloned()
}
}
pub(crate) fn resolve<M>(path: &ModelPath) -> Result<LeafField, DeclarationErrorKind>
where
M: toasty::schema::Model,
{
let model = std::any::type_name::<M>();
if !path.is_embedded() {
return model::single_field::<M>(path);
}
let schema = AppSchema::of_model::<M>()
.map_err(|error| DeclarationErrorKind::Uncompiled { model, error })?;
model::embedded_leaf(&schema, path, model)
}
pub(crate) fn resolve_enum<M, T>(
path: &Path<M, T>,
) -> Result<Option<EnumShape>, DeclarationErrorKind>
where
M: toasty::schema::Model,
{
let model = std::any::type_name::<M>();
let schema = AppSchema::of_model::<M>()
.map_err(|error| DeclarationErrorKind::Uncompiled { model, error })?;
Ok(model::embedded_enum(&schema, &ModelPath::of(path)))
}
#[doc(hidden)]
pub fn form_key<M, T>(path: impl Into<Path<M, T>>) -> String
where
M: toasty::schema::Model,
{
Binding::of(&path.into()).name().to_string()
}
#[cfg(test)]
mod tests;