halo/
select.rs

1//! SelectBuilder:构建 SELECT 语句(对齐 go-sqlbuilder `select.go` 的核心行为)。
2
3use crate::args::Args;
4use crate::cond::{ArgsRef, Cond};
5use crate::cte::CTEBuilder;
6use crate::flavor::Flavor;
7use crate::injection::{Injection, InjectionMarker};
8use crate::modifiers::{Arg, Builder};
9use crate::string_builder::StringBuilder;
10use crate::where_clause::{WhereClause, WhereClauseBuilder, WhereClauseRef};
11use std::cell::RefCell;
12use std::ops::Deref;
13use std::rc::Rc;
14
15const SELECT_MARKER_INIT: InjectionMarker = 0;
16const SELECT_MARKER_AFTER_WITH: InjectionMarker = 1;
17const SELECT_MARKER_AFTER_SELECT: InjectionMarker = 2;
18const SELECT_MARKER_AFTER_FROM: InjectionMarker = 3;
19const SELECT_MARKER_AFTER_JOIN: InjectionMarker = 4;
20const SELECT_MARKER_AFTER_WHERE: InjectionMarker = 5;
21const SELECT_MARKER_AFTER_GROUP_BY: InjectionMarker = 6;
22const SELECT_MARKER_AFTER_ORDER_BY: InjectionMarker = 7;
23const SELECT_MARKER_AFTER_LIMIT: InjectionMarker = 8;
24const SELECT_MARKER_AFTER_FOR: InjectionMarker = 9;
25
26/// JoinOption(对齐 go-sqlbuilder)。
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum JoinOption {
29    FullJoin,
30    FullOuterJoin,
31    InnerJoin,
32    LeftJoin,
33    LeftOuterJoin,
34    RightJoin,
35    RightOuterJoin,
36}
37
38impl JoinOption {
39    fn as_str(self) -> &'static str {
40        match self {
41            Self::FullJoin => "FULL",
42            Self::FullOuterJoin => "FULL OUTER",
43            Self::InnerJoin => "INNER",
44            Self::LeftJoin => "LEFT",
45            Self::LeftOuterJoin => "LEFT OUTER",
46            Self::RightJoin => "RIGHT",
47            Self::RightOuterJoin => "RIGHT OUTER",
48        }
49    }
50}
51
52#[derive(Debug)]
53pub struct SelectBuilder {
54    args: ArgsRef,
55    cond: Cond,
56
57    distinct: bool,
58    tables: Vec<String>,
59    select_cols: Vec<String>,
60
61    join_options: Vec<Option<JoinOption>>,
62    join_tables: Vec<String>,
63    join_exprs: Vec<Vec<String>>,
64
65    where_clause: Option<WhereClauseRef>,
66    where_var: Option<String>,
67    cte_var: Option<String>,
68    cte: Option<CTEBuilder>,
69
70    having_exprs: Vec<String>,
71    group_by_cols: Vec<String>,
72    order_by_cols: Vec<String>,
73    order: Option<&'static str>,
74    limit_var: Option<String>,
75    offset_var: Option<String>,
76    for_what: Option<&'static str>,
77
78    injection: Injection,
79    marker: InjectionMarker,
80}
81
82impl Deref for SelectBuilder {
83    type Target = Cond;
84    fn deref(&self) -> &Self::Target {
85        &self.cond
86    }
87}
88
89impl SelectBuilder {
90    pub fn new() -> Self {
91        let args = Rc::new(RefCell::new(Args::default()));
92        let cond = Cond::with_args(args.clone());
93        Self {
94            args,
95            cond,
96            distinct: false,
97            tables: Vec::new(),
98            select_cols: Vec::new(),
99            join_options: Vec::new(),
100            join_tables: Vec::new(),
101            join_exprs: Vec::new(),
102            where_clause: None,
103            where_var: None,
104            cte_var: None,
105            cte: None,
106            having_exprs: Vec::new(),
107            group_by_cols: Vec::new(),
108            order_by_cols: Vec::new(),
109            order: None,
110            limit_var: None,
111            offset_var: None,
112            for_what: None,
113            injection: Injection::new(),
114            marker: SELECT_MARKER_INIT,
115        }
116    }
117
118    pub fn set_flavor(&mut self, flavor: Flavor) -> Flavor {
119        let mut a = self.args.borrow_mut();
120        let old = a.flavor;
121        a.flavor = flavor;
122        old
123    }
124
125    pub fn flavor(&self) -> Flavor {
126        self.args.borrow().flavor
127    }
128
129    pub fn with(&mut self, cte: &CTEBuilder) -> &mut Self {
130        let placeholder_builder = cte.clone();
131        let ph = self.var(Arg::Builder(Box::new(cte.clone())));
132        self.cte = Some(placeholder_builder);
133        self.cte_var = Some(ph);
134        self.marker = SELECT_MARKER_AFTER_WITH;
135        self
136    }
137
138    fn table_names(&self) -> Vec<String> {
139        let cte_tables = self
140            .cte
141            .as_ref()
142            .map(|cte| cte.table_names_for_from())
143            .unwrap_or_default();
144
145        if self.tables.is_empty() {
146            return cte_tables;
147        }
148
149        if cte_tables.is_empty() {
150            return self.tables.clone();
151        }
152
153        let mut out = Vec::with_capacity(self.tables.len() + cte_tables.len());
154        out.extend(self.tables.clone());
155        out.extend(cte_tables);
156        out
157    }
158
159    /// 返回当前 WhereClause(可用于跨 builder 共享)。
160    pub fn where_clause(&self) -> Option<WhereClauseRef> {
161        self.where_clause.clone()
162    }
163
164    /// 设置/共享 WhereClause(对齐 go-sqlbuilder 公开字段 `WhereClause` 的用法)。
165    ///
166    /// - `None` 等价于清空 WHERE。
167    /// - `Some(wc)` 会把该 WhereClause 绑定到当前 builder,并确保内部 placeholder 指向正确的 builder。
168    pub fn set_where_clause(&mut self, wc: Option<WhereClauseRef>) -> &mut Self {
169        match wc {
170            None => {
171                self.where_clause = None;
172                self.where_var = None;
173            }
174            Some(wc) => {
175                if let Some(ph) = &self.where_var {
176                    self.args.borrow_mut().replace(
177                        ph,
178                        Arg::Builder(Box::new(WhereClauseBuilder::new(wc.clone()))),
179                    );
180                } else {
181                    let ph = self.var(Arg::Builder(Box::new(WhereClauseBuilder::new(wc.clone()))));
182                    self.where_var = Some(ph);
183                }
184                self.where_clause = Some(wc);
185            }
186        }
187        self
188    }
189
190    pub fn clear_where_clause(&mut self) -> &mut Self {
191        self.set_where_clause(None)
192    }
193
194    /// AddWhereExpr:允许显式指定 ArgsRef,把表达式追加到 WhereClause(对齐 go-sqlbuilder)。
195    pub fn add_where_expr(
196        &mut self,
197        args: ArgsRef,
198        exprs: impl IntoIterator<Item = impl Into<String>>,
199    ) -> &mut Self {
200        let exprs: Vec<String> = exprs.into_iter().map(Into::into).collect();
201        if exprs.is_empty() || exprs.iter().all(|s| s.is_empty()) {
202            return self;
203        }
204
205        if self.where_clause.is_none() {
206            let wc = WhereClause::new();
207            let ph = self.var(Arg::Builder(Box::new(WhereClauseBuilder::new(wc.clone()))));
208            self.where_clause = Some(wc);
209            self.where_var = Some(ph);
210        }
211        let wc = self.where_clause.as_ref().unwrap().clone();
212        wc.borrow_mut().add_where_expr(args, exprs);
213        self.marker = SELECT_MARKER_AFTER_WHERE;
214        self
215    }
216
217    pub fn clone_builder(&self) -> Self {
218        let old_args = self.args.borrow().clone();
219        let args = Rc::new(RefCell::new(old_args));
220        let cond = Cond::with_args(args.clone());
221
222        let mut cloned = Self {
223            args,
224            cond,
225            distinct: self.distinct,
226            tables: self.tables.clone(),
227            select_cols: self.select_cols.clone(),
228            join_options: self.join_options.clone(),
229            join_tables: self.join_tables.clone(),
230            join_exprs: self.join_exprs.clone(),
231            where_clause: self.where_clause.clone(),
232            where_var: self.where_var.clone(),
233            cte_var: self.cte_var.clone(),
234            cte: self.cte.clone(),
235            having_exprs: self.having_exprs.clone(),
236            group_by_cols: self.group_by_cols.clone(),
237            order_by_cols: self.order_by_cols.clone(),
238            order: self.order,
239            limit_var: self.limit_var.clone(),
240            offset_var: self.offset_var.clone(),
241            for_what: self.for_what,
242            injection: self.injection.clone(),
243            marker: self.marker,
244        };
245
246        // 深拷贝 WhereClause,并修复 args 中对应 placeholder 的 Builder 指向新 WhereClause
247        if let (Some(wc), Some(ph)) = (&self.where_clause, &self.where_var) {
248            let new_wc = Rc::new(RefCell::new(wc.borrow().clone()));
249            cloned.where_clause = Some(new_wc.clone());
250            cloned
251                .args
252                .borrow_mut()
253                .replace(ph, Arg::Builder(Box::new(WhereClauseBuilder::new(new_wc))));
254        }
255
256        if let (Some(cte), Some(ph)) = (&self.cte, &self.cte_var) {
257            let new_cte = cte.clone();
258            let new_cte_for_field = new_cte.clone();
259            cloned.cte = Some(new_cte_for_field);
260            cloned
261                .args
262                .borrow_mut()
263                .replace(ph, Arg::Builder(Box::new(new_cte)));
264        }
265
266        cloned
267    }
268
269    fn var(&self, v: impl Into<Arg>) -> String {
270        self.args.borrow_mut().add(v)
271    }
272
273    pub fn select(&mut self, cols: impl IntoIterator<Item = impl Into<String>>) -> &mut Self {
274        self.select_cols = cols.into_iter().map(Into::into).collect();
275        self.marker = SELECT_MARKER_AFTER_SELECT;
276        self
277    }
278
279    pub fn select_more(&mut self, cols: impl IntoIterator<Item = impl Into<String>>) -> &mut Self {
280        self.select_cols.extend(cols.into_iter().map(Into::into));
281        self.marker = SELECT_MARKER_AFTER_SELECT;
282        self
283    }
284
285    pub fn distinct(&mut self) -> &mut Self {
286        self.distinct = true;
287        self.marker = SELECT_MARKER_AFTER_SELECT;
288        self
289    }
290
291    pub fn from(&mut self, tables: impl IntoIterator<Item = impl Into<String>>) -> &mut Self {
292        self.tables = tables.into_iter().map(Into::into).collect();
293        self.marker = SELECT_MARKER_AFTER_FROM;
294        self
295    }
296
297    pub fn join(
298        &mut self,
299        table: impl Into<String>,
300        on_expr: impl IntoIterator<Item = impl Into<String>>,
301    ) -> &mut Self {
302        self.join_with_option(None, table, on_expr)
303    }
304
305    pub fn join_with_option(
306        &mut self,
307        option: Option<JoinOption>,
308        table: impl Into<String>,
309        on_expr: impl IntoIterator<Item = impl Into<String>>,
310    ) -> &mut Self {
311        self.join_options.push(option);
312        self.join_tables.push(table.into());
313        self.join_exprs
314            .push(on_expr.into_iter().map(Into::into).collect());
315        self.marker = SELECT_MARKER_AFTER_JOIN;
316        self
317    }
318
319    pub fn where_(&mut self, and_expr: impl IntoIterator<Item = impl Into<String>>) -> &mut Self {
320        let exprs: Vec<String> = and_expr.into_iter().map(Into::into).collect();
321        if exprs.is_empty() || exprs.iter().all(|s| s.is_empty()) {
322            return self;
323        }
324
325        if self.where_clause.is_none() {
326            let wc = WhereClause::new();
327            let ph = self.var(Arg::Builder(Box::new(WhereClauseBuilder::new(wc.clone()))));
328            self.where_clause = Some(wc);
329            self.where_var = Some(ph);
330        }
331
332        let wc = self.where_clause.as_ref().unwrap().clone();
333        wc.borrow_mut().add_where_expr(self.args.clone(), exprs);
334        self.marker = SELECT_MARKER_AFTER_WHERE;
335        self
336    }
337
338    pub fn add_where_clause(&mut self, other: &WhereClause) -> &mut Self {
339        if self.where_clause.is_none() {
340            let wc = WhereClause::new();
341            let ph = self.var(Arg::Builder(Box::new(WhereClauseBuilder::new(wc.clone()))));
342            self.where_clause = Some(wc);
343            self.where_var = Some(ph);
344        }
345        self.where_clause
346            .as_ref()
347            .unwrap()
348            .borrow_mut()
349            .add_where_clause(other);
350        self
351    }
352
353    pub fn add_where_clause_ref(&mut self, other: &WhereClauseRef) -> &mut Self {
354        if self.where_clause.is_none() {
355            let wc = WhereClause::new();
356            let ph = self.var(Arg::Builder(Box::new(WhereClauseBuilder::new(wc.clone()))));
357            self.where_clause = Some(wc);
358            self.where_var = Some(ph);
359        }
360        self.where_clause
361            .as_ref()
362            .unwrap()
363            .borrow_mut()
364            .add_where_clause(&other.borrow());
365        self
366    }
367
368    pub fn having(&mut self, and_expr: impl IntoIterator<Item = impl Into<String>>) -> &mut Self {
369        self.having_exprs
370            .extend(and_expr.into_iter().map(Into::into));
371        self.marker = SELECT_MARKER_AFTER_GROUP_BY;
372        self
373    }
374
375    pub fn group_by(&mut self, cols: impl IntoIterator<Item = impl Into<String>>) -> &mut Self {
376        self.group_by_cols.extend(cols.into_iter().map(Into::into));
377        self.marker = SELECT_MARKER_AFTER_GROUP_BY;
378        self
379    }
380
381    pub fn order_by(&mut self, cols: impl IntoIterator<Item = impl Into<String>>) -> &mut Self {
382        self.order_by_cols.extend(cols.into_iter().map(Into::into));
383        self.marker = SELECT_MARKER_AFTER_ORDER_BY;
384        self
385    }
386
387    pub fn order_by_asc(&mut self, col: impl Into<String>) -> &mut Self {
388        self.order_by_cols.push(format!("{} ASC", col.into()));
389        self.marker = SELECT_MARKER_AFTER_ORDER_BY;
390        self
391    }
392
393    pub fn order_by_desc(&mut self, col: impl Into<String>) -> &mut Self {
394        self.order_by_cols.push(format!("{} DESC", col.into()));
395        self.marker = SELECT_MARKER_AFTER_ORDER_BY;
396        self
397    }
398
399    pub fn asc(&mut self) -> &mut Self {
400        self.order = Some("ASC");
401        self.marker = SELECT_MARKER_AFTER_ORDER_BY;
402        self
403    }
404
405    pub fn desc(&mut self) -> &mut Self {
406        self.order = Some("DESC");
407        self.marker = SELECT_MARKER_AFTER_ORDER_BY;
408        self
409    }
410
411    pub fn limit(&mut self, limit: i64) -> &mut Self {
412        if limit < 0 {
413            self.limit_var = None;
414            return self;
415        }
416        self.limit_var = Some(self.var(limit));
417        self.marker = SELECT_MARKER_AFTER_LIMIT;
418        self
419    }
420
421    pub fn offset(&mut self, offset: i64) -> &mut Self {
422        if offset < 0 {
423            self.offset_var = None;
424            return self;
425        }
426        self.offset_var = Some(self.var(offset));
427        self.marker = SELECT_MARKER_AFTER_LIMIT;
428        self
429    }
430
431    pub fn for_update(&mut self) -> &mut Self {
432        self.for_what = Some("UPDATE");
433        self.marker = SELECT_MARKER_AFTER_FOR;
434        self
435    }
436
437    pub fn for_share(&mut self) -> &mut Self {
438        self.for_what = Some("SHARE");
439        self.marker = SELECT_MARKER_AFTER_FOR;
440        self
441    }
442
443    pub fn as_(&self, name: &str, alias: &str) -> String {
444        format!("{name} AS {alias}")
445    }
446
447    pub fn builder_as(&self, builder: impl Builder + 'static, alias: &str) -> String {
448        format!(
449            "({}) AS {}",
450            self.var(Arg::Builder(Box::new(builder))),
451            alias
452        )
453    }
454
455    pub fn sql(&mut self, sql: impl Into<String>) -> &mut Self {
456        self.injection.sql(self.marker, sql);
457        self
458    }
459}
460
461impl Clone for SelectBuilder {
462    fn clone(&self) -> Self {
463        self.clone_builder()
464    }
465}
466
467impl Default for SelectBuilder {
468    fn default() -> Self {
469        Self::new()
470    }
471}
472
473impl Builder for SelectBuilder {
474    fn build_with_flavor(&self, flavor: Flavor, initial_arg: &[Arg]) -> (String, Vec<Arg>) {
475        let mut buf = StringBuilder::new();
476        write_injection(&mut buf, &self.injection, SELECT_MARKER_INIT);
477
478        if let Some(ph) = &self.cte_var {
479            buf.write_leading(ph);
480            write_injection(&mut buf, &self.injection, SELECT_MARKER_AFTER_WITH);
481        }
482
483        if !self.select_cols.is_empty() {
484            buf.write_leading("SELECT");
485            if self.distinct {
486                buf.write_str(" DISTINCT");
487            }
488            buf.write_str(" ");
489            buf.write_str(&self.select_cols.join(", "));
490        }
491        write_injection(&mut buf, &self.injection, SELECT_MARKER_AFTER_SELECT);
492
493        let table_names = self.table_names();
494        if !table_names.is_empty() {
495            buf.write_leading("FROM");
496            buf.write_str(" ");
497            buf.write_str(&table_names.join(", "));
498        }
499        write_injection(&mut buf, &self.injection, SELECT_MARKER_AFTER_FROM);
500
501        for i in 0..self.join_tables.len() {
502            if let Some(opt) = self.join_options[i] {
503                buf.write_leading(opt.as_str());
504            }
505            buf.write_leading("JOIN");
506            buf.write_str(" ");
507            buf.write_str(&self.join_tables[i]);
508
509            let on = self.join_exprs[i]
510                .iter()
511                .filter(|s| !s.is_empty())
512                .cloned()
513                .collect::<Vec<_>>();
514            if !on.is_empty() {
515                buf.write_str(" ON ");
516                buf.write_str(&on.join(" AND "));
517            }
518        }
519        if !self.join_tables.is_empty() {
520            write_injection(&mut buf, &self.injection, SELECT_MARKER_AFTER_JOIN);
521        }
522
523        if let Some(ph) = &self.where_var {
524            buf.write_leading(ph);
525            write_injection(&mut buf, &self.injection, SELECT_MARKER_AFTER_WHERE);
526        }
527
528        if !self.group_by_cols.is_empty() {
529            buf.write_leading("GROUP BY");
530            buf.write_str(" ");
531            buf.write_str(&self.group_by_cols.join(", "));
532            let having = self
533                .having_exprs
534                .iter()
535                .filter(|s| !s.is_empty())
536                .cloned()
537                .collect::<Vec<_>>();
538            if !having.is_empty() {
539                buf.write_str(" HAVING ");
540                buf.write_str(&having.join(" AND "));
541            }
542            write_injection(&mut buf, &self.injection, SELECT_MARKER_AFTER_GROUP_BY);
543        }
544
545        if !self.order_by_cols.is_empty() {
546            buf.write_leading("ORDER BY");
547            buf.write_str(" ");
548            buf.write_str(&self.order_by_cols.join(", "));
549            if let Some(order) = self.order {
550                buf.write_str(" ");
551                buf.write_str(order);
552            }
553            write_injection(&mut buf, &self.injection, SELECT_MARKER_AFTER_ORDER_BY);
554        }
555
556        // LIMIT/OFFSET 行为按 go-sqlbuilder flavor 规则
557        match flavor {
558            Flavor::MySQL | Flavor::SQLite | Flavor::ClickHouse => {
559                if let Some(lim) = &self.limit_var {
560                    buf.write_leading("LIMIT");
561                    buf.write_str(" ");
562                    buf.write_str(lim);
563                    if let Some(off) = &self.offset_var {
564                        buf.write_leading("OFFSET");
565                        buf.write_str(" ");
566                        buf.write_str(off);
567                    }
568                }
569            }
570            Flavor::CQL => {
571                if let Some(lim) = &self.limit_var {
572                    buf.write_leading("LIMIT");
573                    buf.write_str(" ");
574                    buf.write_str(lim);
575                }
576            }
577            Flavor::PostgreSQL => {
578                if let Some(lim) = &self.limit_var {
579                    buf.write_leading("LIMIT");
580                    buf.write_str(" ");
581                    buf.write_str(lim);
582                }
583                if let Some(off) = &self.offset_var {
584                    buf.write_leading("OFFSET");
585                    buf.write_str(" ");
586                    buf.write_str(off);
587                }
588            }
589            Flavor::Presto => {
590                if let Some(off) = &self.offset_var {
591                    buf.write_leading("OFFSET");
592                    buf.write_str(" ");
593                    buf.write_str(off);
594                }
595                if let Some(lim) = &self.limit_var {
596                    buf.write_leading("LIMIT");
597                    buf.write_str(" ");
598                    buf.write_str(lim);
599                }
600            }
601            Flavor::SQLServer | Flavor::Oracle => {
602                if self.order_by_cols.is_empty()
603                    && (self.limit_var.is_some() || self.offset_var.is_some())
604                    && flavor == Flavor::SQLServer
605                {
606                    buf.write_leading("ORDER BY 1");
607                }
608
609                if let Some(off) = &self.offset_var {
610                    buf.write_leading("OFFSET");
611                    buf.write_str(" ");
612                    buf.write_str(off);
613                    buf.write_str(" ROWS");
614                }
615
616                if let Some(lim) = &self.limit_var {
617                    if self.offset_var.is_none() {
618                        buf.write_leading("OFFSET 0 ROWS");
619                    }
620                    buf.write_leading("FETCH NEXT");
621                    buf.write_str(" ");
622                    buf.write_str(lim);
623                    buf.write_str(" ROWS ONLY");
624                }
625            }
626            Flavor::Informix | Flavor::Doris => {
627                // 后续对齐 go 的特殊行为(Informix/Doris)
628                if let Some(lim) = &self.limit_var {
629                    buf.write_leading("LIMIT");
630                    buf.write_str(" ");
631                    buf.write_str(lim);
632                    if let Some(off) = &self.offset_var {
633                        buf.write_leading("OFFSET");
634                        buf.write_str(" ");
635                        buf.write_str(off);
636                    }
637                }
638            }
639        }
640
641        if self.limit_var.is_some() {
642            write_injection(&mut buf, &self.injection, SELECT_MARKER_AFTER_LIMIT);
643        }
644
645        if let Some(what) = self.for_what {
646            buf.write_leading("FOR");
647            buf.write_str(" ");
648            buf.write_str(what);
649            write_injection(&mut buf, &self.injection, SELECT_MARKER_AFTER_FOR);
650        }
651
652        self.args
653            .borrow()
654            .compile_with_flavor(&buf.into_string(), flavor, initial_arg)
655    }
656
657    fn flavor(&self) -> Flavor {
658        self.flavor()
659    }
660}
661
662fn write_injection(buf: &mut StringBuilder, inj: &Injection, marker: InjectionMarker) {
663    let sqls = inj.at(marker);
664    if sqls.is_empty() {
665        return;
666    }
667    buf.write_leading("");
668    buf.write_str(&sqls.join(" "));
669}