1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::marker::PhantomData;
4
5use crate::orm::query::{
6 FieldAssignment, Filter, FilterOperator, FilterValue, UpdateValue, quote_identifier,
7};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct F {
13 pub field: String,
15}
16
17impl F {
18 pub fn new(field: impl Into<String>) -> Self {
32 Self {
33 field: field.into(),
34 }
35 }
36 pub fn to_sql(&self) -> String {
47 quote_identifier(&self.field)
48 }
49}
50
51impl fmt::Display for F {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 write!(f, "{}", self.field)
54 }
55}
56
57#[derive(Debug, Clone, Copy)]
112pub struct FieldRef<M, T> {
113 name: &'static str,
114 _phantom: PhantomData<(M, T)>,
115}
116
117impl<M, T> FieldRef<M, T> {
118 pub const fn new(name: &'static str) -> Self {
136 Self {
137 name,
138 _phantom: PhantomData,
139 }
140 }
141
142 pub const fn name(&self) -> &'static str {
151 self.name
152 }
153
154 pub fn assign<V: Into<UpdateValue>>(&self, value: V) -> FieldAssignment {
165 FieldAssignment::new(self.name, value)
166 }
167
168 pub fn to_sql(&self) -> String {
177 quote_identifier(self.name)
178 }
179
180 pub fn eq<V: Into<FilterValue>>(&self, value: V) -> Filter {
189 Filter::new(self.name.to_string(), FilterOperator::Eq, value.into())
190 }
191
192 pub fn exact<V: Into<FilterValue>>(&self, value: V) -> Filter {
194 self.eq(value)
195 }
196
197 pub fn iexact<V: Into<FilterValue>>(&self, value: V) -> Filter {
199 Filter::new(self.name.to_string(), FilterOperator::IExact, value.into())
200 }
201
202 pub fn ne<V: Into<FilterValue>>(&self, value: V) -> Filter {
211 Filter::new(self.name.to_string(), FilterOperator::Ne, value.into())
212 }
213
214 pub fn gt<V: Into<FilterValue>>(&self, value: V) -> Filter {
223 Filter::new(self.name.to_string(), FilterOperator::Gt, value.into())
224 }
225
226 pub fn gte<V: Into<FilterValue>>(&self, value: V) -> Filter {
235 Filter::new(self.name.to_string(), FilterOperator::Gte, value.into())
236 }
237
238 pub fn lt<V: Into<FilterValue>>(&self, value: V) -> Filter {
247 Filter::new(self.name.to_string(), FilterOperator::Lt, value.into())
248 }
249
250 pub fn lte<V: Into<FilterValue>>(&self, value: V) -> Filter {
259 Filter::new(self.name.to_string(), FilterOperator::Lte, value.into())
260 }
261
262 pub fn is_in<I, V>(&self, values: I) -> Filter
264 where
265 I: IntoIterator<Item = V>,
266 V: Into<FilterValue>,
267 {
268 Filter::new(
269 self.name.to_string(),
270 FilterOperator::In,
271 FilterValue::List(values.into_iter().map(Into::into).collect()),
272 )
273 }
274
275 pub fn not_in<I, V>(&self, values: I) -> Filter
277 where
278 I: IntoIterator<Item = V>,
279 V: Into<FilterValue>,
280 {
281 Filter::new(
282 self.name.to_string(),
283 FilterOperator::NotIn,
284 FilterValue::List(values.into_iter().map(Into::into).collect()),
285 )
286 }
287
288 pub fn contains<V: Into<FilterValue>>(&self, value: V) -> Filter {
290 Filter::new(
291 self.name.to_string(),
292 FilterOperator::Contains,
293 value.into(),
294 )
295 }
296
297 pub fn icontains<V: Into<FilterValue>>(&self, value: V) -> Filter {
299 Filter::new(
300 self.name.to_string(),
301 FilterOperator::IContains,
302 value.into(),
303 )
304 }
305
306 pub fn starts_with<V: Into<FilterValue>>(&self, value: V) -> Filter {
308 Filter::new(
309 self.name.to_string(),
310 FilterOperator::StartsWith,
311 value.into(),
312 )
313 }
314
315 pub fn istarts_with<V: Into<FilterValue>>(&self, value: V) -> Filter {
317 Filter::new(
318 self.name.to_string(),
319 FilterOperator::IStartsWith,
320 value.into(),
321 )
322 }
323
324 pub fn ends_with<V: Into<FilterValue>>(&self, value: V) -> Filter {
326 Filter::new(
327 self.name.to_string(),
328 FilterOperator::EndsWith,
329 value.into(),
330 )
331 }
332
333 pub fn iends_with<V: Into<FilterValue>>(&self, value: V) -> Filter {
335 Filter::new(
336 self.name.to_string(),
337 FilterOperator::IEndsWith,
338 value.into(),
339 )
340 }
341
342 pub fn is_null(&self) -> Filter {
344 Filter::new(
345 self.name.to_string(),
346 FilterOperator::IsNull,
347 FilterValue::Null,
348 )
349 }
350
351 pub fn is_not_null(&self) -> Filter {
353 Filter::new(
354 self.name.to_string(),
355 FilterOperator::IsNotNull,
356 FilterValue::Null,
357 )
358 }
359
360 pub fn regex<V: Into<FilterValue>>(&self, pattern: V) -> Filter {
362 Filter::new(self.name.to_string(), FilterOperator::Regex, pattern.into())
363 }
364
365 pub fn iregex<V: Into<FilterValue>>(&self, pattern: V) -> Filter {
367 Filter::new(
368 self.name.to_string(),
369 FilterOperator::IRegex,
370 pattern.into(),
371 )
372 }
373
374 pub fn range<V: Into<FilterValue>>(&self, start: V, end: V) -> Filter {
376 Filter::new(
377 self.name.to_string(),
378 FilterOperator::Range,
379 FilterValue::Range(Box::new(start.into()), Box::new(end.into())),
380 )
381 }
382
383 pub fn array_contains<I, V>(&self, values: I) -> Filter
385 where
386 I: IntoIterator<Item = V>,
387 V: ToString,
388 {
389 Filter::new(
390 self.name.to_string(),
391 FilterOperator::ArrayContains,
392 FilterValue::Array(values.into_iter().map(|v| v.to_string()).collect()),
393 )
394 }
395
396 pub fn array_contained_by<I, V>(&self, values: I) -> Filter
398 where
399 I: IntoIterator<Item = V>,
400 V: ToString,
401 {
402 Filter::new(
403 self.name.to_string(),
404 FilterOperator::ArrayContainedBy,
405 FilterValue::Array(values.into_iter().map(|v| v.to_string()).collect()),
406 )
407 }
408
409 pub fn array_overlap<I, V>(&self, values: I) -> Filter
411 where
412 I: IntoIterator<Item = V>,
413 V: ToString,
414 {
415 Filter::new(
416 self.name.to_string(),
417 FilterOperator::ArrayOverlap,
418 FilterValue::Array(values.into_iter().map(|v| v.to_string()).collect()),
419 )
420 }
421
422 pub fn jsonb_contains(&self, json: &str) -> Filter {
424 Filter::new(
425 self.name.to_string(),
426 FilterOperator::JsonbContains,
427 FilterValue::String(json.to_string()),
428 )
429 }
430
431 pub fn jsonb_contained_by(&self, json: &str) -> Filter {
433 Filter::new(
434 self.name.to_string(),
435 FilterOperator::JsonbContainedBy,
436 FilterValue::String(json.to_string()),
437 )
438 }
439
440 pub fn jsonb_has_key(&self, key: &str) -> Filter {
442 Filter::new(
443 self.name.to_string(),
444 FilterOperator::JsonbKeyExists,
445 FilterValue::String(key.to_string()),
446 )
447 }
448
449 pub fn jsonb_has_any_keys<I, V>(&self, keys: I) -> Filter
451 where
452 I: IntoIterator<Item = V>,
453 V: ToString,
454 {
455 Filter::new(
456 self.name.to_string(),
457 FilterOperator::JsonbAnyKeyExists,
458 FilterValue::Array(keys.into_iter().map(|v| v.to_string()).collect()),
459 )
460 }
461
462 pub fn jsonb_has_keys<I, V>(&self, keys: I) -> Filter
464 where
465 I: IntoIterator<Item = V>,
466 V: ToString,
467 {
468 Filter::new(
469 self.name.to_string(),
470 FilterOperator::JsonbAllKeysExist,
471 FilterValue::Array(keys.into_iter().map(|v| v.to_string()).collect()),
472 )
473 }
474
475 pub fn jsonb_path_exists(&self, path: &str) -> Filter {
477 Filter::new(
478 self.name.to_string(),
479 FilterOperator::JsonbPathExists,
480 FilterValue::String(path.to_string()),
481 )
482 }
483
484 pub fn range_contains<V: Into<FilterValue>>(&self, value: V) -> Filter {
486 Filter::new(
487 self.name.to_string(),
488 FilterOperator::RangeContains,
489 value.into(),
490 )
491 }
492
493 pub fn range_contained_by(&self, range: &str) -> Filter {
495 Filter::new(
496 self.name.to_string(),
497 FilterOperator::RangeContainedBy,
498 FilterValue::String(range.to_string()),
499 )
500 }
501
502 pub fn range_overlaps(&self, range: &str) -> Filter {
504 Filter::new(
505 self.name.to_string(),
506 FilterOperator::RangeOverlaps,
507 FilterValue::String(range.to_string()),
508 )
509 }
510
511 pub fn date(&self) -> TransformedFieldRef<M> {
513 self.transform("DATE({field})")
514 }
515
516 pub fn time(&self) -> TransformedFieldRef<M> {
518 self.transform("TIME({field})")
519 }
520
521 pub fn year(&self) -> TransformedFieldRef<M> {
523 self.extract("YEAR")
524 }
525
526 pub fn iso_year(&self) -> TransformedFieldRef<M> {
528 self.extract("ISOYEAR")
529 }
530
531 pub fn month(&self) -> TransformedFieldRef<M> {
533 self.extract("MONTH")
534 }
535
536 pub fn day(&self) -> TransformedFieldRef<M> {
538 self.extract("DAY")
539 }
540
541 pub fn week(&self) -> TransformedFieldRef<M> {
543 self.extract("WEEK")
544 }
545
546 pub fn week_day(&self) -> TransformedFieldRef<M> {
548 self.transform("(EXTRACT(DOW FROM {field}) + 1)")
549 }
550
551 pub fn iso_week_day(&self) -> TransformedFieldRef<M> {
553 self.extract("ISODOW")
554 }
555
556 pub fn quarter(&self) -> TransformedFieldRef<M> {
558 self.extract("QUARTER")
559 }
560
561 pub fn hour(&self) -> TransformedFieldRef<M> {
563 self.extract("HOUR")
564 }
565
566 pub fn minute(&self) -> TransformedFieldRef<M> {
568 self.extract("MINUTE")
569 }
570
571 pub fn second(&self) -> TransformedFieldRef<M> {
573 self.extract("SECOND")
574 }
575
576 fn extract(&self, part: &str) -> TransformedFieldRef<M> {
577 self.transform(&format!("EXTRACT({} FROM {{field}})", part))
578 }
579
580 fn transform(&self, template: &str) -> TransformedFieldRef<M> {
581 let sql = template.replace("{field}", "e_identifier(self.name));
582 TransformedFieldRef::new(sql, self.name)
583 }
584
585 pub fn eq_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
594 Filter::new(
595 self.name.to_string(),
596 FilterOperator::Eq,
597 FilterValue::FieldRef(F::new(other.name)),
598 )
599 }
600
601 pub fn ne_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
610 Filter::new(
611 self.name.to_string(),
612 FilterOperator::Ne,
613 FilterValue::FieldRef(F::new(other.name)),
614 )
615 }
616
617 pub fn gt_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
626 Filter::new(
627 self.name.to_string(),
628 FilterOperator::Gt,
629 FilterValue::FieldRef(F::new(other.name)),
630 )
631 }
632
633 pub fn gte_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
642 Filter::new(
643 self.name.to_string(),
644 FilterOperator::Gte,
645 FilterValue::FieldRef(F::new(other.name)),
646 )
647 }
648
649 pub fn lt_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
658 Filter::new(
659 self.name.to_string(),
660 FilterOperator::Lt,
661 FilterValue::FieldRef(F::new(other.name)),
662 )
663 }
664
665 pub fn lte_field<T2>(&self, other: FieldRef<M, T2>) -> Filter {
674 Filter::new(
675 self.name.to_string(),
676 FilterOperator::Lte,
677 FilterValue::FieldRef(F::new(other.name)),
678 )
679 }
680}
681
682#[derive(Debug, Clone)]
683pub struct TransformedFieldRef<M> {
685 sql: String,
686 source: String,
687 _phantom: PhantomData<M>,
688}
689
690impl<M> TransformedFieldRef<M> {
691 fn new(sql: String, source: &str) -> Self {
692 Self {
693 sql,
694 source: source.to_owned(),
695 _phantom: PhantomData,
696 }
697 }
698
699 fn filter<V: Into<FilterValue>>(&self, operator: FilterOperator, value: V) -> Filter {
700 Filter::expression_with_source(
701 self.sql.clone(),
702 Some(self.source.clone()),
703 operator,
704 value.into(),
705 )
706 }
707
708 pub fn eq<V: Into<FilterValue>>(&self, value: V) -> Filter {
710 self.filter(FilterOperator::Eq, value)
711 }
712
713 pub fn exact<V: Into<FilterValue>>(&self, value: V) -> Filter {
715 self.eq(value)
716 }
717
718 pub fn iexact<V: Into<FilterValue>>(&self, value: V) -> Filter {
720 self.filter(FilterOperator::IExact, value)
721 }
722
723 pub fn ne<V: Into<FilterValue>>(&self, value: V) -> Filter {
725 self.filter(FilterOperator::Ne, value)
726 }
727
728 pub fn gt<V: Into<FilterValue>>(&self, value: V) -> Filter {
730 self.filter(FilterOperator::Gt, value)
731 }
732
733 pub fn gte<V: Into<FilterValue>>(&self, value: V) -> Filter {
735 self.filter(FilterOperator::Gte, value)
736 }
737
738 pub fn lt<V: Into<FilterValue>>(&self, value: V) -> Filter {
740 self.filter(FilterOperator::Lt, value)
741 }
742
743 pub fn lte<V: Into<FilterValue>>(&self, value: V) -> Filter {
745 self.filter(FilterOperator::Lte, value)
746 }
747
748 pub fn is_in<I, V>(&self, values: I) -> Filter
750 where
751 I: IntoIterator<Item = V>,
752 V: Into<FilterValue>,
753 {
754 Filter::expression_with_source(
755 self.sql.clone(),
756 Some(self.source.clone()),
757 FilterOperator::In,
758 FilterValue::List(values.into_iter().map(Into::into).collect()),
759 )
760 }
761
762 pub fn range<V: Into<FilterValue>>(&self, start: V, end: V) -> Filter {
764 Filter::expression_with_source(
765 self.sql.clone(),
766 Some(self.source.clone()),
767 FilterOperator::Range,
768 FilterValue::Range(Box::new(start.into()), Box::new(end.into())),
769 )
770 }
771
772 pub fn to_sql(&self) -> &str {
774 &self.sql
775 }
776}
777
778impl<M, T> fmt::Display for FieldRef<M, T> {
779 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
780 write!(f, "{}", self.name)
781 }
782}
783
784impl<M, T> From<FieldRef<M, T>> for String {
789 fn from(field_ref: FieldRef<M, T>) -> Self {
790 field_ref.name.to_string()
791 }
792}
793
794impl<M, T> From<FieldRef<M, T>> for F {
796 fn from(field_ref: FieldRef<M, T>) -> Self {
797 F::new(field_ref.name)
798 }
799}
800
801#[derive(Debug, Clone, Serialize, Deserialize)]
803pub struct OuterRef {
804 pub field: String,
806}
807
808impl OuterRef {
809 pub fn new(field: impl Into<String>) -> Self {
826 Self {
827 field: field.into(),
828 }
829 }
830 pub fn to_sql(&self) -> String {
841 self.field.clone()
843 }
844}
845
846#[derive(Debug, Clone, Serialize, Deserialize)]
848pub struct Subquery {
849 pub sql: String,
851 pub template: String,
853}
854
855impl Subquery {
856 pub fn new(sql: impl Into<String>) -> Self {
870 Self {
871 sql: sql.into(),
872 template: "(%(subquery)s)".to_string(),
873 }
874 }
875 pub fn with_template(mut self, template: impl Into<String>) -> Self {
887 self.template = template.into();
888 self
889 }
890 pub fn to_sql(&self) -> String {
901 self.template.replace("%(subquery)s", &self.sql)
902 }
903}
904
905#[derive(Debug, Clone, Serialize, Deserialize)]
907pub struct Exists {
908 pub subquery: Subquery,
910}
911
912impl Exists {
913 pub fn new(sql: impl Into<String>) -> Self {
927 Self {
928 subquery: Subquery {
929 sql: sql.into(),
930 template: "%(subquery)s".to_string(),
931 },
932 }
933 }
934 pub fn to_sql(&self) -> String {
945 format!("EXISTS({})", self.subquery.to_sql())
946 }
947}
948
949#[derive(Debug, Clone, Serialize, Deserialize)]
952pub struct Value {
953 pub value: ValueType,
955}
956
957#[derive(Debug, Clone, Serialize, Deserialize)]
958pub enum ValueType {
960 String(String),
962 Integer(i64),
964 Float(f64),
966 Bool(bool),
968 Null,
970}
971
972impl Value {
973 pub fn new<T: Into<ValueType>>(value: T) -> Self {
985 Self {
986 value: value.into(),
987 }
988 }
989 pub fn string(s: impl Into<String>) -> Self {
1000 Self {
1001 value: ValueType::String(s.into()),
1002 }
1003 }
1004 pub fn int(i: i64) -> Self {
1015 Self {
1016 value: ValueType::Integer(i),
1017 }
1018 }
1019 pub fn float(f: f64) -> Self {
1030 Self {
1031 value: ValueType::Float(f),
1032 }
1033 }
1034 pub fn bool(b: bool) -> Self {
1045 Self {
1046 value: ValueType::Bool(b),
1047 }
1048 }
1049 pub fn null() -> Self {
1060 Self {
1061 value: ValueType::Null,
1062 }
1063 }
1064 pub fn to_sql(&self) -> String {
1076 match &self.value {
1077 ValueType::String(s) => format!("'{}'", s.replace('\'', "''")),
1078 ValueType::Integer(i) => i.to_string(),
1079 ValueType::Float(f) => f.to_string(),
1080 ValueType::Bool(b) => if *b { "TRUE" } else { "FALSE" }.to_string(),
1081 ValueType::Null => "NULL".to_string(),
1082 }
1083 }
1084}
1085
1086impl From<String> for ValueType {
1087 fn from(s: String) -> Self {
1088 ValueType::String(s)
1089 }
1090}
1091
1092impl From<&str> for ValueType {
1093 fn from(s: &str) -> Self {
1094 ValueType::String(s.to_string())
1095 }
1096}
1097
1098impl From<i64> for ValueType {
1099 fn from(i: i64) -> Self {
1100 ValueType::Integer(i)
1101 }
1102}
1103
1104impl From<i32> for ValueType {
1105 fn from(i: i32) -> Self {
1106 ValueType::Integer(i as i64)
1107 }
1108}
1109
1110impl From<f64> for ValueType {
1111 fn from(f: f64) -> Self {
1112 ValueType::Float(f)
1113 }
1114}
1115
1116impl From<bool> for ValueType {
1117 fn from(b: bool) -> Self {
1118 ValueType::Bool(b)
1119 }
1120}
1121
1122#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1124pub enum QOperator {
1125 And,
1127 Or,
1129 Not,
1131}
1132
1133impl fmt::Display for QOperator {
1134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1135 match self {
1136 QOperator::And => write!(f, "AND"),
1137 QOperator::Or => write!(f, "OR"),
1138 QOperator::Not => write!(f, "NOT"),
1139 }
1140 }
1141}
1142
1143#[derive(Debug, Clone, Serialize, Deserialize)]
1146pub enum Q {
1147 Condition {
1149 field: String,
1151 operator: String,
1153 value: String,
1155 },
1156 Combined {
1158 operator: QOperator,
1160 conditions: Vec<Q>,
1162 },
1163}
1164
1165impl Q {
1166 pub fn new(
1183 field: impl Into<String>,
1184 operator: impl Into<String>,
1185 value: impl Into<String>,
1186 ) -> Self {
1187 Self::Condition {
1188 field: field.into(),
1189 operator: operator.into(),
1190 value: value.into(),
1191 }
1192 }
1193 pub fn from_sql(sql: &str) -> Self {
1211 let condition = super::sql_condition_parser::SqlConditionParser::parse(sql);
1212 if condition.contains_raw_condition() {
1213 Self::new("", "INVALID", "")
1214 } else {
1215 condition
1216 }
1217 }
1218
1219 pub fn from_raw_sql(sql: impl Into<String>) -> Self {
1224 Self::Condition {
1225 field: String::new(),
1226 operator: String::new(),
1227 value: sql.into(),
1228 }
1229 }
1230
1231 fn contains_raw_condition(&self) -> bool {
1232 match self {
1233 Self::Condition {
1234 field, operator, ..
1235 } => field.is_empty() && operator.is_empty(),
1236 Self::Combined { conditions, .. } => {
1237 conditions.iter().any(Self::contains_raw_condition)
1238 }
1239 }
1240 }
1241 pub fn empty() -> Self {
1244 Self::Combined {
1245 operator: QOperator::And,
1246 conditions: vec![],
1247 }
1248 }
1249 pub fn and(self, other: Q) -> Self {
1252 match self {
1253 Q::Combined {
1254 operator: QOperator::And,
1255 mut conditions,
1256 } => {
1257 conditions.push(other);
1258 Q::Combined {
1259 operator: QOperator::And,
1260 conditions,
1261 }
1262 }
1263 _ => Q::Combined {
1264 operator: QOperator::And,
1265 conditions: vec![self, other],
1266 },
1267 }
1268 }
1269 pub fn or(self, other: Q) -> Self {
1272 match self {
1273 Q::Combined {
1274 operator: QOperator::Or,
1275 mut conditions,
1276 } => {
1277 conditions.push(other);
1278 Q::Combined {
1279 operator: QOperator::Or,
1280 conditions,
1281 }
1282 }
1283 _ => Q::Combined {
1284 operator: QOperator::Or,
1285 conditions: vec![self, other],
1286 },
1287 }
1288 }
1289 #[allow(clippy::should_implement_trait)]
1295 pub fn not(self) -> Self {
1296 Q::Combined {
1297 operator: QOperator::Not,
1298 conditions: vec![self],
1299 }
1300 }
1301 pub fn to_sql(&self) -> String {
1304 match self {
1305 Q::Condition {
1306 field,
1307 operator,
1308 value,
1309 } => {
1310 if field.is_empty() && operator.is_empty() {
1312 return value.clone();
1313 }
1314
1315 let operator = operator.to_ascii_uppercase();
1316 let Some(field) = Self::format_sql_field(field) else {
1317 return "FALSE".to_string();
1318 };
1319 let valid_operator = matches!(
1320 operator.as_str(),
1321 "=" | "!="
1322 | "<>" | ">" | ">="
1323 | "<" | "<=" | "IN"
1324 | "NOT IN" | "LIKE"
1325 | "IS NULL" | "IS NOT NULL"
1326 );
1327 if !valid_operator {
1328 return "FALSE".to_string();
1329 }
1330
1331 if matches!(operator.as_str(), "IS NULL" | "IS NOT NULL") {
1332 return format!("{} {}", field, operator);
1333 }
1334
1335 let formatted_value = if matches!(operator.as_str(), "IN" | "NOT IN") {
1336 let values = value.trim().trim_start_matches('(').trim_end_matches(')');
1337 format!(
1338 "({})",
1339 values
1340 .split(',')
1341 .map(Self::format_sql_value)
1342 .collect::<Vec<_>>()
1343 .join(", ")
1344 )
1345 } else {
1346 Self::format_sql_value(value)
1347 };
1348 format!("{} {} {}", field, operator, formatted_value)
1349 }
1350 Q::Combined {
1351 operator,
1352 conditions,
1353 } => {
1354 let sql_conditions: Vec<String> = conditions.iter().map(|q| q.to_sql()).collect();
1355
1356 match operator {
1357 QOperator::Not => {
1358 if conditions.len() == 1 {
1359 format!("NOT ({})", sql_conditions[0])
1360 } else {
1361 format!("NOT ({})", sql_conditions.join(" AND "))
1362 }
1363 }
1364 QOperator::And => {
1365 if sql_conditions.len() == 1 {
1366 sql_conditions[0].clone()
1367 } else {
1368 format!("({})", sql_conditions.join(" AND "))
1369 }
1370 }
1371 QOperator::Or => {
1372 if sql_conditions.len() == 1 {
1373 sql_conditions[0].clone()
1374 } else {
1375 format!("({})", sql_conditions.join(" OR "))
1376 }
1377 }
1378 }
1379 }
1380 }
1381 }
1382
1383 fn format_sql_value(value: &str) -> String {
1384 let value = value.trim();
1385 if value.parse::<f64>().is_ok()
1386 || value.eq_ignore_ascii_case("TRUE")
1387 || value.eq_ignore_ascii_case("FALSE")
1388 || value.eq_ignore_ascii_case("NULL")
1389 {
1390 return value.to_string();
1391 }
1392
1393 let value = value
1394 .strip_prefix('\'')
1395 .and_then(|value| value.strip_suffix('\''))
1396 .unwrap_or(value);
1397 format!("'{}'", value.replace('\'', "''"))
1398 }
1399
1400 fn format_sql_field(field: &str) -> Option<String> {
1401 for function in ["COUNT", "SUM", "AVG", "MAX", "MIN"] {
1402 if let Some(argument) = field
1403 .strip_prefix(function)
1404 .and_then(|suffix| suffix.strip_prefix('('))
1405 .and_then(|suffix| suffix.strip_suffix(')'))
1406 {
1407 return if argument == "*" {
1408 Some(format!("{function}(*)"))
1409 } else {
1410 Self::format_sql_identifier(argument)
1411 .map(|argument| format!("{function}({argument})"))
1412 };
1413 }
1414 }
1415
1416 Self::format_sql_identifier(field)
1417 }
1418
1419 fn format_sql_identifier(field: &str) -> Option<String> {
1420 let valid = !field.is_empty()
1421 && field.split('.').all(|part| {
1422 !part.is_empty()
1423 && part
1424 .chars()
1425 .all(|character| character.is_ascii_alphanumeric() || character == '_')
1426 });
1427 valid.then(|| quote_identifier(field))
1428 }
1429}
1430
1431#[cfg(test)]
1432mod tests {
1433 use super::*;
1434
1435 #[allow(dead_code)]
1437 struct TestUser {
1438 id: i64,
1439 name: String,
1440 created_at: i64,
1441 }
1442
1443 impl TestUser {
1445 const fn field_id() -> FieldRef<TestUser, i64> {
1446 FieldRef::new("id")
1447 }
1448
1449 const fn field_name() -> FieldRef<TestUser, String> {
1450 FieldRef::new("name")
1451 }
1452
1453 const fn field_created_at() -> FieldRef<TestUser, i64> {
1454 FieldRef::new("created_at")
1455 }
1456 }
1457
1458 #[test]
1459 fn test_field_ref_basic() {
1460 let id_ref = TestUser::field_id();
1461 assert_eq!(id_ref.name(), "id");
1462 assert_eq!(id_ref.to_sql(), "\"id\"");
1463 assert_eq!(format!("{}", id_ref), "id");
1464 }
1465
1466 #[test]
1467 fn test_field_ref_string_field() {
1468 let name_ref = TestUser::field_name();
1469 assert_eq!(name_ref.name(), "name");
1470 assert_eq!(name_ref.to_sql(), "\"name\"");
1471 }
1472
1473 #[test]
1474 fn test_field_ref_to_f_conversion() {
1475 let id_ref = TestUser::field_id();
1476 let f: F = id_ref.into();
1477 assert_eq!(f.to_sql(), "\"id\"");
1478 }
1479
1480 #[test]
1481 fn test_field_ref_django_style_filter_helpers() {
1482 let contains = TestUser::field_name().icontains("alice");
1483 assert_eq!(contains.field, "name");
1484 assert!(matches!(contains.operator, FilterOperator::IContains));
1485 assert!(matches!(contains.value, FilterValue::String(value) if value == "alice"));
1486
1487 let in_filter = TestUser::field_id().is_in([1_i64, 2_i64]);
1488 assert_eq!(in_filter.field, "id");
1489 assert!(matches!(in_filter.operator, FilterOperator::In));
1490 assert!(matches!(in_filter.value, FilterValue::List(values) if values.len() == 2));
1491
1492 let null_filter = TestUser::field_name().is_null();
1493 assert_eq!(null_filter.field, "name");
1494 assert!(matches!(null_filter.operator, FilterOperator::IsNull));
1495 }
1496
1497 #[test]
1498 fn test_field_ref_django_style_date_transform_helpers() {
1499 let year = TestUser::field_created_at().year();
1500 assert_eq!(year.to_sql(), "EXTRACT(YEAR FROM \"created_at\")");
1501
1502 let filter = year.gte(2026);
1503 assert_eq!(filter.field, "EXTRACT(YEAR FROM \"created_at\")");
1504 assert!(matches!(filter.operator, FilterOperator::Gte));
1505 assert!(matches!(filter.value, FilterValue::Integer(2026)));
1506 }
1507
1508 #[test]
1509 fn test_expressions_f_unit() {
1510 let f = F::new("price");
1511 assert_eq!(f.to_sql(), "\"price\"");
1512 assert_eq!(format!("{}", f), "price");
1513 }
1514
1515 #[test]
1516 fn test_q_simple_condition() {
1517 let q = Q::new("age", ">=", "18");
1518 assert_eq!(q.to_sql(), "\"age\" >= 18");
1519 }
1520
1521 #[test]
1522 fn test_q_and_operator() {
1523 let q1 = Q::new("age", ">=", "18");
1524 let q2 = Q::new("country", "=", "US");
1525 let q = q1.and(q2);
1526
1527 let sql = q.to_sql();
1528 assert_eq!(
1529 sql, "(\"age\" >= 18 AND \"country\" = 'US')",
1530 "Expected exact AND query structure, got: {}",
1531 sql
1532 );
1533 }
1534
1535 #[test]
1536 fn test_q_or_operator() {
1537 let q1 = Q::new("status", "=", "active");
1538 let q2 = Q::new("status", "=", "pending");
1539 let q = q1.or(q2);
1540
1541 let sql = q.to_sql();
1542 assert_eq!(
1543 sql, "(\"status\" = 'active' OR \"status\" = 'pending')",
1544 "Expected exact OR query structure, got: {}",
1545 sql
1546 );
1547 }
1548
1549 #[test]
1550 fn test_q_not_operator() {
1551 let q = Q::new("deleted", "=", "1").not();
1552 assert_eq!(q.to_sql(), "NOT (\"deleted\" = 1)");
1553 }
1554
1555 #[test]
1556 fn test_q_complex_query() {
1557 let q1 = Q::new("age", ">=", "18");
1559 let q2 = Q::new("country", "=", "US");
1560 let q3 = Q::new("status", "=", "premium");
1561
1562 let q = q1.and(q2).or(q3);
1563
1564 let sql = q.to_sql();
1565 assert_eq!(
1566 sql, "((\"age\" >= 18 AND \"country\" = 'US') OR \"status\" = 'premium')",
1567 "Expected exact complex query structure, got: {}",
1568 sql
1569 );
1570 }
1571
1572 #[test]
1573 fn test_q_chained_and() {
1574 let q1 = Q::new("a", "=", "1");
1575 let q2 = Q::new("b", "=", "2");
1576 let q3 = Q::new("c", "=", "3");
1577
1578 let q = q1.and(q2).and(q3);
1579
1580 let sql = q.to_sql();
1581 assert_eq!(
1582 sql, "(\"a\" = 1 AND \"b\" = 2 AND \"c\" = 3)",
1583 "Expected exact chained AND query structure, got: {}",
1584 sql
1585 );
1586 }
1587
1588 #[test]
1589 fn test_q_chained_or() {
1590 let q1 = Q::new("x", "=", "1");
1591 let q2 = Q::new("y", "=", "2");
1592 let q3 = Q::new("z", "=", "3");
1593
1594 let q = q1.or(q2).or(q3);
1595
1596 let sql = q.to_sql();
1597 assert_eq!(
1598 sql, "(\"x\" = 1 OR \"y\" = 2 OR \"z\" = 3)",
1599 "Expected exact chained OR query structure, got: {}",
1600 sql
1601 );
1602 }
1603
1604 #[test]
1605 fn test_outer_ref() {
1606 let outer_ref = OuterRef::new("parent_id");
1607 assert_eq!(outer_ref.to_sql(), "parent_id");
1608 }
1609
1610 #[test]
1611 fn test_subquery() {
1612 let subquery = Subquery::new("SELECT id FROM users WHERE active = 1");
1613 let sql = subquery.to_sql();
1614 assert_eq!(
1615 sql, "(SELECT id FROM users WHERE active = 1)",
1616 "Expected exact subquery SQL with parentheses, got: {}",
1617 sql
1618 );
1619 }
1620
1621 #[test]
1622 fn test_subquery_custom_template() {
1623 let subquery =
1624 Subquery::new("SELECT COUNT(*) FROM orders").with_template("COUNT = %(subquery)s");
1625 let sql = subquery.to_sql();
1626 assert_eq!(sql, "COUNT = SELECT COUNT(*) FROM orders");
1627 }
1628
1629 #[test]
1630 fn test_expressions_exists() {
1631 let exists = Exists::new("SELECT 1 FROM orders WHERE user_id = 123");
1632 let sql = exists.to_sql();
1633 assert_eq!(
1634 sql, "EXISTS(SELECT 1 FROM orders WHERE user_id = 123)",
1635 "Expected exact EXISTS SQL structure, got: {}",
1636 sql
1637 );
1638 }
1639
1640 #[test]
1643 fn test_field_ref_to_f_direct_conversion() {
1644 let id_field = TestUser::field_id();
1646 let f: F = id_field.into();
1647
1648 assert_eq!(f.to_sql(), "\"id\"");
1649 assert_eq!(format!("{}", f), "id");
1650 }
1651
1652 #[test]
1653 fn test_field_ref_string_field_to_f() {
1654 let name_field = TestUser::field_name();
1656 let f: F = name_field.into();
1657
1658 assert_eq!(f.to_sql(), "\"name\"");
1659 assert_eq!(format!("{}", f), "name");
1660 }
1661
1662 #[test]
1663 fn test_multiple_field_refs_to_f() {
1664 let id_f: F = TestUser::field_id().into();
1666 let name_f: F = TestUser::field_name().into();
1667
1668 assert_eq!(id_f.to_sql(), "\"id\"");
1669 assert_eq!(name_f.to_sql(), "\"name\"");
1670 assert_ne!(id_f.to_sql(), name_f.to_sql());
1671 }
1672
1673 #[test]
1674 fn test_field_ref_preserves_field_name_in_f() {
1675 let id_field = TestUser::field_id();
1677 let original_name = id_field.name();
1678 let f: F = id_field.into();
1679
1680 assert_eq!(f.to_sql(), quote_identifier(original_name));
1681 }
1682
1683 #[test]
1684 fn test_field_ref_const_to_f_conversion() {
1685 const ID_FIELD: FieldRef<TestUser, i64> = FieldRef::new("id");
1687 let f: F = ID_FIELD.into();
1688
1689 assert_eq!(f.to_sql(), "\"id\"");
1690 }
1691}
1692#[cfg(test)]
1697mod expressions_extended_tests {
1698 use super::*;
1699 use crate::orm::aggregation::*;
1700 use crate::orm::annotation::Value;
1702 use crate::orm::expressions::{F, Q};
1703
1704 #[test]
1705 fn test_values_expression_group_by() {
1707 let val = Value::String("test_group".to_string());
1709 assert_eq!(val.to_sql(), "'test_group'");
1710 }
1711
1712 #[test]
1713 fn test_values_expression_group_by_1() {
1715 let val = Value::Int(42);
1717 assert_eq!(val.to_sql(), "42");
1718 }
1719
1720 #[test]
1721 fn test_aggregate_rawsql_annotation() {
1723 let agg = Aggregate::sum("amount").with_alias("total_amount");
1725 assert_eq!(agg.to_sql(), "SUM(amount) AS total_amount");
1726 }
1727
1728 #[test]
1729 fn test_aggregate_rawsql_annotation_1() {
1731 let agg = Aggregate::max("price").with_alias("max_price");
1733 assert_eq!(agg.to_sql(), "MAX(price) AS max_price");
1734 }
1735
1736 #[test]
1737 fn test_aggregate_subquery_annotation() {
1739 let subquery = Subquery::new("SELECT COUNT(*) FROM orders WHERE status = 'completed'");
1741 let sql = subquery.to_sql();
1742 assert_eq!(
1743 sql, "(SELECT COUNT(*) FROM orders WHERE status = 'completed')",
1744 "Expected exact subquery with aggregate, got: {}",
1745 sql
1746 );
1747 }
1748
1749 #[test]
1750 fn test_aggregate_subquery_annotation_1() {
1752 let subquery = Subquery::new("SELECT AVG(price) FROM products");
1754 let sql = subquery.to_sql();
1755 assert_eq!(
1756 sql, "(SELECT AVG(price) FROM products)",
1757 "Expected exact subquery with AVG aggregate, got: {}",
1758 sql
1759 );
1760 }
1761
1762 #[test]
1763 fn test_aggregates() {
1765 let agg = Aggregate::avg("score");
1767 assert_eq!(agg.to_sql(), "AVG(score)");
1768 }
1769
1770 #[test]
1771 fn test_aggregates_1() {
1773 let agg = Aggregate::min("age");
1775 assert_eq!(agg.to_sql(), "MIN(age)");
1776 }
1777
1778 #[test]
1779 fn test_annotate_by_empty_custom_exists() {
1781 let exists = Exists::new("");
1783 let sql = exists.to_sql();
1784 assert_eq!(sql, "EXISTS()");
1785 }
1786
1787 #[test]
1788 fn test_annotate_by_empty_custom_exists_1() {
1790 let exists = Exists::new("SELECT 1");
1792 let sql = exists.to_sql();
1793 assert_eq!(sql, "EXISTS(SELECT 1)");
1794 }
1795
1796 #[test]
1797 fn test_annotate_values_aggregate() {
1799 let agg = Aggregate::count_all().with_alias("total");
1801 assert_eq!(agg.to_sql(), "COUNT(*) AS total");
1802 }
1803
1804 #[test]
1805 fn test_annotate_values_aggregate_1() {
1807 let agg = Aggregate::sum("quantity").with_alias("total_qty");
1809 assert_eq!(agg.to_sql(), "SUM(quantity) AS total_qty");
1810 }
1811
1812 #[test]
1813 fn test_annotate_values_count() {
1815 let agg = Aggregate::count(Some("id")).with_alias("total");
1816 assert_eq!(agg.to_sql(), "COUNT(id) AS total");
1817 }
1818
1819 #[test]
1820 fn test_annotate_values_count_1() {
1822 let agg = Aggregate::count(Some("id")).with_alias("total");
1823 assert_eq!(agg.to_sql(), "COUNT(id) AS total");
1824 }
1825
1826 #[test]
1827 fn test_annotate_values_filter() {
1829 let q = Q::new("status", "=", "active");
1830 assert_eq!(
1831 q.to_sql(),
1832 "\"status\" = 'active'",
1833 "Expected exact Q condition SQL, got: {}",
1834 q.to_sql()
1835 );
1836 }
1837
1838 #[test]
1839 fn test_annotate_values_filter_1() {
1841 let q = Q::new("status", "=", "active");
1842 assert_eq!(
1843 q.to_sql(),
1844 "\"status\" = 'active'",
1845 "Expected exact Q condition SQL, got: {}",
1846 q.to_sql()
1847 );
1848 }
1849
1850 #[test]
1851 fn test_annotation_with_deeply_nested_outerref() {
1853 let outer_ref = OuterRef::new("parent.grandparent.id");
1855 assert_eq!(outer_ref.to_sql(), "parent.grandparent.id");
1856 }
1857
1858 #[test]
1859 fn test_annotation_with_deeply_nested_outerref_1() {
1861 let outer_ref = OuterRef::new("root.level1.level2.field");
1863 assert_eq!(outer_ref.to_sql(), "root.level1.level2.field");
1864 }
1865
1866 #[test]
1867 fn test_annotation_with_nested_outerref() {
1869 let outer_ref = OuterRef::new("parent.user_id");
1871 assert_eq!(outer_ref.to_sql(), "parent.user_id");
1872 }
1873
1874 #[test]
1875 fn test_annotation_with_nested_outerref_1() {
1877 let outer_ref = OuterRef::new("outer.category_id");
1879 assert_eq!(outer_ref.to_sql(), "outer.category_id");
1880 }
1881
1882 #[test]
1883 fn test_annotation_with_outerref() {
1885 let outer_ref = OuterRef::new("user_id");
1887 assert_eq!(outer_ref.to_sql(), "user_id");
1888 }
1889
1890 #[test]
1891 fn test_annotation_with_outerref_1() {
1893 let outer_ref = OuterRef::new("category_id");
1895 assert_eq!(outer_ref.to_sql(), "category_id");
1896 }
1897
1898 #[test]
1899 fn test_annotation_with_outerref_and_output_field() {
1901 let outer_ref = OuterRef::new("price");
1903 let f = F::new("product_price");
1904 assert_eq!(outer_ref.to_sql(), "price");
1905 assert_eq!(f.to_sql(), "\"product_price\"");
1906 }
1907
1908 #[test]
1909 fn test_annotation_with_outerref_and_output_field_1() {
1911 let outer_ref = OuterRef::new("amount");
1913 assert_eq!(outer_ref.to_sql(), "amount");
1914 }
1915
1916 #[test]
1917 fn test_annotations_within_subquery() {
1919 let subquery = Subquery::new("SELECT id, COUNT(*) as total FROM items GROUP BY id");
1921 assert_eq!(
1922 subquery.to_sql(),
1923 "(SELECT id, COUNT(*) as total FROM items GROUP BY id)",
1924 "Expected exact subquery with annotations, got: {}",
1925 subquery.to_sql()
1926 );
1927 }
1928
1929 #[test]
1930 fn test_annotations_within_subquery_1() {
1932 let subquery =
1934 Subquery::new("SELECT user_id, SUM(amount) as total FROM orders GROUP BY user_id");
1935 assert_eq!(
1936 subquery.to_sql(),
1937 "(SELECT user_id, SUM(amount) as total FROM orders GROUP BY user_id)",
1938 "Expected exact subquery with SUM aggregate, got: {}",
1939 subquery.to_sql()
1940 );
1941 }
1942
1943 #[test]
1944 fn test_case_in_filter_if_boolean_output_field() {
1946 let q = Q::new("status", "=", "active");
1947 assert_eq!(
1948 q.to_sql(),
1949 "\"status\" = 'active'",
1950 "Expected exact Q condition SQL, got: {}",
1951 q.to_sql()
1952 );
1953 }
1954
1955 #[test]
1956 fn test_case_in_filter_if_boolean_output_field_1() {
1958 let q = Q::new("status", "=", "active");
1959 assert_eq!(
1960 q.to_sql(),
1961 "\"status\" = 'active'",
1962 "Expected exact Q condition SQL, got: {}",
1963 q.to_sql()
1964 );
1965 }
1966
1967 #[test]
1968 fn test_date_subquery_subtraction() {
1970 let subquery = Subquery::new("SELECT date1 - date2 FROM events");
1972 assert_eq!(
1973 subquery.to_sql(),
1974 "(SELECT date1 - date2 FROM events)",
1975 "Expected exact subquery with date subtraction, got: {}",
1976 subquery.to_sql()
1977 );
1978 }
1979
1980 #[test]
1981 fn test_date_subquery_subtraction_1() {
1983 let subquery = Subquery::new("SELECT end_date - start_date FROM projects");
1985 assert_eq!(
1986 subquery.to_sql(),
1987 "(SELECT end_date - start_date FROM projects)",
1988 "Expected exact subquery with date subtraction, got: {}",
1989 subquery.to_sql()
1990 );
1991 }
1992
1993 #[test]
1994 fn test_datetime_and_duration_field_addition_with_annotate_and_no_output_field() {
1996 let f = F::new("created_at + INTERVAL 7 DAY");
1998 assert_eq!(f.to_sql(), "\"created_at + INTERVAL 7 DAY\"");
1999 }
2000
2001 #[test]
2002 fn test_datetime_and_duration_field_addition_with_annotate_and_no_output_field_1() {
2004 let f = F::new("start_time + duration");
2006 assert_eq!(f.to_sql(), "\"start_time + duration\"");
2007 }
2008
2009 #[test]
2010 fn test_datetime_and_durationfield_addition_with_filter() {
2012 let q = Q::new("status", "=", "active");
2013 assert_eq!(
2014 q.to_sql(),
2015 "\"status\" = 'active'",
2016 "Expected exact Q condition SQL, got: {}",
2017 q.to_sql()
2018 );
2019 }
2020
2021 #[test]
2022 fn test_datetime_and_durationfield_addition_with_filter_1() {
2024 let q = Q::new("status", "=", "active");
2025 assert_eq!(
2026 q.to_sql(),
2027 "\"status\" = 'active'",
2028 "Expected exact Q condition SQL, got: {}",
2029 q.to_sql()
2030 );
2031 }
2032
2033 #[test]
2034 fn test_datetime_subquery_subtraction() {
2036 let subquery = Subquery::new("SELECT updated_at - created_at FROM records");
2038 assert_eq!(
2039 subquery.to_sql(),
2040 "(SELECT updated_at - created_at FROM records)",
2041 "Expected exact subquery with datetime subtraction, got: {}",
2042 subquery.to_sql()
2043 );
2044 }
2045
2046 #[test]
2047 fn test_datetime_subquery_subtraction_1() {
2049 let subquery = Subquery::new("SELECT NOW() - last_login FROM users");
2051 assert_eq!(
2052 subquery.to_sql(),
2053 "(SELECT NOW() - last_login FROM users)",
2054 "Expected exact subquery with NOW() function, got: {}",
2055 subquery.to_sql()
2056 );
2057 }
2058
2059 #[test]
2060 fn test_datetime_subtraction_with_annotate_and_no_output_field() {
2062 let f = F::new("end_time - start_time");
2064 assert_eq!(f.to_sql(), "\"end_time - start_time\"");
2065 }
2066
2067 #[test]
2068 fn test_datetime_subtraction_with_annotate_and_no_output_field_1() {
2070 let f = F::new("checkout_time - checkin_time");
2072 assert_eq!(f.to_sql(), "\"checkout_time - checkin_time\"");
2073 }
2074
2075 #[test]
2076 fn test_distinct_aggregates() {
2078 let agg = Aggregate::count_distinct("user_id");
2080 assert_eq!(agg.to_sql(), "COUNT(DISTINCT user_id)");
2081 }
2082
2083 #[test]
2084 fn test_distinct_aggregates_1() {
2086 let agg = Aggregate::count_distinct("email");
2088 assert_eq!(agg.to_sql(), "COUNT(DISTINCT email)");
2089 }
2090
2091 #[test]
2092 fn test_empty_group_by() {
2094 let agg = Aggregate::count_all();
2096 assert_eq!(agg.to_sql(), "COUNT(*)");
2097 }
2098
2099 #[test]
2100 fn test_empty_group_by_1() {
2102 let agg = Aggregate::sum("total");
2104 assert_eq!(agg.to_sql(), "SUM(total)");
2105 }
2106
2107 #[test]
2108 fn test_exists_in_filter() {
2110 let q = Q::new("status", "=", "active");
2111 assert_eq!(
2112 q.to_sql(),
2113 "\"status\" = 'active'",
2114 "Expected exact Q condition SQL, got: {}",
2115 q.to_sql()
2116 );
2117 }
2118
2119 #[test]
2120 fn test_exists_in_filter_1() {
2122 let q = Q::new("status", "=", "active");
2123 assert_eq!(
2124 q.to_sql(),
2125 "\"status\" = 'active'",
2126 "Expected exact Q condition SQL, got: {}",
2127 q.to_sql()
2128 );
2129 }
2130
2131 #[test]
2132 fn test_expressions_range_lookups_join_choice() {
2134 let q1 = Q::new("price", ">=", "10");
2136 let q2 = Q::new("price", "<=", "100");
2137 let q = q1.and(q2);
2138 let sql = q.to_sql();
2139 assert_eq!(
2140 sql, "(\"price\" >= 10 AND \"price\" <= 100)",
2141 "Expected exact range query with AND, got: {}",
2142 sql
2143 );
2144 }
2145
2146 #[test]
2147 fn test_expressions_range_lookups_join_choice_1() {
2149 let q1 = Q::new("age", ">", "18");
2151 let q2 = Q::new("age", "<", "65");
2152 let q = q1.and(q2);
2153 let sql = q.to_sql();
2154 assert_eq!(
2155 sql, "(\"age\" > 18 AND \"age\" < 65)",
2156 "Expected exact age range query, got: {}",
2157 sql
2158 );
2159 }
2160
2161 #[test]
2162 fn test_filter() {
2164 let q = Q::new("status", "=", "active");
2165 assert_eq!(
2166 q.to_sql(),
2167 "\"status\" = 'active'",
2168 "Expected exact Q condition SQL, got: {}",
2169 q.to_sql()
2170 );
2171 }
2172
2173 #[test]
2174 fn test_filter_1() {
2176 let q = Q::new("status", "=", "active");
2177 assert_eq!(
2178 q.to_sql(),
2179 "\"status\" = 'active'",
2180 "Expected exact Q condition SQL, got: {}",
2181 q.to_sql()
2182 );
2183 }
2184
2185 #[test]
2186 fn test_filter_by_empty_exists() {
2188 let q = Q::new("status", "=", "active");
2189 assert_eq!(
2190 q.to_sql(),
2191 "\"status\" = 'active'",
2192 "Expected exact Q condition SQL, got: {}",
2193 q.to_sql()
2194 );
2195 }
2196
2197 #[test]
2198 fn test_filter_by_empty_exists_1() {
2200 let q = Q::new("status", "=", "active");
2201 assert_eq!(
2202 q.to_sql(),
2203 "\"status\" = 'active'",
2204 "Expected exact Q condition SQL, got: {}",
2205 q.to_sql()
2206 );
2207 }
2208
2209 #[test]
2210 fn test_filter_decimal_expression() {
2212 let q = Q::new("status", "=", "active");
2213 assert_eq!(
2214 q.to_sql(),
2215 "\"status\" = 'active'",
2216 "Expected exact Q condition SQL, got: {}",
2217 q.to_sql()
2218 );
2219 }
2220
2221 #[test]
2222 fn test_filter_decimal_expression_1() {
2224 let q = Q::new("status", "=", "active");
2225 assert_eq!(
2226 q.to_sql(),
2227 "\"status\" = 'active'",
2228 "Expected exact Q condition SQL, got: {}",
2229 q.to_sql()
2230 );
2231 }
2232
2233 #[test]
2234 fn test_filter_inter_attribute() {
2236 let q = Q::new("status", "=", "active");
2237 assert_eq!(
2238 q.to_sql(),
2239 "\"status\" = 'active'",
2240 "Expected exact Q condition SQL, got: {}",
2241 q.to_sql()
2242 );
2243 }
2244
2245 #[test]
2246 fn test_filter_inter_attribute_1() {
2248 let q = Q::new("status", "=", "active");
2249 assert_eq!(
2250 q.to_sql(),
2251 "\"status\" = 'active'",
2252 "Expected exact Q condition SQL, got: {}",
2253 q.to_sql()
2254 );
2255 }
2256
2257 #[test]
2258 fn test_filter_not_equals_other_field() {
2260 let q = Q::new("status", "=", "active");
2261 assert_eq!(
2262 q.to_sql(),
2263 "\"status\" = 'active'",
2264 "Expected exact Q condition SQL, got: {}",
2265 q.to_sql()
2266 );
2267 }
2268
2269 #[test]
2270 fn test_filter_not_equals_other_field_1() {
2272 let q = Q::new("status", "=", "active");
2273 assert_eq!(
2274 q.to_sql(),
2275 "\"status\" = 'active'",
2276 "Expected exact Q condition SQL, got: {}",
2277 q.to_sql()
2278 );
2279 }
2280
2281 #[test]
2282 fn test_filter_with_join() {
2284 let q = Q::new("status", "=", "active");
2285 assert_eq!(
2286 q.to_sql(),
2287 "\"status\" = 'active'",
2288 "Expected exact Q condition SQL, got: {}",
2289 q.to_sql()
2290 );
2291 }
2292
2293 #[test]
2294 fn test_filter_with_join_1() {
2296 let q = Q::new("status", "=", "active");
2297 assert_eq!(
2298 q.to_sql(),
2299 "\"status\" = 'active'",
2300 "Expected exact Q condition SQL, got: {}",
2301 q.to_sql()
2302 );
2303 }
2304
2305 #[test]
2306 fn test_filtered_aggregates() {
2308 let q = Q::new("status", "=", "active");
2309 assert_eq!(
2310 q.to_sql(),
2311 "\"status\" = 'active'",
2312 "Expected exact Q condition SQL, got: {}",
2313 q.to_sql()
2314 );
2315 }
2316
2317 #[test]
2318 fn test_filtered_aggregates_1() {
2320 let q = Q::new("status", "=", "active");
2321 assert_eq!(
2322 q.to_sql(),
2323 "\"status\" = 'active'",
2324 "Expected exact Q condition SQL, got: {}",
2325 q.to_sql()
2326 );
2327 }
2328
2329 #[test]
2330 fn test_filtering_on_annotate_that_uses_q() {
2332 let q = Q::new("status", "=", "active");
2333 assert_eq!(
2334 q.to_sql(),
2335 "\"status\" = 'active'",
2336 "Expected exact Q condition SQL, got: {}",
2337 q.to_sql()
2338 );
2339 }
2340
2341 #[test]
2342 fn test_filtering_on_annotate_that_uses_q_1() {
2344 let q = Q::new("status", "=", "active");
2345 assert_eq!(
2346 q.to_sql(),
2347 "\"status\" = 'active'",
2348 "Expected exact Q condition SQL, got: {}",
2349 q.to_sql()
2350 );
2351 }
2352
2353 #[test]
2354 fn test_filtering_on_q_that_is_boolean() {
2356 let q = Q::new("status", "=", "active");
2357 assert_eq!(
2358 q.to_sql(),
2359 "\"status\" = 'active'",
2360 "Expected exact Q condition SQL, got: {}",
2361 q.to_sql()
2362 );
2363 }
2364
2365 #[test]
2366 fn test_filtering_on_q_that_is_boolean_1() {
2368 let q = Q::new("status", "=", "active");
2369 assert_eq!(
2370 q.to_sql(),
2371 "\"status\" = 'active'",
2372 "Expected exact Q condition SQL, got: {}",
2373 q.to_sql()
2374 );
2375 }
2376
2377 #[test]
2378 fn test_filtering_on_rawsql_that_is_boolean() {
2380 let q = Q::new("status", "=", "active");
2381 assert_eq!(
2382 q.to_sql(),
2383 "\"status\" = 'active'",
2384 "Expected exact Q condition SQL, got: {}",
2385 q.to_sql()
2386 );
2387 }
2388
2389 #[test]
2390 fn test_filtering_on_rawsql_that_is_boolean_1() {
2392 let q = Q::new("status", "=", "active");
2393 assert_eq!(
2394 q.to_sql(),
2395 "\"status\" = 'active'",
2396 "Expected exact Q condition SQL, got: {}",
2397 q.to_sql()
2398 );
2399 }
2400
2401 #[test]
2402 fn test_in_lookup_allows_f_expressions_and_expressions_for_integers() {
2404 let f = F::new("category_id");
2406 assert_eq!(f.to_sql(), "\"category_id\"");
2407 }
2408
2409 #[test]
2410 fn test_in_lookup_allows_f_expressions_and_expressions_for_integers_1() {
2412 let q = Q::new("id", "IN", "1,2,3,4,5");
2414 assert_eq!(
2415 q.to_sql(),
2416 "\"id\" IN (1, 2, 3, 4, 5)",
2417 "Expected exact IN query, got: {}",
2418 q.to_sql()
2419 );
2420 }
2421
2422 #[test]
2423 fn test_in_subquery() {
2425 let subquery = Subquery::new("SELECT id FROM active_users");
2427 assert_eq!(
2428 subquery.to_sql(),
2429 "(SELECT id FROM active_users)",
2430 "Expected exact subquery for IN clause, got: {}",
2431 subquery.to_sql()
2432 );
2433 }
2434
2435 #[test]
2436 fn test_in_subquery_1() {
2438 let subquery = Subquery::new("SELECT category_id FROM featured_categories");
2440 assert_eq!(
2441 subquery.to_sql(),
2442 "(SELECT category_id FROM featured_categories)",
2443 "Expected exact subquery for featured categories, got: {}",
2444 subquery.to_sql()
2445 );
2446 }
2447
2448 #[test]
2449 fn test_incorrect_field_in_f_expression() {
2451 let f = F::new("nonexistent_field");
2453 assert_eq!(f.to_sql(), "\"nonexistent_field\"");
2454 }
2455
2456 #[test]
2457 fn test_incorrect_field_in_f_expression_1() {
2459 let f = F::new("invalid__field__name");
2461 assert_eq!(f.to_sql(), "\"invalid__field__name\"");
2462 }
2463
2464 #[test]
2465 fn test_incorrect_joined_field_in_f_expression() {
2467 let f = F::new("related__invalid_field");
2469 assert_eq!(f.to_sql(), "\"related__invalid_field\"");
2470 }
2471
2472 #[test]
2473 fn test_incorrect_joined_field_in_f_expression_1() {
2475 let f = F::new("user__profile__missing");
2477 assert_eq!(f.to_sql(), "\"user__profile__missing\"");
2478 }
2479
2480 #[test]
2481 fn test_lookups_subquery() {
2483 let subquery = Subquery::new("SELECT MAX(price) FROM products WHERE available = 1");
2485 assert_eq!(
2486 subquery.to_sql(),
2487 "(SELECT MAX(price) FROM products WHERE available = 1)",
2488 "Expected exact subquery with MAX aggregate, got: {}",
2489 subquery.to_sql()
2490 );
2491 }
2492
2493 #[test]
2494 fn test_lookups_subquery_1() {
2496 let subquery = Subquery::new("SELECT MIN(created_at) FROM events");
2498 assert_eq!(
2499 subquery.to_sql(),
2500 "(SELECT MIN(created_at) FROM events)",
2501 "Expected exact subquery with MIN aggregate, got: {}",
2502 subquery.to_sql()
2503 );
2504 }
2505
2506 #[test]
2507 fn test_mixed_char_date_with_annotate() {
2509 let f1 = F::new("name");
2511 let f2 = F::new("created_date");
2512 assert_eq!(f1.to_sql(), "\"name\"");
2513 assert_eq!(f2.to_sql(), "\"created_date\"");
2514 }
2515
2516 #[test]
2517 fn test_mixed_char_date_with_annotate_1() {
2519 let val_str = Value::String("test".to_string());
2521 let f_date = F::new("birth_date");
2522 assert_eq!(val_str.to_sql(), "'test'");
2523 assert_eq!(f_date.to_sql(), "\"birth_date\"");
2524 }
2525
2526 #[test]
2527 fn test_negated_empty_exists() {
2529 let exists = Exists::new("");
2531 let q = Q::from_raw_sql(exists.to_sql()).not();
2532 assert_eq!(
2533 q.to_sql(),
2534 "NOT (EXISTS())",
2535 "Expected exact negated EXISTS SQL, got: {}",
2536 q.to_sql()
2537 );
2538 }
2539
2540 #[test]
2541 fn test_negated_empty_exists_1() {
2543 let q = Q::new("id", "NOT IN", "SELECT id FROM deleted");
2545 assert_eq!(
2546 q.to_sql(),
2547 "\"id\" NOT IN ('SELECT id FROM deleted')",
2548 "Expected exact NOT IN query, got: {}",
2549 q.to_sql()
2550 );
2551 }
2552
2553 #[test]
2554 fn test_nested_subquery() {
2556 let inner = Subquery::new("SELECT id FROM users WHERE active = 1");
2558 let outer = Subquery::new(format!(
2559 "SELECT * FROM orders WHERE user_id IN {}",
2560 inner.to_sql()
2561 ));
2562 assert_eq!(
2563 outer.to_sql(),
2564 "(SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE active = 1))",
2565 "Expected exact nested subquery, got: {}",
2566 outer.to_sql()
2567 );
2568 }
2569
2570 #[test]
2571 fn test_nested_subquery_1() {
2573 let subquery = Subquery::new(
2575 "SELECT category_id FROM (SELECT * FROM products WHERE price > 100) AS expensive",
2576 );
2577 assert_eq!(
2578 subquery.to_sql(),
2579 "(SELECT category_id FROM (SELECT * FROM products WHERE price > 100) AS expensive)",
2580 "Expected exact nested subquery with alias, got: {}",
2581 subquery.to_sql()
2582 );
2583 }
2584
2585 #[test]
2586 fn test_nested_subquery_join_outer_ref() {
2588 let outer_ref = OuterRef::new("parent.id");
2590 let subquery = Subquery::new(format!(
2591 "SELECT COUNT(*) FROM children WHERE parent_id = {}",
2592 outer_ref.to_sql()
2593 ));
2594 assert_eq!(
2595 subquery.to_sql(),
2596 "(SELECT COUNT(*) FROM children WHERE parent_id = parent.id)",
2597 "Expected exact subquery with OuterRef, got: {}",
2598 subquery.to_sql()
2599 );
2600 }
2601
2602 #[test]
2603 fn test_nested_subquery_join_outer_ref_1() {
2605 let outer_ref = OuterRef::new("order.user_id");
2607 assert_eq!(outer_ref.to_sql(), "order.user_id");
2608 }
2609
2610 #[test]
2611 fn test_nested_subquery_outer_ref_2() {
2613 let outer_ref = OuterRef::new("main.category_id");
2615 assert_eq!(outer_ref.to_sql(), "main.category_id");
2616 }
2617
2618 #[test]
2619 fn test_nested_subquery_outer_ref_2_1() {
2621 let outer_ref = OuterRef::new("outer_table.field");
2623 assert_eq!(outer_ref.to_sql(), "outer_table.field");
2624 }
2625
2626 #[test]
2627 fn test_nested_subquery_outer_ref_with_autofield() {
2629 let outer_ref = OuterRef::new("id");
2631 assert_eq!(outer_ref.to_sql(), "id");
2632 }
2633
2634 #[test]
2635 fn test_nested_subquery_outer_ref_with_autofield_1() {
2637 let outer_ref = OuterRef::new("pk");
2639 assert_eq!(outer_ref.to_sql(), "pk");
2640 }
2641
2642 #[test]
2643 fn test_non_empty_group_by() {
2645 let f = F::new("category");
2647 let agg = Aggregate::count(Some("id"));
2648 assert_eq!(f.to_sql(), "\"category\"");
2649 assert_eq!(agg.to_sql(), "COUNT(id)");
2650 }
2651
2652 #[test]
2653 fn test_non_empty_group_by_1() {
2655 let f1 = F::new("year");
2657 let f2 = F::new("month");
2658 assert_eq!(f1.to_sql(), "\"year\"");
2659 assert_eq!(f2.to_sql(), "\"month\"");
2660 }
2661
2662 #[test]
2663 fn test_object_create_with_aggregate() {
2665 let agg = Aggregate::max("score");
2667 assert_eq!(agg.to_sql(), "MAX(score)");
2668 }
2669
2670 #[test]
2671 fn test_object_create_with_aggregate_1() {
2673 let agg = Aggregate::avg("rating");
2675 assert_eq!(agg.to_sql(), "AVG(rating)");
2676 }
2677
2678 #[test]
2679 fn test_object_create_with_f_expression_in_subquery() {
2681 let f = F::new("price");
2683 let subquery = Subquery::new(format!("SELECT {} FROM products", f.to_sql()));
2684 assert_eq!(
2685 subquery.to_sql(),
2686 "(SELECT \"price\" FROM products)",
2687 "Expected exact subquery with F expression, got: {}",
2688 subquery.to_sql()
2689 );
2690 }
2691
2692 #[test]
2693 fn test_object_create_with_f_expression_in_subquery_1() {
2695 let f = F::new("quantity");
2697 assert_eq!(f.to_sql(), "\"quantity\"");
2698 }
2699
2700 #[test]
2701 fn test_order_by_exists() {
2703 let exists = Exists::new("SELECT 1 FROM related WHERE related.parent_id = main.id");
2705 assert_eq!(
2706 exists.to_sql(),
2707 "EXISTS(SELECT 1 FROM related WHERE related.parent_id = main.id)",
2708 "Expected exact EXISTS with related join, got: {}",
2709 exists.to_sql()
2710 );
2711 }
2712
2713 #[test]
2714 fn test_order_by_exists_1() {
2716 let exists = Exists::new("SELECT 1 FROM tags WHERE tags.item_id = items.id");
2718 assert_eq!(
2719 exists.to_sql(),
2720 "EXISTS(SELECT 1 FROM tags WHERE tags.item_id = items.id)",
2721 "Expected exact EXISTS with correlation, got: {}",
2722 exists.to_sql()
2723 );
2724 }
2725
2726 #[test]
2727 fn test_order_by_multiline_sql() {
2729 let subquery = Subquery::new(
2731 "SELECT id
2732FROM users
2733WHERE active = 1",
2734 );
2735 assert_eq!(
2736 subquery.to_sql(),
2737 "(SELECT id\nFROM users\nWHERE active = 1)",
2738 "Expected exact multiline subquery, got: {}",
2739 subquery.to_sql()
2740 );
2741 }
2742
2743 #[test]
2744 fn test_order_by_multiline_sql_1() {
2746 let subquery = Subquery::new(
2748 "SELECT COUNT(*)
2749FROM orders
2750GROUP BY user_id",
2751 );
2752 assert_eq!(
2753 subquery.to_sql(),
2754 "(SELECT COUNT(*)\nFROM orders\nGROUP BY user_id)",
2755 "Expected exact multiline subquery with GROUP BY, got: {}",
2756 subquery.to_sql()
2757 );
2758 }
2759
2760 #[test]
2761 fn test_order_of_operations() {
2763 let q1 = Q::new("a", "=", "1");
2765 let q2 = Q::new("b", "=", "2");
2766 let q3 = Q::new("c", "=", "3");
2767 let q = q1.and(q2).or(q3);
2768 let sql = q.to_sql();
2769 assert_eq!(
2770 sql, "((\"a\" = 1 AND \"b\" = 2) OR \"c\" = 3)",
2771 "Expected exact order of operations with AND/OR, got: {}",
2772 sql
2773 );
2774 }
2775
2776 #[test]
2777 fn test_order_of_operations_1() {
2779 let q1 = Q::new("x", "=", "1");
2781 let q2 = Q::new("y", "=", "2");
2782 let q = q1.or(q2).not();
2783 assert_eq!(
2784 q.to_sql(),
2785 "NOT ((\"x\" = 1 OR \"y\" = 2))",
2786 "Expected exact NOT with OR operation, got: {}",
2787 q.to_sql()
2788 );
2789 }
2790}
2791
2792#[derive(Debug, Clone, Serialize, Deserialize)]
2794pub struct When {
2795 pub condition: Q,
2797 then: Box<Expression>,
2798}
2799
2800impl When {
2801 pub fn new(condition: Q, then: Expression) -> Self {
2816 Self {
2817 condition,
2818 then: Box::new(then),
2819 }
2820 }
2821
2822 pub fn then(&self) -> &Expression {
2824 &self.then
2825 }
2826
2827 pub fn into_then(self) -> Expression {
2829 *self.then
2830 }
2831
2832 pub fn to_sql(&self) -> String {
2846 format!(
2847 "WHEN {} THEN {}",
2848 self.condition.to_sql(),
2849 self.then.to_sql()
2850 )
2851 }
2852}
2853
2854#[derive(Debug, Clone, Serialize, Deserialize)]
2857pub struct Case {
2858 pub when_clauses: Vec<When>,
2860 default: Option<Box<Expression>>,
2861}
2862
2863impl Case {
2864 pub fn new() -> Self {
2881 Self {
2882 when_clauses: Vec::new(),
2883 default: None,
2884 }
2885 }
2886
2887 pub fn default_value(&self) -> Option<&Expression> {
2889 self.default.as_deref()
2890 }
2891
2892 pub fn into_default(self) -> Option<Expression> {
2894 self.default.map(|b| *b)
2895 }
2896
2897 pub fn when(mut self, when: When) -> Self {
2912 self.when_clauses.push(when);
2913 self
2914 }
2915
2916 pub fn default(mut self, default: Expression) -> Self {
2928 self.default = Some(Box::new(default));
2929 self
2930 }
2931
2932 pub fn to_sql(&self) -> String {
2946 let when_clauses = self
2947 .when_clauses
2948 .iter()
2949 .map(|w| w.to_sql())
2950 .collect::<Vec<_>>()
2951 .join(" ");
2952
2953 let default_clause = self
2954 .default
2955 .as_ref()
2956 .map(|d| format!(" ELSE {}", d.to_sql()))
2957 .unwrap_or_default();
2958
2959 format!("CASE {}{} END", when_clauses, default_clause)
2960 }
2961}
2962
2963impl Default for Case {
2964 fn default() -> Self {
2965 Self::new()
2966 }
2967}
2968
2969#[derive(Debug, Clone, Serialize, Deserialize)]
2971pub enum Expression {
2972 F(F),
2974 Value(Value),
2976 Case(Case),
2978 }
2980
2981impl Expression {
2982 pub fn to_sql(&self) -> String {
2996 match self {
2997 Expression::F(f) => f.to_sql(),
2998 Expression::Value(v) => v.to_sql(),
2999 Expression::Case(c) => c.to_sql(),
3000 }
3001 }
3002}
3003
3004impl From<F> for Expression {
3005 fn from(f: F) -> Self {
3006 Expression::F(f)
3007 }
3008}
3009
3010impl From<Value> for Expression {
3011 fn from(v: Value) -> Self {
3012 Expression::Value(v)
3013 }
3014}
3015
3016impl From<Case> for Expression {
3017 fn from(c: Case) -> Self {
3018 Expression::Case(c)
3019 }
3020}