1use std::fmt::Write;
2
3#[cfg(feature = "postgres")]
4use crate::db_specific::postgres;
5#[cfg(feature = "sqlite")]
6use crate::db_specific::sqlite;
7use crate::on_conflict::OnConflict;
8use crate::value::NullType;
9use crate::Value;
10
11pub trait Insert<'post_build> {
15 fn rollback_transaction(self) -> Self;
25
26 fn build(self) -> (String, Vec<Value<'post_build>>);
31}
32
33#[derive(Debug)]
37pub struct InsertData<'until_build, 'post_build> {
38 pub(crate) into_clause: &'until_build str,
39 pub(crate) columns: &'until_build [&'until_build str],
40 pub(crate) row_values: &'until_build [&'until_build [Value<'post_build>]],
41 pub(crate) lookup: Vec<Value<'post_build>>,
42 pub(crate) on_conflict: OnConflict,
43 pub(crate) returning_clause: Option<&'until_build [&'until_build str]>,
44}
45
46#[derive(Debug)]
52pub enum InsertImpl<'until_build, 'post_build> {
53 #[cfg(feature = "sqlite")]
57 SQLite(InsertData<'until_build, 'post_build>),
58 #[cfg(feature = "postgres")]
62 Postgres(InsertData<'until_build, 'post_build>),
63}
64
65impl<'post_build> Insert<'post_build> for InsertImpl<'_, 'post_build> {
66 fn rollback_transaction(mut self) -> Self {
67 match self {
68 #[cfg(feature = "sqlite")]
69 InsertImpl::SQLite(ref mut d) => d.on_conflict = OnConflict::ROLLBACK,
70 #[cfg(feature = "postgres")]
71 InsertImpl::Postgres(ref mut d) => d.on_conflict = OnConflict::ROLLBACK,
72 };
73 self
74 }
75
76 fn build(self) -> (String, Vec<Value<'post_build>>) {
77 match self {
78 #[cfg(feature = "sqlite")]
79 InsertImpl::SQLite(mut d) => {
80 if d.columns.is_empty() {
82 let mut s = format!(
83 "INSERT {}INTO \"{}\" DEFAULT VALUES",
84 match d.on_conflict {
85 OnConflict::ABORT => "OR ABORT ",
86 OnConflict::ROLLBACK => "OR ROLLBACK ",
87 },
88 d.into_clause,
89 );
90
91 if let Some(ret_clause) = d.returning_clause {
92 write!(s, " RETURNING ").unwrap();
93
94 for (idx, c) in ret_clause.iter().enumerate() {
95 write!(s, "\"{c}\"").unwrap();
96
97 if idx != ret_clause.len() - 1 {
98 write!(s, ", ").unwrap();
99 }
100 }
101 }
102 write!(s, ";").unwrap();
103
104 return (s, d.lookup);
105 }
106
107 let mut s = format!(
108 "INSERT {}INTO \"{}\" (",
109 match d.on_conflict {
110 OnConflict::ABORT => "OR ABORT ",
111 OnConflict::ROLLBACK => "OR ROLLBACK ",
112 },
113 d.into_clause,
114 );
115 for (idx, x) in d.columns.iter().enumerate() {
116 write!(s, "\"{x}\"").unwrap();
117 if idx != d.columns.len() - 1 {
118 write!(s, ", ").unwrap();
119 }
120 }
121 write!(s, ") VALUES ").unwrap();
122
123 for (idx, x) in d.row_values.iter().enumerate() {
124 write!(s, "(").unwrap();
125 for (idx_2, y) in x.iter().enumerate() {
126 match y {
127 Value::Ident(st) => write!(s, "\"{}\"", *st).unwrap(),
128 Value::Choice(c) => write!(s, "{}", sqlite::fmt(c)).unwrap(),
129 Value::Null(NullType::Choice) => write!(s, "NULL").unwrap(),
130 _ => {
131 d.lookup.push(*y);
132 write!(s, "?").unwrap();
133 }
134 }
135 if idx_2 != x.len() - 1 {
136 write!(s, ", ").unwrap();
137 }
138 }
139 write!(s, ")").unwrap();
140 if idx != d.row_values.len() - 1 {
141 write!(s, ", ").unwrap();
142 }
143 }
144
145 if let Some(ret_clause) = d.returning_clause {
146 write!(s, " RETURNING ").unwrap();
147
148 for (idx, c) in ret_clause.iter().enumerate() {
149 write!(s, "\"{c}\"").unwrap();
150
151 if idx != ret_clause.len() - 1 {
152 write!(s, ", ").unwrap();
153 }
154 }
155 }
156
157 write!(s, ";").unwrap();
158
159 (s, d.lookup)
160 }
161 #[cfg(feature = "postgres")]
162 InsertImpl::Postgres(mut d) => {
163 if d.columns.is_empty() {
164 let mut s = format!("INSERT INTO \"{}\" DEFAULT VALUES", d.into_clause);
165
166 if let Some(ret_clause) = d.returning_clause {
167 write!(s, " RETURNING ").unwrap();
168
169 for (idx, c) in ret_clause.iter().enumerate() {
170 write!(s, "\"{c}\"").unwrap();
171
172 if idx != ret_clause.len() - 1 {
173 write!(s, ", ").unwrap();
174 }
175 }
176 }
177 write!(s, ";").unwrap();
178
179 return (s, d.lookup);
180 }
181
182 let mut s = format!("INSERT INTO \"{}\" (", d.into_clause);
183 for (idx, x) in d.columns.iter().enumerate() {
184 write!(s, "\"{x}\"").unwrap();
185 if idx != d.columns.len() - 1 {
186 write!(s, ", ").unwrap();
187 }
188 }
189 write!(s, ") VALUES ").unwrap();
190
191 for (idx, x) in d.row_values.iter().enumerate() {
192 write!(s, "(").unwrap();
193 for (idx_2, y) in x.iter().enumerate() {
194 match y {
195 Value::Ident(st) => write!(s, "\"{}\"", *st).unwrap(),
196 Value::Choice(c) => write!(s, "{}", postgres::fmt(c)).unwrap(),
197 Value::Null(NullType::Choice) => write!(s, "NULL").unwrap(),
198 _ => {
199 d.lookup.push(*y);
200 write!(s, "${}", d.lookup.len()).unwrap();
201 }
202 }
203 if idx_2 != x.len() - 1 {
204 write!(s, ", ").unwrap();
205 }
206 }
207 write!(s, ")").unwrap();
208 if idx != d.row_values.len() - 1 {
209 write!(s, ", ").unwrap();
210 }
211 }
212
213 if let Some(ret_clause) = d.returning_clause {
214 write!(s, " RETURNING ").unwrap();
215
216 for (idx, c) in ret_clause.iter().enumerate() {
217 write!(s, "\"{c}\"").unwrap();
218
219 if idx != ret_clause.len() - 1 {
220 write!(s, ", ").unwrap();
221 }
222 }
223 }
224
225 write!(s, ";").unwrap();
226
227 (s, d.lookup)
228 }
229 }
230 }
231}