ormlite_macro/codegen/
common.rs1use crate::MetadataCache;
2use itertools::Itertools;
3use ormlite_attr::ColumnMeta;
4use ormlite_attr::Ident;
5use ormlite_attr::ModelMeta;
6use ormlite_attr::TableMeta;
7use ormlite_attr::{InnerType, Type};
8use ormlite_core::query_builder::Placeholder;
9use proc_macro2::TokenStream;
10use quote::{quote, ToTokens};
11use std::borrow::Cow;
12
13pub fn generate_conditional_bind(c: &ColumnMeta) -> TokenStream {
14 let name = &c.ident;
15 if c.is_join() {
16 quote! {
17 if let Some(value) = self.#name {
18 q = q.bind(value._id());
19 }
20 }
21 } else if c.json {
22 if c.is_option() {
23 quote! {
24 if let Some(value) = self.#name {
25 q = q.bind(value.map(::ormlite::types::Json));
26 }
27 }
28 } else {
29 quote! {
30 if let Some(value) = self.#name {
31 q = q.bind(::ormlite::types::Json(value));
32 }
33 }
34 }
35 } else {
36 quote! {
37 if let Some(value) = self.#name {
38 q = q.bind(value);
39 }
40 }
41 }
42}
43
44fn ty_is_string(ty: &syn::Type) -> bool {
46 let p = match ty {
47 syn::Type::Path(p) => p,
48 _ => return false,
49 };
50 p.path.segments.last().map(|s| s.ident == "String").unwrap_or(false)
51}
52
53fn recursive_primitive_types_ty<'a>(ty: &'a Type, cache: &'a MetadataCache) -> Vec<Cow<'a, InnerType>> {
54 match ty {
55 Type::Option(ty) => recursive_primitive_types_ty(ty, cache),
56 Type::Vec(ty) => {
57 let inner = recursive_primitive_types_ty(ty, cache);
58 let inner = inner.into_iter().next().expect("Vec must have inner type");
59 let inner: InnerType = inner.into_owned();
60 vec![Cow::Owned(InnerType {
61 path: vec![],
62 ident: Ident::from("Vec"),
63 args: Some(Box::new(inner)),
64 })]
65 }
66 Type::Inner(p) => vec![Cow::Borrowed(p)],
67 Type::Join(j) => {
68 let joined = cache.get(&j.inner_type_name()).expect("Join type not found");
69 recursive_primitive_types(joined, cache)
70 }
71 }
72}
73
74fn recursive_primitive_types<'a>(table: &'a ModelMeta, cache: &'a MetadataCache) -> Vec<Cow<'a, InnerType>> {
75 table
76 .columns
77 .iter()
78 .map(|c| recursive_primitive_types_ty(&c.ty, cache))
79 .flatten()
80 .collect()
81}
82
83pub(crate) fn table_primitive_types<'a>(attr: &'a TableMeta, cache: &'a MetadataCache) -> Vec<Cow<'a, InnerType>> {
84 attr.columns
85 .iter()
86 .filter(|c| !c.skip)
87 .filter(|c| !c.json)
88 .map(|c| recursive_primitive_types_ty(&c.ty, cache))
89 .flatten()
90 .unique()
91 .collect()
92}
93
94pub fn from_row_bounds<'a>(
95 db: &dyn OrmliteCodegen,
96 attr: &'a TableMeta,
97 cache: &'a MetadataCache,
98) -> impl Iterator<Item = TokenStream> + 'a {
99 let database = db.database_ts();
100 table_primitive_types(attr, cache).into_iter().map(move |ty| {
101 quote! {
102 #ty: ::ormlite::decode::Decode<'a, #database>,
103 #ty: ::ormlite::types::Type<#database>,
104 }
105 })
106}
107
108fn is_vec(p: &syn::Path) -> bool {
109 let Some(segment) = p.segments.last() else {
110 return false;
111 };
112 segment.ident == "Vec"
113}
114
115pub fn insertion_binding(c: &ColumnMeta) -> TokenStream {
120 let name = &c.ident;
121 if c.is_join() {
122 quote! {
123 q = q.bind(#name._id());
124 }
125 } else if c.json {
126 if c.is_option() {
127 quote! {
128 q = q.bind(model.#name.map(::ormlite::types::Json));
129 }
130 } else {
131 quote! {
132 q = q.bind(::ormlite::types::Json(model.#name));
133 }
134 }
135 } else {
136 quote! {
137 q = q.bind(model.#name);
138 }
139 }
140}
141
142pub trait OrmliteCodegen {
143 fn dialect_ts(&self) -> TokenStream;
144 fn database_ts(&self) -> TokenStream;
145 fn placeholder_ts(&self) -> TokenStream;
146 fn placeholder(&self) -> Placeholder;
149 fn row(&self) -> TokenStream;
150}