1use crate::types::SqlType;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub enum ReferentialAction {
11 #[default]
14 NoAction,
15 Restrict,
17 Cascade,
19 SetNull,
21 SetDefault,
23}
24
25impl ReferentialAction {
26 #[must_use]
28 pub const fn as_sql(&self) -> &'static str {
29 match self {
30 ReferentialAction::NoAction => "NO ACTION",
31 ReferentialAction::Restrict => "RESTRICT",
32 ReferentialAction::Cascade => "CASCADE",
33 ReferentialAction::SetNull => "SET NULL",
34 ReferentialAction::SetDefault => "SET DEFAULT",
35 }
36 }
37
38 #[must_use]
42 pub fn from_str(s: &str) -> Option<Self> {
43 match s.to_uppercase().as_str() {
44 "NO ACTION" | "NOACTION" | "NO_ACTION" => Some(ReferentialAction::NoAction),
45 "RESTRICT" => Some(ReferentialAction::Restrict),
46 "CASCADE" => Some(ReferentialAction::Cascade),
47 "SET NULL" | "SETNULL" | "SET_NULL" => Some(ReferentialAction::SetNull),
48 "SET DEFAULT" | "SETDEFAULT" | "SET_DEFAULT" => Some(ReferentialAction::SetDefault),
49 _ => None,
50 }
51 }
52}
53
54#[derive(Debug, Clone)]
56pub struct FieldInfo {
57 pub name: &'static str,
59 pub column_name: &'static str,
61 pub sql_type: SqlType,
63 pub sql_type_override: Option<&'static str>,
66 pub precision: Option<u8>,
68 pub scale: Option<u8>,
70 pub nullable: bool,
72 pub primary_key: bool,
74 pub auto_increment: bool,
76 pub unique: bool,
78 pub default: Option<&'static str>,
80 pub foreign_key: Option<&'static str>,
82 pub on_delete: Option<ReferentialAction>,
84 pub on_update: Option<ReferentialAction>,
86 pub index: Option<&'static str>,
88 pub alias: Option<&'static str>,
91 pub validation_alias: Option<&'static str>,
94 pub serialization_alias: Option<&'static str>,
97 pub computed: bool,
101 pub exclude: bool,
104 pub title: Option<&'static str>,
107 pub description: Option<&'static str>,
110 pub schema_extra: Option<&'static str>,
113 pub default_json: Option<&'static str>,
117 pub has_default: bool,
120 pub const_field: bool,
124 pub column_constraints: &'static [&'static str],
127 pub column_comment: Option<&'static str>,
130 pub column_info: Option<&'static str>,
133 pub hybrid_sql: Option<&'static str>,
140 pub discriminator: Option<&'static str>,
162}
163
164impl FieldInfo {
165 pub const fn new(name: &'static str, column_name: &'static str, sql_type: SqlType) -> Self {
167 Self {
168 name,
169 column_name,
170 sql_type,
171 sql_type_override: None,
172 precision: None,
173 scale: None,
174 nullable: false,
175 primary_key: false,
176 auto_increment: false,
177 unique: false,
178 default: None,
179 foreign_key: None,
180 on_delete: None,
181 on_update: None,
182 index: None,
183 alias: None,
184 validation_alias: None,
185 serialization_alias: None,
186 computed: false,
187 exclude: false,
188 title: None,
189 description: None,
190 schema_extra: None,
191 default_json: None,
192 has_default: false,
193 const_field: false,
194 column_constraints: &[],
195 column_comment: None,
196 column_info: None,
197 hybrid_sql: None,
198 discriminator: None,
199 }
200 }
201
202 pub const fn column(mut self, name: &'static str) -> Self {
204 self.column_name = name;
205 self
206 }
207
208 pub const fn sql_type_override(mut self, type_str: &'static str) -> Self {
214 self.sql_type_override = Some(type_str);
215 self
216 }
217
218 pub const fn sql_type_override_opt(mut self, type_str: Option<&'static str>) -> Self {
220 self.sql_type_override = type_str;
221 self
222 }
223
224 pub const fn precision(mut self, value: u8) -> Self {
238 self.precision = Some(value);
239 self
240 }
241
242 pub const fn precision_opt(mut self, value: Option<u8>) -> Self {
244 self.precision = value;
245 self
246 }
247
248 pub const fn scale(mut self, value: u8) -> Self {
253 self.scale = Some(value);
254 self
255 }
256
257 pub const fn scale_opt(mut self, value: Option<u8>) -> Self {
259 self.scale = value;
260 self
261 }
262
263 pub const fn decimal_precision(mut self, precision: u8, scale: u8) -> Self {
273 self.precision = Some(precision);
274 self.scale = Some(scale);
275 self
276 }
277
278 #[must_use]
285 pub fn effective_sql_type(&self) -> String {
286 if let Some(override_str) = self.sql_type_override {
288 return override_str.to_string();
289 }
290
291 match self.sql_type {
293 SqlType::Decimal { .. } | SqlType::Numeric { .. } => {
294 if let (Some(p), Some(s)) = (self.precision, self.scale) {
295 let type_name = match self.sql_type {
296 SqlType::Decimal { .. } => "DECIMAL",
297 SqlType::Numeric { .. } => "NUMERIC",
298 _ => unreachable!(),
299 };
300 return format!("{}({}, {})", type_name, p, s);
301 }
302 }
303 _ => {}
304 }
305
306 self.sql_type.sql_name()
308 }
309
310 pub const fn nullable(mut self, value: bool) -> Self {
312 self.nullable = value;
313 self
314 }
315
316 pub const fn primary_key(mut self, value: bool) -> Self {
318 self.primary_key = value;
319 self
320 }
321
322 pub const fn auto_increment(mut self, value: bool) -> Self {
324 self.auto_increment = value;
325 self
326 }
327
328 pub const fn unique(mut self, value: bool) -> Self {
330 self.unique = value;
331 self
332 }
333
334 pub const fn default(mut self, expr: &'static str) -> Self {
336 self.default = Some(expr);
337 self
338 }
339
340 pub const fn default_opt(mut self, expr: Option<&'static str>) -> Self {
342 self.default = expr;
343 self
344 }
345
346 pub const fn foreign_key(mut self, reference: &'static str) -> Self {
348 self.foreign_key = Some(reference);
349 self
350 }
351
352 pub const fn foreign_key_opt(mut self, reference: Option<&'static str>) -> Self {
354 self.foreign_key = reference;
355 self
356 }
357
358 pub const fn on_delete(mut self, action: ReferentialAction) -> Self {
362 self.on_delete = Some(action);
363 self
364 }
365
366 pub const fn on_delete_opt(mut self, action: Option<ReferentialAction>) -> Self {
368 self.on_delete = action;
369 self
370 }
371
372 pub const fn on_update(mut self, action: ReferentialAction) -> Self {
376 self.on_update = Some(action);
377 self
378 }
379
380 pub const fn on_update_opt(mut self, action: Option<ReferentialAction>) -> Self {
382 self.on_update = action;
383 self
384 }
385
386 pub const fn index(mut self, name: &'static str) -> Self {
388 self.index = Some(name);
389 self
390 }
391
392 pub const fn index_opt(mut self, name: Option<&'static str>) -> Self {
394 self.index = name;
395 self
396 }
397
398 pub const fn alias(mut self, name: &'static str) -> Self {
403 self.alias = Some(name);
404 self
405 }
406
407 pub const fn alias_opt(mut self, name: Option<&'static str>) -> Self {
409 self.alias = name;
410 self
411 }
412
413 pub const fn validation_alias(mut self, name: &'static str) -> Self {
418 self.validation_alias = Some(name);
419 self
420 }
421
422 pub const fn validation_alias_opt(mut self, name: Option<&'static str>) -> Self {
424 self.validation_alias = name;
425 self
426 }
427
428 pub const fn serialization_alias(mut self, name: &'static str) -> Self {
433 self.serialization_alias = Some(name);
434 self
435 }
436
437 pub const fn serialization_alias_opt(mut self, name: Option<&'static str>) -> Self {
439 self.serialization_alias = name;
440 self
441 }
442
443 pub const fn computed(mut self, value: bool) -> Self {
452 self.computed = value;
453 self
454 }
455
456 pub const fn exclude(mut self, value: bool) -> Self {
473 self.exclude = value;
474 self
475 }
476
477 pub const fn title(mut self, value: &'static str) -> Self {
481 self.title = Some(value);
482 self
483 }
484
485 pub const fn title_opt(mut self, value: Option<&'static str>) -> Self {
487 self.title = value;
488 self
489 }
490
491 pub const fn description(mut self, value: &'static str) -> Self {
495 self.description = Some(value);
496 self
497 }
498
499 pub const fn description_opt(mut self, value: Option<&'static str>) -> Self {
501 self.description = value;
502 self
503 }
504
505 pub const fn schema_extra(mut self, value: &'static str) -> Self {
510 self.schema_extra = Some(value);
511 self
512 }
513
514 pub const fn schema_extra_opt(mut self, value: Option<&'static str>) -> Self {
516 self.schema_extra = value;
517 self
518 }
519
520 pub const fn default_json(mut self, value: &'static str) -> Self {
533 self.default_json = Some(value);
534 self.has_default = true;
535 self
536 }
537
538 pub const fn default_json_opt(mut self, value: Option<&'static str>) -> Self {
540 self.default_json = value;
541 if value.is_some() {
542 self.has_default = true;
543 }
544 self
545 }
546
547 pub const fn has_default(mut self, value: bool) -> Self {
552 self.has_default = value;
553 self
554 }
555
556 pub const fn const_field(mut self, value: bool) -> Self {
569 self.const_field = value;
570 self
571 }
572
573 pub const fn column_constraints(mut self, constraints: &'static [&'static str]) -> Self {
585 self.column_constraints = constraints;
586 self
587 }
588
589 pub const fn column_comment(mut self, comment: &'static str) -> Self {
593 self.column_comment = Some(comment);
594 self
595 }
596
597 pub const fn column_comment_opt(mut self, comment: Option<&'static str>) -> Self {
599 self.column_comment = comment;
600 self
601 }
602
603 pub const fn column_info(mut self, info: &'static str) -> Self {
608 self.column_info = Some(info);
609 self
610 }
611
612 pub const fn column_info_opt(mut self, info: Option<&'static str>) -> Self {
614 self.column_info = info;
615 self
616 }
617
618 pub const fn hybrid_sql(mut self, sql: &'static str) -> Self {
620 self.hybrid_sql = Some(sql);
621 self
622 }
623
624 pub const fn hybrid_sql_opt(mut self, sql: Option<&'static str>) -> Self {
626 self.hybrid_sql = sql;
627 self
628 }
629
630 pub const fn discriminator(mut self, field: &'static str) -> Self {
636 self.discriminator = Some(field);
637 self
638 }
639
640 pub const fn discriminator_opt(mut self, field: Option<&'static str>) -> Self {
642 self.discriminator = field;
643 self
644 }
645
646 #[must_use]
650 pub const fn output_name(&self) -> &'static str {
651 if let Some(ser_alias) = self.serialization_alias {
652 ser_alias
653 } else if let Some(alias) = self.alias {
654 alias
655 } else {
656 self.name
657 }
658 }
659
660 #[must_use]
664 pub fn matches_input_name(&self, input: &str) -> bool {
665 if input == self.name {
666 return true;
667 }
668 if let Some(alias) = self.alias {
669 if input == alias {
670 return true;
671 }
672 }
673 if let Some(val_alias) = self.validation_alias {
674 if input == val_alias {
675 return true;
676 }
677 }
678 false
679 }
680
681 #[must_use]
683 pub const fn has_alias(&self) -> bool {
684 self.alias.is_some()
685 || self.validation_alias.is_some()
686 || self.serialization_alias.is_some()
687 }
688}
689
690#[derive(Debug, Clone)]
692pub struct Column {
693 pub table: Option<String>,
695 pub name: String,
697 pub alias: Option<String>,
699}
700
701impl Column {
702 pub fn new(name: impl Into<String>) -> Self {
704 Self {
705 table: None,
706 name: name.into(),
707 alias: None,
708 }
709 }
710
711 pub fn qualified(table: impl Into<String>, name: impl Into<String>) -> Self {
713 Self {
714 table: Some(table.into()),
715 name: name.into(),
716 alias: None,
717 }
718 }
719
720 pub fn alias(mut self, alias: impl Into<String>) -> Self {
722 self.alias = Some(alias.into());
723 self
724 }
725
726 pub fn to_sql(&self) -> String {
728 let mut sql = if let Some(table) = &self.table {
729 format!("{}.{}", table, self.name)
730 } else {
731 self.name.clone()
732 };
733
734 if let Some(alias) = &self.alias {
735 sql.push_str(" AS ");
736 sql.push_str(alias);
737 }
738
739 sql
740 }
741}
742
743#[derive(Debug, Clone, Copy)]
748pub struct Field<T> {
749 pub name: &'static str,
751 _marker: std::marker::PhantomData<T>,
753}
754
755impl<T> Field<T> {
756 pub const fn new(name: &'static str) -> Self {
758 Self {
759 name,
760 _marker: std::marker::PhantomData,
761 }
762 }
763}
764
765#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
769pub enum InheritanceStrategy {
770 #[default]
772 None,
773 Single,
789 Joined,
805 Concrete,
811}
812
813impl InheritanceStrategy {
814 #[must_use]
816 pub const fn uses_discriminator(&self) -> bool {
817 matches!(self, Self::Single)
818 }
819
820 #[must_use]
822 pub const fn requires_join(&self) -> bool {
823 matches!(self, Self::Joined)
824 }
825
826 #[must_use]
828 pub const fn is_inheritance(&self) -> bool {
829 !matches!(self, Self::None)
830 }
831}
832
833#[derive(Debug, Clone, Default)]
838pub struct InheritanceInfo {
839 pub strategy: InheritanceStrategy,
841 pub parent: Option<&'static str>,
845 pub discriminator_column: Option<&'static str>,
850 pub discriminator_value: Option<&'static str>,
855}
856
857impl InheritanceInfo {
858 pub const fn none() -> Self {
860 Self {
861 strategy: InheritanceStrategy::None,
862 parent: None,
863 discriminator_column: None,
864 discriminator_value: None,
865 }
866 }
867
868 pub const fn single_table() -> Self {
870 Self {
871 strategy: InheritanceStrategy::Single,
872 parent: None,
873 discriminator_column: None,
874 discriminator_value: None,
875 }
876 }
877
878 pub const fn joined_table() -> Self {
880 Self {
881 strategy: InheritanceStrategy::Joined,
882 parent: None,
883 discriminator_column: None,
884 discriminator_value: None,
885 }
886 }
887
888 pub const fn concrete_table() -> Self {
890 Self {
891 strategy: InheritanceStrategy::Concrete,
892 parent: None,
893 discriminator_column: None,
894 discriminator_value: None,
895 }
896 }
897
898 pub const fn child(parent: &'static str) -> Self {
900 Self {
901 strategy: InheritanceStrategy::None, parent: Some(parent),
903 discriminator_column: None,
904 discriminator_value: None,
905 }
906 }
907
908 pub const fn with_discriminator_column(mut self, column: &'static str) -> Self {
910 self.discriminator_column = Some(column);
911 self
912 }
913
914 pub const fn with_discriminator_value(mut self, value: &'static str) -> Self {
916 self.discriminator_value = Some(value);
917 self
918 }
919
920 #[must_use]
922 pub const fn is_child(&self) -> bool {
923 self.parent.is_some()
924 }
925
926 #[must_use]
928 pub const fn is_base(&self) -> bool {
929 self.parent.is_none() && self.strategy.is_inheritance()
930 }
931}
932
933#[cfg(test)]
934mod tests {
935 use super::*;
936 use crate::SqlType;
937
938 #[test]
939 fn test_field_info_new() {
940 let field = FieldInfo::new(
941 "price",
942 "price",
943 SqlType::Decimal {
944 precision: 10,
945 scale: 2,
946 },
947 );
948 assert_eq!(field.name, "price");
949 assert_eq!(field.column_name, "price");
950 assert!(field.precision.is_none());
951 assert!(field.scale.is_none());
952 }
953
954 #[test]
955 fn test_field_info_precision_scale() {
956 let field = FieldInfo::new(
957 "amount",
958 "amount",
959 SqlType::Decimal {
960 precision: 10,
961 scale: 2,
962 },
963 )
964 .precision(12)
965 .scale(4);
966 assert_eq!(field.precision, Some(12));
967 assert_eq!(field.scale, Some(4));
968 }
969
970 #[test]
971 fn test_field_info_decimal_precision() {
972 let field = FieldInfo::new(
973 "total",
974 "total",
975 SqlType::Numeric {
976 precision: 10,
977 scale: 2,
978 },
979 )
980 .decimal_precision(18, 6);
981 assert_eq!(field.precision, Some(18));
982 assert_eq!(field.scale, Some(6));
983 }
984
985 #[test]
986 fn test_effective_sql_type_override_takes_precedence() {
987 let field = FieldInfo::new(
988 "amount",
989 "amount",
990 SqlType::Decimal {
991 precision: 10,
992 scale: 2,
993 },
994 )
995 .sql_type_override("MONEY")
996 .precision(18)
997 .scale(4);
998 assert_eq!(field.effective_sql_type(), "MONEY");
1000 }
1001
1002 #[test]
1003 fn test_effective_sql_type_uses_precision_scale() {
1004 let field = FieldInfo::new(
1005 "price",
1006 "price",
1007 SqlType::Decimal {
1008 precision: 10,
1009 scale: 2,
1010 },
1011 )
1012 .precision(15)
1013 .scale(3);
1014 assert_eq!(field.effective_sql_type(), "DECIMAL(15, 3)");
1015 }
1016
1017 #[test]
1018 fn test_effective_sql_type_numeric_uses_precision_scale() {
1019 let field = FieldInfo::new(
1020 "value",
1021 "value",
1022 SqlType::Numeric {
1023 precision: 10,
1024 scale: 2,
1025 },
1026 )
1027 .precision(20)
1028 .scale(8);
1029 assert_eq!(field.effective_sql_type(), "NUMERIC(20, 8)");
1030 }
1031
1032 #[test]
1033 fn test_effective_sql_type_fallback_to_sql_type() {
1034 let field = FieldInfo::new("count", "count", SqlType::BigInt);
1035 assert_eq!(field.effective_sql_type(), "BIGINT");
1036 }
1037
1038 #[test]
1039 fn test_effective_sql_type_decimal_without_precision_scale() {
1040 let field = FieldInfo::new(
1042 "amount",
1043 "amount",
1044 SqlType::Decimal {
1045 precision: 10,
1046 scale: 2,
1047 },
1048 );
1049 assert_eq!(field.effective_sql_type(), "DECIMAL(10, 2)");
1051 }
1052
1053 #[test]
1054 fn test_precision_opt() {
1055 let field = FieldInfo::new(
1056 "test",
1057 "test",
1058 SqlType::Decimal {
1059 precision: 10,
1060 scale: 2,
1061 },
1062 )
1063 .precision_opt(Some(16));
1064 assert_eq!(field.precision, Some(16));
1065
1066 let field2 = FieldInfo::new(
1067 "test2",
1068 "test2",
1069 SqlType::Decimal {
1070 precision: 10,
1071 scale: 2,
1072 },
1073 )
1074 .precision_opt(None);
1075 assert_eq!(field2.precision, None);
1076 }
1077
1078 #[test]
1079 fn test_scale_opt() {
1080 let field = FieldInfo::new(
1081 "test",
1082 "test",
1083 SqlType::Decimal {
1084 precision: 10,
1085 scale: 2,
1086 },
1087 )
1088 .scale_opt(Some(5));
1089 assert_eq!(field.scale, Some(5));
1090
1091 let field2 = FieldInfo::new(
1092 "test2",
1093 "test2",
1094 SqlType::Decimal {
1095 precision: 10,
1096 scale: 2,
1097 },
1098 )
1099 .scale_opt(None);
1100 assert_eq!(field2.scale, None);
1101 }
1102
1103 #[test]
1108 fn test_field_info_alias() {
1109 let field = FieldInfo::new("name", "name", SqlType::Text).alias("userName");
1110 assert_eq!(field.alias, Some("userName"));
1111 assert!(field.validation_alias.is_none());
1112 assert!(field.serialization_alias.is_none());
1113 }
1114
1115 #[test]
1116 fn test_field_info_validation_alias() {
1117 let field = FieldInfo::new("name", "name", SqlType::Text).validation_alias("user_name");
1118 assert!(field.alias.is_none());
1119 assert_eq!(field.validation_alias, Some("user_name"));
1120 assert!(field.serialization_alias.is_none());
1121 }
1122
1123 #[test]
1124 fn test_field_info_serialization_alias() {
1125 let field = FieldInfo::new("name", "name", SqlType::Text).serialization_alias("user-name");
1126 assert!(field.alias.is_none());
1127 assert!(field.validation_alias.is_none());
1128 assert_eq!(field.serialization_alias, Some("user-name"));
1129 }
1130
1131 #[test]
1132 fn test_field_info_all_aliases() {
1133 let field = FieldInfo::new("name", "name", SqlType::Text)
1134 .alias("nm")
1135 .validation_alias("input_name")
1136 .serialization_alias("outputName");
1137
1138 assert_eq!(field.alias, Some("nm"));
1139 assert_eq!(field.validation_alias, Some("input_name"));
1140 assert_eq!(field.serialization_alias, Some("outputName"));
1141 }
1142
1143 #[test]
1144 fn test_field_info_alias_opt() {
1145 let field1 = FieldInfo::new("name", "name", SqlType::Text).alias_opt(Some("userName"));
1146 assert_eq!(field1.alias, Some("userName"));
1147
1148 let field2 = FieldInfo::new("name", "name", SqlType::Text).alias_opt(None);
1149 assert!(field2.alias.is_none());
1150 }
1151
1152 #[test]
1153 fn test_field_info_validation_alias_opt() {
1154 let field1 =
1155 FieldInfo::new("name", "name", SqlType::Text).validation_alias_opt(Some("user_name"));
1156 assert_eq!(field1.validation_alias, Some("user_name"));
1157
1158 let field2 = FieldInfo::new("name", "name", SqlType::Text).validation_alias_opt(None);
1159 assert!(field2.validation_alias.is_none());
1160 }
1161
1162 #[test]
1163 fn test_field_info_serialization_alias_opt() {
1164 let field1 = FieldInfo::new("name", "name", SqlType::Text)
1165 .serialization_alias_opt(Some("user-name"));
1166 assert_eq!(field1.serialization_alias, Some("user-name"));
1167
1168 let field2 = FieldInfo::new("name", "name", SqlType::Text).serialization_alias_opt(None);
1169 assert!(field2.serialization_alias.is_none());
1170 }
1171
1172 #[test]
1173 fn test_field_info_output_name() {
1174 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1176 assert_eq!(field1.output_name(), "name");
1177
1178 let field2 = FieldInfo::new("name", "name", SqlType::Text).alias("nm");
1180 assert_eq!(field2.output_name(), "nm");
1181
1182 let field3 = FieldInfo::new("name", "name", SqlType::Text)
1184 .alias("nm")
1185 .serialization_alias("outputName");
1186 assert_eq!(field3.output_name(), "outputName");
1187
1188 let field4 = FieldInfo::new("name", "name", SqlType::Text).serialization_alias("userName");
1190 assert_eq!(field4.output_name(), "userName");
1191 }
1192
1193 #[test]
1194 fn test_field_info_matches_input_name() {
1195 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1197 assert!(field1.matches_input_name("name"));
1198 assert!(!field1.matches_input_name("userName"));
1199
1200 let field2 = FieldInfo::new("name", "name", SqlType::Text).alias("nm");
1202 assert!(field2.matches_input_name("name"));
1203 assert!(field2.matches_input_name("nm"));
1204 assert!(!field2.matches_input_name("userName"));
1205
1206 let field3 = FieldInfo::new("name", "name", SqlType::Text).validation_alias("user_name");
1208 assert!(field3.matches_input_name("name"));
1209 assert!(field3.matches_input_name("user_name"));
1210 assert!(!field3.matches_input_name("userName"));
1211
1212 let field4 = FieldInfo::new("name", "name", SqlType::Text)
1214 .alias("nm")
1215 .validation_alias("user_name");
1216 assert!(field4.matches_input_name("name"));
1217 assert!(field4.matches_input_name("nm"));
1218 assert!(field4.matches_input_name("user_name"));
1219 }
1220
1221 #[test]
1222 fn test_field_info_has_alias() {
1223 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1224 assert!(!field1.has_alias());
1225
1226 let field2 = FieldInfo::new("name", "name", SqlType::Text).alias("nm");
1227 assert!(field2.has_alias());
1228
1229 let field3 = FieldInfo::new("name", "name", SqlType::Text).validation_alias("user_name");
1230 assert!(field3.has_alias());
1231
1232 let field4 = FieldInfo::new("name", "name", SqlType::Text).serialization_alias("userName");
1233 assert!(field4.has_alias());
1234
1235 let field5 = FieldInfo::new("name", "name", SqlType::Text)
1236 .alias("nm")
1237 .validation_alias("user_name")
1238 .serialization_alias("userName");
1239 assert!(field5.has_alias());
1240 }
1241
1242 #[test]
1243 fn test_field_info_exclude() {
1244 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1246 assert!(!field1.exclude);
1247
1248 let field2 = FieldInfo::new("password", "password", SqlType::Text).exclude(true);
1250 assert!(field2.exclude);
1251
1252 let field3 = FieldInfo::new("email", "email", SqlType::Text).exclude(false);
1254 assert!(!field3.exclude);
1255 }
1256
1257 #[test]
1258 fn test_field_info_exclude_combined_with_other_attrs() {
1259 let field = FieldInfo::new("secret", "secret", SqlType::Text)
1261 .exclude(true)
1262 .nullable(true)
1263 .alias("hidden_value");
1264
1265 assert!(field.exclude);
1266 assert!(field.nullable);
1267 assert_eq!(field.alias, Some("hidden_value"));
1268 }
1269
1270 #[test]
1271 fn test_field_info_title() {
1272 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1273 assert_eq!(field1.title, None);
1274
1275 let field2 = FieldInfo::new("name", "name", SqlType::Text).title("User Name");
1276 assert_eq!(field2.title, Some("User Name"));
1277 }
1278
1279 #[test]
1280 fn test_field_info_description() {
1281 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1282 assert_eq!(field1.description, None);
1283
1284 let field2 =
1285 FieldInfo::new("name", "name", SqlType::Text).description("The full name of the user");
1286 assert_eq!(field2.description, Some("The full name of the user"));
1287 }
1288
1289 #[test]
1290 fn test_field_info_schema_extra() {
1291 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1292 assert_eq!(field1.schema_extra, None);
1293
1294 let field2 =
1295 FieldInfo::new("name", "name", SqlType::Text).schema_extra(r#"{"examples": ["John"]}"#);
1296 assert_eq!(field2.schema_extra, Some(r#"{"examples": ["John"]}"#));
1297 }
1298
1299 #[test]
1300 fn test_field_info_all_schema_metadata() {
1301 let field = FieldInfo::new("name", "name", SqlType::Text)
1302 .title("User Name")
1303 .description("The full name of the user")
1304 .schema_extra(r#"{"examples": ["John Doe"]}"#);
1305
1306 assert_eq!(field.title, Some("User Name"));
1307 assert_eq!(field.description, Some("The full name of the user"));
1308 assert_eq!(field.schema_extra, Some(r#"{"examples": ["John Doe"]}"#));
1309 }
1310
1311 #[test]
1312 fn test_field_info_const_field() {
1313 let field1 = FieldInfo::new("version", "version", SqlType::Text);
1315 assert!(!field1.const_field);
1316
1317 let field2 = FieldInfo::new("version", "version", SqlType::Text).const_field(true);
1319 assert!(field2.const_field);
1320
1321 let field3 = FieldInfo::new("version", "version", SqlType::Text)
1323 .const_field(true)
1324 .default("'1.0.0'");
1325 assert!(field3.const_field);
1326 assert_eq!(field3.default, Some("'1.0.0'"));
1327 }
1328
1329 #[test]
1330 fn test_field_info_column_constraints() {
1331 static CONSTRAINTS: &[&str] = &["CHECK(price > 0)", "CHECK(price < 1000)"];
1332
1333 let field1 = FieldInfo::new("price", "price", SqlType::Integer);
1335 assert!(field1.column_constraints.is_empty());
1336
1337 let field2 =
1339 FieldInfo::new("price", "price", SqlType::Integer).column_constraints(CONSTRAINTS);
1340 assert_eq!(field2.column_constraints.len(), 2);
1341 assert_eq!(field2.column_constraints[0], "CHECK(price > 0)");
1342 }
1343
1344 #[test]
1345 fn test_field_info_column_comment() {
1346 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1348 assert_eq!(field1.column_comment, None);
1349
1350 let field2 =
1352 FieldInfo::new("name", "name", SqlType::Text).column_comment("User's display name");
1353 assert_eq!(field2.column_comment, Some("User's display name"));
1354 }
1355
1356 #[test]
1357 fn test_field_info_column_info() {
1358 let field1 = FieldInfo::new("email", "email", SqlType::Text);
1360 assert_eq!(field1.column_info, None);
1361
1362 let field2 =
1364 FieldInfo::new("email", "email", SqlType::Text).column_info(r#"{"deprecated": true}"#);
1365 assert_eq!(field2.column_info, Some(r#"{"deprecated": true}"#));
1366 }
1367
1368 #[test]
1369 fn test_field_info_discriminator() {
1370 let field1 = FieldInfo::new("pet", "pet", SqlType::Json);
1372 assert_eq!(field1.discriminator, None);
1373
1374 let field2 = FieldInfo::new("pet", "pet", SqlType::Json).discriminator("pet_type");
1376 assert_eq!(field2.discriminator, Some("pet_type"));
1377
1378 let field3 = FieldInfo::new("pet", "pet", SqlType::Json).discriminator_opt(None);
1380 assert_eq!(field3.discriminator, None);
1381
1382 let field4 = FieldInfo::new("pet", "pet", SqlType::Json).discriminator_opt(Some("kind"));
1384 assert_eq!(field4.discriminator, Some("kind"));
1385 }
1386
1387 #[test]
1392 fn test_inheritance_strategy_default() {
1393 let strategy = InheritanceStrategy::default();
1394 assert_eq!(strategy, InheritanceStrategy::None);
1395 assert!(!strategy.is_inheritance());
1396 assert!(!strategy.uses_discriminator());
1397 assert!(!strategy.requires_join());
1398 }
1399
1400 #[test]
1401 fn test_inheritance_strategy_single() {
1402 let strategy = InheritanceStrategy::Single;
1403 assert!(strategy.is_inheritance());
1404 assert!(strategy.uses_discriminator());
1405 assert!(!strategy.requires_join());
1406 }
1407
1408 #[test]
1409 fn test_inheritance_strategy_joined() {
1410 let strategy = InheritanceStrategy::Joined;
1411 assert!(strategy.is_inheritance());
1412 assert!(!strategy.uses_discriminator());
1413 assert!(strategy.requires_join());
1414 }
1415
1416 #[test]
1417 fn test_inheritance_strategy_concrete() {
1418 let strategy = InheritanceStrategy::Concrete;
1419 assert!(strategy.is_inheritance());
1420 assert!(!strategy.uses_discriminator());
1421 assert!(!strategy.requires_join());
1422 }
1423
1424 #[test]
1429 fn test_inheritance_info_none() {
1430 let info = InheritanceInfo::none();
1431 assert_eq!(info.strategy, InheritanceStrategy::None);
1432 assert!(info.parent.is_none());
1433 assert!(info.discriminator_value.is_none());
1434 assert!(!info.is_child());
1435 assert!(!info.is_base());
1436 }
1437
1438 #[test]
1439 fn test_inheritance_info_single_table_base() {
1440 let info = InheritanceInfo::single_table();
1441 assert_eq!(info.strategy, InheritanceStrategy::Single);
1442 assert!(info.parent.is_none());
1443 assert!(info.is_base());
1444 assert!(!info.is_child());
1445 }
1446
1447 #[test]
1448 fn test_inheritance_info_joined_table_base() {
1449 let info = InheritanceInfo::joined_table();
1450 assert_eq!(info.strategy, InheritanceStrategy::Joined);
1451 assert!(info.parent.is_none());
1452 assert!(info.is_base());
1453 assert!(!info.is_child());
1454 }
1455
1456 #[test]
1457 fn test_inheritance_info_concrete_table_base() {
1458 let info = InheritanceInfo::concrete_table();
1459 assert_eq!(info.strategy, InheritanceStrategy::Concrete);
1460 assert!(info.parent.is_none());
1461 assert!(info.is_base());
1462 assert!(!info.is_child());
1463 }
1464
1465 #[test]
1466 fn test_inheritance_info_child() {
1467 let info = InheritanceInfo::child("Employee");
1468 assert_eq!(info.parent, Some("Employee"));
1469 assert!(info.is_child());
1470 assert!(!info.is_base());
1471 }
1472
1473 #[test]
1474 fn test_inheritance_info_child_with_discriminator_value() {
1475 let info = InheritanceInfo::child("Employee").with_discriminator_value("manager");
1476 assert_eq!(info.parent, Some("Employee"));
1477 assert_eq!(info.discriminator_value, Some("manager"));
1478 assert!(info.is_child());
1479 }
1480
1481 #[test]
1482 fn test_inheritance_info_single_table_with_discriminator_column() {
1483 let info = InheritanceInfo::single_table().with_discriminator_column("type");
1484 assert_eq!(info.strategy, InheritanceStrategy::Single);
1485 assert_eq!(info.discriminator_column, Some("type"));
1486 assert!(info.is_base());
1487 }
1488}