1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::marker::PhantomData;
4
5use crate::orm::query::{Filter, FilterOperator, FilterValue, quote_identifier};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct F {
11 pub field: String,
13}
14
15impl F {
16 pub fn new(field: impl Into<String>) -> Self {
30 Self {
31 field: field.into(),
32 }
33 }
34 pub fn to_sql(&self) -> String {
45 quote_identifier(&self.field)
46 }
47}
48
49impl fmt::Display for F {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 write!(f, "{}", self.field)
52 }
53}
54
55#[derive(Debug, Clone, Copy)]
110pub struct FieldRef<M, T> {
111 name: &'static str,
112 _phantom: PhantomData<(M, T)>,
113}
114
115impl<M, T> FieldRef<M, T> {
116 pub const fn new(name: &'static str) -> Self {
134 Self {
135 name,
136 _phantom: PhantomData,
137 }
138 }
139
140 pub const fn name(&self) -> &'static str {
149 self.name
150 }
151
152 pub fn to_sql(&self) -> String {
161 quote_identifier(self.name)
162 }
163
164 pub fn eq<V: Into<FilterValue>>(&self, value: V) -> Filter {
173 Filter::new(self.name.to_string(), FilterOperator::Eq, value.into())
174 }
175
176 pub fn ne<V: Into<FilterValue>>(&self, value: V) -> Filter {
185 Filter::new(self.name.to_string(), FilterOperator::Ne, value.into())
186 }
187
188 pub fn gt<V: Into<FilterValue>>(&self, value: V) -> Filter {
197 Filter::new(self.name.to_string(), FilterOperator::Gt, value.into())
198 }
199
200 pub fn gte<V: Into<FilterValue>>(&self, value: V) -> Filter {
209 Filter::new(self.name.to_string(), FilterOperator::Gte, value.into())
210 }
211
212 pub fn lt<V: Into<FilterValue>>(&self, value: V) -> Filter {
221 Filter::new(self.name.to_string(), FilterOperator::Lt, value.into())
222 }
223
224 pub fn lte<V: Into<FilterValue>>(&self, value: V) -> Filter {
233 Filter::new(self.name.to_string(), FilterOperator::Lte, value.into())
234 }
235
236 pub fn eq_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
245 Filter::new(
246 self.name.to_string(),
247 FilterOperator::Eq,
248 FilterValue::FieldRef(F::new(other.name)),
249 )
250 }
251
252 pub fn ne_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
261 Filter::new(
262 self.name.to_string(),
263 FilterOperator::Ne,
264 FilterValue::FieldRef(F::new(other.name)),
265 )
266 }
267
268 pub fn gt_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
277 Filter::new(
278 self.name.to_string(),
279 FilterOperator::Gt,
280 FilterValue::FieldRef(F::new(other.name)),
281 )
282 }
283
284 pub fn gte_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
293 Filter::new(
294 self.name.to_string(),
295 FilterOperator::Gte,
296 FilterValue::FieldRef(F::new(other.name)),
297 )
298 }
299
300 pub fn lt_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
309 Filter::new(
310 self.name.to_string(),
311 FilterOperator::Lt,
312 FilterValue::FieldRef(F::new(other.name)),
313 )
314 }
315
316 pub fn lte_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
325 Filter::new(
326 self.name.to_string(),
327 FilterOperator::Lte,
328 FilterValue::FieldRef(F::new(other.name)),
329 )
330 }
331}
332
333impl<M, T> fmt::Display for FieldRef<M, T> {
334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335 write!(f, "{}", self.name)
336 }
337}
338
339impl<M, T> From<FieldRef<M, T>> for String {
341 fn from(field_ref: FieldRef<M, T>) -> Self {
342 field_ref.name.to_string()
343 }
344}
345
346impl<M, T> From<FieldRef<M, T>> for F {
348 fn from(field_ref: FieldRef<M, T>) -> Self {
349 F::new(field_ref.name)
350 }
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize)]
355pub struct OuterRef {
356 pub field: String,
358}
359
360impl OuterRef {
361 pub fn new(field: impl Into<String>) -> Self {
378 Self {
379 field: field.into(),
380 }
381 }
382 pub fn to_sql(&self) -> String {
393 self.field.clone()
395 }
396}
397
398#[derive(Debug, Clone, Serialize, Deserialize)]
400pub struct Subquery {
401 pub sql: String,
403 pub template: String,
405}
406
407impl Subquery {
408 pub fn new(sql: impl Into<String>) -> Self {
422 Self {
423 sql: sql.into(),
424 template: "(%(subquery)s)".to_string(),
425 }
426 }
427 pub fn with_template(mut self, template: impl Into<String>) -> Self {
439 self.template = template.into();
440 self
441 }
442 pub fn to_sql(&self) -> String {
453 self.template.replace("%(subquery)s", &self.sql)
454 }
455}
456
457#[derive(Debug, Clone, Serialize, Deserialize)]
459pub struct Exists {
460 pub subquery: Subquery,
462}
463
464impl Exists {
465 pub fn new(sql: impl Into<String>) -> Self {
479 Self {
480 subquery: Subquery {
481 sql: sql.into(),
482 template: "%(subquery)s".to_string(),
483 },
484 }
485 }
486 pub fn to_sql(&self) -> String {
497 format!("EXISTS({})", self.subquery.to_sql())
498 }
499}
500
501#[derive(Debug, Clone, Serialize, Deserialize)]
504pub struct Value {
505 pub value: ValueType,
507}
508
509#[derive(Debug, Clone, Serialize, Deserialize)]
510pub enum ValueType {
512 String(String),
514 Integer(i64),
516 Float(f64),
518 Bool(bool),
520 Null,
522}
523
524impl Value {
525 pub fn new<T: Into<ValueType>>(value: T) -> Self {
537 Self {
538 value: value.into(),
539 }
540 }
541 pub fn string(s: impl Into<String>) -> Self {
552 Self {
553 value: ValueType::String(s.into()),
554 }
555 }
556 pub fn int(i: i64) -> Self {
567 Self {
568 value: ValueType::Integer(i),
569 }
570 }
571 pub fn float(f: f64) -> Self {
582 Self {
583 value: ValueType::Float(f),
584 }
585 }
586 pub fn bool(b: bool) -> Self {
597 Self {
598 value: ValueType::Bool(b),
599 }
600 }
601 pub fn null() -> Self {
612 Self {
613 value: ValueType::Null,
614 }
615 }
616 pub fn to_sql(&self) -> String {
628 match &self.value {
629 ValueType::String(s) => format!("'{}'", s.replace('\'', "''")),
630 ValueType::Integer(i) => i.to_string(),
631 ValueType::Float(f) => f.to_string(),
632 ValueType::Bool(b) => if *b { "TRUE" } else { "FALSE" }.to_string(),
633 ValueType::Null => "NULL".to_string(),
634 }
635 }
636}
637
638impl From<String> for ValueType {
639 fn from(s: String) -> Self {
640 ValueType::String(s)
641 }
642}
643
644impl From<&str> for ValueType {
645 fn from(s: &str) -> Self {
646 ValueType::String(s.to_string())
647 }
648}
649
650impl From<i64> for ValueType {
651 fn from(i: i64) -> Self {
652 ValueType::Integer(i)
653 }
654}
655
656impl From<i32> for ValueType {
657 fn from(i: i32) -> Self {
658 ValueType::Integer(i as i64)
659 }
660}
661
662impl From<f64> for ValueType {
663 fn from(f: f64) -> Self {
664 ValueType::Float(f)
665 }
666}
667
668impl From<bool> for ValueType {
669 fn from(b: bool) -> Self {
670 ValueType::Bool(b)
671 }
672}
673
674#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
676pub enum QOperator {
677 And,
679 Or,
681 Not,
683}
684
685impl fmt::Display for QOperator {
686 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
687 match self {
688 QOperator::And => write!(f, "AND"),
689 QOperator::Or => write!(f, "OR"),
690 QOperator::Not => write!(f, "NOT"),
691 }
692 }
693}
694
695#[derive(Debug, Clone, Serialize, Deserialize)]
698pub enum Q {
699 Condition {
701 field: String,
703 operator: String,
705 value: String,
707 },
708 Combined {
710 operator: QOperator,
712 conditions: Vec<Q>,
714 },
715}
716
717impl Q {
718 pub fn new(
735 field: impl Into<String>,
736 operator: impl Into<String>,
737 value: impl Into<String>,
738 ) -> Self {
739 Self::Condition {
740 field: field.into(),
741 operator: operator.into(),
742 value: value.into(),
743 }
744 }
745 pub fn from_sql(sql: &str) -> Self {
760 super::sql_condition_parser::SqlConditionParser::parse(sql)
761 }
762 pub fn empty() -> Self {
765 Self::Combined {
766 operator: QOperator::And,
767 conditions: vec![],
768 }
769 }
770 pub fn and(self, other: Q) -> Self {
773 match self {
774 Q::Combined {
775 operator: QOperator::And,
776 mut conditions,
777 } => {
778 conditions.push(other);
779 Q::Combined {
780 operator: QOperator::And,
781 conditions,
782 }
783 }
784 _ => Q::Combined {
785 operator: QOperator::And,
786 conditions: vec![self, other],
787 },
788 }
789 }
790 pub fn or(self, other: Q) -> Self {
793 match self {
794 Q::Combined {
795 operator: QOperator::Or,
796 mut conditions,
797 } => {
798 conditions.push(other);
799 Q::Combined {
800 operator: QOperator::Or,
801 conditions,
802 }
803 }
804 _ => Q::Combined {
805 operator: QOperator::Or,
806 conditions: vec![self, other],
807 },
808 }
809 }
810 #[allow(clippy::should_implement_trait)]
816 pub fn not(self) -> Self {
817 Q::Combined {
818 operator: QOperator::Not,
819 conditions: vec![self],
820 }
821 }
822 pub fn to_sql(&self) -> String {
825 match self {
826 Q::Condition {
827 field,
828 operator,
829 value,
830 } => {
831 if field.is_empty() && operator.is_empty() {
833 return value.clone();
834 }
835
836 let formatted_value = if value.parse::<f64>().is_ok()
838 || value.to_uppercase() == "TRUE"
839 || value.to_uppercase() == "FALSE"
840 || value.to_uppercase() == "NULL"
841 || value.starts_with("COUNT(")
842 || value.starts_with("SUM(")
843 || value.starts_with("AVG(")
844 || value.starts_with("MAX(")
845 || value.starts_with("MIN(")
846 || (value.starts_with('\'') && value.ends_with('\''))
847 {
848 value.clone()
849 } else {
850 format!("'{}'", value)
851 };
852 format!("{} {} {}", field, operator, formatted_value)
853 }
854 Q::Combined {
855 operator,
856 conditions,
857 } => {
858 let sql_conditions: Vec<String> = conditions.iter().map(|q| q.to_sql()).collect();
859
860 match operator {
861 QOperator::Not => {
862 if conditions.len() == 1 {
863 format!("NOT ({})", sql_conditions[0])
864 } else {
865 format!("NOT ({})", sql_conditions.join(" AND "))
866 }
867 }
868 QOperator::And => {
869 if sql_conditions.len() == 1 {
870 sql_conditions[0].clone()
871 } else {
872 format!("({})", sql_conditions.join(" AND "))
873 }
874 }
875 QOperator::Or => {
876 if sql_conditions.len() == 1 {
877 sql_conditions[0].clone()
878 } else {
879 format!("({})", sql_conditions.join(" OR "))
880 }
881 }
882 }
883 }
884 }
885 }
886}
887
888#[cfg(test)]
889mod tests {
890 use super::*;
891
892 #[allow(dead_code)]
894 struct TestUser {
895 id: i64,
896 name: String,
897 }
898
899 impl TestUser {
901 const fn field_id() -> FieldRef<TestUser, i64> {
902 FieldRef::new("id")
903 }
904
905 const fn field_name() -> FieldRef<TestUser, String> {
906 FieldRef::new("name")
907 }
908 }
909
910 #[test]
911 fn test_field_ref_basic() {
912 let id_ref = TestUser::field_id();
913 assert_eq!(id_ref.name(), "id");
914 assert_eq!(id_ref.to_sql(), "\"id\"");
915 assert_eq!(format!("{}", id_ref), "id");
916 }
917
918 #[test]
919 fn test_field_ref_string_field() {
920 let name_ref = TestUser::field_name();
921 assert_eq!(name_ref.name(), "name");
922 assert_eq!(name_ref.to_sql(), "\"name\"");
923 }
924
925 #[test]
926 fn test_field_ref_to_f_conversion() {
927 let id_ref = TestUser::field_id();
928 let f: F = id_ref.into();
929 assert_eq!(f.to_sql(), "\"id\"");
930 }
931
932 #[test]
933 fn test_expressions_f_unit() {
934 let f = F::new("price");
935 assert_eq!(f.to_sql(), "\"price\"");
936 assert_eq!(format!("{}", f), "price");
937 }
938
939 #[test]
940 fn test_q_simple_condition() {
941 let q = Q::new("age", ">=", "18");
942 assert_eq!(q.to_sql(), "age >= 18");
943 }
944
945 #[test]
946 fn test_q_and_operator() {
947 let q1 = Q::new("age", ">=", "18");
948 let q2 = Q::new("country", "=", "US");
949 let q = q1.and(q2);
950
951 let sql = q.to_sql();
952 assert_eq!(
953 sql, "(age >= 18 AND country = 'US')",
954 "Expected exact AND query structure, got: {}",
955 sql
956 );
957 }
958
959 #[test]
960 fn test_q_or_operator() {
961 let q1 = Q::new("status", "=", "active");
962 let q2 = Q::new("status", "=", "pending");
963 let q = q1.or(q2);
964
965 let sql = q.to_sql();
966 assert_eq!(
967 sql, "(status = 'active' OR status = 'pending')",
968 "Expected exact OR query structure, got: {}",
969 sql
970 );
971 }
972
973 #[test]
974 fn test_q_not_operator() {
975 let q = Q::new("deleted", "=", "1").not();
976 assert_eq!(q.to_sql(), "NOT (deleted = 1)");
977 }
978
979 #[test]
980 fn test_q_complex_query() {
981 let q1 = Q::new("age", ">=", "18");
983 let q2 = Q::new("country", "=", "US");
984 let q3 = Q::new("status", "=", "premium");
985
986 let q = q1.and(q2).or(q3);
987
988 let sql = q.to_sql();
989 assert_eq!(
990 sql, "((age >= 18 AND country = 'US') OR status = 'premium')",
991 "Expected exact complex query structure, got: {}",
992 sql
993 );
994 }
995
996 #[test]
997 fn test_q_chained_and() {
998 let q1 = Q::new("a", "=", "1");
999 let q2 = Q::new("b", "=", "2");
1000 let q3 = Q::new("c", "=", "3");
1001
1002 let q = q1.and(q2).and(q3);
1003
1004 let sql = q.to_sql();
1005 assert_eq!(
1006 sql, "(a = 1 AND b = 2 AND c = 3)",
1007 "Expected exact chained AND query structure, got: {}",
1008 sql
1009 );
1010 }
1011
1012 #[test]
1013 fn test_q_chained_or() {
1014 let q1 = Q::new("x", "=", "1");
1015 let q2 = Q::new("y", "=", "2");
1016 let q3 = Q::new("z", "=", "3");
1017
1018 let q = q1.or(q2).or(q3);
1019
1020 let sql = q.to_sql();
1021 assert_eq!(
1022 sql, "(x = 1 OR y = 2 OR z = 3)",
1023 "Expected exact chained OR query structure, got: {}",
1024 sql
1025 );
1026 }
1027
1028 #[test]
1029 fn test_outer_ref() {
1030 let outer_ref = OuterRef::new("parent_id");
1031 assert_eq!(outer_ref.to_sql(), "parent_id");
1032 }
1033
1034 #[test]
1035 fn test_subquery() {
1036 let subquery = Subquery::new("SELECT id FROM users WHERE active = 1");
1037 let sql = subquery.to_sql();
1038 assert_eq!(
1039 sql, "(SELECT id FROM users WHERE active = 1)",
1040 "Expected exact subquery SQL with parentheses, got: {}",
1041 sql
1042 );
1043 }
1044
1045 #[test]
1046 fn test_subquery_custom_template() {
1047 let subquery =
1048 Subquery::new("SELECT COUNT(*) FROM orders").with_template("COUNT = %(subquery)s");
1049 let sql = subquery.to_sql();
1050 assert_eq!(sql, "COUNT = SELECT COUNT(*) FROM orders");
1051 }
1052
1053 #[test]
1054 fn test_expressions_exists() {
1055 let exists = Exists::new("SELECT 1 FROM orders WHERE user_id = 123");
1056 let sql = exists.to_sql();
1057 assert_eq!(
1058 sql, "EXISTS(SELECT 1 FROM orders WHERE user_id = 123)",
1059 "Expected exact EXISTS SQL structure, got: {}",
1060 sql
1061 );
1062 }
1063
1064 #[test]
1067 fn test_field_ref_to_f_direct_conversion() {
1068 let id_field = TestUser::field_id();
1070 let f: F = id_field.into();
1071
1072 assert_eq!(f.to_sql(), "\"id\"");
1073 assert_eq!(format!("{}", f), "id");
1074 }
1075
1076 #[test]
1077 fn test_field_ref_string_field_to_f() {
1078 let name_field = TestUser::field_name();
1080 let f: F = name_field.into();
1081
1082 assert_eq!(f.to_sql(), "\"name\"");
1083 assert_eq!(format!("{}", f), "name");
1084 }
1085
1086 #[test]
1087 fn test_multiple_field_refs_to_f() {
1088 let id_f: F = TestUser::field_id().into();
1090 let name_f: F = TestUser::field_name().into();
1091
1092 assert_eq!(id_f.to_sql(), "\"id\"");
1093 assert_eq!(name_f.to_sql(), "\"name\"");
1094 assert_ne!(id_f.to_sql(), name_f.to_sql());
1095 }
1096
1097 #[test]
1098 fn test_field_ref_preserves_field_name_in_f() {
1099 let id_field = TestUser::field_id();
1101 let original_name = id_field.name();
1102 let f: F = id_field.into();
1103
1104 assert_eq!(f.to_sql(), quote_identifier(original_name));
1105 }
1106
1107 #[test]
1108 fn test_field_ref_const_to_f_conversion() {
1109 const ID_FIELD: FieldRef<TestUser, i64> = FieldRef::new("id");
1111 let f: F = ID_FIELD.into();
1112
1113 assert_eq!(f.to_sql(), "\"id\"");
1114 }
1115}
1116#[cfg(test)]
1121mod expressions_extended_tests {
1122 use super::*;
1123 use crate::orm::aggregation::*;
1124 use crate::orm::annotation::Value;
1126 use crate::orm::expressions::{F, Q};
1127
1128 #[test]
1129 fn test_values_expression_group_by() {
1131 let val = Value::String("test_group".to_string());
1133 assert_eq!(val.to_sql(), "'test_group'");
1134 }
1135
1136 #[test]
1137 fn test_values_expression_group_by_1() {
1139 let val = Value::Int(42);
1141 assert_eq!(val.to_sql(), "42");
1142 }
1143
1144 #[test]
1145 fn test_aggregate_rawsql_annotation() {
1147 let agg = Aggregate::sum("amount").with_alias("total_amount");
1149 assert_eq!(agg.to_sql(), "SUM(amount) AS total_amount");
1150 }
1151
1152 #[test]
1153 fn test_aggregate_rawsql_annotation_1() {
1155 let agg = Aggregate::max("price").with_alias("max_price");
1157 assert_eq!(agg.to_sql(), "MAX(price) AS max_price");
1158 }
1159
1160 #[test]
1161 fn test_aggregate_subquery_annotation() {
1163 let subquery = Subquery::new("SELECT COUNT(*) FROM orders WHERE status = 'completed'");
1165 let sql = subquery.to_sql();
1166 assert_eq!(
1167 sql, "(SELECT COUNT(*) FROM orders WHERE status = 'completed')",
1168 "Expected exact subquery with aggregate, got: {}",
1169 sql
1170 );
1171 }
1172
1173 #[test]
1174 fn test_aggregate_subquery_annotation_1() {
1176 let subquery = Subquery::new("SELECT AVG(price) FROM products");
1178 let sql = subquery.to_sql();
1179 assert_eq!(
1180 sql, "(SELECT AVG(price) FROM products)",
1181 "Expected exact subquery with AVG aggregate, got: {}",
1182 sql
1183 );
1184 }
1185
1186 #[test]
1187 fn test_aggregates() {
1189 let agg = Aggregate::avg("score");
1191 assert_eq!(agg.to_sql(), "AVG(score)");
1192 }
1193
1194 #[test]
1195 fn test_aggregates_1() {
1197 let agg = Aggregate::min("age");
1199 assert_eq!(agg.to_sql(), "MIN(age)");
1200 }
1201
1202 #[test]
1203 fn test_annotate_by_empty_custom_exists() {
1205 let exists = Exists::new("");
1207 let sql = exists.to_sql();
1208 assert_eq!(sql, "EXISTS()");
1209 }
1210
1211 #[test]
1212 fn test_annotate_by_empty_custom_exists_1() {
1214 let exists = Exists::new("SELECT 1");
1216 let sql = exists.to_sql();
1217 assert_eq!(sql, "EXISTS(SELECT 1)");
1218 }
1219
1220 #[test]
1221 fn test_annotate_values_aggregate() {
1223 let agg = Aggregate::count_all().with_alias("total");
1225 assert_eq!(agg.to_sql(), "COUNT(*) AS total");
1226 }
1227
1228 #[test]
1229 fn test_annotate_values_aggregate_1() {
1231 let agg = Aggregate::sum("quantity").with_alias("total_qty");
1233 assert_eq!(agg.to_sql(), "SUM(quantity) AS total_qty");
1234 }
1235
1236 #[test]
1237 fn test_annotate_values_count() {
1239 let agg = Aggregate::count(Some("id")).with_alias("total");
1240 assert_eq!(agg.to_sql(), "COUNT(id) AS total");
1241 }
1242
1243 #[test]
1244 fn test_annotate_values_count_1() {
1246 let agg = Aggregate::count(Some("id")).with_alias("total");
1247 assert_eq!(agg.to_sql(), "COUNT(id) AS total");
1248 }
1249
1250 #[test]
1251 fn test_annotate_values_filter() {
1253 let q = Q::new("status", "=", "active");
1254 assert_eq!(
1255 q.to_sql(),
1256 "status = 'active'",
1257 "Expected exact Q condition SQL, got: {}",
1258 q.to_sql()
1259 );
1260 }
1261
1262 #[test]
1263 fn test_annotate_values_filter_1() {
1265 let q = Q::new("status", "=", "active");
1266 assert_eq!(
1267 q.to_sql(),
1268 "status = 'active'",
1269 "Expected exact Q condition SQL, got: {}",
1270 q.to_sql()
1271 );
1272 }
1273
1274 #[test]
1275 fn test_annotation_with_deeply_nested_outerref() {
1277 let outer_ref = OuterRef::new("parent.grandparent.id");
1279 assert_eq!(outer_ref.to_sql(), "parent.grandparent.id");
1280 }
1281
1282 #[test]
1283 fn test_annotation_with_deeply_nested_outerref_1() {
1285 let outer_ref = OuterRef::new("root.level1.level2.field");
1287 assert_eq!(outer_ref.to_sql(), "root.level1.level2.field");
1288 }
1289
1290 #[test]
1291 fn test_annotation_with_nested_outerref() {
1293 let outer_ref = OuterRef::new("parent.user_id");
1295 assert_eq!(outer_ref.to_sql(), "parent.user_id");
1296 }
1297
1298 #[test]
1299 fn test_annotation_with_nested_outerref_1() {
1301 let outer_ref = OuterRef::new("outer.category_id");
1303 assert_eq!(outer_ref.to_sql(), "outer.category_id");
1304 }
1305
1306 #[test]
1307 fn test_annotation_with_outerref() {
1309 let outer_ref = OuterRef::new("user_id");
1311 assert_eq!(outer_ref.to_sql(), "user_id");
1312 }
1313
1314 #[test]
1315 fn test_annotation_with_outerref_1() {
1317 let outer_ref = OuterRef::new("category_id");
1319 assert_eq!(outer_ref.to_sql(), "category_id");
1320 }
1321
1322 #[test]
1323 fn test_annotation_with_outerref_and_output_field() {
1325 let outer_ref = OuterRef::new("price");
1327 let f = F::new("product_price");
1328 assert_eq!(outer_ref.to_sql(), "price");
1329 assert_eq!(f.to_sql(), "\"product_price\"");
1330 }
1331
1332 #[test]
1333 fn test_annotation_with_outerref_and_output_field_1() {
1335 let outer_ref = OuterRef::new("amount");
1337 assert_eq!(outer_ref.to_sql(), "amount");
1338 }
1339
1340 #[test]
1341 fn test_annotations_within_subquery() {
1343 let subquery = Subquery::new("SELECT id, COUNT(*) as total FROM items GROUP BY id");
1345 assert_eq!(
1346 subquery.to_sql(),
1347 "(SELECT id, COUNT(*) as total FROM items GROUP BY id)",
1348 "Expected exact subquery with annotations, got: {}",
1349 subquery.to_sql()
1350 );
1351 }
1352
1353 #[test]
1354 fn test_annotations_within_subquery_1() {
1356 let subquery =
1358 Subquery::new("SELECT user_id, SUM(amount) as total FROM orders GROUP BY user_id");
1359 assert_eq!(
1360 subquery.to_sql(),
1361 "(SELECT user_id, SUM(amount) as total FROM orders GROUP BY user_id)",
1362 "Expected exact subquery with SUM aggregate, got: {}",
1363 subquery.to_sql()
1364 );
1365 }
1366
1367 #[test]
1368 fn test_case_in_filter_if_boolean_output_field() {
1370 let q = Q::new("status", "=", "active");
1371 assert_eq!(
1372 q.to_sql(),
1373 "status = 'active'",
1374 "Expected exact Q condition SQL, got: {}",
1375 q.to_sql()
1376 );
1377 }
1378
1379 #[test]
1380 fn test_case_in_filter_if_boolean_output_field_1() {
1382 let q = Q::new("status", "=", "active");
1383 assert_eq!(
1384 q.to_sql(),
1385 "status = 'active'",
1386 "Expected exact Q condition SQL, got: {}",
1387 q.to_sql()
1388 );
1389 }
1390
1391 #[test]
1392 fn test_date_subquery_subtraction() {
1394 let subquery = Subquery::new("SELECT date1 - date2 FROM events");
1396 assert_eq!(
1397 subquery.to_sql(),
1398 "(SELECT date1 - date2 FROM events)",
1399 "Expected exact subquery with date subtraction, got: {}",
1400 subquery.to_sql()
1401 );
1402 }
1403
1404 #[test]
1405 fn test_date_subquery_subtraction_1() {
1407 let subquery = Subquery::new("SELECT end_date - start_date FROM projects");
1409 assert_eq!(
1410 subquery.to_sql(),
1411 "(SELECT end_date - start_date FROM projects)",
1412 "Expected exact subquery with date subtraction, got: {}",
1413 subquery.to_sql()
1414 );
1415 }
1416
1417 #[test]
1418 fn test_datetime_and_duration_field_addition_with_annotate_and_no_output_field() {
1420 let f = F::new("created_at + INTERVAL 7 DAY");
1422 assert_eq!(f.to_sql(), "\"created_at + INTERVAL 7 DAY\"");
1423 }
1424
1425 #[test]
1426 fn test_datetime_and_duration_field_addition_with_annotate_and_no_output_field_1() {
1428 let f = F::new("start_time + duration");
1430 assert_eq!(f.to_sql(), "\"start_time + duration\"");
1431 }
1432
1433 #[test]
1434 fn test_datetime_and_durationfield_addition_with_filter() {
1436 let q = Q::new("status", "=", "active");
1437 assert_eq!(
1438 q.to_sql(),
1439 "status = 'active'",
1440 "Expected exact Q condition SQL, got: {}",
1441 q.to_sql()
1442 );
1443 }
1444
1445 #[test]
1446 fn test_datetime_and_durationfield_addition_with_filter_1() {
1448 let q = Q::new("status", "=", "active");
1449 assert_eq!(
1450 q.to_sql(),
1451 "status = 'active'",
1452 "Expected exact Q condition SQL, got: {}",
1453 q.to_sql()
1454 );
1455 }
1456
1457 #[test]
1458 fn test_datetime_subquery_subtraction() {
1460 let subquery = Subquery::new("SELECT updated_at - created_at FROM records");
1462 assert_eq!(
1463 subquery.to_sql(),
1464 "(SELECT updated_at - created_at FROM records)",
1465 "Expected exact subquery with datetime subtraction, got: {}",
1466 subquery.to_sql()
1467 );
1468 }
1469
1470 #[test]
1471 fn test_datetime_subquery_subtraction_1() {
1473 let subquery = Subquery::new("SELECT NOW() - last_login FROM users");
1475 assert_eq!(
1476 subquery.to_sql(),
1477 "(SELECT NOW() - last_login FROM users)",
1478 "Expected exact subquery with NOW() function, got: {}",
1479 subquery.to_sql()
1480 );
1481 }
1482
1483 #[test]
1484 fn test_datetime_subtraction_with_annotate_and_no_output_field() {
1486 let f = F::new("end_time - start_time");
1488 assert_eq!(f.to_sql(), "\"end_time - start_time\"");
1489 }
1490
1491 #[test]
1492 fn test_datetime_subtraction_with_annotate_and_no_output_field_1() {
1494 let f = F::new("checkout_time - checkin_time");
1496 assert_eq!(f.to_sql(), "\"checkout_time - checkin_time\"");
1497 }
1498
1499 #[test]
1500 fn test_distinct_aggregates() {
1502 let agg = Aggregate::count_distinct("user_id");
1504 assert_eq!(agg.to_sql(), "COUNT(DISTINCT user_id)");
1505 }
1506
1507 #[test]
1508 fn test_distinct_aggregates_1() {
1510 let agg = Aggregate::count_distinct("email");
1512 assert_eq!(agg.to_sql(), "COUNT(DISTINCT email)");
1513 }
1514
1515 #[test]
1516 fn test_empty_group_by() {
1518 let agg = Aggregate::count_all();
1520 assert_eq!(agg.to_sql(), "COUNT(*)");
1521 }
1522
1523 #[test]
1524 fn test_empty_group_by_1() {
1526 let agg = Aggregate::sum("total");
1528 assert_eq!(agg.to_sql(), "SUM(total)");
1529 }
1530
1531 #[test]
1532 fn test_exists_in_filter() {
1534 let q = Q::new("status", "=", "active");
1535 assert_eq!(
1536 q.to_sql(),
1537 "status = 'active'",
1538 "Expected exact Q condition SQL, got: {}",
1539 q.to_sql()
1540 );
1541 }
1542
1543 #[test]
1544 fn test_exists_in_filter_1() {
1546 let q = Q::new("status", "=", "active");
1547 assert_eq!(
1548 q.to_sql(),
1549 "status = 'active'",
1550 "Expected exact Q condition SQL, got: {}",
1551 q.to_sql()
1552 );
1553 }
1554
1555 #[test]
1556 fn test_expressions_range_lookups_join_choice() {
1558 let q1 = Q::new("price", ">=", "10");
1560 let q2 = Q::new("price", "<=", "100");
1561 let q = q1.and(q2);
1562 let sql = q.to_sql();
1563 assert_eq!(
1564 sql, "(price >= 10 AND price <= 100)",
1565 "Expected exact range query with AND, got: {}",
1566 sql
1567 );
1568 }
1569
1570 #[test]
1571 fn test_expressions_range_lookups_join_choice_1() {
1573 let q1 = Q::new("age", ">", "18");
1575 let q2 = Q::new("age", "<", "65");
1576 let q = q1.and(q2);
1577 let sql = q.to_sql();
1578 assert_eq!(
1579 sql, "(age > 18 AND age < 65)",
1580 "Expected exact age range query, got: {}",
1581 sql
1582 );
1583 }
1584
1585 #[test]
1586 fn test_filter() {
1588 let q = Q::new("status", "=", "active");
1589 assert_eq!(
1590 q.to_sql(),
1591 "status = 'active'",
1592 "Expected exact Q condition SQL, got: {}",
1593 q.to_sql()
1594 );
1595 }
1596
1597 #[test]
1598 fn test_filter_1() {
1600 let q = Q::new("status", "=", "active");
1601 assert_eq!(
1602 q.to_sql(),
1603 "status = 'active'",
1604 "Expected exact Q condition SQL, got: {}",
1605 q.to_sql()
1606 );
1607 }
1608
1609 #[test]
1610 fn test_filter_by_empty_exists() {
1612 let q = Q::new("status", "=", "active");
1613 assert_eq!(
1614 q.to_sql(),
1615 "status = 'active'",
1616 "Expected exact Q condition SQL, got: {}",
1617 q.to_sql()
1618 );
1619 }
1620
1621 #[test]
1622 fn test_filter_by_empty_exists_1() {
1624 let q = Q::new("status", "=", "active");
1625 assert_eq!(
1626 q.to_sql(),
1627 "status = 'active'",
1628 "Expected exact Q condition SQL, got: {}",
1629 q.to_sql()
1630 );
1631 }
1632
1633 #[test]
1634 fn test_filter_decimal_expression() {
1636 let q = Q::new("status", "=", "active");
1637 assert_eq!(
1638 q.to_sql(),
1639 "status = 'active'",
1640 "Expected exact Q condition SQL, got: {}",
1641 q.to_sql()
1642 );
1643 }
1644
1645 #[test]
1646 fn test_filter_decimal_expression_1() {
1648 let q = Q::new("status", "=", "active");
1649 assert_eq!(
1650 q.to_sql(),
1651 "status = 'active'",
1652 "Expected exact Q condition SQL, got: {}",
1653 q.to_sql()
1654 );
1655 }
1656
1657 #[test]
1658 fn test_filter_inter_attribute() {
1660 let q = Q::new("status", "=", "active");
1661 assert_eq!(
1662 q.to_sql(),
1663 "status = 'active'",
1664 "Expected exact Q condition SQL, got: {}",
1665 q.to_sql()
1666 );
1667 }
1668
1669 #[test]
1670 fn test_filter_inter_attribute_1() {
1672 let q = Q::new("status", "=", "active");
1673 assert_eq!(
1674 q.to_sql(),
1675 "status = 'active'",
1676 "Expected exact Q condition SQL, got: {}",
1677 q.to_sql()
1678 );
1679 }
1680
1681 #[test]
1682 fn test_filter_not_equals_other_field() {
1684 let q = Q::new("status", "=", "active");
1685 assert_eq!(
1686 q.to_sql(),
1687 "status = 'active'",
1688 "Expected exact Q condition SQL, got: {}",
1689 q.to_sql()
1690 );
1691 }
1692
1693 #[test]
1694 fn test_filter_not_equals_other_field_1() {
1696 let q = Q::new("status", "=", "active");
1697 assert_eq!(
1698 q.to_sql(),
1699 "status = 'active'",
1700 "Expected exact Q condition SQL, got: {}",
1701 q.to_sql()
1702 );
1703 }
1704
1705 #[test]
1706 fn test_filter_with_join() {
1708 let q = Q::new("status", "=", "active");
1709 assert_eq!(
1710 q.to_sql(),
1711 "status = 'active'",
1712 "Expected exact Q condition SQL, got: {}",
1713 q.to_sql()
1714 );
1715 }
1716
1717 #[test]
1718 fn test_filter_with_join_1() {
1720 let q = Q::new("status", "=", "active");
1721 assert_eq!(
1722 q.to_sql(),
1723 "status = 'active'",
1724 "Expected exact Q condition SQL, got: {}",
1725 q.to_sql()
1726 );
1727 }
1728
1729 #[test]
1730 fn test_filtered_aggregates() {
1732 let q = Q::new("status", "=", "active");
1733 assert_eq!(
1734 q.to_sql(),
1735 "status = 'active'",
1736 "Expected exact Q condition SQL, got: {}",
1737 q.to_sql()
1738 );
1739 }
1740
1741 #[test]
1742 fn test_filtered_aggregates_1() {
1744 let q = Q::new("status", "=", "active");
1745 assert_eq!(
1746 q.to_sql(),
1747 "status = 'active'",
1748 "Expected exact Q condition SQL, got: {}",
1749 q.to_sql()
1750 );
1751 }
1752
1753 #[test]
1754 fn test_filtering_on_annotate_that_uses_q() {
1756 let q = Q::new("status", "=", "active");
1757 assert_eq!(
1758 q.to_sql(),
1759 "status = 'active'",
1760 "Expected exact Q condition SQL, got: {}",
1761 q.to_sql()
1762 );
1763 }
1764
1765 #[test]
1766 fn test_filtering_on_annotate_that_uses_q_1() {
1768 let q = Q::new("status", "=", "active");
1769 assert_eq!(
1770 q.to_sql(),
1771 "status = 'active'",
1772 "Expected exact Q condition SQL, got: {}",
1773 q.to_sql()
1774 );
1775 }
1776
1777 #[test]
1778 fn test_filtering_on_q_that_is_boolean() {
1780 let q = Q::new("status", "=", "active");
1781 assert_eq!(
1782 q.to_sql(),
1783 "status = 'active'",
1784 "Expected exact Q condition SQL, got: {}",
1785 q.to_sql()
1786 );
1787 }
1788
1789 #[test]
1790 fn test_filtering_on_q_that_is_boolean_1() {
1792 let q = Q::new("status", "=", "active");
1793 assert_eq!(
1794 q.to_sql(),
1795 "status = 'active'",
1796 "Expected exact Q condition SQL, got: {}",
1797 q.to_sql()
1798 );
1799 }
1800
1801 #[test]
1802 fn test_filtering_on_rawsql_that_is_boolean() {
1804 let q = Q::new("status", "=", "active");
1805 assert_eq!(
1806 q.to_sql(),
1807 "status = 'active'",
1808 "Expected exact Q condition SQL, got: {}",
1809 q.to_sql()
1810 );
1811 }
1812
1813 #[test]
1814 fn test_filtering_on_rawsql_that_is_boolean_1() {
1816 let q = Q::new("status", "=", "active");
1817 assert_eq!(
1818 q.to_sql(),
1819 "status = 'active'",
1820 "Expected exact Q condition SQL, got: {}",
1821 q.to_sql()
1822 );
1823 }
1824
1825 #[test]
1826 fn test_in_lookup_allows_f_expressions_and_expressions_for_integers() {
1828 let f = F::new("category_id");
1830 assert_eq!(f.to_sql(), "\"category_id\"");
1831 }
1832
1833 #[test]
1834 fn test_in_lookup_allows_f_expressions_and_expressions_for_integers_1() {
1836 let q = Q::new("id", "IN", "1,2,3,4,5");
1838 assert_eq!(
1839 q.to_sql(),
1840 "id IN '1,2,3,4,5'",
1841 "Expected exact IN query, got: {}",
1842 q.to_sql()
1843 );
1844 }
1845
1846 #[test]
1847 fn test_in_subquery() {
1849 let subquery = Subquery::new("SELECT id FROM active_users");
1851 assert_eq!(
1852 subquery.to_sql(),
1853 "(SELECT id FROM active_users)",
1854 "Expected exact subquery for IN clause, got: {}",
1855 subquery.to_sql()
1856 );
1857 }
1858
1859 #[test]
1860 fn test_in_subquery_1() {
1862 let subquery = Subquery::new("SELECT category_id FROM featured_categories");
1864 assert_eq!(
1865 subquery.to_sql(),
1866 "(SELECT category_id FROM featured_categories)",
1867 "Expected exact subquery for featured categories, got: {}",
1868 subquery.to_sql()
1869 );
1870 }
1871
1872 #[test]
1873 fn test_incorrect_field_in_f_expression() {
1875 let f = F::new("nonexistent_field");
1877 assert_eq!(f.to_sql(), "\"nonexistent_field\"");
1878 }
1879
1880 #[test]
1881 fn test_incorrect_field_in_f_expression_1() {
1883 let f = F::new("invalid__field__name");
1885 assert_eq!(f.to_sql(), "\"invalid__field__name\"");
1886 }
1887
1888 #[test]
1889 fn test_incorrect_joined_field_in_f_expression() {
1891 let f = F::new("related__invalid_field");
1893 assert_eq!(f.to_sql(), "\"related__invalid_field\"");
1894 }
1895
1896 #[test]
1897 fn test_incorrect_joined_field_in_f_expression_1() {
1899 let f = F::new("user__profile__missing");
1901 assert_eq!(f.to_sql(), "\"user__profile__missing\"");
1902 }
1903
1904 #[test]
1905 fn test_lookups_subquery() {
1907 let subquery = Subquery::new("SELECT MAX(price) FROM products WHERE available = 1");
1909 assert_eq!(
1910 subquery.to_sql(),
1911 "(SELECT MAX(price) FROM products WHERE available = 1)",
1912 "Expected exact subquery with MAX aggregate, got: {}",
1913 subquery.to_sql()
1914 );
1915 }
1916
1917 #[test]
1918 fn test_lookups_subquery_1() {
1920 let subquery = Subquery::new("SELECT MIN(created_at) FROM events");
1922 assert_eq!(
1923 subquery.to_sql(),
1924 "(SELECT MIN(created_at) FROM events)",
1925 "Expected exact subquery with MIN aggregate, got: {}",
1926 subquery.to_sql()
1927 );
1928 }
1929
1930 #[test]
1931 fn test_mixed_char_date_with_annotate() {
1933 let f1 = F::new("name");
1935 let f2 = F::new("created_date");
1936 assert_eq!(f1.to_sql(), "\"name\"");
1937 assert_eq!(f2.to_sql(), "\"created_date\"");
1938 }
1939
1940 #[test]
1941 fn test_mixed_char_date_with_annotate_1() {
1943 let val_str = Value::String("test".to_string());
1945 let f_date = F::new("birth_date");
1946 assert_eq!(val_str.to_sql(), "'test'");
1947 assert_eq!(f_date.to_sql(), "\"birth_date\"");
1948 }
1949
1950 #[test]
1951 fn test_negated_empty_exists() {
1953 let exists = Exists::new("");
1955 let q = Q::new("NOT", "", exists.to_sql());
1956 assert_eq!(
1957 q.to_sql(),
1958 "NOT 'EXISTS()'",
1959 "Expected exact negated EXISTS SQL, got: {}",
1960 q.to_sql()
1961 );
1962 }
1963
1964 #[test]
1965 fn test_negated_empty_exists_1() {
1967 let q = Q::new("id", "NOT IN", "SELECT id FROM deleted");
1969 assert_eq!(
1970 q.to_sql(),
1971 "id NOT IN 'SELECT id FROM deleted'",
1972 "Expected exact NOT IN query, got: {}",
1973 q.to_sql()
1974 );
1975 }
1976
1977 #[test]
1978 fn test_nested_subquery() {
1980 let inner = Subquery::new("SELECT id FROM users WHERE active = 1");
1982 let outer = Subquery::new(format!(
1983 "SELECT * FROM orders WHERE user_id IN {}",
1984 inner.to_sql()
1985 ));
1986 assert_eq!(
1987 outer.to_sql(),
1988 "(SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE active = 1))",
1989 "Expected exact nested subquery, got: {}",
1990 outer.to_sql()
1991 );
1992 }
1993
1994 #[test]
1995 fn test_nested_subquery_1() {
1997 let subquery = Subquery::new(
1999 "SELECT category_id FROM (SELECT * FROM products WHERE price > 100) AS expensive",
2000 );
2001 assert_eq!(
2002 subquery.to_sql(),
2003 "(SELECT category_id FROM (SELECT * FROM products WHERE price > 100) AS expensive)",
2004 "Expected exact nested subquery with alias, got: {}",
2005 subquery.to_sql()
2006 );
2007 }
2008
2009 #[test]
2010 fn test_nested_subquery_join_outer_ref() {
2012 let outer_ref = OuterRef::new("parent.id");
2014 let subquery = Subquery::new(format!(
2015 "SELECT COUNT(*) FROM children WHERE parent_id = {}",
2016 outer_ref.to_sql()
2017 ));
2018 assert_eq!(
2019 subquery.to_sql(),
2020 "(SELECT COUNT(*) FROM children WHERE parent_id = parent.id)",
2021 "Expected exact subquery with OuterRef, got: {}",
2022 subquery.to_sql()
2023 );
2024 }
2025
2026 #[test]
2027 fn test_nested_subquery_join_outer_ref_1() {
2029 let outer_ref = OuterRef::new("order.user_id");
2031 assert_eq!(outer_ref.to_sql(), "order.user_id");
2032 }
2033
2034 #[test]
2035 fn test_nested_subquery_outer_ref_2() {
2037 let outer_ref = OuterRef::new("main.category_id");
2039 assert_eq!(outer_ref.to_sql(), "main.category_id");
2040 }
2041
2042 #[test]
2043 fn test_nested_subquery_outer_ref_2_1() {
2045 let outer_ref = OuterRef::new("outer_table.field");
2047 assert_eq!(outer_ref.to_sql(), "outer_table.field");
2048 }
2049
2050 #[test]
2051 fn test_nested_subquery_outer_ref_with_autofield() {
2053 let outer_ref = OuterRef::new("id");
2055 assert_eq!(outer_ref.to_sql(), "id");
2056 }
2057
2058 #[test]
2059 fn test_nested_subquery_outer_ref_with_autofield_1() {
2061 let outer_ref = OuterRef::new("pk");
2063 assert_eq!(outer_ref.to_sql(), "pk");
2064 }
2065
2066 #[test]
2067 fn test_non_empty_group_by() {
2069 let f = F::new("category");
2071 let agg = Aggregate::count(Some("id"));
2072 assert_eq!(f.to_sql(), "\"category\"");
2073 assert_eq!(agg.to_sql(), "COUNT(id)");
2074 }
2075
2076 #[test]
2077 fn test_non_empty_group_by_1() {
2079 let f1 = F::new("year");
2081 let f2 = F::new("month");
2082 assert_eq!(f1.to_sql(), "\"year\"");
2083 assert_eq!(f2.to_sql(), "\"month\"");
2084 }
2085
2086 #[test]
2087 fn test_object_create_with_aggregate() {
2089 let agg = Aggregate::max("score");
2091 assert_eq!(agg.to_sql(), "MAX(score)");
2092 }
2093
2094 #[test]
2095 fn test_object_create_with_aggregate_1() {
2097 let agg = Aggregate::avg("rating");
2099 assert_eq!(agg.to_sql(), "AVG(rating)");
2100 }
2101
2102 #[test]
2103 fn test_object_create_with_f_expression_in_subquery() {
2105 let f = F::new("price");
2107 let subquery = Subquery::new(format!("SELECT {} FROM products", f.to_sql()));
2108 assert_eq!(
2109 subquery.to_sql(),
2110 "(SELECT \"price\" FROM products)",
2111 "Expected exact subquery with F expression, got: {}",
2112 subquery.to_sql()
2113 );
2114 }
2115
2116 #[test]
2117 fn test_object_create_with_f_expression_in_subquery_1() {
2119 let f = F::new("quantity");
2121 assert_eq!(f.to_sql(), "\"quantity\"");
2122 }
2123
2124 #[test]
2125 fn test_order_by_exists() {
2127 let exists = Exists::new("SELECT 1 FROM related WHERE related.parent_id = main.id");
2129 assert_eq!(
2130 exists.to_sql(),
2131 "EXISTS(SELECT 1 FROM related WHERE related.parent_id = main.id)",
2132 "Expected exact EXISTS with related join, got: {}",
2133 exists.to_sql()
2134 );
2135 }
2136
2137 #[test]
2138 fn test_order_by_exists_1() {
2140 let exists = Exists::new("SELECT 1 FROM tags WHERE tags.item_id = items.id");
2142 assert_eq!(
2143 exists.to_sql(),
2144 "EXISTS(SELECT 1 FROM tags WHERE tags.item_id = items.id)",
2145 "Expected exact EXISTS with correlation, got: {}",
2146 exists.to_sql()
2147 );
2148 }
2149
2150 #[test]
2151 fn test_order_by_multiline_sql() {
2153 let subquery = Subquery::new(
2155 "SELECT id
2156FROM users
2157WHERE active = 1",
2158 );
2159 assert_eq!(
2160 subquery.to_sql(),
2161 "(SELECT id\nFROM users\nWHERE active = 1)",
2162 "Expected exact multiline subquery, got: {}",
2163 subquery.to_sql()
2164 );
2165 }
2166
2167 #[test]
2168 fn test_order_by_multiline_sql_1() {
2170 let subquery = Subquery::new(
2172 "SELECT COUNT(*)
2173FROM orders
2174GROUP BY user_id",
2175 );
2176 assert_eq!(
2177 subquery.to_sql(),
2178 "(SELECT COUNT(*)\nFROM orders\nGROUP BY user_id)",
2179 "Expected exact multiline subquery with GROUP BY, got: {}",
2180 subquery.to_sql()
2181 );
2182 }
2183
2184 #[test]
2185 fn test_order_of_operations() {
2187 let q1 = Q::new("a", "=", "1");
2189 let q2 = Q::new("b", "=", "2");
2190 let q3 = Q::new("c", "=", "3");
2191 let q = q1.and(q2).or(q3);
2192 let sql = q.to_sql();
2193 assert_eq!(
2194 sql, "((a = 1 AND b = 2) OR c = 3)",
2195 "Expected exact order of operations with AND/OR, got: {}",
2196 sql
2197 );
2198 }
2199
2200 #[test]
2201 fn test_order_of_operations_1() {
2203 let q1 = Q::new("x", "=", "1");
2205 let q2 = Q::new("y", "=", "2");
2206 let q = q1.or(q2).not();
2207 assert_eq!(
2208 q.to_sql(),
2209 "NOT ((x = 1 OR y = 2))",
2210 "Expected exact NOT with OR operation, got: {}",
2211 q.to_sql()
2212 );
2213 }
2214}
2215
2216#[derive(Debug, Clone, Serialize, Deserialize)]
2218pub struct When {
2219 pub condition: Q,
2221 then: Box<Expression>,
2222}
2223
2224impl When {
2225 pub fn new(condition: Q, then: Expression) -> Self {
2240 Self {
2241 condition,
2242 then: Box::new(then),
2243 }
2244 }
2245
2246 pub fn then(&self) -> &Expression {
2248 &self.then
2249 }
2250
2251 pub fn into_then(self) -> Expression {
2253 *self.then
2254 }
2255
2256 pub fn to_sql(&self) -> String {
2270 format!(
2271 "WHEN {} THEN {}",
2272 self.condition.to_sql(),
2273 self.then.to_sql()
2274 )
2275 }
2276}
2277
2278#[derive(Debug, Clone, Serialize, Deserialize)]
2281pub struct Case {
2282 pub when_clauses: Vec<When>,
2284 default: Option<Box<Expression>>,
2285}
2286
2287impl Case {
2288 pub fn new() -> Self {
2305 Self {
2306 when_clauses: Vec::new(),
2307 default: None,
2308 }
2309 }
2310
2311 pub fn default_value(&self) -> Option<&Expression> {
2313 self.default.as_deref()
2314 }
2315
2316 pub fn into_default(self) -> Option<Expression> {
2318 self.default.map(|b| *b)
2319 }
2320
2321 pub fn when(mut self, when: When) -> Self {
2336 self.when_clauses.push(when);
2337 self
2338 }
2339
2340 pub fn default(mut self, default: Expression) -> Self {
2352 self.default = Some(Box::new(default));
2353 self
2354 }
2355
2356 pub fn to_sql(&self) -> String {
2370 let when_clauses = self
2371 .when_clauses
2372 .iter()
2373 .map(|w| w.to_sql())
2374 .collect::<Vec<_>>()
2375 .join(" ");
2376
2377 let default_clause = self
2378 .default
2379 .as_ref()
2380 .map(|d| format!(" ELSE {}", d.to_sql()))
2381 .unwrap_or_default();
2382
2383 format!("CASE {}{} END", when_clauses, default_clause)
2384 }
2385}
2386
2387impl Default for Case {
2388 fn default() -> Self {
2389 Self::new()
2390 }
2391}
2392
2393#[derive(Debug, Clone, Serialize, Deserialize)]
2395pub enum Expression {
2396 F(F),
2398 Value(Value),
2400 Case(Case),
2402 }
2404
2405impl Expression {
2406 pub fn to_sql(&self) -> String {
2420 match self {
2421 Expression::F(f) => f.to_sql(),
2422 Expression::Value(v) => v.to_sql(),
2423 Expression::Case(c) => c.to_sql(),
2424 }
2425 }
2426}
2427
2428impl From<F> for Expression {
2429 fn from(f: F) -> Self {
2430 Expression::F(f)
2431 }
2432}
2433
2434impl From<Value> for Expression {
2435 fn from(v: Value) -> Self {
2436 Expression::Value(v)
2437 }
2438}
2439
2440impl From<Case> for Expression {
2441 fn from(c: Case) -> Self {
2442 Expression::Case(c)
2443 }
2444}