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