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 = if matches!(self.sql_type, SqlType::Decimal { .. }) {
296 "DECIMAL"
297 } else {
298 "NUMERIC"
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 parent_fields_fn: Option<fn() -> &'static [FieldInfo]>,
850 pub discriminator_column: Option<&'static str>,
855 pub discriminator_value: Option<&'static str>,
860}
861
862impl InheritanceInfo {
863 pub const fn none() -> Self {
865 Self {
866 strategy: InheritanceStrategy::None,
867 parent: None,
868 parent_fields_fn: None,
869 discriminator_column: None,
870 discriminator_value: None,
871 }
872 }
873
874 pub const fn single_table() -> Self {
876 Self {
877 strategy: InheritanceStrategy::Single,
878 parent: None,
879 parent_fields_fn: None,
880 discriminator_column: None,
881 discriminator_value: None,
882 }
883 }
884
885 pub const fn joined_table() -> Self {
887 Self {
888 strategy: InheritanceStrategy::Joined,
889 parent: None,
890 parent_fields_fn: None,
891 discriminator_column: None,
892 discriminator_value: None,
893 }
894 }
895
896 pub const fn concrete_table() -> Self {
898 Self {
899 strategy: InheritanceStrategy::Concrete,
900 parent: None,
901 parent_fields_fn: None,
902 discriminator_column: None,
903 discriminator_value: None,
904 }
905 }
906
907 pub const fn child(parent_table: &'static str) -> Self {
909 Self {
910 strategy: InheritanceStrategy::None, parent: Some(parent_table),
912 parent_fields_fn: None,
913 discriminator_column: None,
914 discriminator_value: None,
915 }
916 }
917
918 pub const fn with_discriminator_column(mut self, column: &'static str) -> Self {
920 self.discriminator_column = Some(column);
921 self
922 }
923
924 pub const fn with_discriminator_value(mut self, value: &'static str) -> Self {
926 self.discriminator_value = Some(value);
927 self
928 }
929
930 #[must_use]
932 pub const fn is_child(&self) -> bool {
933 self.parent.is_some()
934 }
935
936 #[must_use]
938 pub const fn is_base(&self) -> bool {
939 self.parent.is_none() && self.strategy.is_inheritance()
940 }
941}
942
943#[cfg(test)]
944mod tests {
945 use super::*;
946 use crate::SqlType;
947
948 #[test]
949 fn test_field_info_new() {
950 let field = FieldInfo::new(
951 "price",
952 "price",
953 SqlType::Decimal {
954 precision: 10,
955 scale: 2,
956 },
957 );
958 assert_eq!(field.name, "price");
959 assert_eq!(field.column_name, "price");
960 assert!(field.precision.is_none());
961 assert!(field.scale.is_none());
962 }
963
964 #[test]
965 fn test_field_info_precision_scale() {
966 let field = FieldInfo::new(
967 "amount",
968 "amount",
969 SqlType::Decimal {
970 precision: 10,
971 scale: 2,
972 },
973 )
974 .precision(12)
975 .scale(4);
976 assert_eq!(field.precision, Some(12));
977 assert_eq!(field.scale, Some(4));
978 }
979
980 #[test]
981 fn test_field_info_decimal_precision() {
982 let field = FieldInfo::new(
983 "total",
984 "total",
985 SqlType::Numeric {
986 precision: 10,
987 scale: 2,
988 },
989 )
990 .decimal_precision(18, 6);
991 assert_eq!(field.precision, Some(18));
992 assert_eq!(field.scale, Some(6));
993 }
994
995 #[test]
996 fn test_effective_sql_type_override_takes_precedence() {
997 let field = FieldInfo::new(
998 "amount",
999 "amount",
1000 SqlType::Decimal {
1001 precision: 10,
1002 scale: 2,
1003 },
1004 )
1005 .sql_type_override("MONEY")
1006 .precision(18)
1007 .scale(4);
1008 assert_eq!(field.effective_sql_type(), "MONEY");
1010 }
1011
1012 #[test]
1013 fn test_effective_sql_type_uses_precision_scale() {
1014 let field = FieldInfo::new(
1015 "price",
1016 "price",
1017 SqlType::Decimal {
1018 precision: 10,
1019 scale: 2,
1020 },
1021 )
1022 .precision(15)
1023 .scale(3);
1024 assert_eq!(field.effective_sql_type(), "DECIMAL(15, 3)");
1025 }
1026
1027 #[test]
1028 fn test_effective_sql_type_numeric_uses_precision_scale() {
1029 let field = FieldInfo::new(
1030 "value",
1031 "value",
1032 SqlType::Numeric {
1033 precision: 10,
1034 scale: 2,
1035 },
1036 )
1037 .precision(20)
1038 .scale(8);
1039 assert_eq!(field.effective_sql_type(), "NUMERIC(20, 8)");
1040 }
1041
1042 #[test]
1043 fn test_effective_sql_type_fallback_to_sql_type() {
1044 let field = FieldInfo::new("count", "count", SqlType::BigInt);
1045 assert_eq!(field.effective_sql_type(), "BIGINT");
1046 }
1047
1048 #[test]
1049 fn test_effective_sql_type_decimal_without_precision_scale() {
1050 let field = FieldInfo::new(
1052 "amount",
1053 "amount",
1054 SqlType::Decimal {
1055 precision: 10,
1056 scale: 2,
1057 },
1058 );
1059 assert_eq!(field.effective_sql_type(), "DECIMAL(10, 2)");
1061 }
1062
1063 #[test]
1064 fn test_precision_opt() {
1065 let field = FieldInfo::new(
1066 "test",
1067 "test",
1068 SqlType::Decimal {
1069 precision: 10,
1070 scale: 2,
1071 },
1072 )
1073 .precision_opt(Some(16));
1074 assert_eq!(field.precision, Some(16));
1075
1076 let field2 = FieldInfo::new(
1077 "test2",
1078 "test2",
1079 SqlType::Decimal {
1080 precision: 10,
1081 scale: 2,
1082 },
1083 )
1084 .precision_opt(None);
1085 assert_eq!(field2.precision, None);
1086 }
1087
1088 #[test]
1089 fn test_scale_opt() {
1090 let field = FieldInfo::new(
1091 "test",
1092 "test",
1093 SqlType::Decimal {
1094 precision: 10,
1095 scale: 2,
1096 },
1097 )
1098 .scale_opt(Some(5));
1099 assert_eq!(field.scale, Some(5));
1100
1101 let field2 = FieldInfo::new(
1102 "test2",
1103 "test2",
1104 SqlType::Decimal {
1105 precision: 10,
1106 scale: 2,
1107 },
1108 )
1109 .scale_opt(None);
1110 assert_eq!(field2.scale, None);
1111 }
1112
1113 #[test]
1118 fn test_field_info_alias() {
1119 let field = FieldInfo::new("name", "name", SqlType::Text).alias("userName");
1120 assert_eq!(field.alias, Some("userName"));
1121 assert!(field.validation_alias.is_none());
1122 assert!(field.serialization_alias.is_none());
1123 }
1124
1125 #[test]
1126 fn test_field_info_validation_alias() {
1127 let field = FieldInfo::new("name", "name", SqlType::Text).validation_alias("user_name");
1128 assert!(field.alias.is_none());
1129 assert_eq!(field.validation_alias, Some("user_name"));
1130 assert!(field.serialization_alias.is_none());
1131 }
1132
1133 #[test]
1134 fn test_field_info_serialization_alias() {
1135 let field = FieldInfo::new("name", "name", SqlType::Text).serialization_alias("user-name");
1136 assert!(field.alias.is_none());
1137 assert!(field.validation_alias.is_none());
1138 assert_eq!(field.serialization_alias, Some("user-name"));
1139 }
1140
1141 #[test]
1142 fn test_field_info_all_aliases() {
1143 let field = FieldInfo::new("name", "name", SqlType::Text)
1144 .alias("nm")
1145 .validation_alias("input_name")
1146 .serialization_alias("outputName");
1147
1148 assert_eq!(field.alias, Some("nm"));
1149 assert_eq!(field.validation_alias, Some("input_name"));
1150 assert_eq!(field.serialization_alias, Some("outputName"));
1151 }
1152
1153 #[test]
1154 fn test_field_info_alias_opt() {
1155 let field1 = FieldInfo::new("name", "name", SqlType::Text).alias_opt(Some("userName"));
1156 assert_eq!(field1.alias, Some("userName"));
1157
1158 let field2 = FieldInfo::new("name", "name", SqlType::Text).alias_opt(None);
1159 assert!(field2.alias.is_none());
1160 }
1161
1162 #[test]
1163 fn test_field_info_validation_alias_opt() {
1164 let field1 =
1165 FieldInfo::new("name", "name", SqlType::Text).validation_alias_opt(Some("user_name"));
1166 assert_eq!(field1.validation_alias, Some("user_name"));
1167
1168 let field2 = FieldInfo::new("name", "name", SqlType::Text).validation_alias_opt(None);
1169 assert!(field2.validation_alias.is_none());
1170 }
1171
1172 #[test]
1173 fn test_field_info_serialization_alias_opt() {
1174 let field1 = FieldInfo::new("name", "name", SqlType::Text)
1175 .serialization_alias_opt(Some("user-name"));
1176 assert_eq!(field1.serialization_alias, Some("user-name"));
1177
1178 let field2 = FieldInfo::new("name", "name", SqlType::Text).serialization_alias_opt(None);
1179 assert!(field2.serialization_alias.is_none());
1180 }
1181
1182 #[test]
1183 fn test_field_info_output_name() {
1184 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1186 assert_eq!(field1.output_name(), "name");
1187
1188 let field2 = FieldInfo::new("name", "name", SqlType::Text).alias("nm");
1190 assert_eq!(field2.output_name(), "nm");
1191
1192 let field3 = FieldInfo::new("name", "name", SqlType::Text)
1194 .alias("nm")
1195 .serialization_alias("outputName");
1196 assert_eq!(field3.output_name(), "outputName");
1197
1198 let field4 = FieldInfo::new("name", "name", SqlType::Text).serialization_alias("userName");
1200 assert_eq!(field4.output_name(), "userName");
1201 }
1202
1203 #[test]
1204 fn test_field_info_matches_input_name() {
1205 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1207 assert!(field1.matches_input_name("name"));
1208 assert!(!field1.matches_input_name("userName"));
1209
1210 let field2 = FieldInfo::new("name", "name", SqlType::Text).alias("nm");
1212 assert!(field2.matches_input_name("name"));
1213 assert!(field2.matches_input_name("nm"));
1214 assert!(!field2.matches_input_name("userName"));
1215
1216 let field3 = FieldInfo::new("name", "name", SqlType::Text).validation_alias("user_name");
1218 assert!(field3.matches_input_name("name"));
1219 assert!(field3.matches_input_name("user_name"));
1220 assert!(!field3.matches_input_name("userName"));
1221
1222 let field4 = FieldInfo::new("name", "name", SqlType::Text)
1224 .alias("nm")
1225 .validation_alias("user_name");
1226 assert!(field4.matches_input_name("name"));
1227 assert!(field4.matches_input_name("nm"));
1228 assert!(field4.matches_input_name("user_name"));
1229 }
1230
1231 #[test]
1232 fn test_field_info_has_alias() {
1233 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1234 assert!(!field1.has_alias());
1235
1236 let field2 = FieldInfo::new("name", "name", SqlType::Text).alias("nm");
1237 assert!(field2.has_alias());
1238
1239 let field3 = FieldInfo::new("name", "name", SqlType::Text).validation_alias("user_name");
1240 assert!(field3.has_alias());
1241
1242 let field4 = FieldInfo::new("name", "name", SqlType::Text).serialization_alias("userName");
1243 assert!(field4.has_alias());
1244
1245 let field5 = FieldInfo::new("name", "name", SqlType::Text)
1246 .alias("nm")
1247 .validation_alias("user_name")
1248 .serialization_alias("userName");
1249 assert!(field5.has_alias());
1250 }
1251
1252 #[test]
1253 fn test_field_info_exclude() {
1254 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1256 assert!(!field1.exclude);
1257
1258 let field2 = FieldInfo::new("password", "password", SqlType::Text).exclude(true);
1260 assert!(field2.exclude);
1261
1262 let field3 = FieldInfo::new("email", "email", SqlType::Text).exclude(false);
1264 assert!(!field3.exclude);
1265 }
1266
1267 #[test]
1268 fn test_field_info_exclude_combined_with_other_attrs() {
1269 let field = FieldInfo::new("secret", "secret", SqlType::Text)
1271 .exclude(true)
1272 .nullable(true)
1273 .alias("hidden_value");
1274
1275 assert!(field.exclude);
1276 assert!(field.nullable);
1277 assert_eq!(field.alias, Some("hidden_value"));
1278 }
1279
1280 #[test]
1281 fn test_field_info_title() {
1282 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1283 assert_eq!(field1.title, None);
1284
1285 let field2 = FieldInfo::new("name", "name", SqlType::Text).title("User Name");
1286 assert_eq!(field2.title, Some("User Name"));
1287 }
1288
1289 #[test]
1290 fn test_field_info_description() {
1291 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1292 assert_eq!(field1.description, None);
1293
1294 let field2 =
1295 FieldInfo::new("name", "name", SqlType::Text).description("The full name of the user");
1296 assert_eq!(field2.description, Some("The full name of the user"));
1297 }
1298
1299 #[test]
1300 fn test_field_info_schema_extra() {
1301 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1302 assert_eq!(field1.schema_extra, None);
1303
1304 let field2 =
1305 FieldInfo::new("name", "name", SqlType::Text).schema_extra(r#"{"examples": ["John"]}"#);
1306 assert_eq!(field2.schema_extra, Some(r#"{"examples": ["John"]}"#));
1307 }
1308
1309 #[test]
1310 fn test_field_info_all_schema_metadata() {
1311 let field = FieldInfo::new("name", "name", SqlType::Text)
1312 .title("User Name")
1313 .description("The full name of the user")
1314 .schema_extra(r#"{"examples": ["John Doe"]}"#);
1315
1316 assert_eq!(field.title, Some("User Name"));
1317 assert_eq!(field.description, Some("The full name of the user"));
1318 assert_eq!(field.schema_extra, Some(r#"{"examples": ["John Doe"]}"#));
1319 }
1320
1321 #[test]
1322 fn test_field_info_const_field() {
1323 let field1 = FieldInfo::new("version", "version", SqlType::Text);
1325 assert!(!field1.const_field);
1326
1327 let field2 = FieldInfo::new("version", "version", SqlType::Text).const_field(true);
1329 assert!(field2.const_field);
1330
1331 let field3 = FieldInfo::new("version", "version", SqlType::Text)
1333 .const_field(true)
1334 .default("'1.0.0'");
1335 assert!(field3.const_field);
1336 assert_eq!(field3.default, Some("'1.0.0'"));
1337 }
1338
1339 #[test]
1340 fn test_field_info_column_constraints() {
1341 static CONSTRAINTS: &[&str] = &["CHECK(price > 0)", "CHECK(price < 1000)"];
1342
1343 let field1 = FieldInfo::new("price", "price", SqlType::Integer);
1345 assert!(field1.column_constraints.is_empty());
1346
1347 let field2 =
1349 FieldInfo::new("price", "price", SqlType::Integer).column_constraints(CONSTRAINTS);
1350 assert_eq!(field2.column_constraints.len(), 2);
1351 assert_eq!(field2.column_constraints[0], "CHECK(price > 0)");
1352 }
1353
1354 #[test]
1355 fn test_field_info_column_comment() {
1356 let field1 = FieldInfo::new("name", "name", SqlType::Text);
1358 assert_eq!(field1.column_comment, None);
1359
1360 let field2 =
1362 FieldInfo::new("name", "name", SqlType::Text).column_comment("User's display name");
1363 assert_eq!(field2.column_comment, Some("User's display name"));
1364 }
1365
1366 #[test]
1367 fn test_field_info_column_info() {
1368 let field1 = FieldInfo::new("email", "email", SqlType::Text);
1370 assert_eq!(field1.column_info, None);
1371
1372 let field2 =
1374 FieldInfo::new("email", "email", SqlType::Text).column_info(r#"{"deprecated": true}"#);
1375 assert_eq!(field2.column_info, Some(r#"{"deprecated": true}"#));
1376 }
1377
1378 #[test]
1379 fn test_field_info_discriminator() {
1380 let field1 = FieldInfo::new("pet", "pet", SqlType::Json);
1382 assert_eq!(field1.discriminator, None);
1383
1384 let field2 = FieldInfo::new("pet", "pet", SqlType::Json).discriminator("pet_type");
1386 assert_eq!(field2.discriminator, Some("pet_type"));
1387
1388 let field3 = FieldInfo::new("pet", "pet", SqlType::Json).discriminator_opt(None);
1390 assert_eq!(field3.discriminator, None);
1391
1392 let field4 = FieldInfo::new("pet", "pet", SqlType::Json).discriminator_opt(Some("kind"));
1394 assert_eq!(field4.discriminator, Some("kind"));
1395 }
1396
1397 #[test]
1402 fn test_inheritance_strategy_default() {
1403 let strategy = InheritanceStrategy::default();
1404 assert_eq!(strategy, InheritanceStrategy::None);
1405 assert!(!strategy.is_inheritance());
1406 assert!(!strategy.uses_discriminator());
1407 assert!(!strategy.requires_join());
1408 }
1409
1410 #[test]
1411 fn test_inheritance_strategy_single() {
1412 let strategy = InheritanceStrategy::Single;
1413 assert!(strategy.is_inheritance());
1414 assert!(strategy.uses_discriminator());
1415 assert!(!strategy.requires_join());
1416 }
1417
1418 #[test]
1419 fn test_inheritance_strategy_joined() {
1420 let strategy = InheritanceStrategy::Joined;
1421 assert!(strategy.is_inheritance());
1422 assert!(!strategy.uses_discriminator());
1423 assert!(strategy.requires_join());
1424 }
1425
1426 #[test]
1427 fn test_inheritance_strategy_concrete() {
1428 let strategy = InheritanceStrategy::Concrete;
1429 assert!(strategy.is_inheritance());
1430 assert!(!strategy.uses_discriminator());
1431 assert!(!strategy.requires_join());
1432 }
1433
1434 #[test]
1439 fn test_inheritance_info_none() {
1440 let info = InheritanceInfo::none();
1441 assert_eq!(info.strategy, InheritanceStrategy::None);
1442 assert!(info.parent.is_none());
1443 assert!(info.discriminator_value.is_none());
1444 assert!(!info.is_child());
1445 assert!(!info.is_base());
1446 }
1447
1448 #[test]
1449 fn test_inheritance_info_single_table_base() {
1450 let info = InheritanceInfo::single_table();
1451 assert_eq!(info.strategy, InheritanceStrategy::Single);
1452 assert!(info.parent.is_none());
1453 assert!(info.is_base());
1454 assert!(!info.is_child());
1455 }
1456
1457 #[test]
1458 fn test_inheritance_info_joined_table_base() {
1459 let info = InheritanceInfo::joined_table();
1460 assert_eq!(info.strategy, InheritanceStrategy::Joined);
1461 assert!(info.parent.is_none());
1462 assert!(info.is_base());
1463 assert!(!info.is_child());
1464 }
1465
1466 #[test]
1467 fn test_inheritance_info_concrete_table_base() {
1468 let info = InheritanceInfo::concrete_table();
1469 assert_eq!(info.strategy, InheritanceStrategy::Concrete);
1470 assert!(info.parent.is_none());
1471 assert!(info.is_base());
1472 assert!(!info.is_child());
1473 }
1474
1475 #[test]
1476 fn test_inheritance_info_child() {
1477 let info = InheritanceInfo::child("employees");
1478 assert_eq!(info.parent, Some("employees"));
1479 assert!(info.is_child());
1480 assert!(!info.is_base());
1481 }
1482
1483 #[test]
1484 fn test_inheritance_info_child_with_discriminator_value() {
1485 let info = InheritanceInfo::child("employees").with_discriminator_value("manager");
1486 assert_eq!(info.parent, Some("employees"));
1487 assert_eq!(info.discriminator_value, Some("manager"));
1488 assert!(info.is_child());
1489 }
1490
1491 #[test]
1492 fn test_inheritance_info_single_table_with_discriminator_column() {
1493 let info = InheritanceInfo::single_table().with_discriminator_column("type");
1494 assert_eq!(info.strategy, InheritanceStrategy::Single);
1495 assert_eq!(info.discriminator_column, Some("type"));
1496 assert!(info.is_base());
1497 }
1498}