ormlite_attr/metadata/
table.rs1use crate::metadata::column::ColumnMeta;
2use crate::DeriveInputExt;
3use crate::Ident;
4use convert_case::{Case, Casing};
5use structmeta::StructMeta;
6use syn::{Attribute, DeriveInput, LitStr};
7
8#[derive(Debug, Clone)]
11pub struct TableMeta {
12 pub name: String,
13 pub ident: Ident,
14 pub columns: Vec<ColumnMeta>,
15 pub databases: Vec<String>,
16
17 pub pkey: Option<String>,
20}
21
22impl TableMeta {
23 pub fn new(ast: &DeriveInput, attrs: &[TableAttr]) -> Self {
24 let ident = &ast.ident;
25 let name = if let Some(value) = attrs.iter().find_map(|a| a.table.as_ref()) {
26 value.value()
27 } else {
28 ident.to_string().to_case(Case::Snake)
29 };
30 let mut columns = ColumnMeta::from_fields(ast.fields());
31 let mut pkey = columns
32 .iter()
33 .find(|&c| c.marked_primary_key)
34 .map(|c| c.clone())
35 .map(|c| c.name.clone());
36 if pkey.is_none() {
37 let candidates = sql::util::pkey_column_names(&name);
38 if let Some(c) = columns.iter_mut().find(|c| candidates.iter().any(|n| c.ident == n)) {
39 c.has_database_default = true;
40 pkey = Some(c.name.clone());
41 }
42 }
43 let databases = attrs.iter().flat_map(|d| &d.database).map(|d| d.value()).collect();
44 Self {
45 name,
46 ident: Ident::from(ident),
47 columns,
48 databases,
49 pkey,
50 }
51 }
52
53 pub fn from_derive(ast: &DeriveInput) -> Self {
54 let attr = TableAttr::from_attrs(&ast.attrs);
55 Self::new(ast, &attr)
56 }
57
58 pub fn all_fields(&self) -> impl Iterator<Item = &Ident> + '_ {
59 self.columns.iter().map(|c| &c.ident)
60 }
61
62 pub fn database_columns(&self) -> impl Iterator<Item = &ColumnMeta> + '_ {
63 self.columns
64 .iter()
65 .filter(|&c| !c.skip)
66 .filter(|&c| !c.is_join() || c.is_join_one())
67 }
68
69 pub fn many_to_one_joins(&self) -> impl Iterator<Item = &ColumnMeta> + '_ {
70 self.columns.iter().filter(|&c| c.is_join_one())
71 }
72
73 #[allow(dead_code)]
74 pub(crate) fn mock(name: &str, columns: Vec<ColumnMeta>) -> Self {
75 TableMeta {
76 name: name.to_string(),
77 ident: Ident::from(name.to_case(Case::Pascal)),
78 pkey: None,
79 columns,
80 databases: vec![],
81 }
82 }
83}
84
85#[derive(StructMeta)]
87pub struct TableAttr {
88 pub table: Option<LitStr>,
95
96 pub insertable: Option<syn::Ident>,
99
100 pub insert: Option<LitStr>,
108
109 pub extra_derives: Option<Vec<syn::Ident>>,
117
118 pub returns: Option<LitStr>,
123
124 pub database: Option<LitStr>,
138}
139
140impl TableAttr {
141 pub fn from_attrs(attrs: &[Attribute]) -> Vec<Self> {
142 attrs
143 .iter()
144 .filter(|&a| a.path().is_ident("ormlite"))
145 .map(|a| a.parse_args().unwrap())
146 .collect()
147 }
148}