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
130pub(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
145pub(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}