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