Skip to main content

sea_orm_codegen/entity/
writer.rs

1use crate::{ActiveEnum, ColumnOption, Entity, util::escape_rust_keyword};
2use heck::ToUpperCamelCase;
3use proc_macro2::TokenStream;
4use quote::{format_ident, quote};
5use std::{collections::BTreeMap, str::FromStr};
6use syn::{punctuated::Punctuated, token::Comma};
7use tracing::info;
8
9mod compact;
10mod dense;
11mod expanded;
12mod frontend;
13mod mermaid;
14
15#[derive(Clone, Debug)]
16pub struct EntityWriter {
17    pub(crate) entities: Vec<Entity>,
18    pub(crate) enums: BTreeMap<String, ActiveEnum>,
19}
20
21pub struct WriterOutput {
22    pub files: Vec<OutputFile>,
23}
24
25pub struct OutputFile {
26    pub name: String,
27    pub content: String,
28}
29
30#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
31pub enum WithPrelude {
32    #[default]
33    All,
34    None,
35    AllAllowUnusedImports,
36}
37
38#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
39pub enum WithSerde {
40    #[default]
41    None,
42    Serialize,
43    Deserialize,
44    Both,
45}
46
47#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
48pub enum DateTimeCrate {
49    #[default]
50    Chrono,
51    Time,
52}
53
54#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
55pub enum BigIntegerType {
56    #[default]
57    I64,
58    I32,
59}
60
61#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
62pub enum EntityFormat {
63    #[default]
64    Compact,
65    Expanded,
66    Frontend,
67    Dense,
68}
69
70#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
71pub enum BannerVersion {
72    Off,
73    Major,
74    #[default]
75    Minor,
76    Patch,
77}
78
79#[derive(Debug)]
80pub struct EntityWriterContext {
81    pub(crate) entity_format: EntityFormat,
82    pub(crate) with_prelude: WithPrelude,
83    pub(crate) with_serde: WithSerde,
84    pub(crate) with_copy_enums: bool,
85    pub(crate) date_time_crate: DateTimeCrate,
86    pub(crate) big_integer_type: BigIntegerType,
87    pub(crate) schema_name: Option<String>,
88    pub(crate) lib: bool,
89    pub(crate) serde_skip_hidden_column: bool,
90    pub(crate) serde_skip_deserializing_primary_key: bool,
91    pub(crate) model_extra_derives: TokenStream,
92    pub(crate) model_extra_attributes: TokenStream,
93    pub(crate) enum_extra_derives: TokenStream,
94    pub(crate) enum_extra_attributes: TokenStream,
95    pub(crate) column_extra_derives: TokenStream,
96    pub(crate) seaography: bool,
97    pub(crate) impl_active_model_behavior: bool,
98    pub(crate) banner_version: BannerVersion,
99}
100
101impl WithSerde {
102    pub fn extra_derive(&self) -> TokenStream {
103        let mut extra_derive = match self {
104            Self::None => {
105                quote! {}
106            }
107            Self::Serialize => {
108                quote! {
109                    Serialize
110                }
111            }
112            Self::Deserialize => {
113                quote! {
114                    Deserialize
115                }
116            }
117            Self::Both => {
118                quote! {
119                    Serialize, Deserialize
120                }
121            }
122        };
123        if !extra_derive.is_empty() {
124            extra_derive = quote! { , #extra_derive }
125        }
126        extra_derive
127    }
128}
129
130/// Converts *_extra_derives argument to token stream
131pub(crate) fn bonus_derive<T, I>(extra_derives: I) -> TokenStream
132where
133    T: Into<String>,
134    I: IntoIterator<Item = T>,
135{
136    extra_derives.into_iter().map(Into::<String>::into).fold(
137        TokenStream::default(),
138        |acc, derive| {
139            let tokens: TokenStream = derive.parse().unwrap();
140            quote! { #acc, #tokens }
141        },
142    )
143}
144
145/// convert *_extra_attributes argument to token stream
146pub(crate) fn bonus_attributes<T, I>(attributes: I) -> TokenStream
147where
148    T: Into<String>,
149    I: IntoIterator<Item = T>,
150{
151    attributes.into_iter().map(Into::<String>::into).fold(
152        TokenStream::default(),
153        |acc, attribute| {
154            let tokens: TokenStream = attribute.parse().unwrap();
155            quote! {
156                #acc
157                #[#tokens]
158            }
159        },
160    )
161}
162
163impl FromStr for WithPrelude {
164    type Err = crate::Error;
165
166    fn from_str(s: &str) -> Result<Self, Self::Err> {
167        Ok(match s {
168            "none" => Self::None,
169            "all-allow-unused-imports" => Self::AllAllowUnusedImports,
170            "all" => Self::All,
171            v => {
172                return Err(crate::Error::TransformError(format!(
173                    "Unsupported enum variant '{v}'"
174                )));
175            }
176        })
177    }
178}
179
180impl FromStr for EntityFormat {
181    type Err = crate::Error;
182
183    fn from_str(s: &str) -> Result<Self, Self::Err> {
184        Ok(match s {
185            "compact" => Self::Compact,
186            "expanded" => Self::Expanded,
187            "frontend" => Self::Frontend,
188            "dense" => Self::Dense,
189            v => {
190                return Err(crate::Error::TransformError(format!(
191                    "Unsupported enum variant '{v}'"
192                )));
193            }
194        })
195    }
196}
197
198impl FromStr for WithSerde {
199    type Err = crate::Error;
200
201    fn from_str(s: &str) -> Result<Self, Self::Err> {
202        Ok(match s {
203            "none" => Self::None,
204            "serialize" => Self::Serialize,
205            "deserialize" => Self::Deserialize,
206            "both" => Self::Both,
207            v => {
208                return Err(crate::Error::TransformError(format!(
209                    "Unsupported enum variant '{v}'"
210                )));
211            }
212        })
213    }
214}
215
216impl EntityWriterContext {
217    #[allow(clippy::too_many_arguments)]
218    pub fn new(
219        entity_format: EntityFormat,
220        with_prelude: WithPrelude,
221        with_serde: WithSerde,
222        with_copy_enums: bool,
223        date_time_crate: DateTimeCrate,
224        big_integer_type: BigIntegerType,
225        schema_name: Option<String>,
226        lib: bool,
227        serde_skip_deserializing_primary_key: bool,
228        serde_skip_hidden_column: bool,
229        model_extra_derives: Vec<String>,
230        model_extra_attributes: Vec<String>,
231        enum_extra_derives: Vec<String>,
232        enum_extra_attributes: Vec<String>,
233        column_extra_derives: Vec<String>,
234        seaography: bool,
235        impl_active_model_behavior: bool,
236        banner_version: BannerVersion,
237    ) -> Self {
238        Self {
239            entity_format,
240            with_prelude,
241            with_serde,
242            with_copy_enums,
243            date_time_crate,
244            big_integer_type,
245            schema_name,
246            lib,
247            serde_skip_deserializing_primary_key,
248            serde_skip_hidden_column,
249            model_extra_derives: bonus_derive(model_extra_derives),
250            model_extra_attributes: bonus_attributes(model_extra_attributes),
251            enum_extra_derives: bonus_derive(enum_extra_derives),
252            enum_extra_attributes: bonus_attributes(enum_extra_attributes),
253            column_extra_derives: bonus_derive(column_extra_derives),
254            seaography,
255            impl_active_model_behavior,
256            banner_version,
257        }
258    }
259
260    fn column_option(&self) -> ColumnOption {
261        ColumnOption {
262            date_time_crate: self.date_time_crate,
263            big_integer_type: self.big_integer_type,
264        }
265    }
266}
267
268impl EntityWriter {
269    pub fn generate(self, context: &EntityWriterContext) -> WriterOutput {
270        let mut files = Vec::new();
271        files.extend(self.write_entities(context));
272        let with_prelude = context.with_prelude != WithPrelude::None;
273        files.push(self.write_index_file(
274            context.lib,
275            with_prelude,
276            context.seaography,
277            context.banner_version,
278        ));
279        if with_prelude {
280            files.push(self.write_prelude(
281                context.with_prelude,
282                context.entity_format,
283                context.banner_version,
284            ));
285        }
286        if !self.enums.is_empty() {
287            files.push(self.write_sea_orm_active_enums(
288                &context.with_serde,
289                context.with_copy_enums,
290                &context.enum_extra_derives,
291                &context.enum_extra_attributes,
292                context.entity_format,
293                context.banner_version,
294            ));
295        }
296        WriterOutput { files }
297    }
298
299    pub fn write_entities(&self, context: &EntityWriterContext) -> Vec<OutputFile> {
300        self.entities
301            .iter()
302            .map(|entity| {
303                let entity_file = format!("{}.rs", entity.get_table_name_snake_case());
304                let column_info = entity
305                    .columns
306                    .iter()
307                    .map(|column| column.get_info(&context.column_option()))
308                    .collect::<Vec<String>>();
309                // Serde must be enabled to use this
310                let serde_skip_deserializing_primary_key = context
311                    .serde_skip_deserializing_primary_key
312                    && matches!(context.with_serde, WithSerde::Both | WithSerde::Deserialize);
313                let serde_skip_hidden_column = context.serde_skip_hidden_column
314                    && matches!(
315                        context.with_serde,
316                        WithSerde::Both | WithSerde::Serialize | WithSerde::Deserialize
317                    );
318
319                info!("Generating {}", entity_file);
320                for info in column_info.iter() {
321                    info!("    > {}", info);
322                }
323
324                let mut lines = Vec::new();
325                Self::write_doc_comment(&mut lines, context.banner_version);
326                let code_blocks = if context.entity_format == EntityFormat::Frontend {
327                    Self::gen_frontend_code_blocks(
328                        entity,
329                        &context.with_serde,
330                        &context.column_option(),
331                        &context.schema_name,
332                        serde_skip_deserializing_primary_key,
333                        serde_skip_hidden_column,
334                        &context.model_extra_derives,
335                        &context.model_extra_attributes,
336                        &context.column_extra_derives,
337                        context.seaography,
338                        context.impl_active_model_behavior,
339                    )
340                } else if context.entity_format == EntityFormat::Expanded {
341                    Self::gen_expanded_code_blocks(
342                        entity,
343                        &context.with_serde,
344                        &context.column_option(),
345                        &context.schema_name,
346                        serde_skip_deserializing_primary_key,
347                        serde_skip_hidden_column,
348                        &context.model_extra_derives,
349                        &context.model_extra_attributes,
350                        &context.column_extra_derives,
351                        context.seaography,
352                        context.impl_active_model_behavior,
353                    )
354                } else if context.entity_format == EntityFormat::Dense {
355                    Self::gen_dense_code_blocks(
356                        entity,
357                        &context.with_serde,
358                        &context.column_option(),
359                        &context.schema_name,
360                        serde_skip_deserializing_primary_key,
361                        serde_skip_hidden_column,
362                        &context.model_extra_derives,
363                        &context.model_extra_attributes,
364                        &context.column_extra_derives,
365                        context.seaography,
366                        context.impl_active_model_behavior,
367                    )
368                } else {
369                    Self::gen_compact_code_blocks(
370                        entity,
371                        &context.with_serde,
372                        &context.column_option(),
373                        &context.schema_name,
374                        serde_skip_deserializing_primary_key,
375                        serde_skip_hidden_column,
376                        &context.model_extra_derives,
377                        &context.model_extra_attributes,
378                        &context.column_extra_derives,
379                        context.seaography,
380                        context.impl_active_model_behavior,
381                    )
382                };
383                Self::write(&mut lines, code_blocks);
384                OutputFile {
385                    name: entity_file,
386                    content: lines.join("\n\n"),
387                }
388            })
389            .collect()
390    }
391
392    pub fn write_index_file(
393        &self,
394        lib: bool,
395        prelude: bool,
396        seaography: bool,
397        banner_version: BannerVersion,
398    ) -> OutputFile {
399        let mut lines = Vec::new();
400        Self::write_doc_comment(&mut lines, banner_version);
401        let code_blocks: Vec<TokenStream> = self.entities.iter().map(Self::gen_mod).collect();
402        if prelude {
403            Self::write(
404                &mut lines,
405                vec![quote! {
406                    pub mod prelude;
407                }],
408            );
409            lines.push("".to_owned());
410        }
411        Self::write(&mut lines, code_blocks);
412        if !self.enums.is_empty() {
413            Self::write(
414                &mut lines,
415                vec![quote! {
416                    pub mod sea_orm_active_enums;
417                }],
418            );
419        }
420
421        if seaography {
422            lines.push("".to_owned());
423            let ts = Self::gen_seaography_entity_mod(&self.entities, &self.enums);
424            Self::write(&mut lines, vec![ts]);
425        }
426
427        let file_name = match lib {
428            true => "lib.rs".to_owned(),
429            false => "mod.rs".to_owned(),
430        };
431
432        OutputFile {
433            name: file_name,
434            content: lines.join("\n"),
435        }
436    }
437
438    pub fn write_prelude(
439        &self,
440        with_prelude: WithPrelude,
441        entity_format: EntityFormat,
442        banner_version: BannerVersion,
443    ) -> OutputFile {
444        let mut lines = Vec::new();
445        Self::write_doc_comment(&mut lines, banner_version);
446        if with_prelude == WithPrelude::AllAllowUnusedImports {
447            Self::write_allow_unused_imports(&mut lines)
448        }
449        let code_blocks = self
450            .entities
451            .iter()
452            .map({
453                if entity_format == EntityFormat::Frontend {
454                    Self::gen_prelude_use_model
455                } else {
456                    Self::gen_prelude_use
457                }
458            })
459            .collect();
460        Self::write(&mut lines, code_blocks);
461        OutputFile {
462            name: "prelude.rs".to_owned(),
463            content: lines.join("\n"),
464        }
465    }
466
467    pub fn write_sea_orm_active_enums(
468        &self,
469        with_serde: &WithSerde,
470        with_copy_enums: bool,
471        extra_derives: &TokenStream,
472        extra_attributes: &TokenStream,
473        entity_format: EntityFormat,
474        banner_version: BannerVersion,
475    ) -> OutputFile {
476        let mut lines = Vec::new();
477        Self::write_doc_comment(&mut lines, banner_version);
478        if entity_format == EntityFormat::Frontend {
479            Self::write(&mut lines, vec![Self::gen_import_serde(with_serde)]);
480        } else {
481            Self::write(&mut lines, vec![Self::gen_import(with_serde)]);
482        }
483        lines.push("".to_owned());
484        let code_blocks = self
485            .enums
486            .values()
487            .map(|active_enum| {
488                active_enum.impl_active_enum(
489                    with_serde,
490                    with_copy_enums,
491                    extra_derives,
492                    extra_attributes,
493                    entity_format,
494                )
495            })
496            .collect();
497        Self::write(&mut lines, code_blocks);
498        OutputFile {
499            name: "sea_orm_active_enums.rs".to_owned(),
500            content: lines.join("\n"),
501        }
502    }
503
504    pub fn write(lines: &mut Vec<String>, code_blocks: Vec<TokenStream>) {
505        lines.extend(
506            code_blocks
507                .into_iter()
508                .map(|code_block| code_block.to_string())
509                .collect::<Vec<_>>(),
510        );
511    }
512
513    pub fn write_doc_comment(lines: &mut Vec<String>, banner_version: BannerVersion) {
514        let ver = env!("CARGO_PKG_VERSION");
515        let version_str = match banner_version {
516            BannerVersion::Off => String::new(),
517            BannerVersion::Patch => ver.to_owned(),
518            _ => {
519                let parts: Vec<&str> = ver.split('.').collect();
520                match banner_version {
521                    BannerVersion::Major => {
522                        parts.first().map(|x| (*x).to_owned()).unwrap_or_default()
523                    }
524                    BannerVersion::Minor => {
525                        if parts.len() >= 2 {
526                            format!("{}.{}", parts[0], parts[1])
527                        } else {
528                            ver.to_owned()
529                        }
530                    }
531                    _ => unreachable!(),
532                }
533            }
534        };
535        let comments = vec![format!(
536            "//! `SeaORM` Entity, @generated by sea-orm-codegen {version_str}"
537        )];
538        lines.extend(comments);
539        lines.push("".to_owned());
540    }
541
542    pub fn write_allow_unused_imports(lines: &mut Vec<String>) {
543        lines.extend(vec!["#![allow(unused_imports)]".to_string()]);
544        lines.push("".to_owned());
545    }
546
547    pub fn gen_import(with_serde: &WithSerde) -> TokenStream {
548        let serde_import = Self::gen_import_serde(with_serde);
549        quote! {
550            use sea_orm::entity::prelude::*;
551            #serde_import
552        }
553    }
554
555    pub fn gen_import_serde(with_serde: &WithSerde) -> TokenStream {
556        match with_serde {
557            WithSerde::None => Default::default(),
558            WithSerde::Serialize => {
559                quote! {
560                    use serde::Serialize;
561                }
562            }
563            WithSerde::Deserialize => {
564                quote! {
565                    use serde::Deserialize;
566                }
567            }
568            WithSerde::Both => {
569                quote! {
570                    use serde::{Deserialize,Serialize};
571                }
572            }
573        }
574    }
575
576    pub fn gen_entity_struct() -> TokenStream {
577        quote! {
578            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
579            pub struct Entity;
580        }
581    }
582
583    pub fn gen_impl_entity_name(entity: &Entity, schema_name: &Option<String>) -> TokenStream {
584        let schema_name = match Self::gen_schema_name(schema_name) {
585            Some(schema_name) => quote! {
586                fn schema_name(&self) -> Option<&str> {
587                    Some(#schema_name)
588                }
589            },
590            None => quote! {},
591        };
592        let table_name = entity.table_name.as_str();
593        let table_name = quote! {
594            fn table_name(&self) -> &'static str {
595                #table_name
596            }
597        };
598        quote! {
599            impl EntityName for Entity {
600                #schema_name
601                #table_name
602            }
603        }
604    }
605
606    pub fn gen_import_active_enum(entity: &Entity) -> TokenStream {
607        entity
608            .columns
609            .iter()
610            .fold(
611                (TokenStream::new(), Vec::new()),
612                |(mut ts, mut enums), col| {
613                    if let sea_query::ColumnType::Enum { name, .. } = col.get_inner_col_type()
614                        && !enums.contains(&name)
615                    {
616                        enums.push(name);
617                        let enum_name = format_ident!("{}", name.to_string().to_upper_camel_case());
618                        ts.extend([quote! {
619                            use super::sea_orm_active_enums::#enum_name;
620                        }]);
621                    }
622                    (ts, enums)
623                },
624            )
625            .0
626    }
627
628    pub fn gen_column_enum(entity: &Entity, column_extra_derives: &TokenStream) -> TokenStream {
629        let column_variants = entity.columns.iter().map(|col| {
630            let variant = col.get_name_camel_case();
631            let mut variant = quote! { #variant };
632            if !col.is_snake_case_name() {
633                let column_name = &col.name;
634                variant = quote! {
635                    #[sea_orm(column_name = #column_name)]
636                    #variant
637                };
638            }
639            variant
640        });
641        quote! {
642            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn #column_extra_derives)]
643            pub enum Column {
644                #(#column_variants,)*
645            }
646        }
647    }
648
649    pub fn gen_primary_key_enum(entity: &Entity) -> TokenStream {
650        let primary_key_names_camel_case = entity.get_primary_key_names_camel_case();
651        quote! {
652            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
653            pub enum PrimaryKey {
654                #(#primary_key_names_camel_case,)*
655            }
656        }
657    }
658
659    pub fn gen_impl_primary_key(entity: &Entity, column_option: &ColumnOption) -> TokenStream {
660        let primary_key_auto_increment = entity.get_primary_key_auto_increment();
661        let value_type = entity.get_primary_key_rs_type(column_option);
662        quote! {
663            impl PrimaryKeyTrait for PrimaryKey {
664                type ValueType = #value_type;
665
666                fn auto_increment() -> bool {
667                    #primary_key_auto_increment
668                }
669            }
670        }
671    }
672
673    pub fn gen_relation_enum(entity: &Entity) -> TokenStream {
674        let relation_enum_name = entity.get_relation_enum_name();
675        quote! {
676            #[derive(Copy, Clone, Debug, EnumIter)]
677            pub enum Relation {
678                #(#relation_enum_name,)*
679            }
680        }
681    }
682
683    pub fn gen_impl_column_trait(entity: &Entity) -> TokenStream {
684        let column_names_camel_case = entity.get_column_names_camel_case();
685        let column_defs = entity.get_column_defs();
686        quote! {
687            impl ColumnTrait for Column {
688                type EntityName = Entity;
689
690                fn def(&self) -> ColumnDef {
691                    match self {
692                        #(Self::#column_names_camel_case => #column_defs,)*
693                    }
694                }
695            }
696        }
697    }
698
699    pub fn gen_impl_relation_trait(entity: &Entity) -> TokenStream {
700        let relation_enum_name = entity.get_relation_enum_name();
701        let relation_defs = entity.get_relation_defs();
702        let quoted = if relation_enum_name.is_empty() {
703            quote! {
704                panic!("No RelationDef")
705            }
706        } else {
707            quote! {
708                match self {
709                    #(Self::#relation_enum_name => #relation_defs,)*
710                }
711            }
712        };
713        quote! {
714            impl RelationTrait for Relation {
715                fn def(&self) -> RelationDef {
716                    #quoted
717                }
718            }
719        }
720    }
721
722    pub fn gen_impl_related(entity: &Entity) -> Vec<TokenStream> {
723        entity
724            .relations
725            .iter()
726            .filter(|rel| !rel.self_referencing && rel.num_suffix == 0 && rel.impl_related)
727            .map(|rel| {
728                let enum_name = rel.get_enum_name();
729                let module_name = rel.get_module_name();
730                let inner = quote! {
731                    fn to() -> RelationDef {
732                        Relation::#enum_name.def()
733                    }
734                };
735                if module_name.is_some() {
736                    quote! {
737                        impl Related<super::#module_name::Entity> for Entity { #inner }
738                    }
739                } else {
740                    quote! {
741                        impl Related<Entity> for Entity { #inner }
742                    }
743                }
744            })
745            .collect()
746    }
747
748    /// Used to generate `enum RelatedEntity` that is useful to the Seaography project
749    pub fn gen_related_entity(entity: &Entity) -> TokenStream {
750        let related_enum_name = entity.get_related_entity_enum_name();
751        let related_attrs = entity.get_related_entity_attrs();
752
753        quote! {
754            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
755            pub enum RelatedEntity {
756                #(
757                    #related_attrs
758                    #related_enum_name
759                ),*
760            }
761        }
762    }
763
764    pub fn gen_impl_conjunct_related(entity: &Entity) -> Vec<TokenStream> {
765        let table_name_camel_case = entity.get_table_name_camel_case_ident();
766        let via_snake_case = entity.get_conjunct_relations_via_snake_case();
767        let to_snake_case = entity.get_conjunct_relations_to_snake_case();
768        let to_upper_camel_case = entity.get_conjunct_relations_to_upper_camel_case();
769        via_snake_case
770            .into_iter()
771            .zip(to_snake_case)
772            .zip(to_upper_camel_case)
773            .map(|((via_snake_case, to_snake_case), to_upper_camel_case)| {
774                quote! {
775                    impl Related<super::#to_snake_case::Entity> for Entity {
776                        fn to() -> RelationDef {
777                            super::#via_snake_case::Relation::#to_upper_camel_case.def()
778                        }
779
780                        fn via() -> Option<RelationDef> {
781                            Some(super::#via_snake_case::Relation::#table_name_camel_case.def().rev())
782                        }
783                    }
784                }
785            })
786            .collect()
787    }
788
789    pub fn impl_active_model_behavior() -> TokenStream {
790        quote! {
791            impl ActiveModelBehavior for ActiveModel {}
792        }
793    }
794
795    pub fn gen_mod(entity: &Entity) -> TokenStream {
796        let table_name_snake_case_ident = format_ident!(
797            "{}",
798            escape_rust_keyword(entity.get_table_name_snake_case_ident())
799        );
800        quote! {
801            pub mod #table_name_snake_case_ident;
802        }
803    }
804
805    pub fn gen_seaography_entity_mod(
806        entities: &[Entity],
807        enums: &BTreeMap<String, ActiveEnum>,
808    ) -> TokenStream {
809        let mut ts = TokenStream::new();
810        for entity in entities {
811            let table_name_snake_case_ident = format_ident!(
812                "{}",
813                escape_rust_keyword(entity.get_table_name_snake_case_ident())
814            );
815            ts = quote! {
816                #ts
817                #table_name_snake_case_ident,
818            }
819        }
820        ts = quote! {
821            seaography::register_entity_modules!([
822                #ts
823            ]);
824        };
825
826        let mut enum_ts = TokenStream::new();
827        for active_enum in enums.values() {
828            let enum_name = &active_enum.enum_name.to_string();
829            let enum_iden = format_ident!("{}", enum_name.to_upper_camel_case());
830            enum_ts = quote! {
831                #enum_ts
832                sea_orm_active_enums::#enum_iden,
833            }
834        }
835        if !enum_ts.is_empty() {
836            ts = quote! {
837                #ts
838
839                seaography::register_active_enums!([
840                    #enum_ts
841                ]);
842            };
843        }
844        ts
845    }
846
847    pub fn gen_prelude_use(entity: &Entity) -> TokenStream {
848        let table_name_snake_case_ident = entity.get_table_name_snake_case_ident();
849        let table_name_camel_case_ident = entity.get_table_name_camel_case_ident();
850        quote! {
851            pub use super::#table_name_snake_case_ident::Entity as #table_name_camel_case_ident;
852        }
853    }
854
855    pub fn gen_prelude_use_model(entity: &Entity) -> TokenStream {
856        let table_name_snake_case_ident = entity.get_table_name_snake_case_ident();
857        let table_name_camel_case_ident = entity.get_table_name_camel_case_ident();
858        quote! {
859            pub use super::#table_name_snake_case_ident::Model as #table_name_camel_case_ident;
860        }
861    }
862
863    pub fn gen_schema_name(schema_name: &Option<String>) -> Option<TokenStream> {
864        schema_name
865            .as_ref()
866            .map(|schema_name| quote! { #schema_name })
867    }
868}
869
870#[cfg(test)]
871mod tests {
872    use crate::{
873        Column, ColumnOption, ConjunctRelation, Entity, EntityWriter, PrimaryKey, Relation,
874        RelationType, WithSerde,
875        entity::writer::{bonus_attributes, bonus_derive},
876    };
877    use pretty_assertions::assert_eq;
878    use proc_macro2::TokenStream;
879    use quote::quote;
880    use sea_query::{Alias, ColumnType, ForeignKeyAction, RcOrArc, SeaRc, StringLen};
881    use std::{
882        io::{self, BufRead, BufReader, Read},
883        sync::Arc,
884    };
885
886    fn default_column_option() -> ColumnOption {
887        Default::default()
888    }
889
890    fn setup() -> Vec<Entity> {
891        vec![
892            Entity {
893                table_name: "cake".to_owned(),
894                columns: vec![
895                    Column {
896                        name: "id".to_owned(),
897                        col_type: ColumnType::Integer,
898                        auto_increment: true,
899                        not_null: true,
900                        unique: false,
901                        unique_key: None,
902                    },
903                    Column {
904                        name: "name".to_owned(),
905                        col_type: ColumnType::Text,
906                        auto_increment: false,
907                        not_null: false,
908                        unique: false,
909                        unique_key: None,
910                    },
911                ],
912                relations: vec![Relation {
913                    ref_table: "fruit".to_owned(),
914                    columns: vec![],
915                    ref_columns: vec![],
916                    rel_type: RelationType::HasMany,
917                    on_delete: None,
918                    on_update: None,
919                    self_referencing: false,
920                    num_suffix: 0,
921                    impl_related: true,
922                }],
923                conjunct_relations: vec![ConjunctRelation {
924                    via: "cake_filling".to_owned(),
925                    to: "filling".to_owned(),
926                }],
927                primary_keys: vec![PrimaryKey {
928                    name: "id".to_owned(),
929                }],
930            },
931            Entity {
932                table_name: "_cake_filling_".to_owned(),
933                columns: vec![
934                    Column {
935                        name: "cake_id".to_owned(),
936                        col_type: ColumnType::Integer,
937                        auto_increment: false,
938                        not_null: true,
939                        unique: false,
940                        unique_key: None,
941                    },
942                    Column {
943                        name: "filling_id".to_owned(),
944                        col_type: ColumnType::Integer,
945                        auto_increment: false,
946                        not_null: true,
947                        unique: false,
948                        unique_key: None,
949                    },
950                ],
951                relations: vec![
952                    Relation {
953                        ref_table: "cake".to_owned(),
954                        columns: vec!["cake_id".to_owned()],
955                        ref_columns: vec!["id".to_owned()],
956                        rel_type: RelationType::BelongsTo,
957                        on_delete: Some(ForeignKeyAction::Cascade),
958                        on_update: Some(ForeignKeyAction::Cascade),
959                        self_referencing: false,
960                        num_suffix: 0,
961                        impl_related: true,
962                    },
963                    Relation {
964                        ref_table: "filling".to_owned(),
965                        columns: vec!["filling_id".to_owned()],
966                        ref_columns: vec!["id".to_owned()],
967                        rel_type: RelationType::BelongsTo,
968                        on_delete: Some(ForeignKeyAction::Cascade),
969                        on_update: Some(ForeignKeyAction::Cascade),
970                        self_referencing: false,
971                        num_suffix: 0,
972                        impl_related: true,
973                    },
974                ],
975                conjunct_relations: vec![],
976                primary_keys: vec![
977                    PrimaryKey {
978                        name: "cake_id".to_owned(),
979                    },
980                    PrimaryKey {
981                        name: "filling_id".to_owned(),
982                    },
983                ],
984            },
985            Entity {
986                table_name: "cake_filling_price".to_owned(),
987                columns: vec![
988                    Column {
989                        name: "cake_id".to_owned(),
990                        col_type: ColumnType::Integer,
991                        auto_increment: false,
992                        not_null: true,
993                        unique: false,
994                        unique_key: None,
995                    },
996                    Column {
997                        name: "filling_id".to_owned(),
998                        col_type: ColumnType::Integer,
999                        auto_increment: false,
1000                        not_null: true,
1001                        unique: false,
1002                        unique_key: None,
1003                    },
1004                    Column {
1005                        name: "price".to_owned(),
1006                        col_type: ColumnType::Decimal(None),
1007                        auto_increment: false,
1008                        not_null: true,
1009                        unique: false,
1010                        unique_key: None,
1011                    },
1012                ],
1013                relations: vec![Relation {
1014                    ref_table: "cake_filling".to_owned(),
1015                    columns: vec!["cake_id".to_owned(), "filling_id".to_owned()],
1016                    ref_columns: vec!["cake_id".to_owned(), "filling_id".to_owned()],
1017                    rel_type: RelationType::BelongsTo,
1018                    on_delete: None,
1019                    on_update: None,
1020                    self_referencing: false,
1021                    num_suffix: 0,
1022                    impl_related: true,
1023                }],
1024                conjunct_relations: vec![],
1025                primary_keys: vec![
1026                    PrimaryKey {
1027                        name: "cake_id".to_owned(),
1028                    },
1029                    PrimaryKey {
1030                        name: "filling_id".to_owned(),
1031                    },
1032                ],
1033            },
1034            Entity {
1035                table_name: "filling".to_owned(),
1036                columns: vec![
1037                    Column {
1038                        name: "id".to_owned(),
1039                        col_type: ColumnType::Integer,
1040                        auto_increment: true,
1041                        not_null: true,
1042                        unique: false,
1043                        unique_key: None,
1044                    },
1045                    Column {
1046                        name: "name".to_owned(),
1047                        col_type: ColumnType::String(StringLen::N(255)),
1048                        auto_increment: false,
1049                        not_null: true,
1050                        unique: false,
1051                        unique_key: None,
1052                    },
1053                ],
1054                relations: vec![],
1055                conjunct_relations: vec![ConjunctRelation {
1056                    via: "cake_filling".to_owned(),
1057                    to: "cake".to_owned(),
1058                }],
1059                primary_keys: vec![PrimaryKey {
1060                    name: "id".to_owned(),
1061                }],
1062            },
1063            Entity {
1064                table_name: "fruit".to_owned(),
1065                columns: vec![
1066                    Column {
1067                        name: "id".to_owned(),
1068                        col_type: ColumnType::Integer,
1069                        auto_increment: true,
1070                        not_null: true,
1071                        unique: false,
1072                        unique_key: None,
1073                    },
1074                    Column {
1075                        name: "name".to_owned(),
1076                        col_type: ColumnType::String(StringLen::N(255)),
1077                        auto_increment: false,
1078                        not_null: true,
1079                        unique: false,
1080                        unique_key: None,
1081                    },
1082                    Column {
1083                        name: "cake_id".to_owned(),
1084                        col_type: ColumnType::Integer,
1085                        auto_increment: false,
1086                        not_null: false,
1087                        unique: false,
1088                        unique_key: None,
1089                    },
1090                ],
1091                relations: vec![
1092                    Relation {
1093                        ref_table: "cake".to_owned(),
1094                        columns: vec!["cake_id".to_owned()],
1095                        ref_columns: vec!["id".to_owned()],
1096                        rel_type: RelationType::BelongsTo,
1097                        on_delete: None,
1098                        on_update: None,
1099                        self_referencing: false,
1100                        num_suffix: 0,
1101                        impl_related: true,
1102                    },
1103                    Relation {
1104                        ref_table: "vendor".to_owned(),
1105                        columns: vec![],
1106                        ref_columns: vec![],
1107                        rel_type: RelationType::HasMany,
1108                        on_delete: None,
1109                        on_update: None,
1110                        self_referencing: false,
1111                        num_suffix: 0,
1112                        impl_related: true,
1113                    },
1114                ],
1115                conjunct_relations: vec![],
1116                primary_keys: vec![PrimaryKey {
1117                    name: "id".to_owned(),
1118                }],
1119            },
1120            Entity {
1121                table_name: "vendor".to_owned(),
1122                columns: vec![
1123                    Column {
1124                        name: "id".to_owned(),
1125                        col_type: ColumnType::Integer,
1126                        auto_increment: true,
1127                        not_null: true,
1128                        unique: false,
1129                        unique_key: None,
1130                    },
1131                    Column {
1132                        name: "_name_".to_owned(),
1133                        col_type: ColumnType::String(StringLen::N(255)),
1134                        auto_increment: false,
1135                        not_null: true,
1136                        unique: false,
1137                        unique_key: None,
1138                    },
1139                    Column {
1140                        name: "fruitId".to_owned(),
1141                        col_type: ColumnType::Integer,
1142                        auto_increment: false,
1143                        not_null: false,
1144                        unique: false,
1145                        unique_key: None,
1146                    },
1147                ],
1148                relations: vec![Relation {
1149                    ref_table: "fruit".to_owned(),
1150                    columns: vec!["fruitId".to_owned()],
1151                    ref_columns: vec!["id".to_owned()],
1152                    rel_type: RelationType::BelongsTo,
1153                    on_delete: None,
1154                    on_update: None,
1155                    self_referencing: false,
1156                    num_suffix: 0,
1157                    impl_related: true,
1158                }],
1159                conjunct_relations: vec![],
1160                primary_keys: vec![PrimaryKey {
1161                    name: "id".to_owned(),
1162                }],
1163            },
1164            Entity {
1165                table_name: "rust_keyword".to_owned(),
1166                columns: vec![
1167                    Column {
1168                        name: "id".to_owned(),
1169                        col_type: ColumnType::Integer,
1170                        auto_increment: true,
1171                        not_null: true,
1172                        unique: false,
1173                        unique_key: None,
1174                    },
1175                    Column {
1176                        name: "testing".to_owned(),
1177                        col_type: ColumnType::TinyInteger,
1178                        auto_increment: false,
1179                        not_null: true,
1180                        unique: false,
1181                        unique_key: None,
1182                    },
1183                    Column {
1184                        name: "rust".to_owned(),
1185                        col_type: ColumnType::TinyUnsigned,
1186                        auto_increment: false,
1187                        not_null: true,
1188                        unique: false,
1189                        unique_key: None,
1190                    },
1191                    Column {
1192                        name: "keywords".to_owned(),
1193                        col_type: ColumnType::SmallInteger,
1194                        auto_increment: false,
1195                        not_null: true,
1196                        unique: false,
1197                        unique_key: None,
1198                    },
1199                    Column {
1200                        name: "type".to_owned(),
1201                        col_type: ColumnType::SmallUnsigned,
1202                        auto_increment: false,
1203                        not_null: true,
1204                        unique: false,
1205                        unique_key: None,
1206                    },
1207                    Column {
1208                        name: "typeof".to_owned(),
1209                        col_type: ColumnType::Integer,
1210                        auto_increment: false,
1211                        not_null: true,
1212                        unique: false,
1213                        unique_key: None,
1214                    },
1215                    Column {
1216                        name: "crate".to_owned(),
1217                        col_type: ColumnType::Unsigned,
1218                        auto_increment: false,
1219                        not_null: true,
1220                        unique: false,
1221                        unique_key: None,
1222                    },
1223                    Column {
1224                        name: "self".to_owned(),
1225                        col_type: ColumnType::BigInteger,
1226                        auto_increment: false,
1227                        not_null: true,
1228                        unique: false,
1229                        unique_key: None,
1230                    },
1231                    Column {
1232                        name: "self_id1".to_owned(),
1233                        col_type: ColumnType::BigUnsigned,
1234                        auto_increment: false,
1235                        not_null: true,
1236                        unique: false,
1237                        unique_key: None,
1238                    },
1239                    Column {
1240                        name: "self_id2".to_owned(),
1241                        col_type: ColumnType::Integer,
1242                        auto_increment: false,
1243                        not_null: true,
1244                        unique: false,
1245                        unique_key: None,
1246                    },
1247                    Column {
1248                        name: "fruit_id1".to_owned(),
1249                        col_type: ColumnType::Integer,
1250                        auto_increment: false,
1251                        not_null: true,
1252                        unique: false,
1253                        unique_key: None,
1254                    },
1255                    Column {
1256                        name: "fruit_id2".to_owned(),
1257                        col_type: ColumnType::Integer,
1258                        auto_increment: false,
1259                        not_null: true,
1260                        unique: false,
1261                        unique_key: None,
1262                    },
1263                    Column {
1264                        name: "cake_id".to_owned(),
1265                        col_type: ColumnType::Integer,
1266                        auto_increment: false,
1267                        not_null: true,
1268                        unique: false,
1269                        unique_key: None,
1270                    },
1271                ],
1272                relations: vec![
1273                    Relation {
1274                        ref_table: "rust_keyword".to_owned(),
1275                        columns: vec!["self_id1".to_owned()],
1276                        ref_columns: vec!["id".to_owned()],
1277                        rel_type: RelationType::BelongsTo,
1278                        on_delete: None,
1279                        on_update: None,
1280                        self_referencing: true,
1281                        num_suffix: 1,
1282                        impl_related: true,
1283                    },
1284                    Relation {
1285                        ref_table: "rust_keyword".to_owned(),
1286                        columns: vec!["self_id2".to_owned()],
1287                        ref_columns: vec!["id".to_owned()],
1288                        rel_type: RelationType::BelongsTo,
1289                        on_delete: None,
1290                        on_update: None,
1291                        self_referencing: true,
1292                        num_suffix: 2,
1293                        impl_related: true,
1294                    },
1295                    Relation {
1296                        ref_table: "fruit".to_owned(),
1297                        columns: vec!["fruit_id1".to_owned()],
1298                        ref_columns: vec!["id".to_owned()],
1299                        rel_type: RelationType::BelongsTo,
1300                        on_delete: None,
1301                        on_update: None,
1302                        self_referencing: false,
1303                        num_suffix: 1,
1304                        impl_related: true,
1305                    },
1306                    Relation {
1307                        ref_table: "fruit".to_owned(),
1308                        columns: vec!["fruit_id2".to_owned()],
1309                        ref_columns: vec!["id".to_owned()],
1310                        rel_type: RelationType::BelongsTo,
1311                        on_delete: None,
1312                        on_update: None,
1313                        self_referencing: false,
1314                        num_suffix: 2,
1315                        impl_related: true,
1316                    },
1317                    Relation {
1318                        ref_table: "cake".to_owned(),
1319                        columns: vec!["cake_id".to_owned()],
1320                        ref_columns: vec!["id".to_owned()],
1321                        rel_type: RelationType::BelongsTo,
1322                        on_delete: None,
1323                        on_update: None,
1324                        self_referencing: false,
1325                        num_suffix: 0,
1326                        impl_related: true,
1327                    },
1328                ],
1329                conjunct_relations: vec![],
1330                primary_keys: vec![PrimaryKey {
1331                    name: "id".to_owned(),
1332                }],
1333            },
1334            Entity {
1335                table_name: "cake_with_float".to_owned(),
1336                columns: vec![
1337                    Column {
1338                        name: "id".to_owned(),
1339                        col_type: ColumnType::Integer,
1340                        auto_increment: true,
1341                        not_null: true,
1342                        unique: false,
1343                        unique_key: None,
1344                    },
1345                    Column {
1346                        name: "name".to_owned(),
1347                        col_type: ColumnType::Text,
1348                        auto_increment: false,
1349                        not_null: false,
1350                        unique: false,
1351                        unique_key: None,
1352                    },
1353                    Column {
1354                        name: "price".to_owned(),
1355                        col_type: ColumnType::Float,
1356                        auto_increment: false,
1357                        not_null: false,
1358                        unique: false,
1359                        unique_key: None,
1360                    },
1361                ],
1362                relations: vec![Relation {
1363                    ref_table: "fruit".to_owned(),
1364                    columns: vec![],
1365                    ref_columns: vec![],
1366                    rel_type: RelationType::HasMany,
1367                    on_delete: None,
1368                    on_update: None,
1369                    self_referencing: false,
1370                    num_suffix: 0,
1371                    impl_related: true,
1372                }],
1373                conjunct_relations: vec![ConjunctRelation {
1374                    via: "cake_filling".to_owned(),
1375                    to: "filling".to_owned(),
1376                }],
1377                primary_keys: vec![PrimaryKey {
1378                    name: "id".to_owned(),
1379                }],
1380            },
1381            Entity {
1382                table_name: "cake_with_double".to_owned(),
1383                columns: vec![
1384                    Column {
1385                        name: "id".to_owned(),
1386                        col_type: ColumnType::Integer,
1387                        auto_increment: true,
1388                        not_null: true,
1389                        unique: false,
1390                        unique_key: None,
1391                    },
1392                    Column {
1393                        name: "name".to_owned(),
1394                        col_type: ColumnType::Text,
1395                        auto_increment: false,
1396                        not_null: false,
1397                        unique: false,
1398                        unique_key: None,
1399                    },
1400                    Column {
1401                        name: "price".to_owned(),
1402                        col_type: ColumnType::Double,
1403                        auto_increment: false,
1404                        not_null: false,
1405                        unique: false,
1406                        unique_key: None,
1407                    },
1408                ],
1409                relations: vec![Relation {
1410                    ref_table: "fruit".to_owned(),
1411                    columns: vec![],
1412                    ref_columns: vec![],
1413                    rel_type: RelationType::HasMany,
1414                    on_delete: None,
1415                    on_update: None,
1416                    self_referencing: false,
1417                    num_suffix: 0,
1418                    impl_related: true,
1419                }],
1420                conjunct_relations: vec![ConjunctRelation {
1421                    via: "cake_filling".to_owned(),
1422                    to: "filling".to_owned(),
1423                }],
1424                primary_keys: vec![PrimaryKey {
1425                    name: "id".to_owned(),
1426                }],
1427            },
1428            Entity {
1429                table_name: "collection".to_owned(),
1430                columns: vec![
1431                    Column {
1432                        name: "id".to_owned(),
1433                        col_type: ColumnType::Integer,
1434                        auto_increment: true,
1435                        not_null: true,
1436                        unique: false,
1437                        unique_key: None,
1438                    },
1439                    Column {
1440                        name: "integers".to_owned(),
1441                        col_type: ColumnType::Array(RcOrArc::new(ColumnType::Integer)),
1442                        auto_increment: false,
1443                        not_null: true,
1444                        unique: false,
1445                        unique_key: None,
1446                    },
1447                    Column {
1448                        name: "integers_opt".to_owned(),
1449                        col_type: ColumnType::Array(RcOrArc::new(ColumnType::Integer)),
1450                        auto_increment: false,
1451                        not_null: false,
1452                        unique: false,
1453                        unique_key: None,
1454                    },
1455                ],
1456                relations: vec![],
1457                conjunct_relations: vec![],
1458                primary_keys: vec![PrimaryKey {
1459                    name: "id".to_owned(),
1460                }],
1461            },
1462            Entity {
1463                table_name: "collection_float".to_owned(),
1464                columns: vec![
1465                    Column {
1466                        name: "id".to_owned(),
1467                        col_type: ColumnType::Integer,
1468                        auto_increment: true,
1469                        not_null: true,
1470                        unique: false,
1471                        unique_key: None,
1472                    },
1473                    Column {
1474                        name: "floats".to_owned(),
1475                        col_type: ColumnType::Array(RcOrArc::new(ColumnType::Float)),
1476                        auto_increment: false,
1477                        not_null: true,
1478                        unique: false,
1479                        unique_key: None,
1480                    },
1481                    Column {
1482                        name: "doubles".to_owned(),
1483                        col_type: ColumnType::Array(RcOrArc::new(ColumnType::Double)),
1484                        auto_increment: false,
1485                        not_null: true,
1486                        unique: false,
1487                        unique_key: None,
1488                    },
1489                ],
1490                relations: vec![],
1491                conjunct_relations: vec![],
1492                primary_keys: vec![PrimaryKey {
1493                    name: "id".to_owned(),
1494                }],
1495            },
1496            Entity {
1497                table_name: "parent".to_owned(),
1498                columns: vec![
1499                    Column {
1500                        name: "id1".to_owned(),
1501                        col_type: ColumnType::Integer,
1502                        auto_increment: false,
1503                        not_null: true,
1504                        unique: false,
1505                        unique_key: None,
1506                    },
1507                    Column {
1508                        name: "id2".to_owned(),
1509                        col_type: ColumnType::Integer,
1510                        auto_increment: false,
1511                        not_null: true,
1512                        unique: false,
1513                        unique_key: None,
1514                    },
1515                ],
1516                relations: vec![Relation {
1517                    ref_table: "child".to_owned(),
1518                    columns: vec![],
1519                    ref_columns: vec![],
1520                    rel_type: RelationType::HasMany,
1521                    on_delete: None,
1522                    on_update: None,
1523                    self_referencing: false,
1524                    num_suffix: 0,
1525                    impl_related: true,
1526                }],
1527                conjunct_relations: vec![],
1528                primary_keys: vec![
1529                    PrimaryKey {
1530                        name: "id1".to_owned(),
1531                    },
1532                    PrimaryKey {
1533                        name: "id2".to_owned(),
1534                    },
1535                ],
1536            },
1537            Entity {
1538                table_name: "child".to_owned(),
1539                columns: vec![
1540                    Column {
1541                        name: "id".to_owned(),
1542                        col_type: ColumnType::Integer,
1543                        auto_increment: true,
1544                        not_null: true,
1545                        unique: false,
1546                        unique_key: None,
1547                    },
1548                    Column {
1549                        name: "parent_id1".to_owned(),
1550                        col_type: ColumnType::Integer,
1551                        auto_increment: false,
1552                        not_null: true,
1553                        unique: false,
1554                        unique_key: None,
1555                    },
1556                    Column {
1557                        name: "parent_id2".to_owned(),
1558                        col_type: ColumnType::Integer,
1559                        auto_increment: false,
1560                        not_null: true,
1561                        unique: false,
1562                        unique_key: None,
1563                    },
1564                ],
1565                relations: vec![Relation {
1566                    ref_table: "parent".to_owned(),
1567                    columns: vec!["parent_id1".to_owned(), "parent_id2".to_owned()],
1568                    ref_columns: vec!["id1".to_owned(), "id2".to_owned()],
1569                    rel_type: RelationType::BelongsTo,
1570                    on_delete: None,
1571                    on_update: None,
1572                    self_referencing: false,
1573                    num_suffix: 0,
1574                    impl_related: true,
1575                }],
1576                conjunct_relations: vec![],
1577                primary_keys: vec![PrimaryKey {
1578                    name: "id".to_owned(),
1579                }],
1580            },
1581            Entity {
1582                table_name: "imports".to_owned(),
1583                columns: vec![
1584                    Column {
1585                        name: "a".to_owned(),
1586                        col_type: ColumnType::Json,
1587                        auto_increment: true,
1588                        not_null: true,
1589                        unique: false,
1590                        unique_key: None,
1591                    },
1592                    Column {
1593                        name: "b".to_owned(),
1594                        col_type: ColumnType::Date,
1595                        auto_increment: true,
1596                        not_null: true,
1597                        unique: false,
1598                        unique_key: None,
1599                    },
1600                    Column {
1601                        name: "c".to_owned(),
1602                        col_type: ColumnType::Time,
1603                        auto_increment: true,
1604                        not_null: true,
1605                        unique: false,
1606                        unique_key: None,
1607                    },
1608                    Column {
1609                        name: "d".to_owned(),
1610                        col_type: ColumnType::DateTime,
1611                        auto_increment: true,
1612                        not_null: true,
1613                        unique: false,
1614                        unique_key: None,
1615                    },
1616                    Column {
1617                        name: "e".to_owned(),
1618                        col_type: ColumnType::TimestampWithTimeZone,
1619                        auto_increment: true,
1620                        not_null: true,
1621                        unique: false,
1622                        unique_key: None,
1623                    },
1624                    Column {
1625                        name: "f".to_owned(),
1626                        col_type: ColumnType::Decimal(None),
1627                        auto_increment: true,
1628                        not_null: true,
1629                        unique: false,
1630                        unique_key: None,
1631                    },
1632                    Column {
1633                        name: "g".to_owned(),
1634                        col_type: ColumnType::Uuid,
1635                        auto_increment: true,
1636                        not_null: true,
1637                        unique: false,
1638                        unique_key: None,
1639                    },
1640                    Column {
1641                        name: "h".to_owned(),
1642                        col_type: ColumnType::Vector(None),
1643                        auto_increment: true,
1644                        not_null: true,
1645                        unique: false,
1646                        unique_key: None,
1647                    },
1648                    Column {
1649                        name: "i".to_owned(),
1650                        col_type: ColumnType::Inet,
1651                        auto_increment: true,
1652                        not_null: true,
1653                        unique: false,
1654                        unique_key: None,
1655                    },
1656                    Column {
1657                        name: "j".to_owned(),
1658                        col_type: ColumnType::Array(Arc::new(ColumnType::Json)),
1659                        auto_increment: true,
1660                        not_null: true,
1661                        unique: false,
1662                        unique_key: None,
1663                    },
1664                    Column {
1665                        name: "k".to_owned(),
1666                        col_type: ColumnType::Array(Arc::new(ColumnType::Array(Arc::new(
1667                            ColumnType::Cidr,
1668                        )))),
1669                        auto_increment: true,
1670                        not_null: true,
1671                        unique: false,
1672                        unique_key: None,
1673                    },
1674                ],
1675                relations: vec![],
1676                conjunct_relations: vec![],
1677                primary_keys: vec![PrimaryKey {
1678                    name: "a".to_owned(),
1679                }],
1680            },
1681        ]
1682    }
1683
1684    fn parse_from_file<R>(inner: R) -> io::Result<TokenStream>
1685    where
1686        R: Read,
1687    {
1688        let mut reader = BufReader::new(inner);
1689        let mut lines: Vec<String> = Vec::new();
1690
1691        reader.read_until(b';', &mut Vec::new())?;
1692
1693        let mut line = String::new();
1694        while reader.read_line(&mut line)? > 0 {
1695            lines.push(line.to_owned());
1696            line.clear();
1697        }
1698        let content = lines.join("");
1699        Ok(content.parse().unwrap())
1700    }
1701
1702    fn parse_from_frontend_file<R>(inner: R) -> io::Result<TokenStream>
1703    where
1704        R: Read,
1705    {
1706        let mut reader = BufReader::new(inner);
1707        let mut lines: Vec<String> = Vec::new();
1708
1709        reader.read_until(b'\n', &mut Vec::new())?;
1710
1711        let mut line = String::new();
1712        while reader.read_line(&mut line)? > 0 {
1713            lines.push(line.to_owned());
1714            line.clear();
1715        }
1716        let content = lines.join("");
1717        Ok(content.parse().unwrap())
1718    }
1719
1720    #[test]
1721    fn test_gen_expanded_code_blocks() -> io::Result<()> {
1722        let entities = setup();
1723        const ENTITY_FILES: [&str; 14] = [
1724            include_str!("../../tests/expanded/cake.rs"),
1725            include_str!("../../tests/expanded/cake_filling.rs"),
1726            include_str!("../../tests/expanded/cake_filling_price.rs"),
1727            include_str!("../../tests/expanded/filling.rs"),
1728            include_str!("../../tests/expanded/fruit.rs"),
1729            include_str!("../../tests/expanded/vendor.rs"),
1730            include_str!("../../tests/expanded/rust_keyword.rs"),
1731            include_str!("../../tests/expanded/cake_with_float.rs"),
1732            include_str!("../../tests/expanded/cake_with_double.rs"),
1733            include_str!("../../tests/expanded/collection.rs"),
1734            include_str!("../../tests/expanded/collection_float.rs"),
1735            include_str!("../../tests/expanded/parent.rs"),
1736            include_str!("../../tests/expanded/child.rs"),
1737            include_str!("../../tests/expanded/imports.rs"),
1738        ];
1739        const ENTITY_FILES_WITH_SCHEMA_NAME: [&str; 14] = [
1740            include_str!("../../tests/expanded_with_schema_name/cake.rs"),
1741            include_str!("../../tests/expanded_with_schema_name/cake_filling.rs"),
1742            include_str!("../../tests/expanded_with_schema_name/cake_filling_price.rs"),
1743            include_str!("../../tests/expanded_with_schema_name/filling.rs"),
1744            include_str!("../../tests/expanded_with_schema_name/fruit.rs"),
1745            include_str!("../../tests/expanded_with_schema_name/vendor.rs"),
1746            include_str!("../../tests/expanded_with_schema_name/rust_keyword.rs"),
1747            include_str!("../../tests/expanded_with_schema_name/cake_with_float.rs"),
1748            include_str!("../../tests/expanded_with_schema_name/cake_with_double.rs"),
1749            include_str!("../../tests/expanded_with_schema_name/collection.rs"),
1750            include_str!("../../tests/expanded_with_schema_name/collection_float.rs"),
1751            include_str!("../../tests/expanded_with_schema_name/parent.rs"),
1752            include_str!("../../tests/expanded_with_schema_name/child.rs"),
1753            include_str!("../../tests/expanded_with_schema_name/imports.rs"),
1754        ];
1755
1756        assert_eq!(entities.len(), ENTITY_FILES.len());
1757
1758        for (i, entity) in entities.iter().enumerate() {
1759            assert_eq!(
1760                parse_from_file(ENTITY_FILES[i].as_bytes())?.to_string(),
1761                EntityWriter::gen_expanded_code_blocks(
1762                    entity,
1763                    &crate::WithSerde::None,
1764                    &default_column_option(),
1765                    &None,
1766                    false,
1767                    false,
1768                    &TokenStream::new(),
1769                    &TokenStream::new(),
1770                    &TokenStream::new(),
1771                    false,
1772                    true,
1773                )
1774                .into_iter()
1775                .skip(1)
1776                .fold(TokenStream::new(), |mut acc, tok| {
1777                    acc.extend(tok);
1778                    acc
1779                })
1780                .to_string()
1781            );
1782            assert_eq!(
1783                parse_from_file(ENTITY_FILES_WITH_SCHEMA_NAME[i].as_bytes())?.to_string(),
1784                EntityWriter::gen_expanded_code_blocks(
1785                    entity,
1786                    &crate::WithSerde::None,
1787                    &default_column_option(),
1788                    &Some("schema_name".to_owned()),
1789                    false,
1790                    false,
1791                    &TokenStream::new(),
1792                    &TokenStream::new(),
1793                    &TokenStream::new(),
1794                    false,
1795                    true,
1796                )
1797                .into_iter()
1798                .skip(1)
1799                .fold(TokenStream::new(), |mut acc, tok| {
1800                    acc.extend(tok);
1801                    acc
1802                })
1803                .to_string()
1804            );
1805        }
1806
1807        Ok(())
1808    }
1809
1810    #[test]
1811    fn test_gen_compact_code_blocks() -> io::Result<()> {
1812        let entities = setup();
1813        const ENTITY_FILES: [&str; 14] = [
1814            include_str!("../../tests/compact/cake.rs"),
1815            include_str!("../../tests/compact/cake_filling.rs"),
1816            include_str!("../../tests/compact/cake_filling_price.rs"),
1817            include_str!("../../tests/compact/filling.rs"),
1818            include_str!("../../tests/compact/fruit.rs"),
1819            include_str!("../../tests/compact/vendor.rs"),
1820            include_str!("../../tests/compact/rust_keyword.rs"),
1821            include_str!("../../tests/compact/cake_with_float.rs"),
1822            include_str!("../../tests/compact/cake_with_double.rs"),
1823            include_str!("../../tests/compact/collection.rs"),
1824            include_str!("../../tests/compact/collection_float.rs"),
1825            include_str!("../../tests/compact/parent.rs"),
1826            include_str!("../../tests/compact/child.rs"),
1827            include_str!("../../tests/compact/imports.rs"),
1828        ];
1829        const ENTITY_FILES_WITH_SCHEMA_NAME: [&str; 14] = [
1830            include_str!("../../tests/compact_with_schema_name/cake.rs"),
1831            include_str!("../../tests/compact_with_schema_name/cake_filling.rs"),
1832            include_str!("../../tests/compact_with_schema_name/cake_filling_price.rs"),
1833            include_str!("../../tests/compact_with_schema_name/filling.rs"),
1834            include_str!("../../tests/compact_with_schema_name/fruit.rs"),
1835            include_str!("../../tests/compact_with_schema_name/vendor.rs"),
1836            include_str!("../../tests/compact_with_schema_name/rust_keyword.rs"),
1837            include_str!("../../tests/compact_with_schema_name/cake_with_float.rs"),
1838            include_str!("../../tests/compact_with_schema_name/cake_with_double.rs"),
1839            include_str!("../../tests/compact_with_schema_name/collection.rs"),
1840            include_str!("../../tests/compact_with_schema_name/collection_float.rs"),
1841            include_str!("../../tests/compact_with_schema_name/parent.rs"),
1842            include_str!("../../tests/compact_with_schema_name/child.rs"),
1843            include_str!("../../tests/compact_with_schema_name/imports.rs"),
1844        ];
1845
1846        assert_eq!(entities.len(), ENTITY_FILES.len());
1847
1848        for (i, entity) in entities.iter().enumerate() {
1849            assert_eq!(
1850                parse_from_file(ENTITY_FILES[i].as_bytes())?.to_string(),
1851                EntityWriter::gen_compact_code_blocks(
1852                    entity,
1853                    &crate::WithSerde::None,
1854                    &default_column_option(),
1855                    &None,
1856                    false,
1857                    false,
1858                    &TokenStream::new(),
1859                    &TokenStream::new(),
1860                    &TokenStream::new(),
1861                    false,
1862                    true,
1863                )
1864                .into_iter()
1865                .skip(1)
1866                .fold(TokenStream::new(), |mut acc, tok| {
1867                    acc.extend(tok);
1868                    acc
1869                })
1870                .to_string()
1871            );
1872            assert_eq!(
1873                parse_from_file(ENTITY_FILES_WITH_SCHEMA_NAME[i].as_bytes())?.to_string(),
1874                EntityWriter::gen_compact_code_blocks(
1875                    entity,
1876                    &crate::WithSerde::None,
1877                    &default_column_option(),
1878                    &Some("schema_name".to_owned()),
1879                    false,
1880                    false,
1881                    &TokenStream::new(),
1882                    &TokenStream::new(),
1883                    &TokenStream::new(),
1884                    false,
1885                    true,
1886                )
1887                .into_iter()
1888                .skip(1)
1889                .fold(TokenStream::new(), |mut acc, tok| {
1890                    acc.extend(tok);
1891                    acc
1892                })
1893                .to_string()
1894            );
1895        }
1896
1897        Ok(())
1898    }
1899
1900    #[test]
1901    fn test_gen_frontend_code_blocks() -> io::Result<()> {
1902        let entities = setup();
1903        const ENTITY_FILES: [&str; 14] = [
1904            include_str!("../../tests/frontend/cake.rs"),
1905            include_str!("../../tests/frontend/cake_filling.rs"),
1906            include_str!("../../tests/frontend/cake_filling_price.rs"),
1907            include_str!("../../tests/frontend/filling.rs"),
1908            include_str!("../../tests/frontend/fruit.rs"),
1909            include_str!("../../tests/frontend/vendor.rs"),
1910            include_str!("../../tests/frontend/rust_keyword.rs"),
1911            include_str!("../../tests/frontend/cake_with_float.rs"),
1912            include_str!("../../tests/frontend/cake_with_double.rs"),
1913            include_str!("../../tests/frontend/collection.rs"),
1914            include_str!("../../tests/frontend/collection_float.rs"),
1915            include_str!("../../tests/frontend/parent.rs"),
1916            include_str!("../../tests/frontend/child.rs"),
1917            include_str!("../../tests/frontend/imports.rs"),
1918        ];
1919        const ENTITY_FILES_WITH_SCHEMA_NAME: [&str; 14] = [
1920            include_str!("../../tests/frontend_with_schema_name/cake.rs"),
1921            include_str!("../../tests/frontend_with_schema_name/cake_filling.rs"),
1922            include_str!("../../tests/frontend_with_schema_name/cake_filling_price.rs"),
1923            include_str!("../../tests/frontend_with_schema_name/filling.rs"),
1924            include_str!("../../tests/frontend_with_schema_name/fruit.rs"),
1925            include_str!("../../tests/frontend_with_schema_name/vendor.rs"),
1926            include_str!("../../tests/frontend_with_schema_name/rust_keyword.rs"),
1927            include_str!("../../tests/frontend_with_schema_name/cake_with_float.rs"),
1928            include_str!("../../tests/frontend_with_schema_name/cake_with_double.rs"),
1929            include_str!("../../tests/frontend_with_schema_name/collection.rs"),
1930            include_str!("../../tests/frontend_with_schema_name/collection_float.rs"),
1931            include_str!("../../tests/frontend_with_schema_name/parent.rs"),
1932            include_str!("../../tests/frontend_with_schema_name/child.rs"),
1933            include_str!("../../tests/frontend_with_schema_name/imports.rs"),
1934        ];
1935
1936        assert_eq!(entities.len(), ENTITY_FILES.len());
1937
1938        for (i, entity) in entities.iter().enumerate() {
1939            assert_eq!(
1940                dbg!(parse_from_frontend_file(ENTITY_FILES[i].as_bytes())?.to_string()),
1941                EntityWriter::gen_frontend_code_blocks(
1942                    entity,
1943                    &crate::WithSerde::None,
1944                    &default_column_option(),
1945                    &None,
1946                    false,
1947                    false,
1948                    &TokenStream::new(),
1949                    &TokenStream::new(),
1950                    &TokenStream::new(),
1951                    false,
1952                    true,
1953                )
1954                .into_iter()
1955                .skip(1)
1956                .fold(TokenStream::new(), |mut acc, tok| {
1957                    acc.extend(tok);
1958                    acc
1959                })
1960                .to_string()
1961            );
1962            assert_eq!(
1963                parse_from_frontend_file(ENTITY_FILES_WITH_SCHEMA_NAME[i].as_bytes())?.to_string(),
1964                EntityWriter::gen_frontend_code_blocks(
1965                    entity,
1966                    &crate::WithSerde::None,
1967                    &default_column_option(),
1968                    &Some("schema_name".to_owned()),
1969                    false,
1970                    false,
1971                    &TokenStream::new(),
1972                    &TokenStream::new(),
1973                    &TokenStream::new(),
1974                    false,
1975                    true,
1976                )
1977                .into_iter()
1978                .skip(1)
1979                .fold(TokenStream::new(), |mut acc, tok| {
1980                    acc.extend(tok);
1981                    acc
1982                })
1983                .to_string()
1984            );
1985        }
1986
1987        Ok(())
1988    }
1989
1990    #[test]
1991    fn test_gen_frontend_imports() -> io::Result<()> {
1992        let imports_entity = setup()
1993            .into_iter()
1994            .find(|e| e.get_table_name_snake_case() == "imports")
1995            .unwrap();
1996
1997        assert_eq!(imports_entity.get_table_name_snake_case(), "imports");
1998
1999        assert_eq!(
2000            comparable_file_string(include_str!("../../tests/frontend_with_imports/imports.rs"))?,
2001            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2002                &imports_entity,
2003                &WithSerde::None,
2004                &default_column_option(),
2005                &None,
2006                true,
2007                false,
2008                &TokenStream::new(),
2009                &TokenStream::new(),
2010                &TokenStream::new(),
2011                false,
2012                true,
2013            ))
2014        );
2015
2016        Ok(())
2017    }
2018
2019    #[test]
2020    fn test_gen_with_serde() -> io::Result<()> {
2021        let cake_entity = setup().get(0).unwrap().clone();
2022
2023        assert_eq!(cake_entity.get_table_name_snake_case(), "cake");
2024
2025        // Compact code blocks
2026        assert_eq!(
2027            comparable_file_string(include_str!("../../tests/compact_with_serde/cake_none.rs"))?,
2028            generated_to_string(EntityWriter::gen_compact_code_blocks(
2029                &cake_entity,
2030                &WithSerde::None,
2031                &default_column_option(),
2032                &None,
2033                false,
2034                false,
2035                &TokenStream::new(),
2036                &TokenStream::new(),
2037                &TokenStream::new(),
2038                false,
2039                true,
2040            ))
2041        );
2042        assert_eq!(
2043            comparable_file_string(include_str!(
2044                "../../tests/compact_with_serde/cake_serialize.rs"
2045            ))?,
2046            generated_to_string(EntityWriter::gen_compact_code_blocks(
2047                &cake_entity,
2048                &WithSerde::Serialize,
2049                &default_column_option(),
2050                &None,
2051                false,
2052                false,
2053                &TokenStream::new(),
2054                &TokenStream::new(),
2055                &TokenStream::new(),
2056                false,
2057                true,
2058            ))
2059        );
2060        assert_eq!(
2061            comparable_file_string(include_str!(
2062                "../../tests/compact_with_serde/cake_deserialize.rs"
2063            ))?,
2064            generated_to_string(EntityWriter::gen_compact_code_blocks(
2065                &cake_entity,
2066                &WithSerde::Deserialize,
2067                &default_column_option(),
2068                &None,
2069                true,
2070                false,
2071                &TokenStream::new(),
2072                &TokenStream::new(),
2073                &TokenStream::new(),
2074                false,
2075                true,
2076            ))
2077        );
2078        assert_eq!(
2079            comparable_file_string(include_str!("../../tests/compact_with_serde/cake_both.rs"))?,
2080            generated_to_string(EntityWriter::gen_compact_code_blocks(
2081                &cake_entity,
2082                &WithSerde::Both,
2083                &default_column_option(),
2084                &None,
2085                true,
2086                false,
2087                &TokenStream::new(),
2088                &TokenStream::new(),
2089                &TokenStream::new(),
2090                false,
2091                true,
2092            ))
2093        );
2094
2095        // Expanded code blocks
2096        assert_eq!(
2097            comparable_file_string(include_str!("../../tests/expanded_with_serde/cake_none.rs"))?,
2098            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2099                &cake_entity,
2100                &WithSerde::None,
2101                &default_column_option(),
2102                &None,
2103                false,
2104                false,
2105                &TokenStream::new(),
2106                &TokenStream::new(),
2107                &TokenStream::new(),
2108                false,
2109                true,
2110            ))
2111        );
2112        assert_eq!(
2113            comparable_file_string(include_str!(
2114                "../../tests/expanded_with_serde/cake_serialize.rs"
2115            ))?,
2116            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2117                &cake_entity,
2118                &WithSerde::Serialize,
2119                &default_column_option(),
2120                &None,
2121                false,
2122                false,
2123                &TokenStream::new(),
2124                &TokenStream::new(),
2125                &TokenStream::new(),
2126                false,
2127                true,
2128            ))
2129        );
2130        assert_eq!(
2131            comparable_file_string(include_str!(
2132                "../../tests/expanded_with_serde/cake_deserialize.rs"
2133            ))?,
2134            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2135                &cake_entity,
2136                &WithSerde::Deserialize,
2137                &default_column_option(),
2138                &None,
2139                true,
2140                false,
2141                &TokenStream::new(),
2142                &TokenStream::new(),
2143                &TokenStream::new(),
2144                false,
2145                true,
2146            ))
2147        );
2148        assert_eq!(
2149            comparable_file_string(include_str!("../../tests/expanded_with_serde/cake_both.rs"))?,
2150            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2151                &cake_entity,
2152                &WithSerde::Both,
2153                &default_column_option(),
2154                &None,
2155                true,
2156                false,
2157                &TokenStream::new(),
2158                &TokenStream::new(),
2159                &TokenStream::new(),
2160                false,
2161                true,
2162            ))
2163        );
2164
2165        // Frontend code blocks
2166        assert_eq!(
2167            comparable_file_string(include_str!("../../tests/frontend_with_serde/cake_none.rs"))?,
2168            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2169                &cake_entity,
2170                &WithSerde::None,
2171                &default_column_option(),
2172                &None,
2173                false,
2174                false,
2175                &TokenStream::new(),
2176                &TokenStream::new(),
2177                &TokenStream::new(),
2178                false,
2179                true,
2180            ))
2181        );
2182        assert_eq!(
2183            comparable_file_string(include_str!(
2184                "../../tests/frontend_with_serde/cake_serialize.rs"
2185            ))?,
2186            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2187                &cake_entity,
2188                &WithSerde::Serialize,
2189                &default_column_option(),
2190                &None,
2191                false,
2192                false,
2193                &TokenStream::new(),
2194                &TokenStream::new(),
2195                &TokenStream::new(),
2196                false,
2197                true,
2198            ))
2199        );
2200        assert_eq!(
2201            comparable_file_string(include_str!(
2202                "../../tests/frontend_with_serde/cake_deserialize.rs"
2203            ))?,
2204            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2205                &cake_entity,
2206                &WithSerde::Deserialize,
2207                &default_column_option(),
2208                &None,
2209                true,
2210                false,
2211                &TokenStream::new(),
2212                &TokenStream::new(),
2213                &TokenStream::new(),
2214                false,
2215                true,
2216            ))
2217        );
2218        assert_eq!(
2219            comparable_file_string(include_str!("../../tests/frontend_with_serde/cake_both.rs"))?,
2220            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2221                &cake_entity,
2222                &WithSerde::Both,
2223                &default_column_option(),
2224                &None,
2225                true,
2226                false,
2227                &TokenStream::new(),
2228                &TokenStream::new(),
2229                &TokenStream::new(),
2230                false,
2231                true,
2232            ))
2233        );
2234
2235        Ok(())
2236    }
2237
2238    #[test]
2239    fn test_gen_with_seaography() -> io::Result<()> {
2240        let cake_entity = Entity {
2241            table_name: "cake".to_owned(),
2242            columns: vec![
2243                Column {
2244                    name: "id".to_owned(),
2245                    col_type: ColumnType::Integer,
2246                    auto_increment: true,
2247                    not_null: true,
2248                    unique: false,
2249                    unique_key: None,
2250                },
2251                Column {
2252                    name: "name".to_owned(),
2253                    col_type: ColumnType::Text,
2254                    auto_increment: false,
2255                    not_null: false,
2256                    unique: false,
2257                    unique_key: None,
2258                },
2259                Column {
2260                    name: "base_id".to_owned(),
2261                    col_type: ColumnType::Integer,
2262                    auto_increment: false,
2263                    not_null: false,
2264                    unique: false,
2265                    unique_key: None,
2266                },
2267            ],
2268            relations: vec![
2269                Relation {
2270                    ref_table: "fruit".to_owned(),
2271                    columns: vec![],
2272                    ref_columns: vec![],
2273                    rel_type: RelationType::HasMany,
2274                    on_delete: None,
2275                    on_update: None,
2276                    self_referencing: false,
2277                    num_suffix: 0,
2278                    impl_related: true,
2279                },
2280                Relation {
2281                    ref_table: "cake".to_owned(),
2282                    columns: vec![],
2283                    ref_columns: vec![],
2284                    rel_type: RelationType::HasOne,
2285                    on_delete: None,
2286                    on_update: None,
2287                    self_referencing: true,
2288                    num_suffix: 0,
2289                    impl_related: true,
2290                },
2291            ],
2292            conjunct_relations: vec![ConjunctRelation {
2293                via: "cake_filling".to_owned(),
2294                to: "filling".to_owned(),
2295            }],
2296            primary_keys: vec![PrimaryKey {
2297                name: "id".to_owned(),
2298            }],
2299        };
2300
2301        assert_eq!(cake_entity.get_table_name_snake_case(), "cake");
2302
2303        // Compact code blocks
2304        assert_eq!(
2305            comparable_file_string(include_str!("../../tests/with_seaography/cake.rs"))?,
2306            generated_to_string(EntityWriter::gen_compact_code_blocks(
2307                &cake_entity,
2308                &WithSerde::None,
2309                &default_column_option(),
2310                &None,
2311                false,
2312                false,
2313                &TokenStream::new(),
2314                &TokenStream::new(),
2315                &TokenStream::new(),
2316                true,
2317                true,
2318            ))
2319        );
2320
2321        // Expanded code blocks
2322        assert_eq!(
2323            comparable_file_string(include_str!("../../tests/with_seaography/cake_expanded.rs"))?,
2324            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2325                &cake_entity,
2326                &WithSerde::None,
2327                &default_column_option(),
2328                &None,
2329                false,
2330                false,
2331                &TokenStream::new(),
2332                &TokenStream::new(),
2333                &TokenStream::new(),
2334                true,
2335                true,
2336            ))
2337        );
2338
2339        // Frontend code blocks
2340        assert_eq!(
2341            comparable_file_string(include_str!("../../tests/with_seaography/cake_frontend.rs"))?,
2342            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2343                &cake_entity,
2344                &WithSerde::None,
2345                &default_column_option(),
2346                &None,
2347                false,
2348                false,
2349                &TokenStream::new(),
2350                &TokenStream::new(),
2351                &TokenStream::new(),
2352                true,
2353                true,
2354            ))
2355        );
2356
2357        Ok(())
2358    }
2359
2360    #[test]
2361    fn test_gen_with_seaography_mod() -> io::Result<()> {
2362        use crate::ActiveEnum;
2363        use sea_query::IntoIden;
2364
2365        let entities = setup();
2366        let enums = vec![
2367            (
2368                "coinflip_result_type",
2369                ActiveEnum {
2370                    enum_name: Alias::new("coinflip_result_type").into_iden(),
2371                    values: vec!["HEADS", "TAILS"]
2372                        .into_iter()
2373                        .map(|variant| Alias::new(variant).into_iden())
2374                        .collect(),
2375                },
2376            ),
2377            (
2378                "media_type",
2379                ActiveEnum {
2380                    enum_name: Alias::new("media_type").into_iden(),
2381                    values: vec![
2382                        "UNKNOWN",
2383                        "BITMAP",
2384                        "DRAWING",
2385                        "AUDIO",
2386                        "VIDEO",
2387                        "MULTIMEDIA",
2388                        "OFFICE",
2389                        "TEXT",
2390                        "EXECUTABLE",
2391                        "ARCHIVE",
2392                        "3D",
2393                    ]
2394                    .into_iter()
2395                    .map(|variant| Alias::new(variant).into_iden())
2396                    .collect(),
2397                },
2398            ),
2399        ]
2400        .into_iter()
2401        .map(|(k, v)| (k.to_string(), v))
2402        .collect();
2403
2404        assert_eq!(
2405            comparable_file_string(include_str!("../../tests/with_seaography/mod.rs"))?,
2406            generated_to_string(vec![EntityWriter::gen_seaography_entity_mod(
2407                &entities, &enums,
2408            )])
2409        );
2410
2411        Ok(())
2412    }
2413
2414    #[test]
2415    fn test_gen_with_derives() -> io::Result<()> {
2416        let mut cake_entity = setup().get_mut(0).unwrap().clone();
2417
2418        assert_eq!(cake_entity.get_table_name_snake_case(), "cake");
2419
2420        // Compact code blocks
2421        assert_eq!(
2422            comparable_file_string(include_str!(
2423                "../../tests/compact_with_derives/cake_none.rs"
2424            ))?,
2425            generated_to_string(EntityWriter::gen_compact_code_blocks(
2426                &cake_entity,
2427                &WithSerde::None,
2428                &default_column_option(),
2429                &None,
2430                false,
2431                false,
2432                &TokenStream::new(),
2433                &TokenStream::new(),
2434                &TokenStream::new(),
2435                false,
2436                true,
2437            ))
2438        );
2439        assert_eq!(
2440            comparable_file_string(include_str!("../../tests/compact_with_derives/cake_one.rs"))?,
2441            generated_to_string(EntityWriter::gen_compact_code_blocks(
2442                &cake_entity,
2443                &WithSerde::None,
2444                &default_column_option(),
2445                &None,
2446                false,
2447                false,
2448                &bonus_derive(["ts_rs::TS"]),
2449                &TokenStream::new(),
2450                &TokenStream::new(),
2451                false,
2452                true,
2453            ))
2454        );
2455        assert_eq!(
2456            comparable_file_string(include_str!(
2457                "../../tests/compact_with_derives/cake_multiple.rs"
2458            ))?,
2459            generated_to_string(EntityWriter::gen_compact_code_blocks(
2460                &cake_entity,
2461                &WithSerde::None,
2462                &default_column_option(),
2463                &None,
2464                false,
2465                false,
2466                &bonus_derive(["ts_rs::TS", "utoipa::ToSchema"]),
2467                &TokenStream::new(),
2468                &TokenStream::new(),
2469                false,
2470                true,
2471            ))
2472        );
2473
2474        // Expanded code blocks
2475        assert_eq!(
2476            comparable_file_string(include_str!(
2477                "../../tests/expanded_with_derives/cake_none.rs"
2478            ))?,
2479            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2480                &cake_entity,
2481                &WithSerde::None,
2482                &default_column_option(),
2483                &None,
2484                false,
2485                false,
2486                &TokenStream::new(),
2487                &TokenStream::new(),
2488                &TokenStream::new(),
2489                false,
2490                true,
2491            ))
2492        );
2493        assert_eq!(
2494            comparable_file_string(include_str!(
2495                "../../tests/expanded_with_derives/cake_one.rs"
2496            ))?,
2497            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2498                &cake_entity,
2499                &WithSerde::None,
2500                &default_column_option(),
2501                &None,
2502                false,
2503                false,
2504                &bonus_derive(["ts_rs::TS"]),
2505                &TokenStream::new(),
2506                &TokenStream::new(),
2507                false,
2508                true,
2509            ))
2510        );
2511        assert_eq!(
2512            comparable_file_string(include_str!(
2513                "../../tests/expanded_with_derives/cake_multiple.rs"
2514            ))?,
2515            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2516                &cake_entity,
2517                &WithSerde::None,
2518                &default_column_option(),
2519                &None,
2520                false,
2521                false,
2522                &bonus_derive(["ts_rs::TS", "utoipa::ToSchema"]),
2523                &TokenStream::new(),
2524                &TokenStream::new(),
2525                false,
2526                true,
2527            ))
2528        );
2529
2530        // Frontend code blocks
2531        assert_eq!(
2532            comparable_file_string(include_str!(
2533                "../../tests/frontend_with_derives/cake_none.rs"
2534            ))?,
2535            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2536                &cake_entity,
2537                &WithSerde::None,
2538                &default_column_option(),
2539                &None,
2540                false,
2541                false,
2542                &TokenStream::new(),
2543                &TokenStream::new(),
2544                &TokenStream::new(),
2545                false,
2546                true,
2547            ))
2548        );
2549        assert_eq!(
2550            comparable_file_string(include_str!(
2551                "../../tests/frontend_with_derives/cake_one.rs"
2552            ))?,
2553            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2554                &cake_entity,
2555                &WithSerde::None,
2556                &default_column_option(),
2557                &None,
2558                false,
2559                false,
2560                &bonus_derive(["ts_rs::TS"]),
2561                &TokenStream::new(),
2562                &TokenStream::new(),
2563                false,
2564                true,
2565            ))
2566        );
2567        assert_eq!(
2568            comparable_file_string(include_str!(
2569                "../../tests/frontend_with_derives/cake_multiple.rs"
2570            ))?,
2571            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2572                &cake_entity,
2573                &WithSerde::None,
2574                &default_column_option(),
2575                &None,
2576                false,
2577                false,
2578                &bonus_derive(["ts_rs::TS", "utoipa::ToSchema"]),
2579                &TokenStream::new(),
2580                &TokenStream::new(),
2581                false,
2582                true,
2583            ))
2584        );
2585
2586        // Make the `name` column of `cake` entity as hidden column
2587        cake_entity.columns[1].name = "_name".into();
2588
2589        assert_serde_variant_results(
2590            &cake_entity,
2591            &(
2592                include_str!("../../tests/compact_with_serde/cake_serialize_with_hidden_column.rs"),
2593                WithSerde::Serialize,
2594                None,
2595            ),
2596            Box::new(EntityWriter::gen_compact_code_blocks),
2597        )?;
2598        assert_serde_variant_results(
2599            &cake_entity,
2600            &(
2601                include_str!(
2602                    "../../tests/expanded_with_serde/cake_serialize_with_hidden_column.rs"
2603                ),
2604                WithSerde::Serialize,
2605                None,
2606            ),
2607            Box::new(EntityWriter::gen_expanded_code_blocks),
2608        )?;
2609        assert_serde_variant_results(
2610            &cake_entity,
2611            &(
2612                include_str!(
2613                    "../../tests/frontend_with_serde/cake_serialize_with_hidden_column.rs"
2614                ),
2615                WithSerde::Serialize,
2616                None,
2617            ),
2618            Box::new(EntityWriter::gen_frontend_code_blocks),
2619        )?;
2620
2621        Ok(())
2622    }
2623
2624    #[test]
2625    fn test_gen_with_column_derives() -> io::Result<()> {
2626        let cake_entity = setup().get_mut(0).unwrap().clone();
2627
2628        assert_eq!(cake_entity.get_table_name_snake_case(), "cake");
2629
2630        assert_eq!(
2631            comparable_file_string(include_str!(
2632                "../../tests/expanded_with_column_derives/cake_one.rs"
2633            ))?,
2634            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2635                &cake_entity,
2636                &WithSerde::None,
2637                &default_column_option(),
2638                &None,
2639                false,
2640                false,
2641                &TokenStream::new(),
2642                &TokenStream::new(),
2643                &bonus_derive(["async_graphql::Enum"]),
2644                false,
2645                true,
2646            ))
2647        );
2648        assert_eq!(
2649            comparable_file_string(include_str!(
2650                "../../tests/expanded_with_column_derives/cake_multiple.rs"
2651            ))?,
2652            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2653                &cake_entity,
2654                &WithSerde::None,
2655                &default_column_option(),
2656                &None,
2657                false,
2658                false,
2659                &TokenStream::new(),
2660                &TokenStream::new(),
2661                &bonus_derive(["async_graphql::Enum", "Eq", "PartialEq"]),
2662                false,
2663                true,
2664            ))
2665        );
2666
2667        Ok(())
2668    }
2669
2670    #[allow(clippy::type_complexity)]
2671    fn assert_serde_variant_results(
2672        cake_entity: &Entity,
2673        entity_serde_variant: &(&str, WithSerde, Option<String>),
2674        generator: Box<
2675            dyn Fn(
2676                &Entity,
2677                &WithSerde,
2678                &ColumnOption,
2679                &Option<String>,
2680                bool,
2681                bool,
2682                &TokenStream,
2683                &TokenStream,
2684                &TokenStream,
2685                bool,
2686                bool,
2687            ) -> Vec<TokenStream>,
2688        >,
2689    ) -> io::Result<()> {
2690        let mut reader = BufReader::new(entity_serde_variant.0.as_bytes());
2691        let mut lines: Vec<String> = Vec::new();
2692        let serde_skip_deserializing_primary_key = matches!(
2693            entity_serde_variant.1,
2694            WithSerde::Both | WithSerde::Deserialize
2695        );
2696        let serde_skip_hidden_column = matches!(entity_serde_variant.1, WithSerde::Serialize);
2697
2698        reader.read_until(b'\n', &mut Vec::new())?;
2699
2700        let mut line = String::new();
2701        while reader.read_line(&mut line)? > 0 {
2702            lines.push(line.to_owned());
2703            line.clear();
2704        }
2705        let content = lines.join("");
2706        let expected: TokenStream = content.parse().unwrap();
2707        println!("{:?}", entity_serde_variant.1);
2708        let generated = generator(
2709            cake_entity,
2710            &entity_serde_variant.1,
2711            &default_column_option(),
2712            &entity_serde_variant.2,
2713            serde_skip_deserializing_primary_key,
2714            serde_skip_hidden_column,
2715            &TokenStream::new(),
2716            &TokenStream::new(),
2717            &TokenStream::new(),
2718            false,
2719            true,
2720        )
2721        .into_iter()
2722        .fold(TokenStream::new(), |mut acc, tok| {
2723            acc.extend(tok);
2724            acc
2725        });
2726
2727        assert_eq!(expected.to_string(), generated.to_string());
2728        Ok(())
2729    }
2730
2731    #[test]
2732    fn test_gen_with_attributes() -> io::Result<()> {
2733        let cake_entity = setup().get(0).unwrap().clone();
2734
2735        assert_eq!(cake_entity.get_table_name_snake_case(), "cake");
2736
2737        // Compact code blocks
2738        assert_eq!(
2739            comparable_file_string(include_str!(
2740                "../../tests/compact_with_attributes/cake_none.rs"
2741            ))?,
2742            generated_to_string(EntityWriter::gen_compact_code_blocks(
2743                &cake_entity,
2744                &WithSerde::None,
2745                &default_column_option(),
2746                &None,
2747                false,
2748                false,
2749                &TokenStream::new(),
2750                &TokenStream::new(),
2751                &TokenStream::new(),
2752                false,
2753                true,
2754            ))
2755        );
2756        assert_eq!(
2757            comparable_file_string(include_str!(
2758                "../../tests/compact_with_attributes/cake_one.rs"
2759            ))?,
2760            generated_to_string(EntityWriter::gen_compact_code_blocks(
2761                &cake_entity,
2762                &WithSerde::None,
2763                &default_column_option(),
2764                &None,
2765                false,
2766                false,
2767                &TokenStream::new(),
2768                &bonus_attributes([r#"serde(rename_all = "camelCase")"#]),
2769                &TokenStream::new(),
2770                false,
2771                true,
2772            ))
2773        );
2774        assert_eq!(
2775            comparable_file_string(include_str!(
2776                "../../tests/compact_with_attributes/cake_multiple.rs"
2777            ))?,
2778            generated_to_string(EntityWriter::gen_compact_code_blocks(
2779                &cake_entity,
2780                &WithSerde::None,
2781                &default_column_option(),
2782                &None,
2783                false,
2784                false,
2785                &TokenStream::new(),
2786                &bonus_attributes([r#"serde(rename_all = "camelCase")"#, "ts(export)"]),
2787                &TokenStream::new(),
2788                false,
2789                true,
2790            ))
2791        );
2792
2793        // Expanded code blocks
2794        assert_eq!(
2795            comparable_file_string(include_str!(
2796                "../../tests/expanded_with_attributes/cake_none.rs"
2797            ))?,
2798            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2799                &cake_entity,
2800                &WithSerde::None,
2801                &default_column_option(),
2802                &None,
2803                false,
2804                false,
2805                &TokenStream::new(),
2806                &TokenStream::new(),
2807                &TokenStream::new(),
2808                false,
2809                true,
2810            ))
2811        );
2812        assert_eq!(
2813            comparable_file_string(include_str!(
2814                "../../tests/expanded_with_attributes/cake_one.rs"
2815            ))?,
2816            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2817                &cake_entity,
2818                &WithSerde::None,
2819                &default_column_option(),
2820                &None,
2821                false,
2822                false,
2823                &TokenStream::new(),
2824                &bonus_attributes([r#"serde(rename_all = "camelCase")"#]),
2825                &TokenStream::new(),
2826                false,
2827                true,
2828            ))
2829        );
2830        assert_eq!(
2831            comparable_file_string(include_str!(
2832                "../../tests/expanded_with_attributes/cake_multiple.rs"
2833            ))?,
2834            generated_to_string(EntityWriter::gen_expanded_code_blocks(
2835                &cake_entity,
2836                &WithSerde::None,
2837                &default_column_option(),
2838                &None,
2839                false,
2840                false,
2841                &TokenStream::new(),
2842                &bonus_attributes([r#"serde(rename_all = "camelCase")"#, "ts(export)"]),
2843                &TokenStream::new(),
2844                false,
2845                true,
2846            ))
2847        );
2848
2849        // Frontend code blocks
2850        assert_eq!(
2851            comparable_file_string(include_str!(
2852                "../../tests/frontend_with_attributes/cake_none.rs"
2853            ))?,
2854            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2855                &cake_entity,
2856                &WithSerde::None,
2857                &default_column_option(),
2858                &None,
2859                false,
2860                false,
2861                &TokenStream::new(),
2862                &TokenStream::new(),
2863                &TokenStream::new(),
2864                false,
2865                true,
2866            ))
2867        );
2868        assert_eq!(
2869            comparable_file_string(include_str!(
2870                "../../tests/frontend_with_attributes/cake_one.rs"
2871            ))?,
2872            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2873                &cake_entity,
2874                &WithSerde::None,
2875                &default_column_option(),
2876                &None,
2877                false,
2878                false,
2879                &TokenStream::new(),
2880                &bonus_attributes([r#"serde(rename_all = "camelCase")"#]),
2881                &TokenStream::new(),
2882                false,
2883                true,
2884            ))
2885        );
2886        assert_eq!(
2887            comparable_file_string(include_str!(
2888                "../../tests/frontend_with_attributes/cake_multiple.rs"
2889            ))?,
2890            generated_to_string(EntityWriter::gen_frontend_code_blocks(
2891                &cake_entity,
2892                &WithSerde::None,
2893                &default_column_option(),
2894                &None,
2895                false,
2896                false,
2897                &TokenStream::new(),
2898                &bonus_attributes([r#"serde(rename_all = "camelCase")"#, "ts(export)"]),
2899                &TokenStream::new(),
2900                false,
2901                true,
2902            ))
2903        );
2904
2905        Ok(())
2906    }
2907
2908    fn generated_to_string(generated: Vec<TokenStream>) -> String {
2909        generated
2910            .into_iter()
2911            .fold(TokenStream::new(), |mut acc, tok| {
2912                acc.extend(tok);
2913                acc
2914            })
2915            .to_string()
2916    }
2917
2918    fn comparable_file_string(file: &str) -> io::Result<String> {
2919        let mut reader = BufReader::new(file.as_bytes());
2920        let mut lines: Vec<String> = Vec::new();
2921
2922        reader.read_until(b'\n', &mut Vec::new())?;
2923
2924        let mut line = String::new();
2925        while reader.read_line(&mut line)? > 0 {
2926            lines.push(line.to_owned());
2927            line.clear();
2928        }
2929        let content = lines.join("");
2930        let expected: TokenStream = content.parse().unwrap();
2931
2932        Ok(expected.to_string())
2933    }
2934
2935    #[test]
2936    fn test_gen_postgres() -> io::Result<()> {
2937        let entities = vec![
2938            // This tests that the JsonBinary column type is annotated
2939            // correctly in compact entity form. More information can be found
2940            // in this issue:
2941            //
2942            // https://github.com/SeaQL/sea-orm/issues/1344
2943            Entity {
2944                table_name: "task".to_owned(),
2945                columns: vec![
2946                    Column {
2947                        name: "id".to_owned(),
2948                        col_type: ColumnType::Integer,
2949                        auto_increment: true,
2950                        not_null: true,
2951                        unique: false,
2952                        unique_key: None,
2953                    },
2954                    Column {
2955                        name: "payload".to_owned(),
2956                        col_type: ColumnType::Json,
2957                        auto_increment: false,
2958                        not_null: true,
2959                        unique: false,
2960                        unique_key: None,
2961                    },
2962                    Column {
2963                        name: "payload_binary".to_owned(),
2964                        col_type: ColumnType::JsonBinary,
2965                        auto_increment: false,
2966                        not_null: true,
2967                        unique: false,
2968                        unique_key: None,
2969                    },
2970                ],
2971                relations: vec![],
2972                conjunct_relations: vec![],
2973                primary_keys: vec![PrimaryKey {
2974                    name: "id".to_owned(),
2975                }],
2976            },
2977        ];
2978        const ENTITY_FILES: [&str; 1] = [include_str!("../../tests/postgres/binary_json.rs")];
2979
2980        const ENTITY_FILES_EXPANDED: [&str; 1] =
2981            [include_str!("../../tests/postgres/binary_json_expanded.rs")];
2982
2983        assert_eq!(entities.len(), ENTITY_FILES.len());
2984
2985        for (i, entity) in entities.iter().enumerate() {
2986            assert_eq!(
2987                parse_from_file(ENTITY_FILES[i].as_bytes())?.to_string(),
2988                EntityWriter::gen_compact_code_blocks(
2989                    entity,
2990                    &crate::WithSerde::None,
2991                    &default_column_option(),
2992                    &None,
2993                    false,
2994                    false,
2995                    &TokenStream::new(),
2996                    &TokenStream::new(),
2997                    &TokenStream::new(),
2998                    false,
2999                    true,
3000                )
3001                .into_iter()
3002                .skip(1)
3003                .fold(TokenStream::new(), |mut acc, tok| {
3004                    acc.extend(tok);
3005                    acc
3006                })
3007                .to_string()
3008            );
3009            assert_eq!(
3010                parse_from_file(ENTITY_FILES_EXPANDED[i].as_bytes())?.to_string(),
3011                EntityWriter::gen_expanded_code_blocks(
3012                    entity,
3013                    &crate::WithSerde::None,
3014                    &default_column_option(),
3015                    &Some("schema_name".to_owned()),
3016                    false,
3017                    false,
3018                    &TokenStream::new(),
3019                    &TokenStream::new(),
3020                    &TokenStream::new(),
3021                    false,
3022                    true,
3023                )
3024                .into_iter()
3025                .skip(1)
3026                .fold(TokenStream::new(), |mut acc, tok| {
3027                    acc.extend(tok);
3028                    acc
3029                })
3030                .to_string()
3031            );
3032        }
3033
3034        Ok(())
3035    }
3036
3037    #[test]
3038    fn test_gen_import_active_enum() -> io::Result<()> {
3039        let entities = vec![
3040            Entity {
3041                table_name: "tea_pairing".to_owned(),
3042                columns: vec![
3043                    Column {
3044                        name: "id".to_owned(),
3045                        col_type: ColumnType::Integer,
3046                        auto_increment: true,
3047                        not_null: true,
3048                        unique: false,
3049                        unique_key: None,
3050                    },
3051                    Column {
3052                        name: "first_tea".to_owned(),
3053                        col_type: ColumnType::Enum {
3054                            name: SeaRc::new(Alias::new("tea_enum")),
3055                            variants: vec![
3056                                SeaRc::new(Alias::new("everyday_tea")),
3057                                SeaRc::new(Alias::new("breakfast_tea")),
3058                            ],
3059                        },
3060                        auto_increment: false,
3061                        not_null: true,
3062                        unique: false,
3063                        unique_key: None,
3064                    },
3065                    Column {
3066                        name: "second_tea".to_owned(),
3067                        col_type: ColumnType::Enum {
3068                            name: SeaRc::new(Alias::new("tea_enum")),
3069                            variants: vec![
3070                                SeaRc::new(Alias::new("everyday_tea")),
3071                                SeaRc::new(Alias::new("breakfast_tea")),
3072                            ],
3073                        },
3074                        auto_increment: false,
3075                        not_null: true,
3076                        unique: false,
3077                        unique_key: None,
3078                    },
3079                ],
3080                relations: vec![],
3081                conjunct_relations: vec![],
3082                primary_keys: vec![PrimaryKey {
3083                    name: "id".to_owned(),
3084                }],
3085            },
3086            Entity {
3087                table_name: "tea_pairing_with_size".to_owned(),
3088                columns: vec![
3089                    Column {
3090                        name: "id".to_owned(),
3091                        col_type: ColumnType::Integer,
3092                        auto_increment: true,
3093                        not_null: true,
3094                        unique: false,
3095                        unique_key: None,
3096                    },
3097                    Column {
3098                        name: "first_tea".to_owned(),
3099                        col_type: ColumnType::Enum {
3100                            name: SeaRc::new(Alias::new("tea_enum")),
3101                            variants: vec![
3102                                SeaRc::new(Alias::new("everyday_tea")),
3103                                SeaRc::new(Alias::new("breakfast_tea")),
3104                            ],
3105                        },
3106                        auto_increment: false,
3107                        not_null: true,
3108                        unique: false,
3109                        unique_key: None,
3110                    },
3111                    Column {
3112                        name: "second_tea".to_owned(),
3113                        col_type: ColumnType::Enum {
3114                            name: SeaRc::new(Alias::new("tea_enum")),
3115                            variants: vec![
3116                                SeaRc::new(Alias::new("everyday_tea")),
3117                                SeaRc::new(Alias::new("breakfast_tea")),
3118                            ],
3119                        },
3120                        auto_increment: false,
3121                        not_null: true,
3122                        unique: false,
3123                        unique_key: None,
3124                    },
3125                    Column {
3126                        name: "size".to_owned(),
3127                        col_type: ColumnType::Enum {
3128                            name: SeaRc::new(Alias::new("tea_size")),
3129                            variants: vec![
3130                                SeaRc::new(Alias::new("small")),
3131                                SeaRc::new(Alias::new("medium")),
3132                                SeaRc::new(Alias::new("huge")),
3133                            ],
3134                        },
3135                        auto_increment: false,
3136                        not_null: true,
3137                        unique: false,
3138                        unique_key: None,
3139                    },
3140                ],
3141                relations: vec![],
3142                conjunct_relations: vec![],
3143                primary_keys: vec![PrimaryKey {
3144                    name: "id".to_owned(),
3145                }],
3146            },
3147        ];
3148
3149        assert_eq!(
3150            quote!(
3151                use super::sea_orm_active_enums::TeaEnum;
3152            )
3153            .to_string(),
3154            EntityWriter::gen_import_active_enum(&entities[0]).to_string()
3155        );
3156
3157        assert_eq!(
3158            quote!(
3159                use super::sea_orm_active_enums::TeaEnum;
3160                use super::sea_orm_active_enums::TeaSize;
3161            )
3162            .to_string(),
3163            EntityWriter::gen_import_active_enum(&entities[1]).to_string()
3164        );
3165
3166        Ok(())
3167    }
3168
3169    #[test]
3170    fn test_gen_dense_code_blocks() -> io::Result<()> {
3171        let entities = setup();
3172        const ENTITY_FILES: [&str; 14] = [
3173            include_str!("../../tests/dense/cake.rs"),
3174            include_str!("../../tests/dense/cake_filling.rs"),
3175            include_str!("../../tests/dense/cake_filling_price.rs"),
3176            include_str!("../../tests/dense/filling.rs"),
3177            include_str!("../../tests/dense/fruit.rs"),
3178            include_str!("../../tests/dense/vendor.rs"),
3179            include_str!("../../tests/dense/rust_keyword.rs"),
3180            include_str!("../../tests/dense/cake_with_float.rs"),
3181            include_str!("../../tests/dense/cake_with_double.rs"),
3182            include_str!("../../tests/dense/collection.rs"),
3183            include_str!("../../tests/dense/collection_float.rs"),
3184            include_str!("../../tests/dense/parent.rs"),
3185            include_str!("../../tests/dense/child.rs"),
3186            include_str!("../../tests/dense/imports.rs"),
3187        ];
3188
3189        assert_eq!(entities.len(), ENTITY_FILES.len());
3190
3191        for (i, entity) in entities.iter().enumerate() {
3192            assert_eq!(
3193                parse_from_file(ENTITY_FILES[i].as_bytes())?.to_string(),
3194                EntityWriter::gen_dense_code_blocks(
3195                    entity,
3196                    &crate::WithSerde::None,
3197                    &default_column_option(),
3198                    &None,
3199                    false,
3200                    false,
3201                    &TokenStream::new(),
3202                    &TokenStream::new(),
3203                    &TokenStream::new(),
3204                    false,
3205                    true,
3206                )
3207                .into_iter()
3208                .skip(1)
3209                .fold(TokenStream::new(), |mut acc, tok| {
3210                    acc.extend(tok);
3211                    acc
3212                })
3213                .to_string()
3214            );
3215        }
3216
3217        Ok(())
3218    }
3219}