1use std::fmt;
27use std::hash::{Hash, Hasher};
28
29#[derive(Debug, Clone)]
59pub struct TableIdentifier {
60 schema_canonical: Option<String>,
62 schema_display: Option<String>,
63 schema_quoted: bool,
64
65 table_canonical: String,
67 table_display: String,
68 table_quoted: bool,
69
70 canonical: String,
75
76 display: String,
79
80 quoted: bool,
84}
85
86impl TableIdentifier {
87 pub fn new(name: &str, quoted: bool) -> Self {
119 let table_canonical = if quoted {
120 name.to_string()
122 } else {
123 name.to_ascii_lowercase()
125 };
126
127 Self {
128 schema_canonical: None,
129 schema_display: None,
130 schema_quoted: false,
131 table_canonical: table_canonical.clone(),
132 table_display: name.to_string(),
133 table_quoted: quoted,
134 canonical: table_canonical,
135 display: name.to_string(),
136 quoted,
137 }
138 }
139
140 pub fn from_canonical(canonical: String, quoted: bool) -> Self {
145 Self {
146 schema_canonical: None,
147 schema_display: None,
148 schema_quoted: false,
149 table_canonical: canonical.clone(),
150 table_display: canonical.clone(),
151 table_quoted: quoted,
152 canonical: canonical.clone(),
153 display: canonical,
154 quoted,
155 }
156 }
157
158 pub fn qualified(
189 schema_name: &str,
190 schema_quoted: bool,
191 table_name: &str,
192 table_quoted: bool,
193 ) -> Self {
194 let schema_canonical =
195 if schema_quoted { schema_name.to_string() } else { schema_name.to_ascii_lowercase() };
196
197 let table_canonical =
198 if table_quoted { table_name.to_string() } else { table_name.to_ascii_lowercase() };
199
200 let canonical = format!("{}.{}", schema_canonical, table_canonical);
201 let display = format!("{}.{}", schema_name, table_name);
202
203 Self {
204 schema_canonical: Some(schema_canonical),
205 schema_display: Some(schema_name.to_string()),
206 schema_quoted,
207 table_canonical,
208 table_display: table_name.to_string(),
209 table_quoted,
210 canonical,
211 display,
212 quoted: table_quoted,
213 }
214 }
215
216 #[inline]
222 pub fn canonical(&self) -> &str {
223 &self.canonical
224 }
225
226 #[inline]
231 pub fn display(&self) -> &str {
232 &self.display
233 }
234
235 #[inline]
237 pub fn is_quoted(&self) -> bool {
238 self.quoted
239 }
240
241 #[inline]
245 pub fn into_canonical(self) -> String {
246 self.canonical
247 }
248
249 #[inline]
251 pub fn is_qualified(&self) -> bool {
252 self.schema_canonical.is_some()
253 }
254
255 #[inline]
257 pub fn schema_canonical(&self) -> Option<&str> {
258 self.schema_canonical.as_deref()
259 }
260
261 #[inline]
263 pub fn schema_display(&self) -> Option<&str> {
264 self.schema_display.as_deref()
265 }
266
267 #[inline]
269 pub fn is_schema_quoted(&self) -> bool {
270 self.schema_quoted
271 }
272
273 #[inline]
278 pub fn table_canonical(&self) -> &str {
279 &self.table_canonical
280 }
281
282 #[inline]
287 pub fn table_display(&self) -> &str {
288 &self.table_display
289 }
290
291 #[inline]
296 pub fn is_table_quoted(&self) -> bool {
297 self.table_quoted
298 }
299
300 pub fn unquoted(name: &str) -> Self {
305 Self::new(name, false)
306 }
307
308 pub fn quoted(name: &str) -> Self {
313 Self::new(name, true)
314 }
315}
316
317impl PartialEq for TableIdentifier {
318 fn eq(&self, other: &Self) -> bool {
320 self.canonical == other.canonical
321 }
322}
323
324impl Eq for TableIdentifier {}
325
326impl Hash for TableIdentifier {
327 fn hash<H: Hasher>(&self, state: &mut H) {
329 self.canonical.hash(state);
330 }
331}
332
333impl fmt::Display for TableIdentifier {
334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 write!(f, "{}", self.display)
337 }
338}
339
340impl From<&str> for TableIdentifier {
341 fn from(s: &str) -> Self {
343 Self::new(s, false)
344 }
345}
346
347impl From<String> for TableIdentifier {
348 fn from(s: String) -> Self {
350 Self::new(&s, false)
351 }
352}
353
354#[derive(Debug, Clone)]
396pub struct ColumnIdentifier {
397 schema_canonical: Option<String>,
399 schema_display: Option<String>,
400 schema_quoted: bool,
401
402 table_canonical: Option<String>,
404 table_display: Option<String>,
405 table_quoted: bool,
406
407 column_canonical: String,
409 column_display: String,
410 column_quoted: bool,
411
412 canonical: String,
415
416 display: String,
419}
420
421impl ColumnIdentifier {
422 pub fn simple(column: &str, quoted: bool) -> Self {
439 let column_canonical =
440 if quoted { column.to_string() } else { column.to_ascii_lowercase() };
441
442 Self {
443 schema_canonical: None,
444 schema_display: None,
445 schema_quoted: false,
446 table_canonical: None,
447 table_display: None,
448 table_quoted: false,
449 column_canonical: column_canonical.clone(),
450 column_display: column.to_string(),
451 column_quoted: quoted,
452 canonical: column_canonical,
453 display: column.to_string(),
454 }
455 }
456
457 pub fn qualified(table: &str, table_quoted: bool, column: &str, column_quoted: bool) -> Self {
477 let table_canonical =
478 if table_quoted { table.to_string() } else { table.to_ascii_lowercase() };
479
480 let column_canonical =
481 if column_quoted { column.to_string() } else { column.to_ascii_lowercase() };
482
483 let canonical = format!("{}.{}", table_canonical, column_canonical);
484 let display = format!("{}.{}", table, column);
485
486 Self {
487 schema_canonical: None,
488 schema_display: None,
489 schema_quoted: false,
490 table_canonical: Some(table_canonical),
491 table_display: Some(table.to_string()),
492 table_quoted,
493 column_canonical,
494 column_display: column.to_string(),
495 column_quoted,
496 canonical,
497 display,
498 }
499 }
500
501 pub fn fully_qualified(
525 schema: &str,
526 schema_quoted: bool,
527 table: &str,
528 table_quoted: bool,
529 column: &str,
530 column_quoted: bool,
531 ) -> Self {
532 let schema_canonical =
533 if schema_quoted { schema.to_string() } else { schema.to_ascii_lowercase() };
534
535 let table_canonical =
536 if table_quoted { table.to_string() } else { table.to_ascii_lowercase() };
537
538 let column_canonical =
539 if column_quoted { column.to_string() } else { column.to_ascii_lowercase() };
540
541 let canonical = format!("{}.{}.{}", schema_canonical, table_canonical, column_canonical);
542 let display = format!("{}.{}.{}", schema, table, column);
543
544 Self {
545 schema_canonical: Some(schema_canonical),
546 schema_display: Some(schema.to_string()),
547 schema_quoted,
548 table_canonical: Some(table_canonical),
549 table_display: Some(table.to_string()),
550 table_quoted,
551 column_canonical,
552 column_display: column.to_string(),
553 column_quoted,
554 canonical,
555 display,
556 }
557 }
558
559 pub fn unquoted(column: &str) -> Self {
572 Self::simple(column, false)
573 }
574
575 pub fn quoted(column: &str) -> Self {
588 Self::simple(column, true)
589 }
590
591 pub fn table_column(table: &str, column: &str) -> Self {
602 Self::qualified(table, false, column, false)
603 }
604
605 pub fn from_canonical(canonical: String, quoted: bool) -> Self {
610 Self {
611 schema_canonical: None,
612 schema_display: None,
613 schema_quoted: false,
614 table_canonical: None,
615 table_display: None,
616 table_quoted: false,
617 column_canonical: canonical.clone(),
618 column_display: canonical.clone(),
619 column_quoted: quoted,
620 canonical: canonical.clone(),
621 display: canonical,
622 }
623 }
624
625 #[inline]
630 pub fn canonical(&self) -> &str {
631 &self.canonical
632 }
633
634 #[inline]
639 pub fn display(&self) -> &str {
640 &self.display
641 }
642
643 #[inline]
645 pub fn column_canonical(&self) -> &str {
646 &self.column_canonical
647 }
648
649 #[inline]
651 pub fn column_display(&self) -> &str {
652 &self.column_display
653 }
654
655 #[inline]
657 pub fn is_column_quoted(&self) -> bool {
658 self.column_quoted
659 }
660
661 #[inline]
663 pub fn table_canonical(&self) -> Option<&str> {
664 self.table_canonical.as_deref()
665 }
666
667 #[inline]
669 pub fn table_display(&self) -> Option<&str> {
670 self.table_display.as_deref()
671 }
672
673 #[inline]
675 pub fn is_table_quoted(&self) -> bool {
676 self.table_quoted
677 }
678
679 #[inline]
681 pub fn schema_canonical(&self) -> Option<&str> {
682 self.schema_canonical.as_deref()
683 }
684
685 #[inline]
687 pub fn schema_display(&self) -> Option<&str> {
688 self.schema_display.as_deref()
689 }
690
691 #[inline]
693 pub fn is_schema_quoted(&self) -> bool {
694 self.schema_quoted
695 }
696
697 #[inline]
699 pub fn is_qualified(&self) -> bool {
700 self.table_canonical.is_some()
701 }
702
703 #[inline]
705 pub fn is_fully_qualified(&self) -> bool {
706 self.schema_canonical.is_some()
707 }
708
709 #[inline]
711 pub fn is_ambiguous(&self) -> bool {
712 self.table_canonical.is_none()
713 }
714
715 #[inline]
717 pub fn into_canonical(self) -> String {
718 self.canonical
719 }
720
721 pub fn matches_column_name(&self, name: &str, case_sensitive: bool) -> bool {
726 if case_sensitive {
727 self.column_canonical == name
728 } else {
729 self.column_canonical == name.to_ascii_lowercase()
730 }
731 }
732
733 pub fn resolve_against(&self, table: &TableIdentifier) -> Self {
738 if self.is_qualified() {
739 return self.clone();
740 }
741
742 if table.is_qualified() {
743 Self::fully_qualified(
745 table.schema_display().unwrap_or_default(),
746 table.is_schema_quoted(),
747 table.table_display(),
748 table.is_table_quoted(),
749 &self.column_display,
750 self.column_quoted,
751 )
752 } else {
753 Self::qualified(
755 table.table_display(),
756 table.is_table_quoted(),
757 &self.column_display,
758 self.column_quoted,
759 )
760 }
761 }
762
763 pub fn matches(&self, other: &ColumnIdentifier) -> bool {
770 if self.is_fully_qualified() != other.is_fully_qualified() {
772 if self.is_ambiguous() {
774 return self.column_canonical == other.column_canonical;
775 }
776 if other.is_ambiguous() {
777 return self.column_canonical == other.column_canonical;
778 }
779 return false;
780 }
781
782 if self.is_qualified() != other.is_qualified() {
783 if self.is_ambiguous() {
785 return self.column_canonical == other.column_canonical;
786 }
787 if other.is_ambiguous() {
788 return self.column_canonical == other.column_canonical;
789 }
790 return false;
791 }
792
793 self.canonical == other.canonical
795 }
796
797 pub fn unqualify(&self) -> Self {
801 Self::simple(&self.column_display, self.column_quoted)
802 }
803
804 pub fn with_table(&self, table: &str, table_quoted: bool) -> Self {
808 if let Some(schema_display) = &self.schema_display {
809 Self::fully_qualified(
810 schema_display,
811 self.schema_quoted,
812 table,
813 table_quoted,
814 &self.column_display,
815 self.column_quoted,
816 )
817 } else {
818 Self::qualified(table, table_quoted, &self.column_display, self.column_quoted)
819 }
820 }
821}
822
823impl PartialEq for ColumnIdentifier {
824 fn eq(&self, other: &Self) -> bool {
826 self.canonical == other.canonical
827 }
828}
829
830impl Eq for ColumnIdentifier {}
831
832impl Hash for ColumnIdentifier {
833 fn hash<H: Hasher>(&self, state: &mut H) {
835 self.canonical.hash(state);
836 }
837}
838
839impl fmt::Display for ColumnIdentifier {
840 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
842 write!(f, "{}", self.display)
843 }
844}
845
846impl From<&str> for ColumnIdentifier {
847 fn from(s: &str) -> Self {
849 Self::simple(s, false)
850 }
851}
852
853impl From<String> for ColumnIdentifier {
854 fn from(s: String) -> Self {
856 Self::simple(&s, false)
857 }
858}
859
860pub type Identifier = TableIdentifier;
864
865#[derive(Debug, Clone)]
882pub struct FunctionIdentifier {
883 canonical: String,
885 display: String,
887}
888
889impl FunctionIdentifier {
890 pub fn new(name: &str) -> Self {
895 Self { canonical: name.to_lowercase(), display: name.to_string() }
896 }
897
898 pub fn canonical(&self) -> &str {
900 &self.canonical
901 }
902
903 pub fn display(&self) -> &str {
905 &self.display
906 }
907
908 pub fn matches(&self, name: &str) -> bool {
910 self.canonical == name.to_lowercase()
911 }
912
913 pub fn as_str(&self) -> &str {
915 &self.canonical
916 }
917
918 pub fn to_lowercase(&self) -> String {
921 self.canonical.clone()
922 }
923
924 pub fn to_uppercase(&self) -> String {
927 self.canonical.to_uppercase()
928 }
929
930 pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
933 self.canonical == other.to_ascii_lowercase()
934 }
935}
936
937impl PartialEq for FunctionIdentifier {
938 fn eq(&self, other: &Self) -> bool {
939 self.canonical == other.canonical
940 }
941}
942
943impl PartialEq<str> for FunctionIdentifier {
944 fn eq(&self, other: &str) -> bool {
945 self.canonical == other.to_lowercase()
946 }
947}
948
949impl PartialEq<&str> for FunctionIdentifier {
950 fn eq(&self, other: &&str) -> bool {
951 self.canonical == other.to_lowercase()
952 }
953}
954
955impl Eq for FunctionIdentifier {}
956
957impl Hash for FunctionIdentifier {
958 fn hash<H: Hasher>(&self, state: &mut H) {
959 self.canonical.hash(state);
960 }
961}
962
963impl fmt::Display for FunctionIdentifier {
964 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
965 write!(f, "{}", self.display)
966 }
967}
968
969impl From<&str> for FunctionIdentifier {
970 fn from(s: &str) -> Self {
971 Self::new(s)
972 }
973}
974
975impl From<String> for FunctionIdentifier {
976 fn from(s: String) -> Self {
977 Self::new(&s)
978 }
979}
980
981#[cfg(test)]
982mod tests {
983 use super::*;
984 use std::collections::HashMap;
985
986 #[test]
987 fn test_unquoted_case_insensitive() {
988 let id1 = TableIdentifier::new("MyTable", false);
989 let id2 = TableIdentifier::new("mytable", false);
990 let id3 = TableIdentifier::new("MYTABLE", false);
991 let id4 = TableIdentifier::new("myTABLE", false);
992
993 assert_eq!(id1, id2);
995 assert_eq!(id2, id3);
996 assert_eq!(id3, id4);
997
998 assert_eq!(id1.canonical(), "mytable");
1000 assert_eq!(id2.canonical(), "mytable");
1001 assert_eq!(id3.canonical(), "mytable");
1002
1003 assert_eq!(id1.display(), "MyTable");
1005 assert_eq!(id2.display(), "mytable");
1006 assert_eq!(id3.display(), "MYTABLE");
1007 }
1008
1009 #[test]
1010 fn test_quoted_case_sensitive() {
1011 let id1 = TableIdentifier::new("MyTable", true);
1012 let id2 = TableIdentifier::new("mytable", true);
1013 let id3 = TableIdentifier::new("MYTABLE", true);
1014
1015 assert_ne!(id1, id2);
1017 assert_ne!(id2, id3);
1018 assert_ne!(id1, id3);
1019
1020 assert_eq!(id1.canonical(), "MyTable");
1022 assert_eq!(id2.canonical(), "mytable");
1023 assert_eq!(id3.canonical(), "MYTABLE");
1024 }
1025
1026 #[test]
1027 fn test_quoted_vs_unquoted() {
1028 let unquoted = TableIdentifier::new("MyTable", false);
1031 let quoted = TableIdentifier::new("MyTable", true);
1032
1033 assert_ne!(unquoted, quoted);
1034 assert_eq!(unquoted.canonical(), "mytable");
1035 assert_eq!(quoted.canonical(), "MyTable");
1036 }
1037
1038 #[test]
1039 fn test_quoted_lowercase_matches_unquoted() {
1040 let unquoted = TableIdentifier::new("MyTable", false);
1043 let quoted_lower = TableIdentifier::new("mytable", true);
1044
1045 assert_eq!(unquoted, quoted_lower);
1046 assert_eq!(unquoted.canonical(), "mytable");
1047 assert_eq!(quoted_lower.canonical(), "mytable");
1048 }
1049
1050 #[test]
1051 fn test_hashmap_lookup() {
1052 let mut map: HashMap<TableIdentifier, i32> = HashMap::new();
1053
1054 let key = TableIdentifier::new("users", false);
1056 map.insert(key, 42);
1057
1058 let lookup1 = TableIdentifier::new("USERS", false);
1060 let lookup2 = TableIdentifier::new("Users", false);
1061 let lookup3 = TableIdentifier::new("users", false);
1062
1063 assert_eq!(map.get(&lookup1), Some(&42));
1064 assert_eq!(map.get(&lookup2), Some(&42));
1065 assert_eq!(map.get(&lookup3), Some(&42));
1066
1067 let quoted_lower = TableIdentifier::new("users", true);
1070 assert_eq!(map.get("ed_lower), Some(&42));
1071
1072 let quoted_upper = TableIdentifier::new("USERS", true);
1074 assert_eq!(map.get("ed_upper), None);
1075 }
1076
1077 #[test]
1078 fn test_hashmap_quoted_keys() {
1079 let mut map: HashMap<TableIdentifier, i32> = HashMap::new();
1080
1081 let key = TableIdentifier::new("MyTable", true);
1083 map.insert(key, 42);
1084
1085 let exact = TableIdentifier::new("MyTable", true);
1087 let wrong_case = TableIdentifier::new("mytable", true);
1088 let unquoted = TableIdentifier::new("MyTable", false); assert_eq!(map.get(&exact), Some(&42));
1091 assert_eq!(map.get(&wrong_case), None); assert_eq!(map.get(&unquoted), None); }
1094
1095 #[test]
1096 fn test_display_trait() {
1097 let id = TableIdentifier::new("MyTable", false);
1098 assert_eq!(format!("{}", id), "MyTable");
1099
1100 let quoted = TableIdentifier::new("MyTable", true);
1101 assert_eq!(format!("{}", quoted), "MyTable");
1102 }
1103
1104 #[test]
1105 fn test_from_traits() {
1106 let id1: TableIdentifier = "MyTable".into();
1107 let id2: TableIdentifier = String::from("MyTable").into();
1108
1109 assert_eq!(id1, id2);
1110 assert_eq!(id1.canonical(), "mytable"); }
1112
1113 #[test]
1114 fn test_helper_constructors() {
1115 let unquoted = TableIdentifier::unquoted("MyTable");
1116 let quoted = TableIdentifier::quoted("MyTable");
1117
1118 assert!(!unquoted.is_quoted());
1119 assert!(quoted.is_quoted());
1120
1121 assert_eq!(unquoted.canonical(), "mytable");
1122 assert_eq!(quoted.canonical(), "MyTable");
1123 }
1124
1125 #[test]
1126 fn test_from_canonical() {
1127 let id = TableIdentifier::from_canonical("mytable".to_string(), false);
1128 assert_eq!(id.canonical(), "mytable");
1129 assert_eq!(id.display(), "mytable");
1130 assert!(!id.is_quoted());
1131
1132 let quoted_id = TableIdentifier::from_canonical("MyTable".to_string(), true);
1133 assert_eq!(quoted_id.canonical(), "MyTable");
1134 assert_eq!(quoted_id.display(), "MyTable");
1135 assert!(quoted_id.is_quoted());
1136 }
1137
1138 #[test]
1139 fn test_into_canonical() {
1140 let id = TableIdentifier::new("MyTable", false);
1141 let canonical: String = id.into_canonical();
1142 assert_eq!(canonical, "mytable");
1143 }
1144
1145 #[test]
1146 fn test_sql_examples_from_issue() {
1147 let created = TableIdentifier::new("MyTable", false);
1153 let lookup1 = TableIdentifier::new("mytable", false);
1154 let lookup2 = TableIdentifier::new("MYTABLE", false);
1155
1156 assert_eq!(created, lookup1);
1157 assert_eq!(created, lookup2);
1158
1159 let quoted_created = TableIdentifier::new("MyTable", true);
1161 assert_ne!(created, quoted_created);
1162
1163 let quoted_lookup = TableIdentifier::new("MyTable", true);
1165 assert_eq!(quoted_created, quoted_lookup);
1166 assert_ne!(created, quoted_lookup);
1167
1168 let unquoted_lookup = TableIdentifier::new("MyTable", false);
1170 assert_eq!(created, unquoted_lookup);
1171 assert_ne!(quoted_created, unquoted_lookup);
1172 }
1173
1174 #[test]
1175 fn test_create_duplicate_detection() {
1176 let first = TableIdentifier::new("test", false);
1179 let second = TableIdentifier::new("TEST", false);
1180 assert_eq!(first, second); assert_eq!(first.canonical(), "test"); let quoted = TableIdentifier::new("TEST", true);
1185 assert_ne!(first, quoted); let quoted_lower = TableIdentifier::new("test", true);
1189 assert_eq!(first, quoted_lower); }
1191
1192 #[test]
1193 fn test_qualified_identifier_unquoted_both() {
1194 let id = TableIdentifier::qualified("myApp", false, "users", false);
1196
1197 assert!(id.is_qualified());
1198 assert_eq!(id.canonical(), "myapp.users");
1199 assert_eq!(id.display(), "myApp.users");
1200
1201 assert_eq!(id.schema_canonical(), Some("myapp"));
1202 assert_eq!(id.schema_display(), Some("myApp"));
1203 assert!(!id.is_schema_quoted());
1204
1205 assert_eq!(id.table_canonical(), "users");
1206 assert_eq!(id.table_display(), "users");
1207 assert!(!id.is_table_quoted());
1208 }
1209
1210 #[test]
1211 fn test_qualified_identifier_quoted_schema() {
1212 let id = TableIdentifier::qualified("myApp", true, "users", false);
1214
1215 assert!(id.is_qualified());
1216 assert_eq!(id.canonical(), "myApp.users");
1217 assert_eq!(id.display(), "myApp.users");
1218
1219 assert_eq!(id.schema_canonical(), Some("myApp"));
1220 assert_eq!(id.schema_display(), Some("myApp"));
1221 assert!(id.is_schema_quoted());
1222
1223 assert_eq!(id.table_canonical(), "users");
1224 assert_eq!(id.table_display(), "users");
1225 assert!(!id.is_table_quoted());
1226 }
1227
1228 #[test]
1229 fn test_qualified_identifier_quoted_table() {
1230 let id = TableIdentifier::qualified("myapp", false, "Users", true);
1232
1233 assert!(id.is_qualified());
1234 assert_eq!(id.canonical(), "myapp.Users");
1235 assert_eq!(id.display(), "myapp.Users");
1236
1237 assert_eq!(id.schema_canonical(), Some("myapp"));
1238 assert_eq!(id.schema_display(), Some("myapp"));
1239 assert!(!id.is_schema_quoted());
1240
1241 assert_eq!(id.table_canonical(), "Users");
1242 assert_eq!(id.table_display(), "Users");
1243 assert!(id.is_table_quoted());
1244 }
1245
1246 #[test]
1247 fn test_qualified_identifier_quoted_both() {
1248 let id = TableIdentifier::qualified("myApp", true, "Users", true);
1250
1251 assert!(id.is_qualified());
1252 assert_eq!(id.canonical(), "myApp.Users");
1253 assert_eq!(id.display(), "myApp.Users");
1254
1255 assert_eq!(id.schema_canonical(), Some("myApp"));
1256 assert_eq!(id.schema_display(), Some("myApp"));
1257 assert!(id.is_schema_quoted());
1258
1259 assert_eq!(id.table_canonical(), "Users");
1260 assert_eq!(id.table_display(), "Users");
1261 assert!(id.is_table_quoted());
1262 }
1263
1264 #[test]
1265 fn test_qualified_identifier_equality() {
1266 let id1 = TableIdentifier::qualified("myApp", false, "users", false);
1268 let id2 = TableIdentifier::qualified("MYAPP", false, "USERS", false);
1269 assert_eq!(id1, id2);
1270 assert_eq!(id1.canonical(), "myapp.users");
1271 assert_eq!(id2.canonical(), "myapp.users");
1272
1273 let id3 = TableIdentifier::qualified("myApp", true, "users", false);
1275 let id4 = TableIdentifier::qualified("MYAPP", true, "users", false);
1276 assert_ne!(id3, id4);
1277 assert_eq!(id3.canonical(), "myApp.users");
1278 assert_eq!(id4.canonical(), "MYAPP.users");
1279
1280 let id5 = TableIdentifier::qualified("myapp", false, "Users", true);
1282 let id6 = TableIdentifier::qualified("myapp", false, "USERS", true);
1283 assert_ne!(id5, id6);
1284 assert_eq!(id5.canonical(), "myapp.Users");
1285 assert_eq!(id6.canonical(), "myapp.USERS");
1286 }
1287
1288 #[test]
1289 fn test_qualified_vs_simple_identifier() {
1290 let simple = TableIdentifier::new("users", false);
1292 let qualified = TableIdentifier::qualified("myapp", false, "users", false);
1293
1294 assert_ne!(simple, qualified);
1295 assert_eq!(simple.canonical(), "users");
1296 assert_eq!(qualified.canonical(), "myapp.users");
1297
1298 assert!(!simple.is_qualified());
1299 assert!(qualified.is_qualified());
1300 }
1301
1302 #[test]
1303 fn test_qualified_identifier_hashmap() {
1304 let mut map: HashMap<TableIdentifier, i32> = HashMap::new();
1305
1306 let key = TableIdentifier::qualified("myApp", true, "users", false);
1308 map.insert(key, 42);
1309
1310 let lookup1 = TableIdentifier::qualified("myApp", true, "USERS", false);
1312 assert_eq!(map.get(&lookup1), Some(&42));
1313
1314 let lookup2 = TableIdentifier::qualified("MYAPP", true, "users", false);
1316 assert_eq!(map.get(&lookup2), None);
1317
1318 let lookup3 = TableIdentifier::qualified("myApp", false, "users", false);
1320 assert_eq!(map.get(&lookup3), None);
1321 }
1322
1323 #[test]
1326 fn test_column_unquoted_case_insensitive() {
1327 let c1 = ColumnIdentifier::simple("MyColumn", false);
1328 let c2 = ColumnIdentifier::simple("mycolumn", false);
1329 let c3 = ColumnIdentifier::simple("MYCOLUMN", false);
1330
1331 assert_eq!(c1, c2);
1333 assert_eq!(c2, c3);
1334
1335 assert_eq!(c1.canonical(), "mycolumn");
1337 assert_eq!(c2.canonical(), "mycolumn");
1338 assert_eq!(c3.canonical(), "mycolumn");
1339
1340 assert_eq!(c1.display(), "MyColumn");
1342 assert_eq!(c2.display(), "mycolumn");
1343 assert_eq!(c3.display(), "MYCOLUMN");
1344 }
1345
1346 #[test]
1347 fn test_column_quoted_case_sensitive() {
1348 let c1 = ColumnIdentifier::simple("MyColumn", true);
1349 let c2 = ColumnIdentifier::simple("mycolumn", true);
1350 let c3 = ColumnIdentifier::simple("MYCOLUMN", true);
1351
1352 assert_ne!(c1, c2);
1354 assert_ne!(c2, c3);
1355 assert_ne!(c1, c3);
1356
1357 assert_eq!(c1.canonical(), "MyColumn");
1359 assert_eq!(c2.canonical(), "mycolumn");
1360 assert_eq!(c3.canonical(), "MYCOLUMN");
1361 }
1362
1363 #[test]
1364 fn test_column_qualified() {
1365 let c = ColumnIdentifier::qualified("Users", false, "ID", false);
1366 assert_eq!(c.canonical(), "users.id");
1367 assert_eq!(c.table_canonical(), Some("users"));
1368 assert_eq!(c.column_canonical(), "id");
1369 assert!(c.is_qualified());
1370 assert!(!c.is_fully_qualified());
1371 assert!(!c.is_ambiguous());
1372 }
1373
1374 #[test]
1375 fn test_column_fully_qualified() {
1376 let c = ColumnIdentifier::fully_qualified(
1377 "myApp", true, "users", false, "ID", false, );
1381 assert_eq!(c.canonical(), "myApp.users.id");
1382 assert_eq!(c.schema_canonical(), Some("myApp"));
1383 assert_eq!(c.table_canonical(), Some("users"));
1384 assert_eq!(c.column_canonical(), "id");
1385 assert!(c.is_qualified());
1386 assert!(c.is_fully_qualified());
1387 assert!(!c.is_ambiguous());
1388 }
1389
1390 #[test]
1391 fn test_column_convenience_constructors() {
1392 let unquoted = ColumnIdentifier::unquoted("MyColumn");
1393 assert_eq!(unquoted.canonical(), "mycolumn");
1394 assert!(!unquoted.is_column_quoted());
1395
1396 let quoted = ColumnIdentifier::quoted("MyColumn");
1397 assert_eq!(quoted.canonical(), "MyColumn");
1398 assert!(quoted.is_column_quoted());
1399
1400 let table_col = ColumnIdentifier::table_column("users", "id");
1401 assert_eq!(table_col.canonical(), "users.id");
1402 assert!(table_col.is_qualified());
1403 }
1404
1405 #[test]
1406 fn test_column_hashmap_lookup() {
1407 let mut map: HashMap<ColumnIdentifier, i32> = HashMap::new();
1408
1409 let key = ColumnIdentifier::simple("userId", false);
1411 map.insert(key, 42);
1412
1413 let lookup1 = ColumnIdentifier::simple("USERID", false);
1415 let lookup2 = ColumnIdentifier::simple("UserId", false);
1416 let lookup3 = ColumnIdentifier::simple("userid", false);
1417
1418 assert_eq!(map.get(&lookup1), Some(&42));
1419 assert_eq!(map.get(&lookup2), Some(&42));
1420 assert_eq!(map.get(&lookup3), Some(&42));
1421
1422 let quoted_lower = ColumnIdentifier::simple("userid", true);
1424 assert_eq!(map.get("ed_lower), Some(&42));
1425
1426 let quoted_upper = ColumnIdentifier::simple("USERID", true);
1428 assert_eq!(map.get("ed_upper), None);
1429 }
1430
1431 #[test]
1432 fn test_column_matches_column_name() {
1433 let c = ColumnIdentifier::qualified("users", false, "id", false);
1434
1435 assert!(c.matches_column_name("id", false));
1437 assert!(c.matches_column_name("ID", false));
1438 assert!(c.matches_column_name("Id", false));
1439
1440 assert!(c.matches_column_name("id", true));
1442 assert!(!c.matches_column_name("ID", true));
1443 assert!(!c.matches_column_name("Id", true));
1444 }
1445
1446 #[test]
1447 fn test_column_matches() {
1448 let c1 = ColumnIdentifier::qualified("users", false, "id", false);
1450 let c2 = ColumnIdentifier::qualified("USERS", false, "ID", false);
1451 assert!(c1.matches(&c2));
1452
1453 let unqualified = ColumnIdentifier::simple("id", false);
1455 assert!(unqualified.matches(&c1));
1456 assert!(c1.matches(&unqualified));
1457
1458 let c3 = ColumnIdentifier::qualified("orders", false, "id", false);
1460 assert!(!c1.matches(&c3));
1461
1462 assert!(unqualified.matches(&c3));
1464 }
1465
1466 #[test]
1467 fn test_column_resolve_against() {
1468 let col = ColumnIdentifier::simple("id", false);
1469 let table = TableIdentifier::new("users", false);
1470
1471 let resolved = col.resolve_against(&table);
1472 assert_eq!(resolved.canonical(), "users.id");
1473 assert!(resolved.is_qualified());
1474
1475 let qualified = ColumnIdentifier::qualified("orders", false, "id", false);
1477 let resolved2 = qualified.resolve_against(&table);
1478 assert_eq!(resolved2.canonical(), "orders.id");
1479 }
1480
1481 #[test]
1482 fn test_column_resolve_against_qualified_table() {
1483 let col = ColumnIdentifier::simple("id", false);
1484 let table = TableIdentifier::qualified("myapp", false, "users", false);
1485
1486 let resolved = col.resolve_against(&table);
1487 assert_eq!(resolved.canonical(), "myapp.users.id");
1488 assert!(resolved.is_fully_qualified());
1489 }
1490
1491 #[test]
1492 fn test_column_unqualify() {
1493 let qualified = ColumnIdentifier::qualified("users", false, "ID", true);
1494 let unqualified = qualified.unqualify();
1495
1496 assert!(!unqualified.is_qualified());
1497 assert_eq!(unqualified.column_canonical(), "ID"); assert!(unqualified.is_column_quoted());
1499 }
1500
1501 #[test]
1502 fn test_column_with_table() {
1503 let col = ColumnIdentifier::simple("id", false);
1504 let with_table = col.with_table("users", false);
1505
1506 assert_eq!(with_table.canonical(), "users.id");
1507 assert_eq!(with_table.table_canonical(), Some("users"));
1508 }
1509
1510 #[test]
1511 fn test_column_display_trait() {
1512 let c = ColumnIdentifier::qualified("Users", false, "ID", false);
1513 assert_eq!(format!("{}", c), "Users.ID");
1514
1515 let simple = ColumnIdentifier::simple("MyColumn", false);
1516 assert_eq!(format!("{}", simple), "MyColumn");
1517 }
1518
1519 #[test]
1520 fn test_column_from_traits() {
1521 let c1: ColumnIdentifier = "MyColumn".into();
1522 let c2: ColumnIdentifier = String::from("MyColumn").into();
1523
1524 assert_eq!(c1, c2);
1525 assert_eq!(c1.canonical(), "mycolumn"); }
1527
1528 #[test]
1529 fn test_column_from_canonical() {
1530 let c = ColumnIdentifier::from_canonical("mycolumn".to_string(), false);
1531 assert_eq!(c.canonical(), "mycolumn");
1532 assert_eq!(c.display(), "mycolumn");
1533 assert!(!c.is_column_quoted());
1534
1535 let quoted = ColumnIdentifier::from_canonical("MyColumn".to_string(), true);
1536 assert_eq!(quoted.canonical(), "MyColumn");
1537 assert_eq!(quoted.display(), "MyColumn");
1538 assert!(quoted.is_column_quoted());
1539 }
1540
1541 #[test]
1542 fn test_column_into_canonical() {
1543 let c = ColumnIdentifier::simple("MyColumn", false);
1544 let canonical: String = c.into_canonical();
1545 assert_eq!(canonical, "mycolumn");
1546 }
1547
1548 #[test]
1549 fn test_column_qualified_equality() {
1550 let c1 = ColumnIdentifier::qualified("Users", false, "id", false);
1552 let c2 = ColumnIdentifier::qualified("USERS", false, "ID", false);
1553 assert_eq!(c1, c2);
1554 assert_eq!(c1.canonical(), "users.id");
1555
1556 let c3 = ColumnIdentifier::qualified("Users", true, "id", false);
1558 let c4 = ColumnIdentifier::qualified("USERS", true, "id", false);
1559 assert_ne!(c3, c4);
1560
1561 let c5 = ColumnIdentifier::qualified("users", false, "Id", true);
1563 let c6 = ColumnIdentifier::qualified("users", false, "ID", true);
1564 assert_ne!(c5, c6);
1565 }
1566
1567 #[test]
1568 fn test_column_qualified_hashmap() {
1569 let mut map: HashMap<ColumnIdentifier, i32> = HashMap::new();
1570
1571 let key = ColumnIdentifier::qualified("Users", true, "id", false);
1573 map.insert(key, 42);
1574
1575 let lookup1 = ColumnIdentifier::qualified("Users", true, "ID", false);
1577 assert_eq!(map.get(&lookup1), Some(&42));
1578
1579 let lookup2 = ColumnIdentifier::qualified("USERS", true, "id", false);
1581 assert_eq!(map.get(&lookup2), None);
1582
1583 let lookup3 = ColumnIdentifier::qualified("Users", false, "id", false);
1585 assert_eq!(map.get(&lookup3), None);
1586 }
1587
1588 #[test]
1589 fn test_column_issue_examples() {
1590 let c1 = ColumnIdentifier::simple("MyColumn", false);
1594 let c2 = ColumnIdentifier::simple("mycolumn", false);
1595 let c3 = ColumnIdentifier::simple("MYCOLUMN", false);
1596 assert_eq!(c1, c2);
1597 assert_eq!(c2, c3);
1598 assert_eq!(c1.canonical(), "mycolumn");
1599
1600 let q1 = ColumnIdentifier::simple("MyColumn", true);
1602 let q2 = ColumnIdentifier::simple("mycolumn", true);
1603 assert_ne!(q1, q2);
1604 assert_eq!(q1.canonical(), "MyColumn");
1605
1606 let qc = ColumnIdentifier::qualified("Users", false, "ID", false);
1608 assert_eq!(qc.canonical(), "users.id");
1609 assert_eq!(qc.table_canonical(), Some("users"));
1610 assert_eq!(qc.column_canonical(), "id");
1611
1612 let fq = ColumnIdentifier::fully_qualified(
1614 "myApp", true, "users", false, "ID", false, );
1618 assert_eq!(fq.canonical(), "myApp.users.id");
1619 }
1620
1621 #[test]
1622 fn test_column_ambiguous_predicates() {
1623 let simple = ColumnIdentifier::simple("id", false);
1624 assert!(simple.is_ambiguous());
1625 assert!(!simple.is_qualified());
1626 assert!(!simple.is_fully_qualified());
1627
1628 let qualified = ColumnIdentifier::qualified("users", false, "id", false);
1629 assert!(!qualified.is_ambiguous());
1630 assert!(qualified.is_qualified());
1631 assert!(!qualified.is_fully_qualified());
1632
1633 let fully = ColumnIdentifier::fully_qualified("myapp", false, "users", false, "id", false);
1634 assert!(!fully.is_ambiguous());
1635 assert!(fully.is_qualified());
1636 assert!(fully.is_fully_qualified());
1637 }
1638}