ormlite_attr/metadata/
model.rs

1use crate::metadata::column::ColumnMeta;
2use crate::metadata::table::TableMeta;
3use crate::Ident;
4use crate::TableAttr;
5use syn::DeriveInput;
6
7/// Metadata used for IntoArguments, TableMeta, and (subset of) Model
8#[derive(Debug, Clone)]
9pub struct ModelMeta {
10    pub table: TableMeta,
11    pub insert_struct: Option<Ident>,
12    pub extra_derives: Option<Vec<Ident>>,
13    pub pkey: ColumnMeta,
14}
15
16impl ModelMeta {
17    pub fn builder_struct(&self) -> Ident {
18        Ident::from(format!("{}Builder", self.ident.as_ref()))
19    }
20
21    pub fn database_columns_except_pkey(&self) -> impl Iterator<Item = &ColumnMeta> + '_ {
22        self.columns
23            .iter()
24            .filter(|&c| !c.skip)
25            .filter(|&c| self.pkey.name != c.name)
26    }
27
28    pub fn from_derive(ast: &DeriveInput) -> Self {
29        let attrs = TableAttr::from_attrs(&ast.attrs);
30        let table = TableMeta::new(ast, &attrs);
31        let pkey = table.pkey.as_deref().expect(&format!(
32            "No column marked with #[ormlite(primary_key)], and no column named id, uuid, {0}_id, or {0}_uuid",
33            table.name,
34        ));
35        let mut insert_struct = None;
36        let mut extra_derives: Option<Vec<syn::Ident>> = None;
37        for attr in attrs {
38            if let Some(v) = attr.insert {
39                insert_struct = Some(v.value());
40            }
41            if let Some(v) = attr.insertable {
42                insert_struct = Some(v.to_string());
43            }
44            if let Some(v) = attr.extra_derives {
45                if !v.is_empty() {
46                    extra_derives = Some(v);
47                }
48            }
49        }
50        let pkey = table.columns.iter().find(|&c| c.name == pkey).unwrap().clone();
51        let insert_struct = insert_struct.map(|v| Ident::from(v));
52        let extra_derives = extra_derives.take().map(|vec| vec.into_iter().map(|v| v.to_string()).map(Ident::from).collect());
53        
54        Self {
55            table,
56            insert_struct,
57            extra_derives, 
58            pkey,
59        }
60    }
61
62    #[doc(hidden)]
63    pub fn mock(name: &str, columns: Vec<ColumnMeta>) -> Self {
64        let inner = TableMeta::mock(name, columns);
65        Self {
66            pkey: inner.columns.iter().find(|c| c.name == "id").unwrap().clone(),
67            table: inner,
68            extra_derives: None,
69            insert_struct: None,
70        }
71    }
72}
73
74impl std::ops::Deref for ModelMeta {
75    type Target = TableMeta;
76
77    fn deref(&self) -> &Self::Target {
78        &self.table
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use syn::ItemStruct;
86
87    #[test]
88    fn test_decode_metadata() {
89        let ast = syn::parse_str::<ItemStruct>(
90            r#"struct User {
91            #[ormlite(column = "Id")]
92            id: i32,
93        }"#,
94        )
95        .unwrap();
96        let input = DeriveInput::from(ast);
97        let meta = ModelMeta::from_derive(&input);
98        assert_eq!(meta.pkey.name, "Id");
99    }
100}