1use crate::clause::{OrderBy, OrderDirection};
7use sqlmodel_core::Value;
8
9pub use sqlmodel_core::Dialect;
13
14#[derive(Debug, Clone)]
16pub enum Expr {
17 Column {
19 table: Option<String>,
21 name: String,
23 },
24
25 Literal(Value),
27
28 Placeholder(usize),
30
31 Binary {
33 left: Box<Expr>,
34 op: BinaryOp,
35 right: Box<Expr>,
36 },
37
38 Unary { op: UnaryOp, expr: Box<Expr> },
40
41 Function { name: String, args: Vec<Expr> },
43
44 Case {
46 when_clauses: Vec<(Expr, Expr)>,
48 else_clause: Option<Box<Expr>>,
50 },
51
52 In {
54 expr: Box<Expr>,
55 values: Vec<Expr>,
56 negated: bool,
57 },
58
59 Between {
61 expr: Box<Expr>,
62 low: Box<Expr>,
63 high: Box<Expr>,
64 negated: bool,
65 },
66
67 IsNull { expr: Box<Expr>, negated: bool },
69
70 IsDistinctFrom {
72 left: Box<Expr>,
73 right: Box<Expr>,
74 negated: bool,
75 },
76
77 Cast { expr: Box<Expr>, type_name: String },
79
80 Like {
82 expr: Box<Expr>,
83 pattern: String,
84 negated: bool,
85 case_insensitive: bool,
86 },
87
88 Subquery(String),
90
91 Exists {
95 subquery: String,
97 params: Vec<Value>,
99 negated: bool,
101 },
102
103 Raw(String),
105
106 Paren(Box<Expr>),
108
109 CountStar,
111
112 Window {
114 function: Box<Expr>,
116 partition_by: Vec<Expr>,
118 order_by: Vec<OrderBy>,
120 frame: Option<WindowFrame>,
122 },
123
124 JsonExtract {
130 expr: Box<Expr>,
132 path: JsonPath,
134 },
135
136 JsonExtractText {
142 expr: Box<Expr>,
144 path: JsonPath,
146 },
147
148 JsonExtractPath {
153 expr: Box<Expr>,
155 path: Vec<String>,
157 },
158
159 JsonExtractPathText {
165 expr: Box<Expr>,
167 path: Vec<String>,
169 },
170
171 JsonContains {
177 expr: Box<Expr>,
179 other: Box<Expr>,
181 },
182
183 JsonContainedBy {
189 expr: Box<Expr>,
191 other: Box<Expr>,
193 },
194
195 JsonHasKey {
201 expr: Box<Expr>,
203 key: String,
205 },
206
207 JsonHasAnyKey {
213 expr: Box<Expr>,
215 keys: Vec<String>,
217 },
218
219 JsonHasAllKeys {
225 expr: Box<Expr>,
227 keys: Vec<String>,
229 },
230
231 JsonArrayLength {
237 expr: Box<Expr>,
239 },
240
241 JsonTypeof {
247 expr: Box<Expr>,
249 },
250}
251
252#[derive(Debug, Clone)]
254pub enum JsonPath {
255 Key(String),
257 Index(i64),
259}
260
261#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263pub enum BinaryOp {
264 Eq,
267 Ne,
269 Lt,
271 Le,
273 Gt,
275 Ge,
277
278 And,
281 Or,
283
284 Add,
287 Sub,
289 Mul,
291 Div,
293 Mod,
295
296 BitAnd,
299 BitOr,
301 BitXor,
303
304 Concat,
307
308 ArrayContains,
311 ArrayContainedBy,
313 ArrayOverlap,
315}
316
317impl BinaryOp {
318 pub const fn as_str(self) -> &'static str {
320 match self {
321 BinaryOp::Eq => "=",
322 BinaryOp::Ne => "<>",
323 BinaryOp::Lt => "<",
324 BinaryOp::Le => "<=",
325 BinaryOp::Gt => ">",
326 BinaryOp::Ge => ">=",
327 BinaryOp::And => "AND",
328 BinaryOp::Or => "OR",
329 BinaryOp::Add => "+",
330 BinaryOp::Sub => "-",
331 BinaryOp::Mul => "*",
332 BinaryOp::Div => "/",
333 BinaryOp::Mod => "%",
334 BinaryOp::BitAnd => "&",
335 BinaryOp::BitOr => "|",
336 BinaryOp::BitXor => "^",
337 BinaryOp::Concat => "||",
338 BinaryOp::ArrayContains => "@>",
339 BinaryOp::ArrayContainedBy => "<@",
340 BinaryOp::ArrayOverlap => "&&",
341 }
342 }
343
344 pub const fn precedence(self) -> u8 {
346 match self {
347 BinaryOp::Or => 1,
348 BinaryOp::And => 2,
349 BinaryOp::Eq
350 | BinaryOp::Ne
351 | BinaryOp::Lt
352 | BinaryOp::Le
353 | BinaryOp::Gt
354 | BinaryOp::Ge
355 | BinaryOp::ArrayContains
356 | BinaryOp::ArrayContainedBy
357 | BinaryOp::ArrayOverlap => 3,
358 BinaryOp::BitOr => 4,
359 BinaryOp::BitXor => 5,
360 BinaryOp::BitAnd => 6,
361 BinaryOp::Add | BinaryOp::Sub | BinaryOp::Concat => 7,
362 BinaryOp::Mul | BinaryOp::Div | BinaryOp::Mod => 8,
363 }
364 }
365}
366
367#[derive(Debug, Clone, Copy, PartialEq, Eq)]
369pub enum UnaryOp {
370 Not,
371 Neg,
372 BitwiseNot,
373}
374
375impl UnaryOp {
376 pub const fn as_str(&self) -> &'static str {
378 match self {
379 UnaryOp::Not => "NOT",
380 UnaryOp::Neg => "-",
381 UnaryOp::BitwiseNot => "~",
382 }
383 }
384}
385
386#[derive(Debug, Clone)]
390pub struct WindowFrame {
391 pub frame_type: WindowFrameType,
393 pub start: WindowFrameBound,
395 pub end: Option<WindowFrameBound>,
397}
398
399#[derive(Debug, Clone, Copy, PartialEq, Eq)]
401pub enum WindowFrameType {
402 Rows,
404 Range,
406 Groups,
408}
409
410impl WindowFrameType {
411 pub const fn as_str(self) -> &'static str {
413 match self {
414 WindowFrameType::Rows => "ROWS",
415 WindowFrameType::Range => "RANGE",
416 WindowFrameType::Groups => "GROUPS",
417 }
418 }
419}
420
421#[derive(Debug, Clone)]
423pub enum WindowFrameBound {
424 UnboundedPreceding,
426 UnboundedFollowing,
428 CurrentRow,
430 Preceding(u64),
432 Following(u64),
434}
435
436impl WindowFrameBound {
437 pub fn to_sql(&self) -> String {
439 match self {
440 WindowFrameBound::UnboundedPreceding => "UNBOUNDED PRECEDING".to_string(),
441 WindowFrameBound::UnboundedFollowing => "UNBOUNDED FOLLOWING".to_string(),
442 WindowFrameBound::CurrentRow => "CURRENT ROW".to_string(),
443 WindowFrameBound::Preceding(n) => format!("{n} PRECEDING"),
444 WindowFrameBound::Following(n) => format!("{n} FOLLOWING"),
445 }
446 }
447}
448
449impl Expr {
450 pub fn col(name: impl Into<String>) -> Self {
454 Expr::Column {
455 table: None,
456 name: name.into(),
457 }
458 }
459
460 pub fn qualified(table: impl Into<String>, column: impl Into<String>) -> Self {
462 Expr::Column {
463 table: Some(table.into()),
464 name: column.into(),
465 }
466 }
467
468 pub fn lit(value: impl Into<Value>) -> Self {
470 Expr::Literal(value.into())
471 }
472
473 pub fn null() -> Self {
475 Expr::Literal(Value::Null)
476 }
477
478 pub fn raw(sql: impl Into<String>) -> Self {
480 Expr::Raw(sql.into())
481 }
482
483 pub fn placeholder(index: usize) -> Self {
485 Expr::Placeholder(index)
486 }
487
488 pub fn eq(self, other: impl Into<Expr>) -> Self {
492 Expr::Binary {
493 left: Box::new(self),
494 op: BinaryOp::Eq,
495 right: Box::new(other.into()),
496 }
497 }
498
499 pub fn ne(self, other: impl Into<Expr>) -> Self {
501 Expr::Binary {
502 left: Box::new(self),
503 op: BinaryOp::Ne,
504 right: Box::new(other.into()),
505 }
506 }
507
508 pub fn lt(self, other: impl Into<Expr>) -> Self {
510 Expr::Binary {
511 left: Box::new(self),
512 op: BinaryOp::Lt,
513 right: Box::new(other.into()),
514 }
515 }
516
517 pub fn le(self, other: impl Into<Expr>) -> Self {
519 Expr::Binary {
520 left: Box::new(self),
521 op: BinaryOp::Le,
522 right: Box::new(other.into()),
523 }
524 }
525
526 pub fn gt(self, other: impl Into<Expr>) -> Self {
528 Expr::Binary {
529 left: Box::new(self),
530 op: BinaryOp::Gt,
531 right: Box::new(other.into()),
532 }
533 }
534
535 pub fn ge(self, other: impl Into<Expr>) -> Self {
537 Expr::Binary {
538 left: Box::new(self),
539 op: BinaryOp::Ge,
540 right: Box::new(other.into()),
541 }
542 }
543
544 pub fn and(self, other: impl Into<Expr>) -> Self {
548 Expr::Binary {
549 left: Box::new(self),
550 op: BinaryOp::And,
551 right: Box::new(other.into()),
552 }
553 }
554
555 pub fn or(self, other: impl Into<Expr>) -> Self {
557 Expr::Binary {
558 left: Box::new(self),
559 op: BinaryOp::Or,
560 right: Box::new(other.into()),
561 }
562 }
563
564 pub fn not(self) -> Self {
566 Expr::Unary {
567 op: UnaryOp::Not,
568 expr: Box::new(self),
569 }
570 }
571
572 pub fn is_null(self) -> Self {
576 Expr::IsNull {
577 expr: Box::new(self),
578 negated: false,
579 }
580 }
581
582 pub fn is_not_null(self) -> Self {
584 Expr::IsNull {
585 expr: Box::new(self),
586 negated: true,
587 }
588 }
589
590 pub fn is_distinct_from(self, other: impl Into<Expr>) -> Self {
595 Expr::IsDistinctFrom {
596 left: Box::new(self),
597 right: Box::new(other.into()),
598 negated: false,
599 }
600 }
601
602 pub fn is_not_distinct_from(self, other: impl Into<Expr>) -> Self {
607 Expr::IsDistinctFrom {
608 left: Box::new(self),
609 right: Box::new(other.into()),
610 negated: true,
611 }
612 }
613
614 pub fn cast(self, type_name: impl Into<String>) -> Self {
624 Expr::Cast {
625 expr: Box::new(self),
626 type_name: type_name.into(),
627 }
628 }
629
630 pub fn like(self, pattern: impl Into<String>) -> Self {
634 Expr::Like {
635 expr: Box::new(self),
636 pattern: pattern.into(),
637 negated: false,
638 case_insensitive: false,
639 }
640 }
641
642 pub fn not_like(self, pattern: impl Into<String>) -> Self {
644 Expr::Like {
645 expr: Box::new(self),
646 pattern: pattern.into(),
647 negated: true,
648 case_insensitive: false,
649 }
650 }
651
652 pub fn ilike(self, pattern: impl Into<String>) -> Self {
654 Expr::Like {
655 expr: Box::new(self),
656 pattern: pattern.into(),
657 negated: false,
658 case_insensitive: true,
659 }
660 }
661
662 pub fn not_ilike(self, pattern: impl Into<String>) -> Self {
664 Expr::Like {
665 expr: Box::new(self),
666 pattern: pattern.into(),
667 negated: true,
668 case_insensitive: true,
669 }
670 }
671
672 pub fn contains(self, pattern: impl AsRef<str>) -> Self {
680 let pattern = format!("%{}%", pattern.as_ref());
681 Expr::Like {
682 expr: Box::new(self),
683 pattern,
684 negated: false,
685 case_insensitive: false,
686 }
687 }
688
689 pub fn starts_with(self, pattern: impl AsRef<str>) -> Self {
697 let pattern = format!("{}%", pattern.as_ref());
698 Expr::Like {
699 expr: Box::new(self),
700 pattern,
701 negated: false,
702 case_insensitive: false,
703 }
704 }
705
706 pub fn ends_with(self, pattern: impl AsRef<str>) -> Self {
714 let pattern = format!("%{}", pattern.as_ref());
715 Expr::Like {
716 expr: Box::new(self),
717 pattern,
718 negated: false,
719 case_insensitive: false,
720 }
721 }
722
723 pub fn icontains(self, pattern: impl AsRef<str>) -> Self {
725 let pattern = format!("%{}%", pattern.as_ref());
726 Expr::Like {
727 expr: Box::new(self),
728 pattern,
729 negated: false,
730 case_insensitive: true,
731 }
732 }
733
734 pub fn istarts_with(self, pattern: impl AsRef<str>) -> Self {
736 let pattern = format!("{}%", pattern.as_ref());
737 Expr::Like {
738 expr: Box::new(self),
739 pattern,
740 negated: false,
741 case_insensitive: true,
742 }
743 }
744
745 pub fn iends_with(self, pattern: impl AsRef<str>) -> Self {
747 let pattern = format!("%{}", pattern.as_ref());
748 Expr::Like {
749 expr: Box::new(self),
750 pattern,
751 negated: false,
752 case_insensitive: true,
753 }
754 }
755
756 pub fn in_list(self, values: Vec<impl Into<Expr>>) -> Self {
760 if values.is_empty() {
761 return Expr::raw("1 = 0");
762 }
763 Expr::In {
764 expr: Box::new(self),
765 values: values.into_iter().map(Into::into).collect(),
766 negated: false,
767 }
768 }
769
770 pub fn not_in_list(self, values: Vec<impl Into<Expr>>) -> Self {
772 if values.is_empty() {
773 return Expr::raw("1 = 1");
774 }
775 Expr::In {
776 expr: Box::new(self),
777 values: values.into_iter().map(Into::into).collect(),
778 negated: true,
779 }
780 }
781
782 pub fn between(self, low: impl Into<Expr>, high: impl Into<Expr>) -> Self {
786 Expr::Between {
787 expr: Box::new(self),
788 low: Box::new(low.into()),
789 high: Box::new(high.into()),
790 negated: false,
791 }
792 }
793
794 pub fn not_between(self, low: impl Into<Expr>, high: impl Into<Expr>) -> Self {
796 Expr::Between {
797 expr: Box::new(self),
798 low: Box::new(low.into()),
799 high: Box::new(high.into()),
800 negated: true,
801 }
802 }
803
804 pub fn add(self, other: impl Into<Expr>) -> Self {
808 Expr::Binary {
809 left: Box::new(self),
810 op: BinaryOp::Add,
811 right: Box::new(other.into()),
812 }
813 }
814
815 pub fn sub(self, other: impl Into<Expr>) -> Self {
817 Expr::Binary {
818 left: Box::new(self),
819 op: BinaryOp::Sub,
820 right: Box::new(other.into()),
821 }
822 }
823
824 pub fn mul(self, other: impl Into<Expr>) -> Self {
826 Expr::Binary {
827 left: Box::new(self),
828 op: BinaryOp::Mul,
829 right: Box::new(other.into()),
830 }
831 }
832
833 pub fn div(self, other: impl Into<Expr>) -> Self {
835 Expr::Binary {
836 left: Box::new(self),
837 op: BinaryOp::Div,
838 right: Box::new(other.into()),
839 }
840 }
841
842 pub fn modulo(self, other: impl Into<Expr>) -> Self {
844 Expr::Binary {
845 left: Box::new(self),
846 op: BinaryOp::Mod,
847 right: Box::new(other.into()),
848 }
849 }
850
851 pub fn neg(self) -> Self {
853 Expr::Unary {
854 op: UnaryOp::Neg,
855 expr: Box::new(self),
856 }
857 }
858
859 pub fn concat(self, other: impl Into<Expr>) -> Self {
863 Expr::Binary {
864 left: Box::new(self),
865 op: BinaryOp::Concat,
866 right: Box::new(other.into()),
867 }
868 }
869
870 pub fn array_contains(self, other: impl Into<Expr>) -> Self {
874 Expr::Binary {
875 left: Box::new(self),
876 op: BinaryOp::ArrayContains,
877 right: Box::new(other.into()),
878 }
879 }
880
881 pub fn array_contained_by(self, other: impl Into<Expr>) -> Self {
883 Expr::Binary {
884 left: Box::new(self),
885 op: BinaryOp::ArrayContainedBy,
886 right: Box::new(other.into()),
887 }
888 }
889
890 pub fn array_overlap(self, other: impl Into<Expr>) -> Self {
892 Expr::Binary {
893 left: Box::new(self),
894 op: BinaryOp::ArrayOverlap,
895 right: Box::new(other.into()),
896 }
897 }
898
899 pub fn array_any_eq(self, value: impl Into<Expr>) -> Self {
903 let val = value.into();
904 Expr::Binary {
905 left: Box::new(val),
906 op: BinaryOp::Eq,
907 right: Box::new(Expr::Function {
908 name: "ANY".to_string(),
909 args: vec![self],
910 }),
911 }
912 }
913
914 pub fn bit_and(self, other: impl Into<Expr>) -> Self {
918 Expr::Binary {
919 left: Box::new(self),
920 op: BinaryOp::BitAnd,
921 right: Box::new(other.into()),
922 }
923 }
924
925 pub fn bit_or(self, other: impl Into<Expr>) -> Self {
927 Expr::Binary {
928 left: Box::new(self),
929 op: BinaryOp::BitOr,
930 right: Box::new(other.into()),
931 }
932 }
933
934 pub fn bit_xor(self, other: impl Into<Expr>) -> Self {
936 Expr::Binary {
937 left: Box::new(self),
938 op: BinaryOp::BitXor,
939 right: Box::new(other.into()),
940 }
941 }
942
943 pub fn bit_not(self) -> Self {
945 Expr::Unary {
946 op: UnaryOp::BitwiseNot,
947 expr: Box::new(self),
948 }
949 }
950
951 pub fn case() -> CaseBuilder {
963 CaseBuilder {
964 when_clauses: Vec::new(),
965 }
966 }
967
968 pub fn count_star() -> Self {
972 Expr::CountStar
973 }
974
975 pub fn count(self) -> Self {
977 Expr::Function {
978 name: "COUNT".to_string(),
979 args: vec![self],
980 }
981 }
982
983 pub fn sum(self) -> Self {
985 Expr::Function {
986 name: "SUM".to_string(),
987 args: vec![self],
988 }
989 }
990
991 pub fn avg(self) -> Self {
993 Expr::Function {
994 name: "AVG".to_string(),
995 args: vec![self],
996 }
997 }
998
999 pub fn min(self) -> Self {
1001 Expr::Function {
1002 name: "MIN".to_string(),
1003 args: vec![self],
1004 }
1005 }
1006
1007 pub fn max(self) -> Self {
1009 Expr::Function {
1010 name: "MAX".to_string(),
1011 args: vec![self],
1012 }
1013 }
1014
1015 pub fn function(name: impl Into<String>, args: Vec<Expr>) -> Self {
1017 Expr::Function {
1018 name: name.into(),
1019 args,
1020 }
1021 }
1022
1023 pub fn row_number() -> Self {
1028 Expr::Function {
1029 name: "ROW_NUMBER".to_string(),
1030 args: vec![],
1031 }
1032 }
1033
1034 pub fn rank() -> Self {
1037 Expr::Function {
1038 name: "RANK".to_string(),
1039 args: vec![],
1040 }
1041 }
1042
1043 pub fn dense_rank() -> Self {
1046 Expr::Function {
1047 name: "DENSE_RANK".to_string(),
1048 args: vec![],
1049 }
1050 }
1051
1052 pub fn percent_rank() -> Self {
1055 Expr::Function {
1056 name: "PERCENT_RANK".to_string(),
1057 args: vec![],
1058 }
1059 }
1060
1061 pub fn cume_dist() -> Self {
1064 Expr::Function {
1065 name: "CUME_DIST".to_string(),
1066 args: vec![],
1067 }
1068 }
1069
1070 pub fn ntile(n: i64) -> Self {
1073 Expr::Function {
1074 name: "NTILE".to_string(),
1075 args: vec![Expr::Literal(Value::BigInt(n))],
1076 }
1077 }
1078
1079 pub fn lag(self) -> Self {
1082 Expr::Function {
1083 name: "LAG".to_string(),
1084 args: vec![self],
1085 }
1086 }
1087
1088 pub fn lag_offset(self, offset: i64) -> Self {
1091 Expr::Function {
1092 name: "LAG".to_string(),
1093 args: vec![self, Expr::Literal(Value::BigInt(offset))],
1094 }
1095 }
1096
1097 pub fn lag_with_default(self, offset: i64, default: impl Into<Expr>) -> Self {
1100 Expr::Function {
1101 name: "LAG".to_string(),
1102 args: vec![self, Expr::Literal(Value::BigInt(offset)), default.into()],
1103 }
1104 }
1105
1106 pub fn lead(self) -> Self {
1109 Expr::Function {
1110 name: "LEAD".to_string(),
1111 args: vec![self],
1112 }
1113 }
1114
1115 pub fn lead_offset(self, offset: i64) -> Self {
1118 Expr::Function {
1119 name: "LEAD".to_string(),
1120 args: vec![self, Expr::Literal(Value::BigInt(offset))],
1121 }
1122 }
1123
1124 pub fn lead_with_default(self, offset: i64, default: impl Into<Expr>) -> Self {
1127 Expr::Function {
1128 name: "LEAD".to_string(),
1129 args: vec![self, Expr::Literal(Value::BigInt(offset)), default.into()],
1130 }
1131 }
1132
1133 pub fn first_value(self) -> Self {
1136 Expr::Function {
1137 name: "FIRST_VALUE".to_string(),
1138 args: vec![self],
1139 }
1140 }
1141
1142 pub fn last_value(self) -> Self {
1145 Expr::Function {
1146 name: "LAST_VALUE".to_string(),
1147 args: vec![self],
1148 }
1149 }
1150
1151 pub fn nth_value(self, n: i64) -> Self {
1154 Expr::Function {
1155 name: "NTH_VALUE".to_string(),
1156 args: vec![self, Expr::Literal(Value::BigInt(n))],
1157 }
1158 }
1159
1160 pub fn over(self) -> WindowBuilder {
1180 WindowBuilder {
1181 function: self,
1182 partition_by: Vec::new(),
1183 order_by: Vec::new(),
1184 frame: None,
1185 }
1186 }
1187
1188 pub fn coalesce(args: Vec<impl Into<Expr>>) -> Self {
1198 Expr::Function {
1199 name: "COALESCE".to_string(),
1200 args: args.into_iter().map(Into::into).collect(),
1201 }
1202 }
1203
1204 pub fn nullif(expr1: impl Into<Expr>, expr2: impl Into<Expr>) -> Self {
1212 Expr::Function {
1213 name: "NULLIF".to_string(),
1214 args: vec![expr1.into(), expr2.into()],
1215 }
1216 }
1217
1218 pub fn ifnull(expr1: impl Into<Expr>, expr2: impl Into<Expr>) -> Self {
1222 Expr::Function {
1224 name: "COALESCE".to_string(),
1225 args: vec![expr1.into(), expr2.into()],
1226 }
1227 }
1228
1229 pub fn upper(self) -> Self {
1233 Expr::Function {
1234 name: "UPPER".to_string(),
1235 args: vec![self],
1236 }
1237 }
1238
1239 pub fn lower(self) -> Self {
1241 Expr::Function {
1242 name: "LOWER".to_string(),
1243 args: vec![self],
1244 }
1245 }
1246
1247 pub fn length(self) -> Self {
1249 Expr::Function {
1250 name: "LENGTH".to_string(),
1251 args: vec![self],
1252 }
1253 }
1254
1255 pub fn trim(self) -> Self {
1257 Expr::Function {
1258 name: "TRIM".to_string(),
1259 args: vec![self],
1260 }
1261 }
1262
1263 pub fn ltrim(self) -> Self {
1265 Expr::Function {
1266 name: "LTRIM".to_string(),
1267 args: vec![self],
1268 }
1269 }
1270
1271 pub fn rtrim(self) -> Self {
1273 Expr::Function {
1274 name: "RTRIM".to_string(),
1275 args: vec![self],
1276 }
1277 }
1278
1279 pub fn substr(self, start: impl Into<Expr>, length: Option<impl Into<Expr>>) -> Self {
1285 let mut args = vec![self, start.into()];
1286 if let Some(len) = length {
1287 args.push(len.into());
1288 }
1289 Expr::Function {
1290 name: "SUBSTR".to_string(),
1291 args,
1292 }
1293 }
1294
1295 pub fn replace(self, from: impl Into<Expr>, to: impl Into<Expr>) -> Self {
1297 Expr::Function {
1298 name: "REPLACE".to_string(),
1299 args: vec![self, from.into(), to.into()],
1300 }
1301 }
1302
1303 pub fn abs(self) -> Self {
1307 Expr::Function {
1308 name: "ABS".to_string(),
1309 args: vec![self],
1310 }
1311 }
1312
1313 pub fn round(self, decimals: impl Into<Expr>) -> Self {
1315 Expr::Function {
1316 name: "ROUND".to_string(),
1317 args: vec![self, decimals.into()],
1318 }
1319 }
1320
1321 pub fn floor(self) -> Self {
1323 Expr::Function {
1324 name: "FLOOR".to_string(),
1325 args: vec![self],
1326 }
1327 }
1328
1329 pub fn ceil(self) -> Self {
1331 Expr::Function {
1332 name: "CEIL".to_string(),
1333 args: vec![self],
1334 }
1335 }
1336
1337 pub fn asc(self) -> OrderBy {
1341 OrderBy {
1342 expr: self,
1343 direction: OrderDirection::Asc,
1344 nulls: None,
1345 }
1346 }
1347
1348 pub fn desc(self) -> OrderBy {
1350 OrderBy {
1351 expr: self,
1352 direction: OrderDirection::Desc,
1353 nulls: None,
1354 }
1355 }
1356
1357 pub fn paren(self) -> Self {
1361 Expr::Paren(Box::new(self))
1362 }
1363
1364 pub fn subquery(sql: impl Into<String>) -> Self {
1366 Expr::Subquery(sql.into())
1367 }
1368
1369 pub fn exists(subquery_sql: impl Into<String>, params: Vec<Value>) -> Self {
1386 Expr::Exists {
1387 subquery: subquery_sql.into(),
1388 params,
1389 negated: false,
1390 }
1391 }
1392
1393 pub fn not_exists(subquery_sql: impl Into<String>, params: Vec<Value>) -> Self {
1408 Expr::Exists {
1409 subquery: subquery_sql.into(),
1410 params,
1411 negated: true,
1412 }
1413 }
1414
1415 pub fn json_get(self, key: impl Into<String>) -> Self {
1431 Expr::JsonExtract {
1432 expr: Box::new(self),
1433 path: JsonPath::Key(key.into()),
1434 }
1435 }
1436
1437 pub fn json_get_index(self, index: i64) -> Self {
1450 Expr::JsonExtract {
1451 expr: Box::new(self),
1452 path: JsonPath::Index(index),
1453 }
1454 }
1455
1456 pub fn json_get_text(self, key: impl Into<String>) -> Self {
1469 Expr::JsonExtractText {
1470 expr: Box::new(self),
1471 path: JsonPath::Key(key.into()),
1472 }
1473 }
1474
1475 pub fn json_get_text_index(self, index: i64) -> Self {
1483 Expr::JsonExtractText {
1484 expr: Box::new(self),
1485 path: JsonPath::Index(index),
1486 }
1487 }
1488
1489 pub fn json_path(self, path: &[&str]) -> Self {
1502 Expr::JsonExtractPath {
1503 expr: Box::new(self),
1504 path: path.iter().map(|s| (*s).to_string()).collect(),
1505 }
1506 }
1507
1508 pub fn json_path_text(self, path: &[&str]) -> Self {
1521 Expr::JsonExtractPathText {
1522 expr: Box::new(self),
1523 path: path.iter().map(|s| (*s).to_string()).collect(),
1524 }
1525 }
1526
1527 pub fn json_contains(self, other: impl Into<Expr>) -> Self {
1539 Expr::JsonContains {
1540 expr: Box::new(self),
1541 other: Box::new(other.into()),
1542 }
1543 }
1544
1545 pub fn json_contained_by(self, other: impl Into<Expr>) -> Self {
1556 Expr::JsonContainedBy {
1557 expr: Box::new(self),
1558 other: Box::new(other.into()),
1559 }
1560 }
1561
1562 pub fn json_has_key(self, key: impl Into<String>) -> Self {
1575 Expr::JsonHasKey {
1576 expr: Box::new(self),
1577 key: key.into(),
1578 }
1579 }
1580
1581 pub fn json_has_any_key(self, keys: &[&str]) -> Self {
1593 Expr::JsonHasAnyKey {
1594 expr: Box::new(self),
1595 keys: keys.iter().map(|s| (*s).to_string()).collect(),
1596 }
1597 }
1598
1599 pub fn json_has_all_keys(self, keys: &[&str]) -> Self {
1611 Expr::JsonHasAllKeys {
1612 expr: Box::new(self),
1613 keys: keys.iter().map(|s| (*s).to_string()).collect(),
1614 }
1615 }
1616
1617 pub fn json_array_length(self) -> Self {
1629 Expr::JsonArrayLength {
1630 expr: Box::new(self),
1631 }
1632 }
1633
1634 pub fn json_typeof(self) -> Self {
1646 Expr::JsonTypeof {
1647 expr: Box::new(self),
1648 }
1649 }
1650
1651 pub fn build(&self, params: &mut Vec<Value>, offset: usize) -> String {
1655 self.build_with_dialect(Dialect::Postgres, params, offset)
1656 }
1657
1658 pub fn build_with_dialect(
1660 &self,
1661 dialect: Dialect,
1662 params: &mut Vec<Value>,
1663 offset: usize,
1664 ) -> String {
1665 match self {
1666 Expr::Column { table, name } => {
1667 if let Some(t) = table {
1668 format!(
1669 "{}.{}",
1670 dialect.quote_identifier(t),
1671 dialect.quote_identifier(name)
1672 )
1673 } else {
1674 dialect.quote_identifier(name)
1675 }
1676 }
1677
1678 Expr::Literal(value) => {
1679 if matches!(value, Value::Default) {
1680 "DEFAULT".to_string()
1681 } else {
1682 params.push(value.clone());
1683 dialect.placeholder(offset + params.len())
1684 }
1685 }
1686
1687 Expr::Placeholder(idx) => dialect.placeholder(*idx),
1688
1689 Expr::Binary { left, op, right } => {
1690 let left_sql = left.build_with_dialect(dialect, params, offset);
1691 let right_sql = right.build_with_dialect(dialect, params, offset);
1692 if *op == BinaryOp::Concat && dialect == Dialect::Mysql {
1693 format!("CONCAT({left_sql}, {right_sql})")
1694 } else {
1695 format!("{left_sql} {} {right_sql}", op.as_str())
1696 }
1697 }
1698
1699 Expr::Unary { op, expr } => {
1700 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1701 match op {
1702 UnaryOp::Not => format!("NOT {expr_sql}"),
1703 UnaryOp::Neg => format!("-{expr_sql}"),
1704 UnaryOp::BitwiseNot => format!("~{expr_sql}"),
1705 }
1706 }
1707
1708 Expr::Function { name, args } => {
1709 let arg_sqls: Vec<_> = args
1710 .iter()
1711 .map(|a| a.build_with_dialect(dialect, params, offset))
1712 .collect();
1713 format!("{name}({})", arg_sqls.join(", "))
1714 }
1715
1716 Expr::Case {
1717 when_clauses,
1718 else_clause,
1719 } => {
1720 let mut sql = String::from("CASE");
1721 for (condition, result) in when_clauses {
1722 let cond_sql = condition.build_with_dialect(dialect, params, offset);
1723 let result_sql = result.build_with_dialect(dialect, params, offset);
1724 sql.push_str(&format!(" WHEN {cond_sql} THEN {result_sql}"));
1725 }
1726 if let Some(else_expr) = else_clause {
1727 let else_sql = else_expr.build_with_dialect(dialect, params, offset);
1728 sql.push_str(&format!(" ELSE {else_sql}"));
1729 }
1730 sql.push_str(" END");
1731 sql
1732 }
1733
1734 Expr::In {
1735 expr,
1736 values,
1737 negated,
1738 } => {
1739 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1740 let value_sqls: Vec<_> = values
1741 .iter()
1742 .map(|v| v.build_with_dialect(dialect, params, offset))
1743 .collect();
1744 let not_str = if *negated { "NOT " } else { "" };
1745 format!("{expr_sql} {not_str}IN ({})", value_sqls.join(", "))
1746 }
1747
1748 Expr::Between {
1749 expr,
1750 low,
1751 high,
1752 negated,
1753 } => {
1754 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1755 let low_sql = low.build_with_dialect(dialect, params, offset);
1756 let high_sql = high.build_with_dialect(dialect, params, offset);
1757 let not_str = if *negated { "NOT " } else { "" };
1758 format!("{expr_sql} {not_str}BETWEEN {low_sql} AND {high_sql}")
1759 }
1760
1761 Expr::IsNull { expr, negated } => {
1762 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1763 let not_str = if *negated { " NOT" } else { "" };
1764 format!("{expr_sql} IS{not_str} NULL")
1765 }
1766
1767 Expr::IsDistinctFrom {
1768 left,
1769 right,
1770 negated,
1771 } => {
1772 let left_sql = left.build_with_dialect(dialect, params, offset);
1773 let right_sql = right.build_with_dialect(dialect, params, offset);
1774 let not_str = if *negated { " NOT" } else { "" };
1775 format!("{left_sql} IS{not_str} DISTINCT FROM {right_sql}")
1777 }
1778
1779 Expr::Cast { expr, type_name } => {
1780 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1781 format!("CAST({expr_sql} AS {type_name})")
1782 }
1783
1784 Expr::Like {
1785 expr,
1786 pattern,
1787 negated,
1788 case_insensitive,
1789 } => {
1790 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1791 params.push(Value::Text(pattern.clone()));
1792 let param = dialect.placeholder(offset + params.len());
1793 let not_str = if *negated { "NOT " } else { "" };
1794 let op = if *case_insensitive && dialect.supports_ilike() {
1795 "ILIKE"
1796 } else if *case_insensitive {
1797 return format!("LOWER({expr_sql}) {not_str}LIKE LOWER({param})");
1799 } else {
1800 "LIKE"
1801 };
1802 format!("{expr_sql} {not_str}{op} {param}")
1803 }
1804
1805 Expr::Subquery(sql) => format!("({sql})"),
1806
1807 Expr::Exists {
1808 subquery,
1809 params: subquery_params,
1810 negated,
1811 } => {
1812 let start_idx = offset + params.len();
1816 params.extend(subquery_params.iter().cloned());
1817
1818 let adjusted_subquery = if subquery_params.is_empty() {
1822 subquery.clone()
1823 } else {
1824 adjust_placeholder_indices(subquery, start_idx, dialect)
1826 };
1827
1828 let not_str = if *negated { "NOT " } else { "" };
1829 format!("{not_str}EXISTS ({adjusted_subquery})")
1830 }
1831
1832 Expr::Raw(sql) => sql.clone(),
1833
1834 Expr::Paren(expr) => {
1835 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1836 format!("({expr_sql})")
1837 }
1838
1839 Expr::CountStar => "COUNT(*)".to_string(),
1840
1841 Expr::Window {
1842 function,
1843 partition_by,
1844 order_by,
1845 frame,
1846 } => {
1847 let func_sql = function.build_with_dialect(dialect, params, offset);
1848 let mut over_parts: Vec<String> = Vec::new();
1849
1850 if !partition_by.is_empty() {
1852 let partition_sqls: Vec<_> = partition_by
1853 .iter()
1854 .map(|e| e.build_with_dialect(dialect, params, offset))
1855 .collect();
1856 over_parts.push(format!("PARTITION BY {}", partition_sqls.join(", ")));
1857 }
1858
1859 if !order_by.is_empty() {
1861 let order_sqls: Vec<_> = order_by
1862 .iter()
1863 .map(|o| {
1864 let expr_sql = o.expr.build_with_dialect(dialect, params, offset);
1865 let dir = match o.direction {
1866 OrderDirection::Asc => "ASC",
1867 OrderDirection::Desc => "DESC",
1868 };
1869 let nulls = match o.nulls {
1870 Some(crate::clause::NullsOrder::First) => " NULLS FIRST",
1871 Some(crate::clause::NullsOrder::Last) => " NULLS LAST",
1872 None => "",
1873 };
1874 format!("{expr_sql} {dir}{nulls}")
1875 })
1876 .collect();
1877 over_parts.push(format!("ORDER BY {}", order_sqls.join(", ")));
1878 }
1879
1880 if let Some(f) = frame {
1882 let frame_sql = if let Some(end) = &f.end {
1883 format!(
1884 "{} BETWEEN {} AND {}",
1885 f.frame_type.as_str(),
1886 f.start.to_sql(),
1887 end.to_sql()
1888 )
1889 } else {
1890 format!("{} {}", f.frame_type.as_str(), f.start.to_sql())
1891 };
1892 over_parts.push(frame_sql);
1893 }
1894
1895 if over_parts.is_empty() {
1896 format!("{func_sql} OVER ()")
1897 } else {
1898 format!("{func_sql} OVER ({})", over_parts.join(" "))
1899 }
1900 }
1901
1902 Expr::JsonExtract { expr, path } => {
1904 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1905 match dialect {
1906 Dialect::Postgres => match path {
1907 JsonPath::Key(key) => format!("{expr_sql} -> '{key}'"),
1908 JsonPath::Index(idx) => format!("{expr_sql} -> {idx}"),
1909 },
1910 Dialect::Mysql => {
1911 let json_path = match path {
1912 JsonPath::Key(key) => format!("$.{key}"),
1913 JsonPath::Index(idx) => format!("$[{idx}]"),
1914 };
1915 format!("JSON_EXTRACT({expr_sql}, '{json_path}')")
1916 }
1917 Dialect::Sqlite => {
1918 let json_path = match path {
1919 JsonPath::Key(key) => format!("$.{key}"),
1920 JsonPath::Index(idx) => format!("$[{idx}]"),
1921 };
1922 format!("json_extract({expr_sql}, '{json_path}')")
1923 }
1924 }
1925 }
1926
1927 Expr::JsonExtractText { expr, path } => {
1928 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1929 match dialect {
1930 Dialect::Postgres => match path {
1931 JsonPath::Key(key) => format!("{expr_sql} ->> '{key}'"),
1932 JsonPath::Index(idx) => format!("{expr_sql} ->> {idx}"),
1933 },
1934 Dialect::Mysql => {
1935 let json_path = match path {
1936 JsonPath::Key(key) => format!("$.{key}"),
1937 JsonPath::Index(idx) => format!("$[{idx}]"),
1938 };
1939 format!("JSON_UNQUOTE(JSON_EXTRACT({expr_sql}, '{json_path}'))")
1940 }
1941 Dialect::Sqlite => {
1942 let json_path = match path {
1944 JsonPath::Key(key) => format!("$.{key}"),
1945 JsonPath::Index(idx) => format!("$[{idx}]"),
1946 };
1947 format!("json_extract({expr_sql}, '{json_path}')")
1948 }
1949 }
1950 }
1951
1952 Expr::JsonExtractPath { expr, path } => {
1953 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1954 match dialect {
1955 Dialect::Postgres => {
1956 let path_array = path.join(", ");
1957 format!("{expr_sql} #> '{{{path_array}}}'")
1958 }
1959 Dialect::Mysql | Dialect::Sqlite => {
1960 let json_path = format!("$.{}", path.join("."));
1961 let func = if dialect == Dialect::Mysql {
1962 "JSON_EXTRACT"
1963 } else {
1964 "json_extract"
1965 };
1966 format!("{func}({expr_sql}, '{json_path}')")
1967 }
1968 }
1969 }
1970
1971 Expr::JsonExtractPathText { expr, path } => {
1972 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1973 match dialect {
1974 Dialect::Postgres => {
1975 let path_array = path.join(", ");
1976 format!("{expr_sql} #>> '{{{path_array}}}'")
1977 }
1978 Dialect::Mysql => {
1979 let json_path = format!("$.{}", path.join("."));
1980 format!("JSON_UNQUOTE(JSON_EXTRACT({expr_sql}, '{json_path}'))")
1981 }
1982 Dialect::Sqlite => {
1983 let json_path = format!("$.{}", path.join("."));
1984 format!("json_extract({expr_sql}, '{json_path}')")
1985 }
1986 }
1987 }
1988
1989 Expr::JsonContains { expr, other } => {
1990 let expr_sql = expr.build_with_dialect(dialect, params, offset);
1991 let other_sql = other.build_with_dialect(dialect, params, offset);
1992 match dialect {
1993 Dialect::Postgres => format!("{expr_sql} @> {other_sql}"),
1994 Dialect::Mysql => format!("JSON_CONTAINS({expr_sql}, {other_sql})"),
1995 Dialect::Sqlite => {
1996 format!(
1998 "/* JSON containment not supported in SQLite */ ({expr_sql} = {other_sql})"
1999 )
2000 }
2001 }
2002 }
2003
2004 Expr::JsonContainedBy { expr, other } => {
2005 let expr_sql = expr.build_with_dialect(dialect, params, offset);
2006 let other_sql = other.build_with_dialect(dialect, params, offset);
2007 match dialect {
2008 Dialect::Postgres => format!("{expr_sql} <@ {other_sql}"),
2009 Dialect::Mysql => format!("JSON_CONTAINS({other_sql}, {expr_sql})"),
2010 Dialect::Sqlite => {
2011 format!(
2012 "/* JSON contained-by not supported in SQLite */ ({expr_sql} = {other_sql})"
2013 )
2014 }
2015 }
2016 }
2017
2018 Expr::JsonHasKey { expr, key } => {
2019 let expr_sql = expr.build_with_dialect(dialect, params, offset);
2020 match dialect {
2021 Dialect::Postgres => format!("{expr_sql} ? '{key}'"),
2022 Dialect::Mysql => format!("JSON_CONTAINS_PATH({expr_sql}, 'one', '$.{key}')"),
2023 Dialect::Sqlite => format!("json_type({expr_sql}, '$.{key}') IS NOT NULL"),
2024 }
2025 }
2026
2027 Expr::JsonHasAnyKey { expr, keys } => {
2028 let expr_sql = expr.build_with_dialect(dialect, params, offset);
2029 match dialect {
2030 Dialect::Postgres => {
2031 let keys_array = keys
2032 .iter()
2033 .map(|k| format!("'{k}'"))
2034 .collect::<Vec<_>>()
2035 .join(", ");
2036 format!("{expr_sql} ?| array[{keys_array}]")
2037 }
2038 Dialect::Mysql => {
2039 let paths = keys
2040 .iter()
2041 .map(|k| format!("'$.{k}'"))
2042 .collect::<Vec<_>>()
2043 .join(", ");
2044 format!("JSON_CONTAINS_PATH({expr_sql}, 'one', {paths})")
2045 }
2046 Dialect::Sqlite => {
2047 let checks = keys
2048 .iter()
2049 .map(|k| format!("json_type({expr_sql}, '$.{k}') IS NOT NULL"))
2050 .collect::<Vec<_>>()
2051 .join(" OR ");
2052 format!("({checks})")
2053 }
2054 }
2055 }
2056
2057 Expr::JsonHasAllKeys { expr, keys } => {
2058 let expr_sql = expr.build_with_dialect(dialect, params, offset);
2059 match dialect {
2060 Dialect::Postgres => {
2061 let keys_array = keys
2062 .iter()
2063 .map(|k| format!("'{k}'"))
2064 .collect::<Vec<_>>()
2065 .join(", ");
2066 format!("{expr_sql} ?& array[{keys_array}]")
2067 }
2068 Dialect::Mysql => {
2069 let paths = keys
2070 .iter()
2071 .map(|k| format!("'$.{k}'"))
2072 .collect::<Vec<_>>()
2073 .join(", ");
2074 format!("JSON_CONTAINS_PATH({expr_sql}, 'all', {paths})")
2075 }
2076 Dialect::Sqlite => {
2077 let checks = keys
2078 .iter()
2079 .map(|k| format!("json_type({expr_sql}, '$.{k}') IS NOT NULL"))
2080 .collect::<Vec<_>>()
2081 .join(" AND ");
2082 format!("({checks})")
2083 }
2084 }
2085 }
2086
2087 Expr::JsonArrayLength { expr } => {
2088 let expr_sql = expr.build_with_dialect(dialect, params, offset);
2089 match dialect {
2090 Dialect::Postgres => format!("jsonb_array_length({expr_sql})"),
2091 Dialect::Mysql => format!("JSON_LENGTH({expr_sql})"),
2092 Dialect::Sqlite => format!("json_array_length({expr_sql})"),
2093 }
2094 }
2095
2096 Expr::JsonTypeof { expr } => {
2097 let expr_sql = expr.build_with_dialect(dialect, params, offset);
2098 match dialect {
2099 Dialect::Postgres => format!("jsonb_typeof({expr_sql})"),
2100 Dialect::Mysql => format!("JSON_TYPE({expr_sql})"),
2101 Dialect::Sqlite => format!("json_type({expr_sql})"),
2102 }
2103 }
2104 }
2105 }
2106}
2107
2108#[derive(Debug, Clone)]
2112pub struct CaseBuilder {
2113 when_clauses: Vec<(Expr, Expr)>,
2114}
2115
2116impl CaseBuilder {
2117 pub fn when(mut self, condition: impl Into<Expr>, result: impl Into<Expr>) -> Self {
2119 self.when_clauses.push((condition.into(), result.into()));
2120 self
2121 }
2122
2123 pub fn otherwise(self, else_result: impl Into<Expr>) -> Expr {
2125 Expr::Case {
2126 when_clauses: self.when_clauses,
2127 else_clause: Some(Box::new(else_result.into())),
2128 }
2129 }
2130
2131 pub fn end(self) -> Expr {
2133 Expr::Case {
2134 when_clauses: self.when_clauses,
2135 else_clause: None,
2136 }
2137 }
2138}
2139
2140#[derive(Debug, Clone)]
2144pub struct WindowBuilder {
2145 function: Expr,
2146 partition_by: Vec<Expr>,
2147 order_by: Vec<OrderBy>,
2148 frame: Option<WindowFrame>,
2149}
2150
2151impl WindowBuilder {
2152 pub fn partition_by(mut self, expr: impl Into<Expr>) -> Self {
2156 self.partition_by.push(expr.into());
2157 self
2158 }
2159
2160 pub fn partition_by_many(mut self, exprs: Vec<impl Into<Expr>>) -> Self {
2162 self.partition_by.extend(exprs.into_iter().map(Into::into));
2163 self
2164 }
2165
2166 pub fn order_by(mut self, order: OrderBy) -> Self {
2170 self.order_by.push(order);
2171 self
2172 }
2173
2174 pub fn order_by_asc(mut self, expr: impl Into<Expr>) -> Self {
2176 self.order_by.push(OrderBy {
2177 expr: expr.into(),
2178 direction: OrderDirection::Asc,
2179 nulls: None,
2180 });
2181 self
2182 }
2183
2184 pub fn order_by_desc(mut self, expr: impl Into<Expr>) -> Self {
2186 self.order_by.push(OrderBy {
2187 expr: expr.into(),
2188 direction: OrderDirection::Desc,
2189 nulls: None,
2190 });
2191 self
2192 }
2193
2194 pub fn rows_between(mut self, start: WindowFrameBound, end: WindowFrameBound) -> Self {
2202 self.frame = Some(WindowFrame {
2203 frame_type: WindowFrameType::Rows,
2204 start,
2205 end: Some(end),
2206 });
2207 self
2208 }
2209
2210 pub fn rows(mut self, start: WindowFrameBound) -> Self {
2218 self.frame = Some(WindowFrame {
2219 frame_type: WindowFrameType::Rows,
2220 start,
2221 end: None,
2222 });
2223 self
2224 }
2225
2226 pub fn range_between(mut self, start: WindowFrameBound, end: WindowFrameBound) -> Self {
2234 self.frame = Some(WindowFrame {
2235 frame_type: WindowFrameType::Range,
2236 start,
2237 end: Some(end),
2238 });
2239 self
2240 }
2241
2242 pub fn range(mut self, start: WindowFrameBound) -> Self {
2244 self.frame = Some(WindowFrame {
2245 frame_type: WindowFrameType::Range,
2246 start,
2247 end: None,
2248 });
2249 self
2250 }
2251
2252 pub fn groups_between(mut self, start: WindowFrameBound, end: WindowFrameBound) -> Self {
2254 self.frame = Some(WindowFrame {
2255 frame_type: WindowFrameType::Groups,
2256 start,
2257 end: Some(end),
2258 });
2259 self
2260 }
2261
2262 pub fn build(self) -> Expr {
2264 Expr::Window {
2265 function: Box::new(self.function),
2266 partition_by: self.partition_by,
2267 order_by: self.order_by,
2268 frame: self.frame,
2269 }
2270 }
2271}
2272
2273impl From<Value> for Expr {
2275 fn from(v: Value) -> Self {
2276 Expr::Literal(v)
2277 }
2278}
2279
2280impl From<&str> for Expr {
2281 fn from(s: &str) -> Self {
2282 Expr::Literal(Value::Text(s.to_string()))
2283 }
2284}
2285
2286impl From<String> for Expr {
2287 fn from(s: String) -> Self {
2288 Expr::Literal(Value::Text(s))
2289 }
2290}
2291
2292impl From<i32> for Expr {
2293 fn from(n: i32) -> Self {
2294 Expr::Literal(Value::Int(n))
2295 }
2296}
2297
2298impl From<i64> for Expr {
2299 fn from(n: i64) -> Self {
2300 Expr::Literal(Value::BigInt(n))
2301 }
2302}
2303
2304impl From<bool> for Expr {
2305 fn from(b: bool) -> Self {
2306 Expr::Literal(Value::Bool(b))
2307 }
2308}
2309
2310impl From<f64> for Expr {
2311 fn from(n: f64) -> Self {
2312 Expr::Literal(Value::Double(n))
2313 }
2314}
2315
2316impl From<f32> for Expr {
2317 fn from(n: f32) -> Self {
2318 Expr::Literal(Value::Float(n))
2319 }
2320}
2321
2322fn adjust_placeholder_indices(sql: &str, offset: usize, dialect: Dialect) -> String {
2329 if offset == 0 {
2330 return sql.to_string();
2331 }
2332
2333 match dialect {
2334 Dialect::Postgres => {
2335 let mut result = String::with_capacity(sql.len() + 20);
2337 let mut chars = sql.chars().peekable();
2338
2339 while let Some(c) = chars.next() {
2340 if c == '$' {
2341 let mut num_str = String::new();
2343 while let Some(&d) = chars.peek() {
2344 if d.is_ascii_digit() {
2345 num_str.push(chars.next().unwrap());
2346 } else {
2347 break;
2348 }
2349 }
2350 if let Ok(n) = num_str.parse::<usize>() {
2351 result.push_str(&format!("${}", n + offset));
2352 } else {
2353 result.push('$');
2354 result.push_str(&num_str);
2355 }
2356 } else {
2357 result.push(c);
2358 }
2359 }
2360 result
2361 }
2362 Dialect::Sqlite => {
2363 let mut result = String::with_capacity(sql.len() + 20);
2365 let mut chars = sql.chars().peekable();
2366
2367 while let Some(c) = chars.next() {
2368 if c == '?' {
2369 let mut num_str = String::new();
2371 while let Some(&d) = chars.peek() {
2372 if d.is_ascii_digit() {
2373 num_str.push(chars.next().unwrap());
2374 } else {
2375 break;
2376 }
2377 }
2378 if let Ok(n) = num_str.parse::<usize>() {
2379 result.push_str(&format!("?{}", n + offset));
2380 } else {
2381 result.push('?');
2382 result.push_str(&num_str);
2383 }
2384 } else {
2385 result.push(c);
2386 }
2387 }
2388 result
2389 }
2390 Dialect::Mysql => {
2391 sql.to_string()
2393 }
2394 }
2395}
2396
2397#[cfg(test)]
2400mod tests {
2401 use super::*;
2402
2403 #[test]
2406 fn test_column_simple() {
2407 let expr = Expr::col("name");
2408 let mut params = Vec::new();
2409 let sql = expr.build(&mut params, 0);
2410 assert_eq!(sql, "\"name\"");
2411 assert!(params.is_empty());
2412 }
2413
2414 #[test]
2415 fn test_column_qualified() {
2416 let expr = Expr::qualified("users", "name");
2417 let mut params = Vec::new();
2418 let sql = expr.build(&mut params, 0);
2419 assert_eq!(sql, "\"users\".\"name\"");
2420 assert!(params.is_empty());
2421 }
2422
2423 #[test]
2426 fn test_literal_int() {
2427 let expr = Expr::lit(42);
2428 let mut params = Vec::new();
2429 let sql = expr.build(&mut params, 0);
2430 assert_eq!(sql, "$1");
2431 assert_eq!(params.len(), 1);
2432 assert_eq!(params[0], Value::Int(42));
2433 }
2434
2435 #[test]
2436 fn test_literal_string() {
2437 let expr = Expr::lit("hello");
2438 let mut params = Vec::new();
2439 let sql = expr.build(&mut params, 0);
2440 assert_eq!(sql, "$1");
2441 assert_eq!(params[0], Value::Text("hello".to_string()));
2442 }
2443
2444 #[test]
2445 fn test_literal_null() {
2446 let expr = Expr::null();
2447 let mut params = Vec::new();
2448 let sql = expr.build(&mut params, 0);
2449 assert_eq!(sql, "$1");
2450 assert_eq!(params[0], Value::Null);
2451 }
2452
2453 #[test]
2456 fn test_eq() {
2457 let expr = Expr::col("age").eq(18);
2458 let mut params = Vec::new();
2459 let sql = expr.build(&mut params, 0);
2460 assert_eq!(sql, "\"age\" = $1");
2461 assert_eq!(params[0], Value::Int(18));
2462 }
2463
2464 #[test]
2465 fn test_ne() {
2466 let expr = Expr::col("status").ne("deleted");
2467 let mut params = Vec::new();
2468 let sql = expr.build(&mut params, 0);
2469 assert_eq!(sql, "\"status\" <> $1");
2470 }
2471
2472 #[test]
2473 fn test_lt_le_gt_ge() {
2474 let mut params = Vec::new();
2475
2476 let lt = Expr::col("age").lt(18).build(&mut params, 0);
2477 assert_eq!(lt, "\"age\" < $1");
2478
2479 params.clear();
2480 let le = Expr::col("age").le(18).build(&mut params, 0);
2481 assert_eq!(le, "\"age\" <= $1");
2482
2483 params.clear();
2484 let gt = Expr::col("age").gt(18).build(&mut params, 0);
2485 assert_eq!(gt, "\"age\" > $1");
2486
2487 params.clear();
2488 let ge = Expr::col("age").ge(18).build(&mut params, 0);
2489 assert_eq!(ge, "\"age\" >= $1");
2490 }
2491
2492 #[test]
2495 fn test_and() {
2496 let expr = Expr::col("a").eq(1).and(Expr::col("b").eq(2));
2497 let mut params = Vec::new();
2498 let sql = expr.build(&mut params, 0);
2499 assert_eq!(sql, "\"a\" = $1 AND \"b\" = $2");
2500 }
2501
2502 #[test]
2503 fn test_or() {
2504 let expr = Expr::col("a").eq(1).or(Expr::col("b").eq(2));
2505 let mut params = Vec::new();
2506 let sql = expr.build(&mut params, 0);
2507 assert_eq!(sql, "\"a\" = $1 OR \"b\" = $2");
2508 }
2509
2510 #[test]
2511 fn test_not() {
2512 let expr = Expr::col("active").not();
2513 let mut params = Vec::new();
2514 let sql = expr.build(&mut params, 0);
2515 assert_eq!(sql, "NOT \"active\"");
2516 }
2517
2518 #[test]
2521 fn test_is_null() {
2522 let expr = Expr::col("deleted_at").is_null();
2523 let mut params = Vec::new();
2524 let sql = expr.build(&mut params, 0);
2525 assert_eq!(sql, "\"deleted_at\" IS NULL");
2526 }
2527
2528 #[test]
2529 fn test_is_not_null() {
2530 let expr = Expr::col("name").is_not_null();
2531 let mut params = Vec::new();
2532 let sql = expr.build(&mut params, 0);
2533 assert_eq!(sql, "\"name\" IS NOT NULL");
2534 }
2535
2536 #[test]
2539 fn test_like() {
2540 let expr = Expr::col("name").like("%john%");
2541 let mut params = Vec::new();
2542 let sql = expr.build(&mut params, 0);
2543 assert_eq!(sql, "\"name\" LIKE $1");
2544 assert_eq!(params[0], Value::Text("%john%".to_string()));
2545 }
2546
2547 #[test]
2548 fn test_not_like() {
2549 let expr = Expr::col("name").not_like("%test%");
2550 let mut params = Vec::new();
2551 let sql = expr.build(&mut params, 0);
2552 assert_eq!(sql, "\"name\" NOT LIKE $1");
2553 }
2554
2555 #[test]
2556 fn test_ilike_postgres() {
2557 let expr = Expr::col("name").ilike("%JOHN%");
2558 let mut params = Vec::new();
2559 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
2560 assert_eq!(sql, "\"name\" ILIKE $1");
2561 }
2562
2563 #[test]
2564 fn test_ilike_fallback_sqlite() {
2565 let expr = Expr::col("name").ilike("%JOHN%");
2566 let mut params = Vec::new();
2567 let sql = expr.build_with_dialect(Dialect::Sqlite, &mut params, 0);
2568 assert_eq!(sql, "LOWER(\"name\") LIKE LOWER(?1)");
2569 }
2570
2571 #[test]
2574 fn test_in_list() {
2575 let expr = Expr::col("status").in_list(vec![1, 2, 3]);
2576 let mut params = Vec::new();
2577 let sql = expr.build(&mut params, 0);
2578 assert_eq!(sql, "\"status\" IN ($1, $2, $3)");
2579 assert_eq!(params.len(), 3);
2580 }
2581
2582 #[test]
2583 fn test_not_in_list() {
2584 let expr = Expr::col("status").not_in_list(vec![4, 5]);
2585 let mut params = Vec::new();
2586 let sql = expr.build(&mut params, 0);
2587 assert_eq!(sql, "\"status\" NOT IN ($1, $2)");
2588 }
2589
2590 #[test]
2593 fn test_between() {
2594 let expr = Expr::col("age").between(18, 65);
2595 let mut params = Vec::new();
2596 let sql = expr.build(&mut params, 0);
2597 assert_eq!(sql, "\"age\" BETWEEN $1 AND $2");
2598 assert_eq!(params[0], Value::Int(18));
2599 assert_eq!(params[1], Value::Int(65));
2600 }
2601
2602 #[test]
2603 fn test_not_between() {
2604 let expr = Expr::col("age").not_between(0, 17);
2605 let mut params = Vec::new();
2606 let sql = expr.build(&mut params, 0);
2607 assert_eq!(sql, "\"age\" NOT BETWEEN $1 AND $2");
2608 }
2609
2610 #[test]
2613 fn test_arithmetic() {
2614 let mut params = Vec::new();
2615
2616 let add = Expr::col("a").add(Expr::col("b")).build(&mut params, 0);
2617 assert_eq!(add, "\"a\" + \"b\"");
2618
2619 let sub = Expr::col("a").sub(Expr::col("b")).build(&mut params, 0);
2620 assert_eq!(sub, "\"a\" - \"b\"");
2621
2622 let mul = Expr::col("a").mul(Expr::col("b")).build(&mut params, 0);
2623 assert_eq!(mul, "\"a\" * \"b\"");
2624
2625 let div = Expr::col("a").div(Expr::col("b")).build(&mut params, 0);
2626 assert_eq!(div, "\"a\" / \"b\"");
2627
2628 let modulo = Expr::col("a").modulo(Expr::col("b")).build(&mut params, 0);
2629 assert_eq!(modulo, "\"a\" % \"b\"");
2630 }
2631
2632 #[test]
2633 fn test_neg() {
2634 let expr = Expr::col("balance").neg();
2635 let mut params = Vec::new();
2636 let sql = expr.build(&mut params, 0);
2637 assert_eq!(sql, "-\"balance\"");
2638 }
2639
2640 #[test]
2643 fn test_bitwise() {
2644 let mut params = Vec::new();
2645
2646 let bit_and = Expr::col("flags")
2647 .bit_and(Expr::lit(0xFF))
2648 .build(&mut params, 0);
2649 assert_eq!(bit_and, "\"flags\" & $1");
2650
2651 params.clear();
2652 let or_sql = Expr::col("flags")
2653 .bit_or(Expr::lit(0x01))
2654 .build(&mut params, 0);
2655 assert_eq!(or_sql, "\"flags\" | $1");
2656
2657 params.clear();
2658 let xor_sql = Expr::col("flags")
2659 .bit_xor(Expr::lit(0x0F))
2660 .build(&mut params, 0);
2661 assert_eq!(xor_sql, "\"flags\" ^ $1");
2662
2663 let bit_not = Expr::col("flags").bit_not().build(&mut params, 0);
2664 assert_eq!(bit_not, "~\"flags\"");
2665 }
2666
2667 #[test]
2670 fn test_case_simple() {
2671 let expr = Expr::case()
2672 .when(Expr::col("status").eq("active"), "Yes")
2673 .when(Expr::col("status").eq("pending"), "Maybe")
2674 .otherwise("No");
2675
2676 let mut params = Vec::new();
2677 let sql = expr.build(&mut params, 0);
2678 assert_eq!(
2679 sql,
2680 "CASE WHEN \"status\" = $1 THEN $2 WHEN \"status\" = $3 THEN $4 ELSE $5 END"
2681 );
2682 assert_eq!(params.len(), 5);
2683 }
2684
2685 #[test]
2686 fn test_case_without_else() {
2687 let expr = Expr::case().when(Expr::col("age").gt(18), "adult").end();
2688
2689 let mut params = Vec::new();
2690 let sql = expr.build(&mut params, 0);
2691 assert_eq!(sql, "CASE WHEN \"age\" > $1 THEN $2 END");
2692 }
2693
2694 #[test]
2697 fn test_count_star() {
2698 let expr = Expr::count_star();
2699 let mut params = Vec::new();
2700 let sql = expr.build(&mut params, 0);
2701 assert_eq!(sql, "COUNT(*)");
2702 }
2703
2704 #[test]
2705 fn test_count() {
2706 let expr = Expr::col("id").count();
2707 let mut params = Vec::new();
2708 let sql = expr.build(&mut params, 0);
2709 assert_eq!(sql, "COUNT(\"id\")");
2710 }
2711
2712 #[test]
2713 fn test_aggregates() {
2714 let mut params = Vec::new();
2715
2716 let sum = Expr::col("amount").sum().build(&mut params, 0);
2717 assert_eq!(sum, "SUM(\"amount\")");
2718
2719 let avg = Expr::col("price").avg().build(&mut params, 0);
2720 assert_eq!(avg, "AVG(\"price\")");
2721
2722 let min = Expr::col("age").min().build(&mut params, 0);
2723 assert_eq!(min, "MIN(\"age\")");
2724
2725 let max = Expr::col("score").max().build(&mut params, 0);
2726 assert_eq!(max, "MAX(\"score\")");
2727 }
2728
2729 #[test]
2732 fn test_function() {
2733 let expr = Expr::function("UPPER", vec![Expr::col("name")]);
2734 let mut params = Vec::new();
2735 let sql = expr.build(&mut params, 0);
2736 assert_eq!(sql, "UPPER(\"name\")");
2737 }
2738
2739 #[test]
2740 fn test_function_multiple_args() {
2741 let expr = Expr::function("COALESCE", vec![Expr::col("name"), Expr::lit("Unknown")]);
2742 let mut params = Vec::new();
2743 let sql = expr.build(&mut params, 0);
2744 assert_eq!(sql, "COALESCE(\"name\", $1)");
2745 }
2746
2747 #[test]
2750 fn test_order_asc() {
2751 let order = Expr::col("name").asc();
2752 let mut params = Vec::new();
2753 let sql = order.build(Dialect::Postgres, &mut params, 0);
2754 assert_eq!(sql, "\"name\" ASC");
2755 }
2756
2757 #[test]
2758 fn test_order_desc() {
2759 let order = Expr::col("created_at").desc();
2760 let mut params = Vec::new();
2761 let sql = order.build(Dialect::Postgres, &mut params, 0);
2762 assert_eq!(sql, "\"created_at\" DESC");
2763 }
2764
2765 #[test]
2766 fn test_order_nulls() {
2767 let order_first = Expr::col("name").asc().nulls_first();
2768 let mut params = Vec::new();
2769 let sql = order_first.build(Dialect::Postgres, &mut params, 0);
2770 assert_eq!(sql, "\"name\" ASC NULLS FIRST");
2771
2772 let order_last = Expr::col("name").desc().nulls_last();
2773 let sql = order_last.build(Dialect::Postgres, &mut params, 0);
2774 assert_eq!(sql, "\"name\" DESC NULLS LAST");
2775 }
2776
2777 #[test]
2780 fn test_dialect_postgres() {
2781 let expr = Expr::col("id").eq(1);
2782 let mut params = Vec::new();
2783 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
2784 assert_eq!(sql, "\"id\" = $1");
2785 }
2786
2787 #[test]
2788 fn test_dialect_sqlite() {
2789 let expr = Expr::col("id").eq(1);
2790 let mut params = Vec::new();
2791 let sql = expr.build_with_dialect(Dialect::Sqlite, &mut params, 0);
2792 assert_eq!(sql, "\"id\" = ?1");
2793 }
2794
2795 #[test]
2796 fn test_dialect_mysql() {
2797 let expr = Expr::col("id").eq(1);
2798 let mut params = Vec::new();
2799 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
2800 assert_eq!(sql, "`id` = ?");
2801 }
2802
2803 #[test]
2806 fn test_complex_nested() {
2807 let expr = Expr::col("age")
2809 .gt(18)
2810 .and(Expr::col("status").eq("active"))
2811 .paren()
2812 .or(Expr::col("is_admin").eq(true));
2813
2814 let mut params = Vec::new();
2815 let sql = expr.build(&mut params, 0);
2816 assert_eq!(
2817 sql,
2818 "(\"age\" > $1 AND \"status\" = $2) OR \"is_admin\" = $3"
2819 );
2820 }
2821
2822 #[test]
2823 fn test_parameter_offset() {
2824 let expr = Expr::col("name").eq("test");
2825 let mut params = Vec::new();
2826 let sql = expr.build(&mut params, 5);
2827 assert_eq!(sql, "\"name\" = $6");
2828 }
2829
2830 #[test]
2833 fn test_concat() {
2834 let expr = Expr::col("first_name")
2835 .concat(" ")
2836 .concat(Expr::col("last_name"));
2837 let mut params = Vec::new();
2838 let sql = expr.build(&mut params, 0);
2839 assert_eq!(sql, "\"first_name\" || $1 || \"last_name\"");
2840 }
2841
2842 #[test]
2845 fn test_placeholder() {
2846 let expr = Expr::col("id").eq(Expr::placeholder(1));
2847 let mut params = Vec::new();
2848 let sql = expr.build(&mut params, 0);
2849 assert_eq!(sql, "\"id\" = $1");
2850 assert!(params.is_empty()); }
2852
2853 #[test]
2856 fn test_subquery() {
2857 let expr = Expr::col("dept_id").in_list(vec![Expr::subquery(
2858 "SELECT id FROM departments WHERE active = true",
2859 )]);
2860 let mut params = Vec::new();
2861 let sql = expr.build(&mut params, 0);
2862 assert_eq!(
2863 sql,
2864 "\"dept_id\" IN ((SELECT id FROM departments WHERE active = true))"
2865 );
2866 }
2867
2868 #[test]
2871 fn test_raw() {
2872 let expr = Expr::raw("NOW()");
2873 let mut params = Vec::new();
2874 let sql = expr.build(&mut params, 0);
2875 assert_eq!(sql, "NOW()");
2876 }
2877
2878 #[test]
2881 fn test_precedence() {
2882 assert!(BinaryOp::Mul.precedence() > BinaryOp::Add.precedence());
2883 assert!(BinaryOp::And.precedence() > BinaryOp::Or.precedence());
2884 assert!(BinaryOp::Eq.precedence() > BinaryOp::And.precedence());
2885 }
2886
2887 #[test]
2890 fn test_quote_identifier_escapes_postgres() {
2891 assert_eq!(Dialect::Postgres.quote_identifier("simple"), "\"simple\"");
2893 assert_eq!(
2894 Dialect::Postgres.quote_identifier("with\"quote"),
2895 "\"with\"\"quote\""
2896 );
2897 assert_eq!(
2898 Dialect::Postgres.quote_identifier("multi\"\"quotes"),
2899 "\"multi\"\"\"\"quotes\""
2900 );
2901 }
2902
2903 #[test]
2904 fn test_quote_identifier_escapes_sqlite() {
2905 assert_eq!(Dialect::Sqlite.quote_identifier("simple"), "\"simple\"");
2907 assert_eq!(
2908 Dialect::Sqlite.quote_identifier("with\"quote"),
2909 "\"with\"\"quote\""
2910 );
2911 }
2912
2913 #[test]
2914 fn test_quote_identifier_escapes_mysql() {
2915 assert_eq!(Dialect::Mysql.quote_identifier("simple"), "`simple`");
2917 assert_eq!(
2918 Dialect::Mysql.quote_identifier("with`backtick"),
2919 "`with``backtick`"
2920 );
2921 assert_eq!(
2922 Dialect::Mysql.quote_identifier("multi``ticks"),
2923 "`multi````ticks`"
2924 );
2925 }
2926
2927 #[test]
2930 fn test_window_row_number_empty_over() {
2931 let expr = Expr::row_number().over().build();
2932 let mut params = Vec::new();
2933 let sql = expr.build(&mut params, 0);
2934 assert_eq!(sql, "ROW_NUMBER() OVER ()");
2935 }
2936
2937 #[test]
2938 fn test_window_row_number_order_by() {
2939 let expr = Expr::row_number()
2940 .over()
2941 .order_by_desc(Expr::col("created_at"))
2942 .build();
2943 let mut params = Vec::new();
2944 let sql = expr.build(&mut params, 0);
2945 assert_eq!(sql, "ROW_NUMBER() OVER (ORDER BY \"created_at\" DESC)");
2946 }
2947
2948 #[test]
2949 fn test_window_partition_by() {
2950 let expr = Expr::row_number()
2951 .over()
2952 .partition_by(Expr::col("department"))
2953 .order_by_asc(Expr::col("hire_date"))
2954 .build();
2955 let mut params = Vec::new();
2956 let sql = expr.build(&mut params, 0);
2957 assert_eq!(
2958 sql,
2959 "ROW_NUMBER() OVER (PARTITION BY \"department\" ORDER BY \"hire_date\" ASC)"
2960 );
2961 }
2962
2963 #[test]
2964 fn test_window_multiple_partition_by() {
2965 let expr = Expr::rank()
2966 .over()
2967 .partition_by(Expr::col("region"))
2968 .partition_by(Expr::col("product"))
2969 .order_by_desc(Expr::col("sales"))
2970 .build();
2971 let mut params = Vec::new();
2972 let sql = expr.build(&mut params, 0);
2973 assert_eq!(
2974 sql,
2975 "RANK() OVER (PARTITION BY \"region\", \"product\" ORDER BY \"sales\" DESC)"
2976 );
2977 }
2978
2979 #[test]
2980 fn test_window_dense_rank() {
2981 let expr = Expr::dense_rank()
2982 .over()
2983 .order_by_asc(Expr::col("score"))
2984 .build();
2985 let mut params = Vec::new();
2986 let sql = expr.build(&mut params, 0);
2987 assert_eq!(sql, "DENSE_RANK() OVER (ORDER BY \"score\" ASC)");
2988 }
2989
2990 #[test]
2991 fn test_window_ntile() {
2992 let expr = Expr::ntile(4)
2993 .over()
2994 .order_by_asc(Expr::col("salary"))
2995 .build();
2996 let mut params = Vec::new();
2997 let sql = expr.build(&mut params, 0);
2998 assert_eq!(sql, "NTILE($1) OVER (ORDER BY \"salary\" ASC)");
2999 assert_eq!(params[0], Value::BigInt(4));
3000 }
3001
3002 #[test]
3003 fn test_window_lag() {
3004 let expr = Expr::col("price")
3005 .lag()
3006 .over()
3007 .order_by_asc(Expr::col("date"))
3008 .build();
3009 let mut params = Vec::new();
3010 let sql = expr.build(&mut params, 0);
3011 assert_eq!(sql, "LAG(\"price\") OVER (ORDER BY \"date\" ASC)");
3012 }
3013
3014 #[test]
3015 fn test_window_lag_with_offset() {
3016 let expr = Expr::col("price")
3017 .lag_offset(3)
3018 .over()
3019 .order_by_asc(Expr::col("date"))
3020 .build();
3021 let mut params = Vec::new();
3022 let sql = expr.build(&mut params, 0);
3023 assert_eq!(sql, "LAG(\"price\", $1) OVER (ORDER BY \"date\" ASC)");
3024 assert_eq!(params[0], Value::BigInt(3));
3025 }
3026
3027 #[test]
3028 fn test_window_lead_with_default() {
3029 let expr = Expr::col("price")
3030 .lead_with_default(1, 0)
3031 .over()
3032 .order_by_asc(Expr::col("date"))
3033 .build();
3034 let mut params = Vec::new();
3035 let sql = expr.build(&mut params, 0);
3036 assert_eq!(sql, "LEAD(\"price\", $1, $2) OVER (ORDER BY \"date\" ASC)");
3037 assert_eq!(params[0], Value::BigInt(1));
3038 assert_eq!(params[1], Value::Int(0));
3039 }
3040
3041 #[test]
3042 fn test_window_first_value() {
3043 let expr = Expr::col("salary")
3044 .first_value()
3045 .over()
3046 .partition_by(Expr::col("department"))
3047 .order_by_desc(Expr::col("salary"))
3048 .build();
3049 let mut params = Vec::new();
3050 let sql = expr.build(&mut params, 0);
3051 assert_eq!(
3052 sql,
3053 "FIRST_VALUE(\"salary\") OVER (PARTITION BY \"department\" ORDER BY \"salary\" DESC)"
3054 );
3055 }
3056
3057 #[test]
3058 fn test_window_last_value() {
3059 let expr = Expr::col("amount")
3060 .last_value()
3061 .over()
3062 .order_by_asc(Expr::col("created_at"))
3063 .build();
3064 let mut params = Vec::new();
3065 let sql = expr.build(&mut params, 0);
3066 assert_eq!(
3067 sql,
3068 "LAST_VALUE(\"amount\") OVER (ORDER BY \"created_at\" ASC)"
3069 );
3070 }
3071
3072 #[test]
3073 fn test_window_nth_value() {
3074 let expr = Expr::col("score")
3075 .nth_value(3)
3076 .over()
3077 .order_by_desc(Expr::col("score"))
3078 .build();
3079 let mut params = Vec::new();
3080 let sql = expr.build(&mut params, 0);
3081 assert_eq!(
3082 sql,
3083 "NTH_VALUE(\"score\", $1) OVER (ORDER BY \"score\" DESC)"
3084 );
3085 assert_eq!(params[0], Value::BigInt(3));
3086 }
3087
3088 #[test]
3089 fn test_window_aggregate_sum() {
3090 let expr = Expr::col("amount")
3091 .sum()
3092 .over()
3093 .partition_by(Expr::col("customer_id"))
3094 .build();
3095 let mut params = Vec::new();
3096 let sql = expr.build(&mut params, 0);
3097 assert_eq!(sql, "SUM(\"amount\") OVER (PARTITION BY \"customer_id\")");
3098 }
3099
3100 #[test]
3101 fn test_window_aggregate_avg_running() {
3102 let expr = Expr::col("price")
3103 .avg()
3104 .over()
3105 .order_by_asc(Expr::col("date"))
3106 .rows_between(
3107 WindowFrameBound::UnboundedPreceding,
3108 WindowFrameBound::CurrentRow,
3109 )
3110 .build();
3111 let mut params = Vec::new();
3112 let sql = expr.build(&mut params, 0);
3113 assert_eq!(
3114 sql,
3115 "AVG(\"price\") OVER (ORDER BY \"date\" ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)"
3116 );
3117 }
3118
3119 #[test]
3120 fn test_window_frame_rows_preceding() {
3121 let expr = Expr::col("value")
3122 .sum()
3123 .over()
3124 .order_by_asc(Expr::col("idx"))
3125 .rows_between(WindowFrameBound::Preceding(2), WindowFrameBound::CurrentRow)
3126 .build();
3127 let mut params = Vec::new();
3128 let sql = expr.build(&mut params, 0);
3129 assert_eq!(
3130 sql,
3131 "SUM(\"value\") OVER (ORDER BY \"idx\" ASC ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)"
3132 );
3133 }
3134
3135 #[test]
3136 fn test_window_frame_rows_following() {
3137 let expr = Expr::col("value")
3138 .avg()
3139 .over()
3140 .order_by_asc(Expr::col("idx"))
3141 .rows_between(WindowFrameBound::CurrentRow, WindowFrameBound::Following(3))
3142 .build();
3143 let mut params = Vec::new();
3144 let sql = expr.build(&mut params, 0);
3145 assert_eq!(
3146 sql,
3147 "AVG(\"value\") OVER (ORDER BY \"idx\" ASC ROWS BETWEEN CURRENT ROW AND 3 FOLLOWING)"
3148 );
3149 }
3150
3151 #[test]
3152 fn test_window_frame_range_unbounded() {
3153 let expr = Expr::col("total")
3154 .sum()
3155 .over()
3156 .partition_by(Expr::col("category"))
3157 .order_by_asc(Expr::col("date"))
3158 .range_between(
3159 WindowFrameBound::UnboundedPreceding,
3160 WindowFrameBound::UnboundedFollowing,
3161 )
3162 .build();
3163 let mut params = Vec::new();
3164 let sql = expr.build(&mut params, 0);
3165 assert_eq!(
3166 sql,
3167 "SUM(\"total\") OVER (PARTITION BY \"category\" ORDER BY \"date\" ASC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)"
3168 );
3169 }
3170
3171 #[test]
3172 fn test_window_frame_rows_single_bound() {
3173 let expr = Expr::col("value")
3174 .sum()
3175 .over()
3176 .order_by_asc(Expr::col("idx"))
3177 .rows(WindowFrameBound::UnboundedPreceding)
3178 .build();
3179 let mut params = Vec::new();
3180 let sql = expr.build(&mut params, 0);
3181 assert_eq!(
3182 sql,
3183 "SUM(\"value\") OVER (ORDER BY \"idx\" ASC ROWS UNBOUNDED PRECEDING)"
3184 );
3185 }
3186
3187 #[test]
3188 fn test_window_percent_rank() {
3189 let expr = Expr::percent_rank()
3190 .over()
3191 .order_by_asc(Expr::col("score"))
3192 .build();
3193 let mut params = Vec::new();
3194 let sql = expr.build(&mut params, 0);
3195 assert_eq!(sql, "PERCENT_RANK() OVER (ORDER BY \"score\" ASC)");
3196 }
3197
3198 #[test]
3199 fn test_window_cume_dist() {
3200 let expr = Expr::cume_dist()
3201 .over()
3202 .partition_by(Expr::col("group_id"))
3203 .order_by_asc(Expr::col("value"))
3204 .build();
3205 let mut params = Vec::new();
3206 let sql = expr.build(&mut params, 0);
3207 assert_eq!(
3208 sql,
3209 "CUME_DIST() OVER (PARTITION BY \"group_id\" ORDER BY \"value\" ASC)"
3210 );
3211 }
3212
3213 #[test]
3214 fn test_window_frame_groups() {
3215 let expr = Expr::col("amount")
3216 .sum()
3217 .over()
3218 .order_by_asc(Expr::col("group_rank"))
3219 .groups_between(
3220 WindowFrameBound::Preceding(1),
3221 WindowFrameBound::Following(1),
3222 )
3223 .build();
3224 let mut params = Vec::new();
3225 let sql = expr.build(&mut params, 0);
3226 assert_eq!(
3227 sql,
3228 "SUM(\"amount\") OVER (ORDER BY \"group_rank\" ASC GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING)"
3229 );
3230 }
3231
3232 #[test]
3235 fn test_exists_basic() {
3236 let expr = Expr::exists(
3238 "SELECT 1 FROM orders WHERE orders.customer_id = customers.id",
3239 vec![],
3240 );
3241 let mut params = Vec::new();
3242 let sql = expr.build(&mut params, 0);
3243 assert_eq!(
3244 sql,
3245 "EXISTS (SELECT 1 FROM orders WHERE orders.customer_id = customers.id)"
3246 );
3247 assert!(params.is_empty());
3248 }
3249
3250 #[test]
3251 fn test_not_exists() {
3252 let expr = Expr::not_exists(
3254 "SELECT 1 FROM orders WHERE orders.customer_id = customers.id",
3255 vec![],
3256 );
3257 let mut params = Vec::new();
3258 let sql = expr.build(&mut params, 0);
3259 assert_eq!(
3260 sql,
3261 "NOT EXISTS (SELECT 1 FROM orders WHERE orders.customer_id = customers.id)"
3262 );
3263 assert!(params.is_empty());
3264 }
3265
3266 #[test]
3267 fn test_exists_with_params() {
3268 let expr = Expr::exists(
3270 "SELECT 1 FROM orders WHERE status = $1",
3271 vec![Value::Text("active".to_string())],
3272 );
3273 let mut params = Vec::new();
3274 let sql = expr.build(&mut params, 0);
3275 assert_eq!(sql, "EXISTS (SELECT 1 FROM orders WHERE status = $1)");
3276 assert_eq!(params.len(), 1);
3277 assert_eq!(params[0], Value::Text("active".to_string()));
3278 }
3279
3280 #[test]
3281 fn test_exists_with_params_offset() {
3282 let expr = Expr::exists(
3284 "SELECT 1 FROM orders WHERE status = $1 AND type = $2",
3285 vec![
3286 Value::Text("active".to_string()),
3287 Value::Text("online".to_string()),
3288 ],
3289 );
3290 let mut params = Vec::new();
3291 let sql = expr.build(&mut params, 3);
3293 assert_eq!(
3294 sql,
3295 "EXISTS (SELECT 1 FROM orders WHERE status = $4 AND type = $5)"
3296 );
3297 assert_eq!(params.len(), 2);
3298 }
3299
3300 #[test]
3301 fn test_exists_in_where_clause() {
3302 let exists_expr = Expr::exists("SELECT 1 FROM orders o WHERE o.customer_id = c.id", vec![]);
3304 let expr = Expr::col("active").eq(true).and(exists_expr);
3305 let mut params = Vec::new();
3306 let sql = expr.build(&mut params, 0);
3307 assert_eq!(
3308 sql,
3309 "\"active\" = $1 AND EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id)"
3310 );
3311 assert_eq!(params[0], Value::Bool(true));
3312 }
3313
3314 #[test]
3315 fn test_exists_sqlite_dialect() {
3316 let expr = Expr::exists(
3317 "SELECT 1 FROM orders WHERE status = ?1",
3318 vec![Value::Text("active".to_string())],
3319 );
3320 let mut params = Vec::new();
3321 let sql = expr.build_with_dialect(Dialect::Sqlite, &mut params, 0);
3322 assert_eq!(sql, "EXISTS (SELECT 1 FROM orders WHERE status = ?1)");
3323 assert_eq!(params.len(), 1);
3324 }
3325
3326 #[test]
3327 fn test_exists_sqlite_with_offset() {
3328 let expr = Expr::exists(
3329 "SELECT 1 FROM orders WHERE status = ?1",
3330 vec![Value::Text("active".to_string())],
3331 );
3332 let mut params = Vec::new();
3333 let sql = expr.build_with_dialect(Dialect::Sqlite, &mut params, 2);
3334 assert_eq!(sql, "EXISTS (SELECT 1 FROM orders WHERE status = ?3)");
3335 assert_eq!(params.len(), 1);
3336 }
3337
3338 #[test]
3339 fn test_exists_mysql_dialect() {
3340 let expr = Expr::exists(
3342 "SELECT 1 FROM orders WHERE status = ?",
3343 vec![Value::Text("active".to_string())],
3344 );
3345 let mut params = Vec::new();
3346 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
3347 assert_eq!(sql, "EXISTS (SELECT 1 FROM orders WHERE status = ?)");
3348 assert_eq!(params.len(), 1);
3349 }
3350
3351 #[test]
3352 fn test_not_exists_with_offset() {
3353 let expr = Expr::not_exists(
3354 "SELECT 1 FROM orders WHERE status = $1",
3355 vec![Value::Text("pending".to_string())],
3356 );
3357 let mut params = Vec::new();
3358 let sql = expr.build(&mut params, 5);
3359 assert_eq!(sql, "NOT EXISTS (SELECT 1 FROM orders WHERE status = $6)");
3360 assert_eq!(params.len(), 1);
3361 }
3362
3363 #[test]
3366 fn test_adjust_placeholder_indices_postgres() {
3367 let sql = "SELECT * FROM t WHERE a = $1 AND b = $2";
3368 let adjusted = super::adjust_placeholder_indices(sql, 3, Dialect::Postgres);
3369 assert_eq!(adjusted, "SELECT * FROM t WHERE a = $4 AND b = $5");
3370 }
3371
3372 #[test]
3373 fn test_adjust_placeholder_indices_sqlite() {
3374 let sql = "SELECT * FROM t WHERE a = ?1 AND b = ?2";
3375 let adjusted = super::adjust_placeholder_indices(sql, 3, Dialect::Sqlite);
3376 assert_eq!(adjusted, "SELECT * FROM t WHERE a = ?4 AND b = ?5");
3377 }
3378
3379 #[test]
3380 fn test_adjust_placeholder_indices_zero_offset() {
3381 let sql = "SELECT * FROM t WHERE a = $1";
3382 let adjusted = super::adjust_placeholder_indices(sql, 0, Dialect::Postgres);
3383 assert_eq!(adjusted, sql);
3384 }
3385
3386 #[test]
3387 fn test_adjust_placeholder_indices_mysql() {
3388 let sql = "SELECT * FROM t WHERE a = ? AND b = ?";
3390 let adjusted = super::adjust_placeholder_indices(sql, 3, Dialect::Mysql);
3391 assert_eq!(adjusted, sql);
3392 }
3393
3394 #[test]
3397 fn test_json_get_key_postgres() {
3398 let expr = Expr::col("data").json_get("name");
3399 let mut params = Vec::new();
3400 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3401 assert_eq!(sql, "\"data\" -> 'name'");
3402 assert!(params.is_empty());
3403 }
3404
3405 #[test]
3406 fn test_json_get_key_mysql() {
3407 let expr = Expr::col("data").json_get("name");
3408 let mut params = Vec::new();
3409 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
3410 assert_eq!(sql, "JSON_EXTRACT(`data`, '$.name')");
3411 assert!(params.is_empty());
3412 }
3413
3414 #[test]
3415 fn test_json_get_key_sqlite() {
3416 let expr = Expr::col("data").json_get("name");
3417 let mut params = Vec::new();
3418 let sql = expr.build_with_dialect(Dialect::Sqlite, &mut params, 0);
3419 assert_eq!(sql, "json_extract(\"data\", '$.name')");
3420 assert!(params.is_empty());
3421 }
3422
3423 #[test]
3424 fn test_json_get_index_postgres() {
3425 let expr = Expr::col("items").json_get_index(0);
3426 let mut params = Vec::new();
3427 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3428 assert_eq!(sql, "\"items\" -> 0");
3429 }
3430
3431 #[test]
3432 fn test_json_get_index_mysql() {
3433 let expr = Expr::col("items").json_get_index(0);
3434 let mut params = Vec::new();
3435 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
3436 assert_eq!(sql, "JSON_EXTRACT(`items`, '$[0]')");
3437 }
3438
3439 #[test]
3440 fn test_json_get_text_postgres() {
3441 let expr = Expr::col("data").json_get_text("name");
3442 let mut params = Vec::new();
3443 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3444 assert_eq!(sql, "\"data\" ->> 'name'");
3445 }
3446
3447 #[test]
3448 fn test_json_get_text_mysql() {
3449 let expr = Expr::col("data").json_get_text("name");
3450 let mut params = Vec::new();
3451 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
3452 assert_eq!(sql, "JSON_UNQUOTE(JSON_EXTRACT(`data`, '$.name'))");
3453 }
3454
3455 #[test]
3456 fn test_json_path_postgres() {
3457 let expr = Expr::col("data").json_path(&["address", "city"]);
3458 let mut params = Vec::new();
3459 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3460 assert_eq!(sql, "\"data\" #> '{address, city}'");
3461 }
3462
3463 #[test]
3464 fn test_json_path_mysql() {
3465 let expr = Expr::col("data").json_path(&["address", "city"]);
3466 let mut params = Vec::new();
3467 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
3468 assert_eq!(sql, "JSON_EXTRACT(`data`, '$.address.city')");
3469 }
3470
3471 #[test]
3472 fn test_json_path_text_postgres() {
3473 let expr = Expr::col("data").json_path_text(&["address", "city"]);
3474 let mut params = Vec::new();
3475 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3476 assert_eq!(sql, "\"data\" #>> '{address, city}'");
3477 }
3478
3479 #[test]
3480 fn test_json_contains_postgres() {
3481 let expr = Expr::col("tags").json_contains(Expr::raw("'[\"rust\"]'"));
3482 let mut params = Vec::new();
3483 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3484 assert_eq!(sql, "\"tags\" @> '[\"rust\"]'");
3485 }
3486
3487 #[test]
3488 fn test_json_contains_mysql() {
3489 let expr = Expr::col("tags").json_contains(Expr::raw("'[\"rust\"]'"));
3490 let mut params = Vec::new();
3491 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
3492 assert_eq!(sql, "JSON_CONTAINS(`tags`, '[\"rust\"]')");
3493 }
3494
3495 #[test]
3496 fn test_json_has_key_postgres() {
3497 let expr = Expr::col("data").json_has_key("email");
3498 let mut params = Vec::new();
3499 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3500 assert_eq!(sql, "\"data\" ? 'email'");
3501 }
3502
3503 #[test]
3504 fn test_json_has_key_mysql() {
3505 let expr = Expr::col("data").json_has_key("email");
3506 let mut params = Vec::new();
3507 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
3508 assert_eq!(sql, "JSON_CONTAINS_PATH(`data`, 'one', '$.email')");
3509 }
3510
3511 #[test]
3512 fn test_json_has_key_sqlite() {
3513 let expr = Expr::col("data").json_has_key("email");
3514 let mut params = Vec::new();
3515 let sql = expr.build_with_dialect(Dialect::Sqlite, &mut params, 0);
3516 assert_eq!(sql, "json_type(\"data\", '$.email') IS NOT NULL");
3517 }
3518
3519 #[test]
3520 fn test_json_has_any_key_postgres() {
3521 let expr = Expr::col("data").json_has_any_key(&["email", "phone"]);
3522 let mut params = Vec::new();
3523 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3524 assert_eq!(sql, "\"data\" ?| array['email', 'phone']");
3525 }
3526
3527 #[test]
3528 fn test_json_has_all_keys_postgres() {
3529 let expr = Expr::col("data").json_has_all_keys(&["email", "phone"]);
3530 let mut params = Vec::new();
3531 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3532 assert_eq!(sql, "\"data\" ?& array['email', 'phone']");
3533 }
3534
3535 #[test]
3536 fn test_json_array_length_postgres() {
3537 let expr = Expr::col("items").json_array_length();
3538 let mut params = Vec::new();
3539 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3540 assert_eq!(sql, "jsonb_array_length(\"items\")");
3541 }
3542
3543 #[test]
3544 fn test_json_array_length_mysql() {
3545 let expr = Expr::col("items").json_array_length();
3546 let mut params = Vec::new();
3547 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
3548 assert_eq!(sql, "JSON_LENGTH(`items`)");
3549 }
3550
3551 #[test]
3552 fn test_json_array_length_sqlite() {
3553 let expr = Expr::col("items").json_array_length();
3554 let mut params = Vec::new();
3555 let sql = expr.build_with_dialect(Dialect::Sqlite, &mut params, 0);
3556 assert_eq!(sql, "json_array_length(\"items\")");
3557 }
3558
3559 #[test]
3560 fn test_json_typeof_postgres() {
3561 let expr = Expr::col("data").json_typeof();
3562 let mut params = Vec::new();
3563 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3564 assert_eq!(sql, "jsonb_typeof(\"data\")");
3565 }
3566
3567 #[test]
3568 fn test_json_typeof_mysql() {
3569 let expr = Expr::col("data").json_typeof();
3570 let mut params = Vec::new();
3571 let sql = expr.build_with_dialect(Dialect::Mysql, &mut params, 0);
3572 assert_eq!(sql, "JSON_TYPE(`data`)");
3573 }
3574
3575 #[test]
3576 fn test_json_chained_extraction() {
3577 let expr = Expr::col("data").json_get("user").json_get_text("name");
3579 let mut params = Vec::new();
3580 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3581 assert_eq!(sql, "\"data\" -> 'user' ->> 'name'");
3584 }
3585
3586 #[test]
3587 fn test_json_in_where_clause() {
3588 let expr = Expr::col("data").json_get_text("status").eq("active");
3590 let mut params = Vec::new();
3591 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3592 assert_eq!(sql, "\"data\" ->> 'status' = $1");
3593 assert_eq!(params.len(), 1);
3594 }
3595
3596 #[test]
3599 fn test_array_contains() {
3600 let expr = Expr::col("tags").array_contains(Expr::col("other_tags"));
3601 let mut params = Vec::new();
3602 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3603 assert_eq!(sql, "\"tags\" @> \"other_tags\"");
3604 }
3605
3606 #[test]
3607 fn test_array_contained_by() {
3608 let expr = Expr::col("tags").array_contained_by(Expr::col("all_tags"));
3609 let mut params = Vec::new();
3610 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3611 assert_eq!(sql, "\"tags\" <@ \"all_tags\"");
3612 }
3613
3614 #[test]
3615 fn test_array_overlap() {
3616 let expr = Expr::col("tags").array_overlap(Expr::col("search_tags"));
3617 let mut params = Vec::new();
3618 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3619 assert_eq!(sql, "\"tags\" && \"search_tags\"");
3620 }
3621
3622 #[test]
3623 fn test_array_any_eq() {
3624 let expr = Expr::col("tags").array_any_eq("admin");
3625 let mut params = Vec::new();
3626 let sql = expr.build_with_dialect(Dialect::Postgres, &mut params, 0);
3627 assert_eq!(sql, "$1 = ANY(\"tags\")");
3628 assert_eq!(params.len(), 1);
3629 }
3630}