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 #[allow(deprecated)]
128 Value::Ident(st) => write!(s, "\"{}\"", *st).unwrap(),
129 Value::Choice(c) => write!(s, "{}", sqlite::fmt(c)).unwrap(),
130 Value::Null(NullType::Choice) => write!(s, "NULL").unwrap(),
131 _ => {
132 d.lookup.push(*y);
133 write!(s, "?").unwrap();
134 }
135 }
136 if idx_2 != x.len() - 1 {
137 write!(s, ", ").unwrap();
138 }
139 }
140 write!(s, ")").unwrap();
141 if idx != d.row_values.len() - 1 {
142 write!(s, ", ").unwrap();
143 }
144 }
145
146 if let Some(ret_clause) = d.returning_clause {
147 write!(s, " RETURNING ").unwrap();
148
149 for (idx, c) in ret_clause.iter().enumerate() {
150 write!(s, "\"{c}\"").unwrap();
151
152 if idx != ret_clause.len() - 1 {
153 write!(s, ", ").unwrap();
154 }
155 }
156 }
157
158 write!(s, ";").unwrap();
159
160 (s, d.lookup)
161 }
162 #[cfg(feature = "postgres")]
163 InsertImpl::Postgres(mut d) => {
164 if d.columns.is_empty() {
165 let mut s = format!("INSERT INTO \"{}\" DEFAULT VALUES", d.into_clause);
166
167 if let Some(ret_clause) = d.returning_clause {
168 write!(s, " RETURNING ").unwrap();
169
170 for (idx, c) in ret_clause.iter().enumerate() {
171 write!(s, "\"{c}\"").unwrap();
172
173 if idx != ret_clause.len() - 1 {
174 write!(s, ", ").unwrap();
175 }
176 }
177 }
178 write!(s, ";").unwrap();
179
180 return (s, d.lookup);
181 }
182
183 let mut s = format!("INSERT INTO \"{}\" (", d.into_clause);
184 for (idx, x) in d.columns.iter().enumerate() {
185 write!(s, "\"{x}\"").unwrap();
186 if idx != d.columns.len() - 1 {
187 write!(s, ", ").unwrap();
188 }
189 }
190 write!(s, ") VALUES ").unwrap();
191
192 for (idx, x) in d.row_values.iter().enumerate() {
193 write!(s, "(").unwrap();
194 for (idx_2, y) in x.iter().enumerate() {
195 match y {
196 #[allow(deprecated)]
197 Value::Ident(st) => write!(s, "\"{}\"", *st).unwrap(),
198 Value::Choice(c) => write!(s, "{}", postgres::fmt(c)).unwrap(),
199 Value::Null(NullType::Choice) => write!(s, "NULL").unwrap(),
200 _ => {
201 d.lookup.push(*y);
202 write!(s, "${}", d.lookup.len()).unwrap();
203 }
204 }
205 if idx_2 != x.len() - 1 {
206 write!(s, ", ").unwrap();
207 }
208 }
209 write!(s, ")").unwrap();
210 if idx != d.row_values.len() - 1 {
211 write!(s, ", ").unwrap();
212 }
213 }
214
215 if let Some(ret_clause) = d.returning_clause {
216 write!(s, " RETURNING ").unwrap();
217
218 for (idx, c) in ret_clause.iter().enumerate() {
219 write!(s, "\"{c}\"").unwrap();
220
221 if idx != ret_clause.len() - 1 {
222 write!(s, ", ").unwrap();
223 }
224 }
225 }
226
227 write!(s, ";").unwrap();
228
229 (s, d.lookup)
230 }
231 }
232 }
233}