halo_space/
create_table.rs

1//! CreateTableBuilder: build CREATE TABLE statements.
2
3use crate::args::Args;
4use crate::flavor::Flavor;
5use crate::injection::{Injection, InjectionMarker};
6use crate::macros::{IntoStrings, collect_into_strings};
7use crate::modifiers::{Arg, Builder, escape};
8use crate::string_builder::StringBuilder;
9use std::cell::RefCell;
10use std::rc::Rc;
11
12const CT_MARKER_INIT: InjectionMarker = 0;
13const CT_MARKER_AFTER_CREATE: InjectionMarker = 1;
14const CT_MARKER_AFTER_DEFINE: InjectionMarker = 2;
15const CT_MARKER_AFTER_OPTION: InjectionMarker = 3;
16
17#[derive(Debug, Clone)]
18pub struct CreateTableBuilder {
19    verb: &'static str,
20    if_not_exists: bool,
21    table: Option<String>,
22    defs: Vec<Vec<String>>,
23    options: Vec<Vec<String>>,
24
25    args: Rc<RefCell<Args>>,
26    injection: Injection,
27    marker: InjectionMarker,
28}
29
30impl Default for CreateTableBuilder {
31    fn default() -> Self {
32        Self::new()
33    }
34}
35
36impl CreateTableBuilder {
37    pub fn new() -> Self {
38        Self {
39            verb: "CREATE TABLE",
40            if_not_exists: false,
41            table: None,
42            defs: Vec::new(),
43            options: Vec::new(),
44            args: Rc::new(RefCell::new(Args::default())),
45            injection: Injection::new(),
46            marker: CT_MARKER_INIT,
47        }
48    }
49
50    pub fn set_flavor(&mut self, flavor: Flavor) -> Flavor {
51        let mut a = self.args.borrow_mut();
52        let old = a.flavor;
53        a.flavor = flavor;
54        old
55    }
56
57    pub fn flavor(&self) -> Flavor {
58        self.args.borrow().flavor
59    }
60
61    pub fn create_table(&mut self, table: &str) -> &mut Self {
62        self.table = Some(escape(table));
63        self.marker = CT_MARKER_AFTER_CREATE;
64        self
65    }
66
67    pub fn create_temp_table(&mut self, table: &str) -> &mut Self {
68        self.verb = "CREATE TEMPORARY TABLE";
69        self.table = Some(escape(table));
70        self.marker = CT_MARKER_AFTER_CREATE;
71        self
72    }
73
74    pub fn if_not_exists(&mut self) -> &mut Self {
75        self.if_not_exists = true;
76        self
77    }
78
79    pub fn define<T>(&mut self, def: T) -> &mut Self
80    where
81        T: IntoStrings,
82    {
83        self.defs.push(collect_into_strings(def));
84        self.marker = CT_MARKER_AFTER_DEFINE;
85        self
86    }
87
88    pub fn option<T>(&mut self, opt: T) -> &mut Self
89    where
90        T: IntoStrings,
91    {
92        self.options.push(collect_into_strings(opt));
93        self.marker = CT_MARKER_AFTER_OPTION;
94        self
95    }
96
97    pub fn sql(&mut self, sql: impl Into<String>) -> &mut Self {
98        self.injection.sql(self.marker, sql);
99        self
100    }
101
102    pub fn num_define(&self) -> usize {
103        self.defs.len()
104    }
105
106    // CreateTableBuilder currently doesn't need placeholders; add later if needed.
107}
108
109impl Builder for CreateTableBuilder {
110    fn build_with_flavor(&self, flavor: Flavor, initial_arg: &[Arg]) -> (String, Vec<Arg>) {
111        let mut buf = StringBuilder::new();
112        write_injection(&mut buf, &self.injection, CT_MARKER_INIT);
113
114        buf.write_leading(self.verb);
115        if self.if_not_exists {
116            buf.write_leading("IF NOT EXISTS");
117        }
118        if let Some(t) = &self.table {
119            buf.write_leading(t);
120        }
121        write_injection(&mut buf, &self.injection, CT_MARKER_AFTER_CREATE);
122
123        if !self.defs.is_empty() {
124            let defs: Vec<String> = self.defs.iter().map(|d| d.join(" ")).collect();
125            buf.write_leading("(");
126            buf.write_str(&defs.join(", "));
127            buf.write_str(")");
128            write_injection(&mut buf, &self.injection, CT_MARKER_AFTER_DEFINE);
129        }
130
131        if !self.options.is_empty() {
132            let opts: Vec<String> = self.options.iter().map(|o| o.join(" ")).collect();
133            buf.write_leading(&opts.join(", "));
134            write_injection(&mut buf, &self.injection, CT_MARKER_AFTER_OPTION);
135        }
136
137        // flavor currently only affects placeholders; CREATE TABLE typically doesn't produce placeholders
138        let _ = flavor;
139        self.args
140            .borrow()
141            .compile_with_flavor(&buf.into_string(), self.flavor(), initial_arg)
142    }
143
144    fn flavor(&self) -> Flavor {
145        self.flavor()
146    }
147}
148
149pub fn create_table(table: impl Into<String>) -> CreateTableBuilder {
150    let mut builder = CreateTableBuilder::new();
151    builder.create_table(&table.into());
152    builder
153}
154
155pub fn create_temp_table(table: impl Into<String>) -> CreateTableBuilder {
156    let mut builder = CreateTableBuilder::new();
157    builder.create_temp_table(&table.into());
158    builder
159}
160
161fn write_injection(buf: &mut StringBuilder, inj: &Injection, marker: InjectionMarker) {
162    let sqls = inj.at(marker);
163    if sqls.is_empty() {
164        return;
165    }
166    buf.write_leading("");
167    buf.write_str(&sqls.join(" "));
168}