1use crate::builder::{self, engine, Expr};
8use crate::dialects::Dialect;
9use crate::error::{Error, Result};
10use crate::expressions::*;
11use crate::generator::NotInStyle;
12use crate::Expression;
13use serde::{Deserialize, Serialize};
14#[cfg(feature = "bindings")]
15use ts_rs::TS;
16
17pub const BUILDER_PROTOCOL_VERSION: u8 = 1;
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
20#[cfg_attr(feature = "bindings", derive(TS))]
21#[serde(tag = "kind", content = "value", rename_all = "snake_case")]
22pub enum BuilderValue {
23 Null,
24 Bool(bool),
25 Integer(#[cfg_attr(feature = "bindings", ts(type = "number"))] i64),
26 Float(f64),
27 String(String),
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
31#[cfg_attr(feature = "bindings", derive(TS))]
32#[serde(rename_all = "snake_case")]
33pub enum BinaryOperator {
34 Eq,
35 Neq,
36 Lt,
37 Lte,
38 Gt,
39 Gte,
40 And,
41 Or,
42 Xor,
43 Add,
44 Sub,
45 Mul,
46 Div,
47 Mod,
48 Like,
49 Ilike,
50 Rlike,
51 Is,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
55#[cfg_attr(feature = "bindings", derive(TS))]
56#[serde(rename_all = "snake_case")]
57pub enum UnaryOperator {
58 Not,
59 Neg,
60 IsNull,
61 IsNotNull,
62}
63
64impl std::convert::From<BinaryOperator> for engine::BinaryKind {
65 fn from(value: BinaryOperator) -> Self {
66 match value {
67 BinaryOperator::Eq => Self::Eq,
68 BinaryOperator::Neq => Self::Neq,
69 BinaryOperator::Lt => Self::Lt,
70 BinaryOperator::Lte => Self::Lte,
71 BinaryOperator::Gt => Self::Gt,
72 BinaryOperator::Gte => Self::Gte,
73 BinaryOperator::And => Self::And,
74 BinaryOperator::Or => Self::Or,
75 BinaryOperator::Xor => Self::Xor,
76 BinaryOperator::Add => Self::Add,
77 BinaryOperator::Sub => Self::Sub,
78 BinaryOperator::Mul => Self::Mul,
79 BinaryOperator::Div => Self::Div,
80 BinaryOperator::Mod => Self::Mod,
81 BinaryOperator::Like => Self::Like,
82 BinaryOperator::Ilike => Self::ILike,
83 BinaryOperator::Rlike => Self::RLike,
84 BinaryOperator::Is => Self::Is,
85 }
86 }
87}
88
89impl std::convert::From<UnaryOperator> for engine::UnaryKind {
90 fn from(value: UnaryOperator) -> Self {
91 match value {
92 UnaryOperator::Not => Self::Not,
93 UnaryOperator::Neg => Self::Neg,
94 UnaryOperator::IsNull => Self::IsNull,
95 UnaryOperator::IsNotNull => Self::IsNotNull,
96 }
97 }
98}
99
100#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
101#[cfg_attr(feature = "bindings", derive(TS))]
102#[serde(rename_all = "snake_case")]
103pub enum JoinType {
104 #[default]
105 Inner,
106 Left,
107 Right,
108 Full,
109 Cross,
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
113#[cfg_attr(feature = "bindings", derive(TS))]
114#[serde(rename_all = "snake_case")]
115pub enum LockType {
116 Update,
117 Share,
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
121#[cfg_attr(feature = "bindings", derive(TS))]
122#[serde(rename_all = "snake_case")]
123pub enum BuiltinFunction {
124 Count,
125 CountStar,
126 CountDistinct,
127 Sum,
128 Avg,
129 Min,
130 Max,
131 ApproxDistinct,
132 Upper,
133 Lower,
134 Length,
135 Trim,
136 Ltrim,
137 Rtrim,
138 Reverse,
139 Initcap,
140 Substring,
141 Replace,
142 ConcatWs,
143 Coalesce,
144 NullIf,
145 IfNull,
146 Abs,
147 Round,
148 Floor,
149 Ceil,
150 Power,
151 Sqrt,
152 Ln,
153 Exp,
154 Sign,
155 Greatest,
156 Least,
157 CurrentDate,
158 CurrentTime,
159 CurrentTimestamp,
160 RowNumber,
161 Rank,
162 DenseRank,
163}
164
165#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
166#[cfg_attr(feature = "bindings", derive(TS))]
167#[serde(tag = "kind", rename_all = "snake_case")]
168pub enum BuildNode {
169 Plan {
170 plan: Box<BuilderPlan>,
171 },
172 Ast {
173 expression: Box<Expression>,
174 },
175 Sql {
176 sql: String,
177 },
178 Literal {
179 value: BuilderValue,
180 },
181 Column {
182 name: String,
183 },
184 Table {
185 name: String,
186 },
187 Star,
188 Function {
189 name: String,
190 args: Vec<BuildNode>,
191 },
192 Builtin {
193 function: BuiltinFunction,
194 #[serde(default)]
195 args: Vec<BuildNode>,
196 },
197 Extract {
198 field: String,
199 expression: Box<BuildNode>,
200 },
201 Binary {
202 op: BinaryOperator,
203 left: Box<BuildNode>,
204 right: Box<BuildNode>,
205 },
206 Unary {
207 op: UnaryOperator,
208 expression: Box<BuildNode>,
209 },
210 Alias {
211 expression: Box<BuildNode>,
212 alias: String,
213 },
214 Cast {
215 expression: Box<BuildNode>,
216 to: String,
217 },
218 Between {
219 expression: Box<BuildNode>,
220 low: Box<BuildNode>,
221 high: Box<BuildNode>,
222 },
223 InList {
224 expression: Box<BuildNode>,
225 values: Vec<BuildNode>,
226 #[serde(default)]
227 negated: bool,
228 },
229 Ordered {
230 expression: Box<BuildNode>,
231 #[serde(default)]
232 desc: bool,
233 },
234 Select {
235 expressions: Vec<BuildNode>,
236 },
237 Case {
238 operand: Option<Box<BuildNode>>,
239 },
240 Update {
241 table: String,
242 #[serde(default)]
243 assignments: Vec<BuilderAssignment>,
244 where_clause: Option<Box<BuildNode>>,
245 from: Option<String>,
246 },
247 Delete {
248 table: String,
249 where_clause: Option<Box<BuildNode>>,
250 },
251 Insert {
252 into: String,
253 expression: Option<Box<BuildNode>>,
254 #[serde(default)]
255 columns: Vec<String>,
256 },
257 Merge {
258 target: String,
259 },
260}
261
262#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
265#[cfg_attr(feature = "bindings", derive(TS))]
266pub struct BuilderPlan {
267 pub base: BuildNode,
268 #[serde(default)]
269 pub operations: Vec<BuildOperation>,
270}
271
272impl BuilderPlan {
273 pub fn new(base: BuildNode) -> Self {
274 Self {
275 base,
276 operations: Vec::new(),
277 }
278 }
279
280 pub fn apply(mut self, operation: BuildOperation) -> Self {
281 self.operations.push(operation);
282 self
283 }
284
285 pub fn into_node(self) -> BuildNode {
286 BuildNode::Plan {
287 plan: Box::new(self),
288 }
289 }
290}
291
292#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
293#[cfg_attr(feature = "bindings", derive(TS))]
294pub struct BuilderAssignment {
295 pub column: String,
296 pub value: BuildNode,
297}
298
299#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
300#[cfg_attr(feature = "bindings", derive(TS))]
301#[serde(tag = "kind", rename_all = "snake_case")]
302pub enum BuildOperation {
303 Select {
304 expressions: Vec<BuildNode>,
305 #[serde(default = "default_true")]
306 append: bool,
307 },
308 From {
309 source: BuildNode,
310 },
311 Join {
312 source: BuildNode,
313 on: Option<BuildNode>,
314 #[serde(default)]
315 join_type: JoinType,
316 },
317 Where {
318 expressions: Vec<BuildNode>,
319 #[serde(default = "default_true")]
320 append: bool,
321 },
322 GroupBy {
323 expressions: Vec<BuildNode>,
324 #[serde(default = "default_true")]
325 append: bool,
326 },
327 Having {
328 expressions: Vec<BuildNode>,
329 #[serde(default = "default_true")]
330 append: bool,
331 },
332 OrderBy {
333 expressions: Vec<BuildNode>,
334 #[serde(default = "default_true")]
335 append: bool,
336 },
337 SortBy {
338 expressions: Vec<BuildNode>,
339 #[serde(default = "default_true")]
340 append: bool,
341 },
342 Limit {
343 expression: BuildNode,
344 },
345 Offset {
346 expression: BuildNode,
347 },
348 Distinct {
349 #[serde(default = "default_true")]
350 enabled: bool,
351 },
352 Qualify {
353 expressions: Vec<BuildNode>,
354 #[serde(default = "default_true")]
355 append: bool,
356 },
357 LateralView {
358 expression: BuildNode,
359 table_alias: Option<String>,
360 #[serde(default)]
361 column_aliases: Vec<String>,
362 #[serde(default)]
363 outer: bool,
364 },
365 Window {
366 name: String,
367 #[serde(default)]
368 partition_by: Vec<BuildNode>,
369 #[serde(default)]
370 order_by: Vec<BuildNode>,
371 },
372 Lock {
373 lock_type: LockType,
374 },
375 Hint {
376 text: String,
377 },
378 Ctas {
379 table: String,
380 #[serde(default)]
381 replace: bool,
382 #[serde(default)]
383 temporary: bool,
384 },
385 Subquery {
386 alias: Option<String>,
387 },
388 Union {
389 other: BuildNode,
390 #[serde(default = "default_true")]
391 distinct: bool,
392 },
393 Intersect {
394 other: BuildNode,
395 #[serde(default = "default_true")]
396 distinct: bool,
397 },
398 Except {
399 other: BuildNode,
400 #[serde(default = "default_true")]
401 distinct: bool,
402 },
403 When {
404 condition: BuildNode,
405 result: BuildNode,
406 },
407 Else {
408 result: BuildNode,
409 },
410 Set {
411 assignments: Vec<BuilderAssignment>,
412 },
413 InsertColumns {
414 columns: Vec<String>,
415 },
416 Values {
417 rows: Vec<Vec<BuildNode>>,
418 #[serde(default = "default_true")]
419 append: bool,
420 },
421 Query {
422 query: BuildNode,
423 },
424 MergeUsing {
425 source: BuildNode,
426 on: BuildNode,
427 },
428 WhenMatchedUpdate {
429 assignments: Vec<BuilderAssignment>,
430 condition: Option<BuildNode>,
431 },
432 WhenMatchedDelete {
433 condition: Option<BuildNode>,
434 },
435 WhenNotMatchedInsert {
436 columns: Vec<String>,
437 values: Vec<BuildNode>,
438 condition: Option<BuildNode>,
439 },
440}
441
442fn default_true() -> bool {
443 true
444}
445
446#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
447#[cfg_attr(feature = "bindings", derive(TS))]
448#[serde(tag = "kind", rename_all = "snake_case")]
449pub enum BuilderOutput {
450 Ast,
451 Sql {
452 #[serde(default = "generic_dialect")]
453 dialect: String,
454 },
455}
456
457fn generic_dialect() -> String {
458 "generic".to_string()
459}
460
461#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
462#[cfg_attr(feature = "bindings", derive(TS))]
463pub struct BuildRequest {
464 #[serde(default = "protocol_version")]
465 pub version: u8,
466 #[serde(default = "generic_dialect")]
467 pub read_dialect: String,
468 pub plan: BuilderPlan,
469 #[serde(default = "ast_output")]
470 pub output: BuilderOutput,
471}
472
473fn protocol_version() -> u8 {
474 BUILDER_PROTOCOL_VERSION
475}
476
477fn ast_output() -> BuilderOutput {
478 BuilderOutput::Ast
479}
480
481#[derive(Debug, Clone, PartialEq)]
482pub enum BuildResult {
483 Ast(Expression),
484 Sql(String),
485}
486
487pub fn execute(request: &BuildRequest) -> Result<BuildResult> {
488 if request.version != BUILDER_PROTOCOL_VERSION {
489 return Err(Error::invalid_input(format!(
490 "unsupported builder protocol version {}; expected {}",
491 request.version, BUILDER_PROTOCOL_VERSION
492 )));
493 }
494 let expression = evaluate(&request.plan, &request.read_dialect)?;
495 match &request.output {
496 BuilderOutput::Ast => Ok(BuildResult::Ast(expression)),
497 BuilderOutput::Sql { dialect } => {
498 let dialect = resolve_dialect(dialect)?;
499 dialect
500 .generate_with_overrides(&expression, |config| {
501 config.not_in_style = NotInStyle::Infix;
502 })
503 .map(BuildResult::Sql)
504 }
505 }
506}
507
508pub fn evaluate(plan: &BuilderPlan, read_dialect: &str) -> Result<Expression> {
509 Evaluator::new(read_dialect)?.evaluate_plan(plan)
510}
511
512struct Evaluator {
513 dialect: Dialect,
514}
515
516impl Evaluator {
517 fn new(name: &str) -> Result<Self> {
518 Ok(Self {
519 dialect: resolve_dialect(name)?,
520 })
521 }
522
523 fn evaluate_plan(&self, plan: &BuilderPlan) -> Result<Expression> {
524 let mut expression = if matches!(
525 plan.operations.first(),
526 Some(
527 BuildOperation::Union { .. }
528 | BuildOperation::Intersect { .. }
529 | BuildOperation::Except { .. }
530 )
531 ) {
532 self.evaluate_query(&plan.base)?
533 } else {
534 self.evaluate_node(&plan.base)?
535 };
536 for operation in &plan.operations {
537 if matches!(
538 operation,
539 BuildOperation::Union { .. }
540 | BuildOperation::Intersect { .. }
541 | BuildOperation::Except { .. }
542 ) && !engine::is_query(&expression)
543 {
544 return Err(Error::invalid_input(
545 "set operations require query expressions",
546 ));
547 }
548 expression = self.apply(expression, operation)?;
549 }
550 Ok(expression)
551 }
552
553 fn evaluate_node(&self, node: &BuildNode) -> Result<Expression> {
554 match node {
555 BuildNode::Plan { plan } => self.evaluate_plan(plan),
556 BuildNode::Ast { expression } => Ok((**expression).clone()),
557 BuildNode::Sql { sql } => self.parse_expression(sql),
558 BuildNode::Literal { value } => Ok(match value {
559 BuilderValue::Null => builder::null().into_inner(),
560 BuilderValue::Bool(value) => builder::boolean(*value).into_inner(),
561 BuilderValue::Integer(value) => builder::lit(*value).into_inner(),
562 BuilderValue::Float(value) => builder::lit(*value).into_inner(),
563 BuilderValue::String(value) => builder::lit(value.as_str()).into_inner(),
564 }),
565 BuildNode::Column { name } => Ok(builder::col(name).into_inner()),
566 BuildNode::Table { name } => Ok(builder::table(name).into_inner()),
567 BuildNode::Star => Ok(builder::star().into_inner()),
568 BuildNode::Function { name, args } => {
569 let args = args
570 .iter()
571 .map(|arg| self.evaluate_node(arg).map(Expr))
572 .collect::<Result<Vec<_>>>()?;
573 Ok(builder::func(name, args).into_inner())
574 }
575 BuildNode::Builtin { function, args } => {
576 let args = args
577 .iter()
578 .map(|arg| self.evaluate_node(arg).map(Expr))
579 .collect::<Result<Vec<_>>>()?;
580 self.builtin(*function, args)
581 }
582 BuildNode::Extract { field, expression } => {
583 Ok(builder::extract_(field, Expr(self.evaluate_node(expression)?)).into_inner())
584 }
585 BuildNode::Binary { op, left, right } => Ok(engine::binary(
586 (*op).into(),
587 self.evaluate_node(left)?,
588 self.evaluate_node(right)?,
589 )),
590 BuildNode::Unary { op, expression } => {
591 Ok(engine::unary((*op).into(), self.evaluate_node(expression)?))
592 }
593 BuildNode::Alias { expression, alias } => {
594 Ok(builder::alias(Expr(self.evaluate_node(expression)?), alias).into_inner())
595 }
596 BuildNode::Cast { expression, to } => {
597 Ok(builder::cast(Expr(self.evaluate_node(expression)?), to).into_inner())
598 }
599 BuildNode::Between {
600 expression,
601 low,
602 high,
603 } => Ok(Expr(self.evaluate_node(expression)?)
604 .between(
605 Expr(self.evaluate_node(low)?),
606 Expr(self.evaluate_node(high)?),
607 )
608 .into_inner()),
609 BuildNode::InList {
610 expression,
611 values,
612 negated,
613 } => {
614 let values = values
615 .iter()
616 .map(|v| self.evaluate_node(v).map(Expr))
617 .collect::<Result<Vec<_>>>()?;
618 let expr = Expr(self.evaluate_node(expression)?);
619 Ok(if *negated {
620 expr.not_in(values)
621 } else {
622 expr.in_list(values)
623 }
624 .into_inner())
625 }
626 BuildNode::Ordered { expression, desc } => {
627 let expr = Expr(self.evaluate_node(expression)?);
628 Ok(if *desc { expr.desc() } else { expr.asc() }.into_inner())
629 }
630 BuildNode::Select { expressions } => {
631 let expressions = self.evaluate_expression_list(expressions)?;
632 Ok(Expression::Select(Box::new(Select {
633 expressions,
634 ..Select::new()
635 })))
636 }
637 BuildNode::Case { operand } => Ok(engine::case(
638 operand
639 .as_deref()
640 .map(|value| self.evaluate_node(value))
641 .transpose()?,
642 )),
643 BuildNode::Update {
644 table,
645 assignments,
646 where_clause,
647 from,
648 } => {
649 let mut expression = builder::update(table).build();
650 engine::append_update_assignments(
651 &mut expression,
652 self.evaluate_assignments(assignments)?,
653 )?;
654 if let Some(where_clause) = where_clause {
655 engine::apply_where(&mut expression, self.evaluate_node(where_clause)?, false)?;
656 }
657 if let Some(from) = from {
658 engine::set_from(&mut expression, self.parse_from(from)?)?;
659 }
660 Ok(expression)
661 }
662 BuildNode::Delete {
663 table,
664 where_clause,
665 } => {
666 let mut expression = builder::delete(table).build();
667 if let Some(where_clause) = where_clause {
668 engine::apply_where(&mut expression, self.evaluate_node(where_clause)?, false)?;
669 }
670 Ok(expression)
671 }
672 BuildNode::Insert {
673 into,
674 expression,
675 columns,
676 } => {
677 let mut result = builder::insert_into(into).columns(columns).build();
678 if let Some(expression) = expression {
679 let source = match expression.as_ref() {
680 BuildNode::Sql { sql } => self.parse_statement(sql)?,
681 node => self.evaluate_node(node)?,
682 };
683 match source {
684 Expression::Values(values) => engine::apply_insert_values(
685 &mut result,
686 values
687 .expressions
688 .into_iter()
689 .map(|tuple| tuple.expressions)
690 .collect(),
691 false,
692 )?,
693 query => engine::set_insert_query(&mut result, query)?,
694 }
695 }
696 Ok(result)
697 }
698 BuildNode::Merge { target } => Ok(engine::merge(builder::table(target).into_inner())),
699 }
700 }
701
702 fn apply(&self, mut expression: Expression, operation: &BuildOperation) -> Result<Expression> {
703 match operation {
704 BuildOperation::Select {
705 expressions,
706 append,
707 } => {
708 let values = self.evaluate_expression_list(expressions)?;
709 engine::append_select(&mut expression, values, *append)?;
710 }
711 BuildOperation::From { source } => {
712 let values = self.evaluate_source(source)?;
713 engine::set_from(&mut expression, values)?;
714 }
715 BuildOperation::Join {
716 source,
717 on,
718 join_type,
719 } => {
720 let source = self
721 .evaluate_source(source)?
722 .into_iter()
723 .next()
724 .ok_or_else(|| Error::invalid_input("join source is empty"))?;
725 let on = on
726 .as_ref()
727 .map(|value| self.evaluate_node(value))
728 .transpose()?;
729 let kind = match join_type {
730 JoinType::Inner => JoinKind::Inner,
731 JoinType::Left => JoinKind::Left,
732 JoinType::Right => JoinKind::Right,
733 JoinType::Full => JoinKind::Full,
734 JoinType::Cross => JoinKind::Cross,
735 };
736 engine::append_join(
737 &mut expression,
738 Join {
739 this: source,
740 on,
741 using: Vec::new(),
742 kind,
743 use_inner_keyword: false,
744 use_outer_keyword: false,
745 deferred_condition: false,
746 join_hint: None,
747 match_condition: None,
748 pivots: Vec::new(),
749 comments: Vec::new(),
750 nesting_group: 0,
751 directed: false,
752 },
753 )?;
754 }
755 BuildOperation::Where {
756 expressions,
757 append,
758 } => {
759 let condition = self.combine_conditions(expressions)?;
760 engine::apply_where(&mut expression, condition, *append)?;
761 }
762 BuildOperation::GroupBy {
763 expressions,
764 append,
765 } => {
766 let values = self.evaluate_expression_list(expressions)?;
767 engine::apply_group_by(&mut expression, values, *append)?;
768 }
769 BuildOperation::Having {
770 expressions,
771 append,
772 } => {
773 let condition = self.combine_conditions(expressions)?;
774 engine::apply_having(&mut expression, condition, *append)?;
775 }
776 BuildOperation::OrderBy {
777 expressions,
778 append,
779 } => {
780 let values = self.evaluate_ordered_list(expressions)?;
781 engine::apply_order_by(&mut expression, values, *append)?;
782 }
783 BuildOperation::SortBy {
784 expressions,
785 append,
786 } => {
787 let values = self.evaluate_ordered_list(expressions)?;
788 engine::apply_sort_by(&mut expression, values, *append)?;
789 }
790 BuildOperation::Limit { expression: value } => {
791 engine::apply_limit(&mut expression, self.evaluate_node(value)?)?
792 }
793 BuildOperation::Offset { expression: value } => {
794 engine::apply_offset(&mut expression, self.evaluate_node(value)?)?
795 }
796 BuildOperation::Distinct { enabled } => {
797 engine::apply_distinct(&mut expression, *enabled)?
798 }
799 BuildOperation::Qualify {
800 expressions,
801 append,
802 } => {
803 let condition = self.combine_conditions(expressions)?;
804 engine::apply_qualify(&mut expression, condition, *append)?;
805 }
806 BuildOperation::LateralView {
807 expression: value,
808 table_alias,
809 column_aliases,
810 outer,
811 } => {
812 engine::append_lateral_view(
813 &mut expression,
814 self.evaluate_node(value)?,
815 table_alias.as_deref().map(Identifier::new),
816 column_aliases
817 .iter()
818 .map(|alias| Identifier::new(alias))
819 .collect(),
820 *outer,
821 )?;
822 }
823 BuildOperation::Window {
824 name,
825 partition_by,
826 order_by,
827 } => {
828 engine::append_window(
829 &mut expression,
830 Identifier::new(name),
831 self.evaluate_expression_list(partition_by)?,
832 self.evaluate_ordered_list(order_by)?,
833 )?;
834 }
835 BuildOperation::Lock { lock_type } => {
836 engine::append_lock(
837 &mut expression,
838 match lock_type {
839 LockType::Update => engine::LockKind::Update,
840 LockType::Share => engine::LockKind::Share,
841 },
842 )?;
843 }
844 BuildOperation::Hint { text } => {
845 engine::append_hint(&mut expression, text.clone())?;
846 }
847 BuildOperation::Ctas {
848 table,
849 replace,
850 temporary,
851 } => {
852 let table = match builder::table(table).into_inner() {
853 Expression::Table(table) => *table,
854 _ => unreachable!("builder::table returns a table"),
855 };
856 expression = engine::create_table_as(expression, table, *replace, *temporary)?;
857 }
858 BuildOperation::Subquery { alias } => {
859 expression =
860 engine::subquery(expression, alias.as_ref().map(Identifier::new), false)?;
861 }
862 BuildOperation::Union { other, distinct } => {
863 expression = engine::set_operation(
864 engine::SetKind::Union,
865 expression,
866 self.evaluate_query(other)?,
867 *distinct,
868 )?
869 }
870 BuildOperation::Intersect { other, distinct } => {
871 expression = engine::set_operation(
872 engine::SetKind::Intersect,
873 expression,
874 self.evaluate_query(other)?,
875 *distinct,
876 )?
877 }
878 BuildOperation::Except { other, distinct } => {
879 expression = engine::set_operation(
880 engine::SetKind::Except,
881 expression,
882 self.evaluate_query(other)?,
883 *distinct,
884 )?
885 }
886 BuildOperation::When { condition, result } => {
887 let condition = self.evaluate_node(condition)?;
888 let result = self.evaluate_node(result)?;
889 engine::append_case_when(&mut expression, condition, result)?;
890 }
891 BuildOperation::Else { result } => {
892 let result = self.evaluate_node(result)?;
893 engine::set_case_else(&mut expression, result)?;
894 }
895 BuildOperation::Set { assignments } => {
896 let values = self.evaluate_assignments(assignments)?;
897 engine::append_update_assignments(&mut expression, values)?;
898 }
899 BuildOperation::InsertColumns { columns } => engine::set_insert_columns(
900 &mut expression,
901 columns.iter().map(Identifier::new).collect(),
902 )?,
903 BuildOperation::Values { rows, append } => {
904 let evaluated = rows
905 .iter()
906 .map(|row| self.evaluate_expression_list(row))
907 .collect::<Result<Vec<_>>>()?;
908 engine::apply_insert_values(&mut expression, evaluated, *append)?;
909 }
910 BuildOperation::Query { query } => {
911 let query = self.evaluate_query(query)?;
912 engine::set_insert_query(&mut expression, query)?;
913 }
914 BuildOperation::MergeUsing { source, on } => {
915 engine::set_merge_using(
916 &mut expression,
917 self.evaluate_source(source)?
918 .into_iter()
919 .next()
920 .ok_or_else(|| Error::invalid_input("merge source is empty"))?,
921 self.evaluate_node(on)?,
922 )?;
923 }
924 BuildOperation::WhenMatchedUpdate {
925 assignments,
926 condition,
927 } => {
928 engine::append_merge_update(
929 &mut expression,
930 self.evaluate_assignments(assignments)?,
931 condition
932 .as_ref()
933 .map(|value| self.evaluate_node(value))
934 .transpose()?,
935 )?;
936 }
937 BuildOperation::WhenMatchedDelete { condition } => {
938 engine::append_merge_delete(
939 &mut expression,
940 condition
941 .as_ref()
942 .map(|value| self.evaluate_node(value))
943 .transpose()?,
944 )?;
945 }
946 BuildOperation::WhenNotMatchedInsert {
947 columns,
948 values,
949 condition,
950 } => {
951 engine::append_merge_insert(
952 &mut expression,
953 columns.iter().map(Identifier::new).collect(),
954 self.evaluate_expression_list(values)?,
955 condition
956 .as_ref()
957 .map(|value| self.evaluate_node(value))
958 .transpose()?,
959 )?;
960 }
961 }
962 Ok(expression)
963 }
964
965 fn builtin(&self, function: BuiltinFunction, mut args: Vec<Expr>) -> Result<Expression> {
966 let name = format!("{function:?}");
967 let exact = |args: &mut Vec<Expr>, count: usize| -> Result<Vec<Expr>> {
968 if args.len() != count {
969 return Err(Error::invalid_input(format!(
970 "{name} expects {count} argument(s), got {}",
971 args.len()
972 )));
973 }
974 Ok(std::mem::take(args))
975 };
976 let one = |args: &mut Vec<Expr>| -> Result<Expr> {
977 Ok(exact(args, 1)?.pop().expect("one validated argument"))
978 };
979
980 let result = match function {
981 BuiltinFunction::Count => builder::count(one(&mut args)?),
982 BuiltinFunction::CountStar => {
983 exact(&mut args, 0)?;
984 builder::count_star()
985 }
986 BuiltinFunction::CountDistinct => builder::count_distinct(one(&mut args)?),
987 BuiltinFunction::Sum => builder::sum(one(&mut args)?),
988 BuiltinFunction::Avg => builder::avg(one(&mut args)?),
989 BuiltinFunction::Min => builder::min_(one(&mut args)?),
990 BuiltinFunction::Max => builder::max_(one(&mut args)?),
991 BuiltinFunction::ApproxDistinct => builder::approx_distinct(one(&mut args)?),
992 BuiltinFunction::Upper => builder::upper(one(&mut args)?),
993 BuiltinFunction::Lower => builder::lower(one(&mut args)?),
994 BuiltinFunction::Length => builder::length(one(&mut args)?),
995 BuiltinFunction::Trim => builder::trim(one(&mut args)?),
996 BuiltinFunction::Ltrim => builder::ltrim(one(&mut args)?),
997 BuiltinFunction::Rtrim => builder::rtrim(one(&mut args)?),
998 BuiltinFunction::Reverse => builder::reverse(one(&mut args)?),
999 BuiltinFunction::Initcap => builder::initcap(one(&mut args)?),
1000 BuiltinFunction::Substring => match args.len() {
1001 2 => {
1002 let mut args = exact(&mut args, 2)?;
1003 let start = args.pop().expect("start argument");
1004 builder::substring(args.pop().expect("value argument"), start, None)
1005 }
1006 3 => {
1007 let mut args = exact(&mut args, 3)?;
1008 let length = args.pop().expect("length argument");
1009 let start = args.pop().expect("start argument");
1010 builder::substring(args.pop().expect("value argument"), start, Some(length))
1011 }
1012 count => {
1013 return Err(Error::invalid_input(format!(
1014 "Substring expects 2 or 3 arguments, got {count}"
1015 )))
1016 }
1017 },
1018 BuiltinFunction::Replace => {
1019 let mut args = exact(&mut args, 3)?;
1020 let new = args.pop().expect("new argument");
1021 let old = args.pop().expect("old argument");
1022 builder::replace_(args.pop().expect("value argument"), old, new)
1023 }
1024 BuiltinFunction::ConcatWs => {
1025 if args.is_empty() {
1026 return Err(Error::invalid_input(
1027 "ConcatWs expects at least one argument",
1028 ));
1029 }
1030 let values = args.split_off(1);
1031 builder::concat_ws(args.pop().expect("separator argument"), values)
1032 }
1033 BuiltinFunction::Coalesce => builder::coalesce(args),
1034 BuiltinFunction::NullIf => {
1035 let mut args = exact(&mut args, 2)?;
1036 let right = args.pop().expect("right argument");
1037 builder::null_if(args.pop().expect("left argument"), right)
1038 }
1039 BuiltinFunction::IfNull => {
1040 let mut args = exact(&mut args, 2)?;
1041 let fallback = args.pop().expect("fallback argument");
1042 builder::if_null(args.pop().expect("value argument"), fallback)
1043 }
1044 BuiltinFunction::Abs => builder::abs(one(&mut args)?),
1045 BuiltinFunction::Round => match args.len() {
1046 1 => builder::round(one(&mut args)?, None),
1047 2 => {
1048 let mut args = exact(&mut args, 2)?;
1049 let decimals = args.pop().expect("decimals argument");
1050 builder::round(args.pop().expect("value argument"), Some(decimals))
1051 }
1052 count => {
1053 return Err(Error::invalid_input(format!(
1054 "Round expects 1 or 2 arguments, got {count}"
1055 )))
1056 }
1057 },
1058 BuiltinFunction::Floor => builder::floor(one(&mut args)?),
1059 BuiltinFunction::Ceil => builder::ceil(one(&mut args)?),
1060 BuiltinFunction::Power => {
1061 let mut args = exact(&mut args, 2)?;
1062 let exponent = args.pop().expect("exponent argument");
1063 builder::power(args.pop().expect("base argument"), exponent)
1064 }
1065 BuiltinFunction::Sqrt => builder::sqrt(one(&mut args)?),
1066 BuiltinFunction::Ln => builder::ln(one(&mut args)?),
1067 BuiltinFunction::Exp => builder::exp_(one(&mut args)?),
1068 BuiltinFunction::Sign => builder::sign(one(&mut args)?),
1069 BuiltinFunction::Greatest => builder::greatest(args),
1070 BuiltinFunction::Least => builder::least(args),
1071 BuiltinFunction::CurrentDate => {
1072 exact(&mut args, 0)?;
1073 builder::current_date_()
1074 }
1075 BuiltinFunction::CurrentTime => {
1076 exact(&mut args, 0)?;
1077 builder::current_time_()
1078 }
1079 BuiltinFunction::CurrentTimestamp => {
1080 exact(&mut args, 0)?;
1081 builder::current_timestamp_()
1082 }
1083 BuiltinFunction::RowNumber => {
1084 exact(&mut args, 0)?;
1085 builder::row_number()
1086 }
1087 BuiltinFunction::Rank => {
1088 exact(&mut args, 0)?;
1089 builder::rank_()
1090 }
1091 BuiltinFunction::DenseRank => {
1092 exact(&mut args, 0)?;
1093 builder::dense_rank()
1094 }
1095 };
1096 Ok(result.into_inner())
1097 }
1098
1099 fn parse_expression(&self, sql: &str) -> Result<Expression> {
1100 self.parse_expression_list(sql)?
1101 .into_iter()
1102 .next()
1103 .ok_or_else(|| Error::invalid_input("SQL expression is empty"))
1104 }
1105
1106 fn parse_statement(&self, sql: &str) -> Result<Expression> {
1107 let mut statements = self.dialect.parse(sql)?;
1108 if statements.len() != 1 {
1109 return Err(Error::invalid_input(
1110 "builder SQL must contain exactly one statement",
1111 ));
1112 }
1113 Ok(statements.remove(0))
1114 }
1115
1116 fn evaluate_query(&self, node: &BuildNode) -> Result<Expression> {
1117 let expression = match node {
1118 BuildNode::Sql { sql } => self.parse_statement(sql)?,
1119 _ => self.evaluate_node(node)?,
1120 };
1121 if engine::is_query(&expression) {
1122 Ok(expression)
1123 } else {
1124 Err(Error::invalid_input(
1125 "set operations require query expressions",
1126 ))
1127 }
1128 }
1129
1130 fn parse_expression_list(&self, sql: &str) -> Result<Vec<Expression>> {
1131 let statements = self.dialect.parse(&format!("SELECT {sql}"))?;
1132 match statements.into_iter().next() {
1133 Some(Expression::Select(select)) => Ok(select.expressions),
1134 _ => Err(Error::invalid_input(
1135 "failed to parse SQL expression fragment",
1136 )),
1137 }
1138 }
1139
1140 fn parse_from(&self, sql: &str) -> Result<Vec<Expression>> {
1141 let statements = self.dialect.parse(&format!("SELECT * FROM {sql}"))?;
1142 match statements.into_iter().next() {
1143 Some(Expression::Select(select)) => select
1144 .from
1145 .map(|from| from.expressions)
1146 .ok_or_else(|| Error::invalid_input("failed to parse FROM fragment")),
1147 _ => Err(Error::invalid_input("failed to parse FROM fragment")),
1148 }
1149 }
1150
1151 fn parse_ordered(&self, sql: &str) -> Result<Vec<Ordered>> {
1152 let statements = self.dialect.parse(&format!(
1153 "SELECT * FROM __polyglot_builder__ ORDER BY {sql}"
1154 ))?;
1155 match statements.into_iter().next() {
1156 Some(Expression::Select(select)) => select
1157 .order_by
1158 .map(|order| order.expressions)
1159 .ok_or_else(|| Error::invalid_input("failed to parse ORDER BY fragment")),
1160 _ => Err(Error::invalid_input("failed to parse ORDER BY fragment")),
1161 }
1162 }
1163
1164 fn evaluate_expression_list(&self, values: &[BuildNode]) -> Result<Vec<Expression>> {
1165 let mut result = Vec::new();
1166 for value in values {
1167 match value {
1168 BuildNode::Sql { sql } => result.extend(self.parse_expression_list(sql)?),
1169 _ => result.push(self.evaluate_node(value)?),
1170 }
1171 }
1172 Ok(result)
1173 }
1174
1175 fn evaluate_ordered_list(&self, values: &[BuildNode]) -> Result<Vec<Ordered>> {
1176 let mut result = Vec::new();
1177 for value in values {
1178 match value {
1179 BuildNode::Sql { sql } => result.extend(self.parse_ordered(sql)?),
1180 _ => match self.evaluate_node(value)? {
1181 Expression::Ordered(ordered) => result.push(*ordered),
1182 expression => result.push(engine::ordered(expression)),
1183 },
1184 }
1185 }
1186 Ok(result)
1187 }
1188
1189 fn evaluate_source(&self, value: &BuildNode) -> Result<Vec<Expression>> {
1190 match value {
1191 BuildNode::Sql { sql } => self.parse_from(sql),
1192 BuildNode::Table { name } => Ok(vec![builder::table(name).into_inner()]),
1193 _ => Ok(vec![self.evaluate_node(value)?]),
1194 }
1195 }
1196
1197 fn combine_conditions(&self, values: &[BuildNode]) -> Result<Expression> {
1198 let mut values = values.iter();
1199 let first = values
1200 .next()
1201 .ok_or_else(|| Error::invalid_input("at least one condition is required"))?;
1202 let mut result = self.evaluate_node(first)?;
1203 for value in values {
1204 result = engine::binary(engine::BinaryKind::And, result, self.evaluate_node(value)?);
1205 }
1206 Ok(result)
1207 }
1208
1209 fn evaluate_assignments(
1210 &self,
1211 assignments: &[BuilderAssignment],
1212 ) -> Result<Vec<(Identifier, Expression)>> {
1213 assignments
1214 .iter()
1215 .map(|assignment| {
1216 Ok((
1217 Identifier::new(&assignment.column),
1218 self.evaluate_node(&assignment.value)?,
1219 ))
1220 })
1221 .collect()
1222 }
1223}
1224
1225fn resolve_dialect(name: &str) -> Result<Dialect> {
1226 Dialect::get_by_name(if name.is_empty() { "generic" } else { name })
1227 .ok_or_else(|| Error::invalid_input(format!("unknown dialect: {name}")))
1228}
1229
1230#[cfg(test)]
1231mod tests {
1232 use super::*;
1233
1234 #[test]
1235 #[cfg(feature = "bindings")]
1236 fn export_typescript_types_builder_protocol() {
1237 BuildRequest::export_all(&ts_rs::Config::default())
1238 .expect("failed to export builder protocol types");
1239 }
1240
1241 fn sql(plan: BuilderPlan) -> String {
1242 match execute(&BuildRequest {
1243 version: 1,
1244 read_dialect: "generic".into(),
1245 plan,
1246 output: BuilderOutput::Sql {
1247 dialect: "generic".into(),
1248 },
1249 })
1250 .unwrap()
1251 {
1252 BuildResult::Sql(sql) => sql,
1253 _ => unreachable!(),
1254 }
1255 }
1256
1257 #[test]
1258 fn builds_sqlglot_style_select() {
1259 let query = BuilderPlan::new(BuildNode::Select {
1260 expressions: vec![BuildNode::Sql {
1261 sql: "x, COUNT(*) AS n".into(),
1262 }],
1263 })
1264 .apply(BuildOperation::From {
1265 source: BuildNode::Sql {
1266 sql: "events".into(),
1267 },
1268 })
1269 .apply(BuildOperation::Where {
1270 expressions: vec![BuildNode::Sql {
1271 sql: "active = TRUE".into(),
1272 }],
1273 append: true,
1274 });
1275 assert_eq!(
1276 sql(query),
1277 "SELECT x, COUNT(*) AS n FROM events WHERE active = TRUE"
1278 );
1279 }
1280
1281 #[test]
1282 fn appends_conditions_without_mutating_the_original_plan() {
1283 let base = BuilderPlan::new(BuildNode::Select {
1284 expressions: vec![BuildNode::Sql { sql: "x".into() }],
1285 })
1286 .apply(BuildOperation::Where {
1287 expressions: vec![BuildNode::Sql {
1288 sql: "x > 0".into(),
1289 }],
1290 append: true,
1291 });
1292 let appended = base.clone().apply(BuildOperation::Where {
1293 expressions: vec![BuildNode::Sql {
1294 sql: "x < 9".into(),
1295 }],
1296 append: true,
1297 });
1298 assert_eq!(sql(base), "SELECT x WHERE x > 0");
1299 assert_eq!(sql(appended), "SELECT x WHERE x > 0 AND x < 9");
1300 }
1301
1302 #[test]
1303 fn distinguishes_sql_and_literal_strings() {
1304 let comparison = BuildNode::Binary {
1305 op: BinaryOperator::Eq,
1306 left: Box::new(BuildNode::Column {
1307 name: "status".into(),
1308 }),
1309 right: Box::new(BuildNode::Literal {
1310 value: BuilderValue::String("active".into()),
1311 }),
1312 };
1313 assert_eq!(sql(BuilderPlan::new(comparison)), "status = 'active'");
1314
1315 let not_in = BuildNode::InList {
1316 expression: Box::new(BuildNode::Column { name: "x".into() }),
1317 values: vec![
1318 BuildNode::Literal {
1319 value: BuilderValue::Integer(1),
1320 },
1321 BuildNode::Literal {
1322 value: BuilderValue::Integer(2),
1323 },
1324 ],
1325 negated: true,
1326 };
1327 assert_eq!(sql(BuilderPlan::new(not_in)), "x NOT IN (1, 2)");
1328 }
1329
1330 #[test]
1331 fn parses_full_query_strings_in_query_contexts() {
1332 let union = BuilderPlan::new(BuildNode::Sql {
1333 sql: "SELECT id".into(),
1334 })
1335 .apply(BuildOperation::Union {
1336 other: BuildNode::Sql {
1337 sql: "SELECT id FROM archive".into(),
1338 },
1339 distinct: false,
1340 });
1341 assert_eq!(sql(union), "SELECT id UNION ALL SELECT id FROM archive");
1342
1343 let insert = BuildNode::Insert {
1344 into: "users".into(),
1345 expression: Some(Box::new(BuildNode::Sql {
1346 sql: "SELECT id FROM staging".into(),
1347 })),
1348 columns: vec!["id".into()],
1349 };
1350 assert_eq!(
1351 sql(BuilderPlan::new(insert)),
1352 "INSERT INTO users (id) SELECT id FROM staging"
1353 );
1354 }
1355
1356 #[test]
1357 fn supports_typed_builtins_and_advanced_query_operations() {
1358 let plan = BuilderPlan::new(BuildNode::Select {
1359 expressions: vec![
1360 BuildNode::Column {
1361 name: "department".into(),
1362 },
1363 BuildNode::Alias {
1364 expression: Box::new(BuildNode::Builtin {
1365 function: BuiltinFunction::Count,
1366 args: vec![BuildNode::Column { name: "id".into() }],
1367 }),
1368 alias: "employees".into(),
1369 },
1370 ],
1371 })
1372 .apply(BuildOperation::From {
1373 source: BuildNode::Table {
1374 name: "employees".into(),
1375 },
1376 })
1377 .apply(BuildOperation::Join {
1378 source: BuildNode::Table {
1379 name: "departments".into(),
1380 },
1381 on: Some(BuildNode::Sql {
1382 sql: "employees.department_id = departments.id".into(),
1383 }),
1384 join_type: JoinType::Full,
1385 })
1386 .apply(BuildOperation::Window {
1387 name: "w".into(),
1388 partition_by: vec![BuildNode::Column {
1389 name: "department".into(),
1390 }],
1391 order_by: vec![BuildNode::Ordered {
1392 expression: Box::new(BuildNode::Column {
1393 name: "salary".into(),
1394 }),
1395 desc: true,
1396 }],
1397 })
1398 .apply(BuildOperation::Lock {
1399 lock_type: LockType::Share,
1400 });
1401
1402 assert_eq!(
1403 sql(plan),
1404 "SELECT department, COUNT(id) AS employees FROM employees FULL JOIN departments ON employees.department_id = departments.id WINDOW w AS (PARTITION BY department ORDER BY salary DESC) FOR SHARE"
1405 );
1406 }
1407
1408 #[test]
1409 fn repeated_clauses_append_by_default_and_can_replace() {
1410 let base = BuilderPlan::new(BuildNode::Select {
1411 expressions: vec![BuildNode::Column { name: "x".into() }],
1412 })
1413 .apply(BuildOperation::Where {
1414 expressions: vec![BuildNode::Sql {
1415 sql: "x > 0".into(),
1416 }],
1417 append: true,
1418 });
1419 let appended = base.clone().apply(BuildOperation::Where {
1420 expressions: vec![BuildNode::Sql {
1421 sql: "x < 10".into(),
1422 }],
1423 append: true,
1424 });
1425 let replaced = base.apply(BuildOperation::Where {
1426 expressions: vec![BuildNode::Sql {
1427 sql: "x = 5".into(),
1428 }],
1429 append: false,
1430 });
1431
1432 assert_eq!(sql(appended), "SELECT x WHERE x > 0 AND x < 10");
1433 assert_eq!(sql(replaced), "SELECT x WHERE x = 5");
1434 }
1435
1436 #[test]
1437 fn supports_conditional_merge_actions() {
1438 let plan = BuilderPlan::new(BuildNode::Merge {
1439 target: "target".into(),
1440 })
1441 .apply(BuildOperation::MergeUsing {
1442 source: BuildNode::Table {
1443 name: "source".into(),
1444 },
1445 on: BuildNode::Sql {
1446 sql: "target.id = source.id".into(),
1447 },
1448 })
1449 .apply(BuildOperation::WhenMatchedUpdate {
1450 assignments: vec![BuilderAssignment {
1451 column: "name".into(),
1452 value: BuildNode::Column {
1453 name: "source.name".into(),
1454 },
1455 }],
1456 condition: Some(BuildNode::Sql {
1457 sql: "source.active".into(),
1458 }),
1459 })
1460 .apply(BuildOperation::WhenMatchedDelete {
1461 condition: Some(BuildNode::Sql {
1462 sql: "source.deleted".into(),
1463 }),
1464 })
1465 .apply(BuildOperation::WhenNotMatchedInsert {
1466 columns: vec!["id".into()],
1467 values: vec![BuildNode::Column {
1468 name: "source.id".into(),
1469 }],
1470 condition: Some(BuildNode::Sql {
1471 sql: "source.active".into(),
1472 }),
1473 });
1474
1475 let sql = sql(plan);
1476 assert!(sql.contains("WHEN MATCHED AND source.active THEN UPDATE SET name = source.name"));
1477 assert!(sql.contains("WHEN MATCHED AND source.deleted THEN DELETE"));
1478 assert!(
1479 sql.contains("WHEN NOT MATCHED AND source.active THEN INSERT (id) VALUES (source.id)")
1480 );
1481 }
1482}