1use crate::ast::{
52 BinaryOperator, DataType, Expr, FromClause, JoinClause, JoinType, OrderByItem, QuoteStyle,
53 SelectItem, SelectStatement, Statement, TableRef, TableSource,
54};
55use crate::dialects::Dialect;
56use crate::parser::parse;
57
58#[must_use]
77pub fn column(name: &str, table: Option<&str>) -> Expr {
78 Expr::Column {
79 table: table.map(String::from),
80 name: name.to_string(),
81 quote_style: QuoteStyle::None,
82 table_quote_style: QuoteStyle::None,
83 }
84}
85
86#[must_use]
101pub fn table(name: &str, schema: Option<&str>) -> TableRef {
102 TableRef {
103 catalog: None,
104 schema: schema.map(String::from),
105 name: name.to_string(),
106 alias: None,
107 name_quote_style: QuoteStyle::None,
108 alias_quote_style: QuoteStyle::None,
109 }
110}
111
112#[must_use]
127pub fn table_full(name: &str, schema: Option<&str>, catalog: Option<&str>) -> TableRef {
128 TableRef {
129 catalog: catalog.map(String::from),
130 schema: schema.map(String::from),
131 name: name.to_string(),
132 alias: None,
133 name_quote_style: QuoteStyle::None,
134 alias_quote_style: QuoteStyle::None,
135 }
136}
137
138#[must_use]
148pub fn literal<T: ToString>(value: T) -> Expr {
149 Expr::Number(value.to_string())
150}
151
152#[must_use]
162pub fn string_literal(value: &str) -> Expr {
163 Expr::StringLiteral(value.to_string())
164}
165
166#[must_use]
177pub fn boolean(value: bool) -> Expr {
178 Expr::Boolean(value)
179}
180
181#[must_use]
191pub fn null() -> Expr {
192 Expr::Null
193}
194
195#[must_use]
210pub fn cast(expr: Expr, data_type: DataType) -> Expr {
211 Expr::Cast {
212 expr: Box::new(expr),
213 data_type,
214 }
215}
216
217#[must_use]
242pub fn and_all<I>(conditions: I) -> Option<Expr>
243where
244 I: IntoIterator<Item = Expr>,
245{
246 let mut iter = conditions.into_iter();
247 let first = iter.next()?;
248 Some(iter.fold(first, |acc, cond| Expr::BinaryOp {
249 left: Box::new(acc),
250 op: BinaryOperator::And,
251 right: Box::new(cond),
252 }))
253}
254
255#[must_use]
280pub fn or_all<I>(conditions: I) -> Option<Expr>
281where
282 I: IntoIterator<Item = Expr>,
283{
284 let mut iter = conditions.into_iter();
285 let first = iter.next()?;
286 Some(iter.fold(first, |acc, cond| Expr::BinaryOp {
287 left: Box::new(acc),
288 op: BinaryOperator::Or,
289 right: Box::new(cond),
290 }))
291}
292
293#[must_use]
303pub fn not(expr: Expr) -> Expr {
304 Expr::UnaryOp {
305 op: crate::ast::UnaryOperator::Not,
306 expr: Box::new(expr),
307 }
308}
309
310#[must_use]
325pub fn func(name: &str, args: Vec<Expr>) -> Expr {
326 Expr::Function {
327 name: name.to_string(),
328 args,
329 distinct: false,
330 filter: None,
331 over: None,
332 order_by: vec![],
333 within_group: false,
334 }
335}
336
337#[must_use]
347pub fn func_distinct(name: &str, args: Vec<Expr>) -> Expr {
348 Expr::Function {
349 name: name.to_string(),
350 args,
351 distinct: true,
352 filter: None,
353 over: None,
354 order_by: vec![],
355 within_group: false,
356 }
357}
358
359#[must_use]
369pub fn star() -> Expr {
370 Expr::Star
371}
372
373#[must_use]
383pub fn qualified_star(table: &str) -> Expr {
384 Expr::QualifiedWildcard {
385 table: table.to_string(),
386 }
387}
388
389#[must_use]
400pub fn subquery(statement: Statement) -> Expr {
401 Expr::Subquery(Box::new(statement))
402}
403
404#[must_use]
415pub fn exists(statement: Statement, negated: bool) -> Expr {
416 Expr::Exists {
417 subquery: Box::new(statement),
418 negated,
419 }
420}
421
422#[must_use]
432pub fn alias(expr: Expr, name: &str) -> Expr {
433 Expr::Alias {
434 expr: Box::new(expr),
435 name: name.to_string(),
436 }
437}
438
439#[must_use]
445pub fn eq(left: Expr, right: Expr) -> Expr {
446 Expr::BinaryOp {
447 left: Box::new(left),
448 op: BinaryOperator::Eq,
449 right: Box::new(right),
450 }
451}
452
453#[must_use]
455pub fn neq(left: Expr, right: Expr) -> Expr {
456 Expr::BinaryOp {
457 left: Box::new(left),
458 op: BinaryOperator::Neq,
459 right: Box::new(right),
460 }
461}
462
463#[must_use]
465pub fn lt(left: Expr, right: Expr) -> Expr {
466 Expr::BinaryOp {
467 left: Box::new(left),
468 op: BinaryOperator::Lt,
469 right: Box::new(right),
470 }
471}
472
473#[must_use]
475pub fn lte(left: Expr, right: Expr) -> Expr {
476 Expr::BinaryOp {
477 left: Box::new(left),
478 op: BinaryOperator::LtEq,
479 right: Box::new(right),
480 }
481}
482
483#[must_use]
485pub fn gt(left: Expr, right: Expr) -> Expr {
486 Expr::BinaryOp {
487 left: Box::new(left),
488 op: BinaryOperator::Gt,
489 right: Box::new(right),
490 }
491}
492
493#[must_use]
495pub fn gte(left: Expr, right: Expr) -> Expr {
496 Expr::BinaryOp {
497 left: Box::new(left),
498 op: BinaryOperator::GtEq,
499 right: Box::new(right),
500 }
501}
502
503#[must_use]
505pub fn is_null(expr: Expr) -> Expr {
506 Expr::IsNull {
507 expr: Box::new(expr),
508 negated: false,
509 }
510}
511
512#[must_use]
514pub fn is_not_null(expr: Expr) -> Expr {
515 Expr::IsNull {
516 expr: Box::new(expr),
517 negated: true,
518 }
519}
520
521#[must_use]
523pub fn between(expr: Expr, low: Expr, high: Expr) -> Expr {
524 Expr::Between {
525 expr: Box::new(expr),
526 low: Box::new(low),
527 high: Box::new(high),
528 negated: false,
529 }
530}
531
532#[must_use]
534pub fn in_list(expr: Expr, list: Vec<Expr>) -> Expr {
535 Expr::InList {
536 expr: Box::new(expr),
537 list,
538 negated: false,
539 }
540}
541
542#[must_use]
544pub fn not_in_list(expr: Expr, list: Vec<Expr>) -> Expr {
545 Expr::InList {
546 expr: Box::new(expr),
547 list,
548 negated: true,
549 }
550}
551
552#[must_use]
554pub fn in_subquery(expr: Expr, query: Statement) -> Expr {
555 Expr::InSubquery {
556 expr: Box::new(expr),
557 subquery: Box::new(query),
558 negated: false,
559 }
560}
561
562#[must_use]
564pub fn like(expr: Expr, pattern: Expr) -> Expr {
565 Expr::Like {
566 expr: Box::new(expr),
567 pattern: Box::new(pattern),
568 negated: false,
569 escape: None,
570 }
571}
572
573#[must_use]
579pub fn add(left: Expr, right: Expr) -> Expr {
580 Expr::BinaryOp {
581 left: Box::new(left),
582 op: BinaryOperator::Plus,
583 right: Box::new(right),
584 }
585}
586
587#[must_use]
589pub fn sub(left: Expr, right: Expr) -> Expr {
590 Expr::BinaryOp {
591 left: Box::new(left),
592 op: BinaryOperator::Minus,
593 right: Box::new(right),
594 }
595}
596
597#[must_use]
599pub fn mul(left: Expr, right: Expr) -> Expr {
600 Expr::BinaryOp {
601 left: Box::new(left),
602 op: BinaryOperator::Multiply,
603 right: Box::new(right),
604 }
605}
606
607#[must_use]
609pub fn div(left: Expr, right: Expr) -> Expr {
610 Expr::BinaryOp {
611 left: Box::new(left),
612 op: BinaryOperator::Divide,
613 right: Box::new(right),
614 }
615}
616
617#[must_use]
634pub fn parse_expr(sql: &str) -> Option<Expr> {
635 parse_expr_dialect(sql, Dialect::Ansi)
636}
637
638#[must_use]
640pub fn parse_expr_dialect(sql: &str, dialect: Dialect) -> Option<Expr> {
641 let query = format!("SELECT {sql}");
643 match parse(&query, dialect) {
644 Ok(Statement::Select(select)) => {
645 if let Some(SelectItem::Expr { expr, .. }) = select.columns.first() {
646 Some(expr.clone())
647 } else {
648 None
649 }
650 }
651 _ => None,
652 }
653}
654
655#[must_use]
665pub fn parse_condition(sql: &str) -> Option<Expr> {
666 parse_condition_dialect(sql, Dialect::Ansi)
667}
668
669#[must_use]
671pub fn parse_condition_dialect(sql: &str, dialect: Dialect) -> Option<Expr> {
672 let query = format!("SELECT 1 WHERE {sql}");
674 match parse(&query, dialect) {
675 Ok(Statement::Select(select)) => select.where_clause,
676 _ => None,
677 }
678}
679
680#[derive(Debug, Clone)]
697pub struct ConditionBuilder {
698 expr: Option<Expr>,
699 dialect: Dialect,
700}
701
702impl ConditionBuilder {
703 #[must_use]
705 pub fn new(condition: &str) -> Self {
706 Self::new_with_dialect(condition, Dialect::Ansi)
707 }
708
709 #[must_use]
711 pub fn new_with_dialect(condition: &str, dialect: Dialect) -> Self {
712 Self {
713 expr: parse_condition_dialect(condition, dialect),
714 dialect,
715 }
716 }
717
718 #[must_use]
720 pub fn from_expr(expr: Expr) -> Self {
721 Self {
722 expr: Some(expr),
723 dialect: Dialect::Ansi,
724 }
725 }
726
727 #[must_use]
729 pub fn and(self, condition: &str) -> Self {
730 let dialect = self.dialect;
731 self.and_expr(parse_condition_dialect(condition, dialect))
732 }
733
734 #[must_use]
736 pub fn and_expr(self, other: Option<Expr>) -> Self {
737 let expr = match (self.expr, other) {
738 (Some(left), Some(right)) => Some(Expr::BinaryOp {
739 left: Box::new(left),
740 op: BinaryOperator::And,
741 right: Box::new(right),
742 }),
743 (Some(e), None) | (None, Some(e)) => Some(e),
744 (None, None) => None,
745 };
746 Self {
747 expr,
748 dialect: self.dialect,
749 }
750 }
751
752 #[must_use]
754 pub fn or(self, condition: &str) -> Self {
755 let dialect = self.dialect;
756 self.or_expr(parse_condition_dialect(condition, dialect))
757 }
758
759 #[must_use]
761 pub fn or_expr(self, other: Option<Expr>) -> Self {
762 let expr = match (self.expr, other) {
763 (Some(left), Some(right)) => Some(Expr::BinaryOp {
764 left: Box::new(left),
765 op: BinaryOperator::Or,
766 right: Box::new(right),
767 }),
768 (Some(e), None) | (None, Some(e)) => Some(e),
769 (None, None) => None,
770 };
771 Self {
772 expr,
773 dialect: self.dialect,
774 }
775 }
776
777 #[must_use]
779 pub fn not(self) -> Self {
780 let expr = self.expr.map(|e| Expr::UnaryOp {
781 op: crate::ast::UnaryOperator::Not,
782 expr: Box::new(e),
783 });
784 Self {
785 expr,
786 dialect: self.dialect,
787 }
788 }
789
790 #[must_use]
792 pub fn build(self) -> Option<Expr> {
793 self.expr
794 }
795}
796
797#[must_use]
807pub fn condition(cond: &str) -> ConditionBuilder {
808 ConditionBuilder::new(cond)
809}
810
811#[must_use]
813pub fn condition_dialect(cond: &str, dialect: Dialect) -> ConditionBuilder {
814 ConditionBuilder::new_with_dialect(cond, dialect)
815}
816
817#[derive(Debug, Clone)]
836pub struct SelectBuilder {
837 statement: SelectStatement,
838 dialect: Dialect,
839}
840
841impl Default for SelectBuilder {
842 fn default() -> Self {
843 Self::new()
844 }
845}
846
847impl SelectBuilder {
848 #[must_use]
850 pub fn new() -> Self {
851 Self {
852 statement: SelectStatement {
853 comments: Vec::new(),
854 ctes: Vec::new(),
855 distinct: false,
856 top: None,
857 columns: Vec::new(),
858 from: None,
859 joins: Vec::new(),
860 where_clause: None,
861 group_by: Vec::new(),
862 having: None,
863 order_by: Vec::new(),
864 limit: None,
865 offset: None,
866 fetch_first: None,
867 qualify: None,
868 window_definitions: Vec::new(),
869 },
870 dialect: Dialect::Ansi,
871 }
872 }
873
874 #[must_use]
876 pub fn dialect(mut self, dialect: Dialect) -> Self {
877 self.dialect = dialect;
878 self
879 }
880
881 #[must_use]
885 pub fn columns(mut self, cols: &[&str]) -> Self {
886 for col in cols {
887 if let Some(expr) = parse_expr_dialect(col, self.dialect) {
888 self.statement.columns.push(SelectItem::Expr {
889 expr,
890 alias: None,
891 alias_quote_style: QuoteStyle::None,
892 });
893 }
894 }
895 self
896 }
897
898 #[must_use]
900 pub fn column_expr(mut self, expr: Expr, alias: Option<&str>) -> Self {
901 self.statement.columns.push(SelectItem::Expr {
902 expr,
903 alias: alias.map(String::from),
904 alias_quote_style: QuoteStyle::None,
905 });
906 self
907 }
908
909 #[must_use]
911 pub fn all(mut self) -> Self {
912 self.statement.columns.push(SelectItem::Wildcard);
913 self
914 }
915
916 #[must_use]
918 pub fn all_from(mut self, table: &str) -> Self {
919 self.statement.columns.push(SelectItem::QualifiedWildcard {
920 table: table.to_string(),
921 });
922 self
923 }
924
925 #[must_use]
927 pub fn distinct(mut self) -> Self {
928 self.statement.distinct = true;
929 self
930 }
931
932 #[must_use]
934 pub fn from(mut self, table_name: &str) -> Self {
935 self.statement.from = Some(FromClause {
936 source: TableSource::Table(table(table_name, None)),
937 });
938 self
939 }
940
941 #[must_use]
943 pub fn from_table(mut self, table_ref: TableRef) -> Self {
944 self.statement.from = Some(FromClause {
945 source: TableSource::Table(table_ref),
946 });
947 self
948 }
949
950 #[must_use]
952 pub fn from_subquery(mut self, query: Statement, alias: &str) -> Self {
953 self.statement.from = Some(FromClause {
954 source: TableSource::Subquery {
955 query: Box::new(query),
956 alias: Some(alias.to_string()),
957 alias_quote_style: QuoteStyle::None,
958 },
959 });
960 self
961 }
962
963 #[must_use]
965 pub fn join(self, table_name: &str, on: &str) -> Self {
966 self.join_type(table_name, on, JoinType::Inner)
967 }
968
969 #[must_use]
971 pub fn left_join(self, table_name: &str, on: &str) -> Self {
972 self.join_type(table_name, on, JoinType::Left)
973 }
974
975 #[must_use]
977 pub fn right_join(self, table_name: &str, on: &str) -> Self {
978 self.join_type(table_name, on, JoinType::Right)
979 }
980
981 #[must_use]
983 pub fn full_join(self, table_name: &str, on: &str) -> Self {
984 self.join_type(table_name, on, JoinType::Full)
985 }
986
987 #[must_use]
989 pub fn cross_join(mut self, table_name: &str) -> Self {
990 self.statement.joins.push(JoinClause {
991 join_type: JoinType::Cross,
992 table: TableSource::Table(table(table_name, None)),
993 on: None,
994 using: Vec::new(),
995 });
996 self
997 }
998
999 #[must_use]
1001 fn join_type(mut self, table_name: &str, on: &str, join_type: JoinType) -> Self {
1002 let on_expr = parse_condition_dialect(on, self.dialect);
1003 self.statement.joins.push(JoinClause {
1004 join_type,
1005 table: TableSource::Table(table(table_name, None)),
1006 on: on_expr,
1007 using: Vec::new(),
1008 });
1009 self
1010 }
1011
1012 #[must_use]
1014 pub fn join_using(mut self, table_name: &str, columns: &[&str], join_type: JoinType) -> Self {
1015 self.statement.joins.push(JoinClause {
1016 join_type,
1017 table: TableSource::Table(table(table_name, None)),
1018 on: None,
1019 using: columns.iter().map(|s| s.to_string()).collect(),
1020 });
1021 self
1022 }
1023
1024 #[must_use]
1026 pub fn join_subquery(
1027 mut self,
1028 query: Statement,
1029 alias: &str,
1030 on: &str,
1031 join_type: JoinType,
1032 ) -> Self {
1033 let on_expr = parse_condition_dialect(on, self.dialect);
1034 self.statement.joins.push(JoinClause {
1035 join_type,
1036 table: TableSource::Subquery {
1037 query: Box::new(query),
1038 alias: Some(alias.to_string()),
1039 alias_quote_style: QuoteStyle::None,
1040 },
1041 on: on_expr,
1042 using: Vec::new(),
1043 });
1044 self
1045 }
1046
1047 #[must_use]
1049 pub fn where_clause(mut self, condition: &str) -> Self {
1050 self.statement.where_clause = parse_condition_dialect(condition, self.dialect);
1051 self
1052 }
1053
1054 #[must_use]
1056 pub fn where_expr(mut self, expr: Expr) -> Self {
1057 self.statement.where_clause = Some(expr);
1058 self
1059 }
1060
1061 #[must_use]
1063 pub fn and_where(mut self, condition: &str) -> Self {
1064 let new_cond = parse_condition_dialect(condition, self.dialect);
1065 self.statement.where_clause = match (self.statement.where_clause, new_cond) {
1066 (Some(existing), Some(new)) => Some(Expr::BinaryOp {
1067 left: Box::new(existing),
1068 op: BinaryOperator::And,
1069 right: Box::new(new),
1070 }),
1071 (Some(e), None) | (None, Some(e)) => Some(e),
1072 (None, None) => None,
1073 };
1074 self
1075 }
1076
1077 #[must_use]
1079 pub fn or_where(mut self, condition: &str) -> Self {
1080 let new_cond = parse_condition_dialect(condition, self.dialect);
1081 self.statement.where_clause = match (self.statement.where_clause, new_cond) {
1082 (Some(existing), Some(new)) => Some(Expr::BinaryOp {
1083 left: Box::new(existing),
1084 op: BinaryOperator::Or,
1085 right: Box::new(new),
1086 }),
1087 (Some(e), None) | (None, Some(e)) => Some(e),
1088 (None, None) => None,
1089 };
1090 self
1091 }
1092
1093 #[must_use]
1095 pub fn group_by(mut self, exprs: &[&str]) -> Self {
1096 self.statement.group_by = exprs
1097 .iter()
1098 .filter_map(|e| parse_expr_dialect(e, self.dialect))
1099 .collect();
1100 self
1101 }
1102
1103 #[must_use]
1105 pub fn add_group_by(mut self, expr: &str) -> Self {
1106 if let Some(e) = parse_expr_dialect(expr, self.dialect) {
1107 self.statement.group_by.push(e);
1108 }
1109 self
1110 }
1111
1112 #[must_use]
1114 pub fn having(mut self, condition: &str) -> Self {
1115 self.statement.having = parse_condition_dialect(condition, self.dialect);
1116 self
1117 }
1118
1119 #[must_use]
1121 pub fn order_by(mut self, exprs: &[&str]) -> Self {
1122 self.statement.order_by = exprs
1123 .iter()
1124 .filter_map(|e| parse_order_by_item(e, self.dialect))
1125 .collect();
1126 self
1127 }
1128
1129 #[must_use]
1131 pub fn add_order_by(mut self, expr: &str) -> Self {
1132 if let Some(item) = parse_order_by_item(expr, self.dialect) {
1133 self.statement.order_by.push(item);
1134 }
1135 self
1136 }
1137
1138 #[must_use]
1140 pub fn add_order_by_expr(
1141 mut self,
1142 expr: Expr,
1143 ascending: bool,
1144 nulls_first: Option<bool>,
1145 ) -> Self {
1146 self.statement.order_by.push(OrderByItem {
1147 expr,
1148 ascending,
1149 nulls_first,
1150 });
1151 self
1152 }
1153
1154 #[must_use]
1156 pub fn limit(mut self, n: i64) -> Self {
1157 self.statement.limit = Some(Expr::Number(n.to_string()));
1158 self
1159 }
1160
1161 #[must_use]
1163 pub fn limit_expr(mut self, expr: Expr) -> Self {
1164 self.statement.limit = Some(expr);
1165 self
1166 }
1167
1168 #[must_use]
1170 pub fn offset(mut self, n: i64) -> Self {
1171 self.statement.offset = Some(Expr::Number(n.to_string()));
1172 self
1173 }
1174
1175 #[must_use]
1177 pub fn offset_expr(mut self, expr: Expr) -> Self {
1178 self.statement.offset = Some(expr);
1179 self
1180 }
1181
1182 #[must_use]
1184 pub fn top(mut self, n: i64) -> Self {
1185 self.statement.top = Some(Box::new(Expr::Number(n.to_string())));
1186 self
1187 }
1188
1189 #[must_use]
1191 pub fn qualify(mut self, condition: &str) -> Self {
1192 self.statement.qualify = parse_condition_dialect(condition, self.dialect);
1193 self
1194 }
1195
1196 #[must_use]
1198 pub fn build(self) -> Statement {
1199 Statement::Select(self.statement)
1200 }
1201
1202 #[must_use]
1204 pub fn build_select(self) -> SelectStatement {
1205 self.statement
1206 }
1207}
1208
1209#[must_use]
1219pub fn select(columns: &[&str]) -> SelectBuilder {
1220 SelectBuilder::new().columns(columns)
1221}
1222
1223#[must_use]
1233pub fn select_all() -> SelectBuilder {
1234 SelectBuilder::new().all()
1235}
1236
1237#[must_use]
1247pub fn select_distinct(columns: &[&str]) -> SelectBuilder {
1248 SelectBuilder::new().distinct().columns(columns)
1249}
1250
1251impl SelectStatement {
1256 pub fn add_select(&mut self, expr_str: &str) {
1267 self.add_select_dialect(expr_str, Dialect::Ansi);
1268 }
1269
1270 pub fn add_select_dialect(&mut self, expr_str: &str, dialect: Dialect) {
1272 if let Some(expr) = parse_expr_dialect(expr_str, dialect) {
1273 self.columns.push(SelectItem::Expr {
1274 expr,
1275 alias: None,
1276 alias_quote_style: QuoteStyle::None,
1277 });
1278 }
1279 }
1280
1281 pub fn add_select_expr(&mut self, expr: Expr, alias: Option<&str>) {
1283 self.columns.push(SelectItem::Expr {
1284 expr,
1285 alias: alias.map(String::from),
1286 alias_quote_style: QuoteStyle::None,
1287 });
1288 }
1289
1290 pub fn add_where(&mut self, condition: &str) {
1302 self.add_where_dialect(condition, Dialect::Ansi);
1303 }
1304
1305 pub fn add_where_dialect(&mut self, condition: &str, dialect: Dialect) {
1307 let new_cond = parse_condition_dialect(condition, dialect);
1308 self.where_clause = match (self.where_clause.take(), new_cond) {
1309 (Some(existing), Some(new)) => Some(Expr::BinaryOp {
1310 left: Box::new(existing),
1311 op: BinaryOperator::And,
1312 right: Box::new(new),
1313 }),
1314 (Some(e), None) | (None, Some(e)) => Some(e),
1315 (None, None) => None,
1316 };
1317 }
1318
1319 pub fn add_where_expr(&mut self, expr: Expr) {
1321 self.where_clause = match self.where_clause.take() {
1322 Some(existing) => Some(Expr::BinaryOp {
1323 left: Box::new(existing),
1324 op: BinaryOperator::And,
1325 right: Box::new(expr),
1326 }),
1327 None => Some(expr),
1328 };
1329 }
1330
1331 pub fn add_join(&mut self, table_name: &str, on: &str, join_type: JoinType) {
1343 self.add_join_dialect(table_name, on, join_type, Dialect::Ansi);
1344 }
1345
1346 pub fn add_join_dialect(
1348 &mut self,
1349 table_name: &str,
1350 on: &str,
1351 join_type: JoinType,
1352 dialect: Dialect,
1353 ) {
1354 let on_expr = parse_condition_dialect(on, dialect);
1355 self.joins.push(JoinClause {
1356 join_type,
1357 table: TableSource::Table(table(table_name, None)),
1358 on: on_expr,
1359 using: Vec::new(),
1360 });
1361 }
1362
1363 pub fn add_join_subquery(
1365 &mut self,
1366 query: Statement,
1367 alias: &str,
1368 on: &str,
1369 join_type: JoinType,
1370 ) {
1371 self.add_join_subquery_dialect(query, alias, on, join_type, Dialect::Ansi);
1372 }
1373
1374 pub fn add_join_subquery_dialect(
1376 &mut self,
1377 query: Statement,
1378 alias: &str,
1379 on: &str,
1380 join_type: JoinType,
1381 dialect: Dialect,
1382 ) {
1383 let on_expr = parse_condition_dialect(on, dialect);
1384 self.joins.push(JoinClause {
1385 join_type,
1386 table: TableSource::Subquery {
1387 query: Box::new(query),
1388 alias: Some(alias.to_string()),
1389 alias_quote_style: QuoteStyle::None,
1390 },
1391 on: on_expr,
1392 using: Vec::new(),
1393 });
1394 }
1395
1396 #[must_use]
1407 pub fn as_subquery(self, alias: &str) -> TableSource {
1408 TableSource::Subquery {
1409 query: Box::new(Statement::Select(self)),
1410 alias: Some(alias.to_string()),
1411 alias_quote_style: QuoteStyle::None,
1412 }
1413 }
1414}
1415
1416fn parse_order_by_item(s: &str, dialect: Dialect) -> Option<OrderByItem> {
1422 let s = s.trim();
1423 let upper = s.to_uppercase();
1424
1425 let nulls_first = if upper.contains("NULLS FIRST") {
1427 Some(true)
1428 } else if upper.contains("NULLS LAST") {
1429 Some(false)
1430 } else {
1431 None
1432 };
1433
1434 let s = s
1436 .replace("NULLS FIRST", "")
1437 .replace("NULLS LAST", "")
1438 .replace("nulls first", "")
1439 .replace("nulls last", "");
1440 let s = s.trim();
1441
1442 let (expr_str, ascending) = if s.to_uppercase().ends_with(" DESC") {
1444 (&s[..s.len() - 5], false)
1445 } else if s.to_uppercase().ends_with(" ASC") {
1446 (&s[..s.len() - 4], true)
1447 } else {
1448 (s, true)
1449 };
1450
1451 parse_expr_dialect(expr_str.trim(), dialect).map(|expr| OrderByItem {
1452 expr,
1453 ascending,
1454 nulls_first,
1455 })
1456}
1457
1458#[cfg(test)]
1459mod tests {
1460 use super::*;
1461 use crate::generate;
1462
1463 #[test]
1464 fn test_column() {
1465 let col = column("name", None);
1466 assert!(
1467 matches!(col, Expr::Column { name, table, .. } if name == "name" && table.is_none())
1468 );
1469
1470 let qualified = column("id", Some("users"));
1471 assert!(matches!(qualified, Expr::Column { name, table, .. }
1472 if name == "id" && table == Some("users".to_string())));
1473 }
1474
1475 #[test]
1476 fn test_table() {
1477 let tbl = table("users", None);
1478 assert_eq!(tbl.name, "users");
1479 assert!(tbl.schema.is_none());
1480
1481 let qualified = table("orders", Some("public"));
1482 assert_eq!(qualified.name, "orders");
1483 assert_eq!(qualified.schema, Some("public".to_string()));
1484 }
1485
1486 #[test]
1487 fn test_literals() {
1488 assert!(matches!(literal(42), Expr::Number(n) if n == "42"));
1489 assert!(matches!(string_literal("hello"), Expr::StringLiteral(s) if s == "hello"));
1490 assert!(matches!(boolean(true), Expr::Boolean(true)));
1491 assert!(matches!(null(), Expr::Null));
1492 }
1493
1494 #[test]
1495 fn test_cast() {
1496 let col = column("id", None);
1497 let casted = cast(col, DataType::BigInt);
1498 assert!(matches!(
1499 casted,
1500 Expr::Cast {
1501 data_type: DataType::BigInt,
1502 ..
1503 }
1504 ));
1505 }
1506
1507 #[test]
1508 fn test_and_all() {
1509 let cond1 = eq(column("x", None), literal(1));
1510 let cond2 = eq(column("y", None), literal(2));
1511
1512 let combined = and_all(vec![cond1, cond2]).unwrap();
1513 assert!(matches!(
1514 combined,
1515 Expr::BinaryOp {
1516 op: BinaryOperator::And,
1517 ..
1518 }
1519 ));
1520
1521 assert!(and_all(Vec::<Expr>::new()).is_none());
1523 }
1524
1525 #[test]
1526 fn test_or_all() {
1527 let cond1 = eq(column("x", None), literal(1));
1528 let cond2 = eq(column("y", None), literal(2));
1529
1530 let combined = or_all(vec![cond1, cond2]).unwrap();
1531 assert!(matches!(
1532 combined,
1533 Expr::BinaryOp {
1534 op: BinaryOperator::Or,
1535 ..
1536 }
1537 ));
1538 }
1539
1540 #[test]
1541 fn test_parse_expr() {
1542 let expr = parse_expr("x + 1").unwrap();
1543 assert!(matches!(
1544 expr,
1545 Expr::BinaryOp {
1546 op: BinaryOperator::Plus,
1547 ..
1548 }
1549 ));
1550 }
1551
1552 #[test]
1553 fn test_parse_condition() {
1554 let cond = parse_condition("x > 1 AND y < 10").unwrap();
1555 assert!(matches!(
1556 cond,
1557 Expr::BinaryOp {
1558 op: BinaryOperator::And,
1559 ..
1560 }
1561 ));
1562 }
1563
1564 #[test]
1565 fn test_condition_builder() {
1566 let cond = condition("x = 1").and("y = 2").or("z = 3").build();
1567 assert!(cond.is_some());
1568 }
1569
1570 #[test]
1571 fn test_condition_builder_not() {
1572 let cond = condition("x = 1").not().build().unwrap();
1573 assert!(matches!(
1574 cond,
1575 Expr::UnaryOp {
1576 op: crate::ast::UnaryOperator::Not,
1577 ..
1578 }
1579 ));
1580 }
1581
1582 #[test]
1583 fn test_select_builder_basic() {
1584 let query = select(&["a", "b"]).from("users").build();
1585 let sql = generate(&query, Dialect::Ansi);
1586 assert!(sql.contains("SELECT"));
1587 assert!(sql.contains("a"));
1588 assert!(sql.contains("b"));
1589 assert!(sql.contains("FROM users"));
1590 }
1591
1592 #[test]
1593 fn test_select_builder_where() {
1594 let query = select(&["*"])
1595 .from("users")
1596 .where_clause("active = true")
1597 .build();
1598 let sql = generate(&query, Dialect::Ansi);
1599 assert!(sql.contains("WHERE"));
1600 }
1601
1602 #[test]
1603 fn test_select_builder_join() {
1604 let query = select(&["u.name", "o.total"])
1605 .from("users")
1606 .join("orders", "users.id = orders.user_id")
1607 .build();
1608 let sql = generate(&query, Dialect::Ansi);
1609 assert!(sql.contains("JOIN"));
1610 }
1611
1612 #[test]
1613 fn test_select_builder_group_by() {
1614 let query = select(&["category", "COUNT(*)"])
1615 .from("products")
1616 .group_by(&["category"])
1617 .having("COUNT(*) > 5")
1618 .build();
1619 let sql = generate(&query, Dialect::Ansi);
1620 assert!(sql.contains("GROUP BY"));
1621 assert!(sql.contains("HAVING"));
1622 }
1623
1624 #[test]
1625 fn test_select_builder_order_limit() {
1626 let query = select(&["*"])
1627 .from("users")
1628 .order_by(&["created_at DESC"])
1629 .limit(10)
1630 .offset(5)
1631 .build();
1632 let sql = generate(&query, Dialect::Ansi);
1633 assert!(sql.contains("ORDER BY"));
1634 assert!(sql.contains("LIMIT 10"));
1635 assert!(sql.contains("OFFSET 5"));
1636 }
1637
1638 #[test]
1639 fn test_select_builder_distinct() {
1640 let query = select_distinct(&["category"]).from("products").build();
1641 let sql = generate(&query, Dialect::Ansi);
1642 assert!(sql.contains("SELECT DISTINCT"));
1643 }
1644
1645 #[test]
1646 fn test_select_all() {
1647 let query = select_all().from("users").build();
1648 let sql = generate(&query, Dialect::Ansi);
1649 assert!(sql.contains("SELECT *"));
1650 }
1651
1652 #[test]
1653 fn test_mutation_add_select() {
1654 let mut stmt = select(&["a"]).from("t").build_select();
1655 stmt.add_select("b");
1656 assert_eq!(stmt.columns.len(), 2);
1657 }
1658
1659 #[test]
1660 fn test_mutation_add_where() {
1661 let mut stmt = select(&["*"]).from("t").build_select();
1662 stmt.add_where("x > 1");
1663 stmt.add_where("y < 10");
1664 assert!(stmt.where_clause.is_some());
1666 }
1667
1668 #[test]
1669 fn test_mutation_add_join() {
1670 let mut stmt = select(&["*"]).from("users").build_select();
1671 stmt.add_join("orders", "users.id = orders.user_id", JoinType::Inner);
1672 assert_eq!(stmt.joins.len(), 1);
1673 }
1674
1675 #[test]
1676 fn test_as_subquery() {
1677 let inner = select(&["id"]).from("users").build_select();
1678 let source = inner.as_subquery("u");
1679 assert!(matches!(source, TableSource::Subquery { alias: Some(a), .. } if a == "u"));
1680 }
1681
1682 #[test]
1683 fn test_comparison_helpers() {
1684 let e = eq(column("a", None), literal(1));
1685 assert!(matches!(
1686 e,
1687 Expr::BinaryOp {
1688 op: BinaryOperator::Eq,
1689 ..
1690 }
1691 ));
1692
1693 let e = neq(column("a", None), literal(1));
1694 assert!(matches!(
1695 e,
1696 Expr::BinaryOp {
1697 op: BinaryOperator::Neq,
1698 ..
1699 }
1700 ));
1701
1702 let e = lt(column("a", None), literal(1));
1703 assert!(matches!(
1704 e,
1705 Expr::BinaryOp {
1706 op: BinaryOperator::Lt,
1707 ..
1708 }
1709 ));
1710
1711 let e = gt(column("a", None), literal(1));
1712 assert!(matches!(
1713 e,
1714 Expr::BinaryOp {
1715 op: BinaryOperator::Gt,
1716 ..
1717 }
1718 ));
1719 }
1720
1721 #[test]
1722 fn test_arithmetic_helpers() {
1723 let e = add(column("a", None), literal(1));
1724 assert!(matches!(
1725 e,
1726 Expr::BinaryOp {
1727 op: BinaryOperator::Plus,
1728 ..
1729 }
1730 ));
1731
1732 let e = mul(column("a", None), literal(2));
1733 assert!(matches!(
1734 e,
1735 Expr::BinaryOp {
1736 op: BinaryOperator::Multiply,
1737 ..
1738 }
1739 ));
1740 }
1741
1742 #[test]
1743 fn test_is_null_helpers() {
1744 let e = is_null(column("a", None));
1745 assert!(matches!(e, Expr::IsNull { negated: false, .. }));
1746
1747 let e = is_not_null(column("a", None));
1748 assert!(matches!(e, Expr::IsNull { negated: true, .. }));
1749 }
1750
1751 #[test]
1752 fn test_between() {
1753 let e = between(column("x", None), literal(1), literal(10));
1754 assert!(matches!(e, Expr::Between { negated: false, .. }));
1755 }
1756
1757 #[test]
1758 fn test_in_list() {
1759 let e = in_list(
1760 column("status", None),
1761 vec![string_literal("active"), string_literal("pending")],
1762 );
1763 assert!(matches!(e, Expr::InList { negated: false, .. }));
1764 }
1765
1766 #[test]
1767 fn test_like() {
1768 let e = like(column("name", None), string_literal("%John%"));
1769 assert!(matches!(e, Expr::Like { negated: false, .. }));
1770 }
1771
1772 #[test]
1773 fn test_func() {
1774 let f = func("UPPER", vec![column("name", None)]);
1775 assert!(matches!(f, Expr::Function { name, distinct: false, .. } if name == "UPPER"));
1776 }
1777
1778 #[test]
1779 fn test_func_distinct() {
1780 let f = func_distinct("COUNT", vec![column("id", None)]);
1781 assert!(matches!(f, Expr::Function { name, distinct: true, .. } if name == "COUNT"));
1782 }
1783
1784 #[test]
1785 fn test_alias() {
1786 let e = alias(column("first_name", None), "name");
1787 assert!(matches!(e, Expr::Alias { name, .. } if name == "name"));
1788 }
1789
1790 #[test]
1791 fn test_subquery_and_exists() {
1792 let inner = select(&["1"]).from("users").where_clause("id = 1").build();
1793 let sub = subquery(inner.clone());
1794 assert!(matches!(sub, Expr::Subquery(_)));
1795
1796 let ex = exists(inner, false);
1797 assert!(matches!(ex, Expr::Exists { negated: false, .. }));
1798 }
1799
1800 #[test]
1801 fn test_star_and_qualified_star() {
1802 let s = star();
1803 assert!(matches!(s, Expr::Star));
1804
1805 let qs = qualified_star("users");
1806 assert!(matches!(qs, Expr::QualifiedWildcard { table } if table == "users"));
1807 }
1808
1809 #[test]
1810 fn test_complex_query() {
1811 let query = select(&["u.id", "u.name", "COUNT(o.id) AS order_count"])
1813 .from("users")
1814 .join("orders", "u.id = o.user_id")
1815 .where_clause("u.active = true")
1816 .and_where("o.created_at > '2024-01-01'")
1817 .group_by(&["u.id", "u.name"])
1818 .having("COUNT(o.id) > 0")
1819 .order_by(&["order_count DESC"])
1820 .limit(10)
1821 .build();
1822
1823 let sql = generate(&query, Dialect::Postgres);
1824 assert!(sql.contains("SELECT"));
1825 assert!(sql.contains("JOIN"));
1826 assert!(sql.contains("WHERE"));
1827 assert!(sql.contains("GROUP BY"));
1828 assert!(sql.contains("HAVING"));
1829 assert!(sql.contains("ORDER BY"));
1830 assert!(sql.contains("LIMIT"));
1831 }
1832
1833 #[test]
1834 fn test_subquery_in_from() {
1835 let inner = select(&["id", "name"])
1836 .from("users")
1837 .where_clause("active = true")
1838 .build();
1839 let outer = select(&["*"]).from_subquery(inner, "active_users").build();
1840
1841 let sql = generate(&outer, Dialect::Ansi);
1842 assert!(sql.contains("FROM (SELECT"));
1843 assert!(sql.contains(") AS active_users"));
1844 }
1845}