halo_space/
create_table.rs1use 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 }
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 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}