sea_orm_codegen/entity/writer/
dense.rs1use super::*;
2use crate::{Relation, RelationType};
3use heck::ToSnakeCase;
4
5impl EntityWriter {
6 #[allow(clippy::too_many_arguments)]
7 pub fn gen_dense_code_blocks(
8 entity: &Entity,
9 with_serde: &WithSerde,
10 column_option: &ColumnOption,
11 schema_name: &Option<String>,
12 serde_skip_deserializing_primary_key: bool,
13 serde_skip_hidden_column: bool,
14 model_extra_derives: &TokenStream,
15 model_extra_attributes: &TokenStream,
16 _column_extra_derives: &TokenStream,
17 _seaography: bool,
18 impl_active_model_behavior: bool,
19 ) -> Vec<TokenStream> {
20 let mut imports = Self::gen_import(with_serde);
21 let active_enums = Self::gen_import_active_enum(entity);
22 imports.extend(active_enums.imports);
23 let mut code_blocks = vec![
24 imports,
25 Self::gen_dense_model_struct(
26 entity,
27 with_serde,
28 column_option,
29 schema_name,
30 serde_skip_deserializing_primary_key,
31 serde_skip_hidden_column,
32 model_extra_derives,
33 model_extra_attributes,
34 &active_enums.type_idents,
35 ),
36 ];
37 if impl_active_model_behavior {
38 code_blocks.push(Self::impl_active_model_behavior());
39 }
40 code_blocks
41 }
42
43 #[allow(clippy::too_many_arguments)]
44 pub fn gen_dense_model_struct(
45 entity: &Entity,
46 with_serde: &WithSerde,
47 column_option: &ColumnOption,
48 schema_name: &Option<String>,
49 serde_skip_deserializing_primary_key: bool,
50 serde_skip_hidden_column: bool,
51 model_extra_derives: &TokenStream,
52 model_extra_attributes: &TokenStream,
53 active_enum_type_idents: &ActiveEnumTypeIdents,
54 ) -> TokenStream {
55 let table_name = entity.table_name.as_str();
56 let column_names_snake_case = entity.get_column_names_snake_case();
57 let column_rs_types = Self::get_column_rs_types_with_enum_idents(
58 entity,
59 column_option,
60 active_enum_type_idents,
61 );
62 let if_eq_needed = entity.get_eq_needed();
63 let primary_keys: Vec<String> = entity
64 .primary_keys
65 .iter()
66 .map(|pk| pk.name.clone())
67 .collect();
68 let attrs: Vec<TokenStream> = entity
69 .columns
70 .iter()
71 .map(|col| {
72 let mut attrs: Punctuated<_, Comma> = Punctuated::new();
73 let is_primary_key = primary_keys.contains(&col.name);
74 if !col.is_snake_case_name() {
75 let column_name = &col.name;
76 attrs.push(quote! { column_name = #column_name });
77 }
78 if is_primary_key {
79 attrs.push(quote! { primary_key });
80 if !col.auto_increment {
81 attrs.push(quote! { auto_increment = false });
82 }
83 }
84 if let Some(ts) = col.get_col_type_attrs() {
85 attrs.extend([ts]);
86 if !col.not_null {
87 attrs.push(quote! { nullable });
88 }
89 };
90 if col.unique {
91 attrs.push(quote! { unique });
92 } else if let Some(unique_key) = &col.unique_key {
93 attrs.push(quote! { unique_key = #unique_key });
94 }
95 let mut ts = quote! {};
96 if !attrs.is_empty() {
97 for (i, attr) in attrs.into_iter().enumerate() {
98 if i > 0 {
99 ts = quote! { #ts, };
100 }
101 ts = quote! { #ts #attr };
102 }
103 ts = quote! { #[sea_orm(#ts)] };
104 }
105 let serde_attribute = col.get_serde_attribute(
106 is_primary_key,
107 serde_skip_deserializing_primary_key,
108 serde_skip_hidden_column,
109 );
110 ts = quote! {
111 #ts
112 #serde_attribute
113 };
114 ts
115 })
116 .collect();
117 let schema_name = match Self::gen_schema_name(schema_name) {
118 Some(schema_name) => quote! {
119 schema_name = #schema_name,
120 },
121 None => quote! {},
122 };
123 let extra_derive = with_serde.extra_derive();
124
125 let mut compound_objects: Punctuated<_, Comma> = Punctuated::new();
126
127 let map_col = |a: &syn::Ident| -> String {
128 let a = a.to_string();
129 let b = a.to_snake_case();
130 if a != b.to_upper_camel_case() {
131 a
133 } else {
134 b
135 }
136 };
137 let map_punctuated = |punctuated: Vec<String>| -> String {
138 let len = punctuated.len();
139 let punctuated = punctuated.join(", ");
140 match len {
141 0..=1 => punctuated,
142 _ => format!("({punctuated})"),
143 }
144 };
145
146 let via_entities = entity.get_conjunct_relations_via_snake_case();
147 for rel in entity.relations.iter() {
148 if !rel.self_referencing && rel.impl_related {
149 let (rel_type, sea_orm_attr) = match rel.rel_type {
150 RelationType::HasOne => (format_ident!("HasOne"), quote!(#[sea_orm(has_one)])),
151 RelationType::HasMany => {
152 (format_ident!("HasMany"), quote!(#[sea_orm(has_many)]))
153 }
154 RelationType::BelongsTo => {
155 let (from, to) = rel.get_src_ref_columns(map_col, map_col, map_punctuated);
156 let on_update = if let Some(action) = &rel.on_update {
157 let action = Relation::get_foreign_key_action(action);
158 quote!(, on_update = #action)
159 } else {
160 quote!()
161 };
162 let on_delete = if let Some(action) = &rel.on_delete {
163 let action = Relation::get_foreign_key_action(action);
164 quote!(, on_delete = #action)
165 } else {
166 quote!()
167 };
168 let relation_enum = if rel.num_suffix > 0 {
169 let relation_enum = rel.get_enum_name().to_string();
170 quote!(relation_enum = #relation_enum,)
171 } else {
172 quote!()
173 };
174 (
175 format_ident!("HasOne"),
176 quote!(#[sea_orm(belongs_to, #relation_enum from = #from, to = #to #on_update #on_delete)]),
177 )
178 }
179 };
180
181 if let Some(to_entity) = rel.get_module_name()
182 && !via_entities.contains(&to_entity)
183 {
184 let field = if matches!(rel.rel_type, RelationType::HasMany) {
186 format_ident!(
187 "{}",
188 pluralizer::pluralize(&to_entity.to_string(), 2, false)
189 )
190 } else {
191 to_entity.clone()
192 };
193 let field = if rel.num_suffix == 0 {
194 field
195 } else {
196 format_ident!("{field}_{}", rel.num_suffix)
197 };
198 compound_objects.push(quote! {
199 #sea_orm_attr
200 pub #field: #rel_type<super::#to_entity::Entity>
201 });
202 }
203 } else if rel.self_referencing {
204 let (from, to) = rel.get_src_ref_columns(map_col, map_col, map_punctuated);
205 let on_update = if let Some(action) = &rel.on_update {
206 let action = Relation::get_foreign_key_action(action);
207 quote!(, on_update = #action)
208 } else {
209 quote!()
210 };
211 let on_delete = if let Some(action) = &rel.on_delete {
212 let action = Relation::get_foreign_key_action(action);
213 quote!(, on_delete = #action)
214 } else {
215 quote!()
216 };
217 let relation_enum = rel.get_enum_name().to_string();
218 let field = format_ident!(
219 "{}{}",
220 entity.get_table_name_snake_case_ident(),
221 if rel.num_suffix > 0 {
222 format!("_{}", rel.num_suffix)
223 } else {
224 "".into()
225 }
226 );
227
228 compound_objects.push(quote! {
229 #[sea_orm(self_ref, relation_enum = #relation_enum, from = #from, to = #to #on_update #on_delete)]
230 pub #field: HasOne<Entity>
231 });
232 }
233 }
234 for (to_entity, via_entity) in entity
235 .get_conjunct_relations_to_snake_case()
236 .into_iter()
237 .zip(via_entities)
238 {
239 let field = format_ident!(
240 "{}",
241 pluralizer::pluralize(&to_entity.to_string(), 2, false)
242 );
243 let via_entity = via_entity.to_string();
244 compound_objects.push(quote! {
245 #[sea_orm(has_many, via = #via_entity)]
246 pub #field: HasMany<super::#to_entity::Entity>
247 });
248 }
249
250 if !compound_objects.is_empty() {
251 compound_objects.push_punct(<syn::Token![,]>::default());
252 }
253
254 quote! {
255 #[sea_orm::model]
256 #[derive(Clone, Debug, PartialEq #if_eq_needed, DeriveEntityModel #extra_derive #model_extra_derives)]
257 #[sea_orm(
258 #schema_name
259 table_name = #table_name
260 )]
261 #model_extra_attributes
262 pub struct Model {
263 #(
264 #attrs
265 pub #column_names_snake_case: #column_rs_types,
266 )*
267 #compound_objects
268 }
269 }
270 }
271
272 #[allow(dead_code)]
273 fn gen_dense_related_entity(entity: &Entity) -> TokenStream {
274 let via_entities = entity.get_conjunct_relations_via_snake_case();
275
276 let related_modules = entity.get_related_entity_modules();
277 let related_attrs = entity.get_related_entity_attrs();
278 let related_enum_names = entity.get_related_entity_enum_name();
279
280 let items: Vec<_> = related_modules
281 .into_iter()
282 .zip(related_attrs)
283 .zip(related_enum_names)
284 .filter_map(|((related_module, related_attr), related_enum_name)| {
285 if !via_entities.contains(&related_module) {
286 Some(quote!(#related_attr #related_enum_name))
288 } else {
289 None
290 }
291 })
292 .collect();
293
294 quote! {
295 #[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
296 pub enum RelatedEntity {
297 #(#items),*
298 }
299 }
300 }
301}
302
303#[cfg(test)]
304mod test {
305 #[test]
306 #[ignore]
307 fn test_name() {
308 panic!("{}", pluralizer::pluralize("filling", 2, false));
309 }
310}