1use crate::{
2 alias_translator::AliasTranslator,
3 backend::{map, Backend},
4 error::ToqlError,
5 parameter_map::ParameterMap,
6 query::field_path::FieldPath,
7 result::Result,
8 sql::Sql,
9 sql_builder::{sql_builder_error::SqlBuilderError, SqlBuilder},
10 sql_expr::resolver::Resolver,
11 table_mapper::{mapped::Mapped, TableMapper},
12 toql_api::{insert::Insert, paths::Paths},
13 tree::{
14 tree_identity::{IdentityAction, TreeIdentity},
15 tree_insert::TreeInsert,
16 },
17};
18use std::{
19 borrow::BorrowMut,
20 cell::RefCell,
21 collections::{HashMap, HashSet},
22};
23
24pub async fn insert<B, Q, T, R, E>(
25 backend: &mut B,
26 entities: &mut [Q],
27 paths: Paths,
28) -> std::result::Result<(), E>
29where
30 Q: BorrowMut<T>,
31 T: Insert,
32 B: Backend<R, E>,
33 E: From<ToqlError>,
34{
35 {
36 let registry = &mut *backend.registry_mut()?;
37 map::map::<T>(registry)?;
38 }
39
40 let mut joins: Vec<HashSet<String>> = Vec::new();
50 let mut partials: Vec<HashSet<String>> = Vec::new();
51 let mut merges: HashSet<String> = HashSet::new();
52
53 plan_insert_order::<T, _>(
54 &backend.registry()?.mappers,
55 paths.list.as_ref(),
56 &mut joins,
57 &mut merges,
58 &mut partials,
59 )?;
60
61 for l in (0..joins.len()).rev() {
63 for p in joins.get(l).unwrap() {
64 let path = FieldPath::from(&p);
65
66 let sql = build_insert_sql(
67 backend,
68 entities,
69 &path,
70 &mut std::iter::repeat(&true),
71 "",
72 "",
73 )?;
74 insert_sql(backend, path, sql, entities).await?;
75 }
76 }
77
78 let home_path = FieldPath::default();
80 let sql = build_insert_sql(
81 backend,
82 entities,
83 &home_path,
84 &mut std::iter::repeat(&true),
85 "",
86 "",
87 )?;
88 insert_sql(backend, home_path, sql, entities).await?;
89
90 for p in &merges {
92 let path = FieldPath::from(&p);
93
94 let sql = build_insert_sql(
95 backend,
96 entities,
97 &path,
98 &mut std::iter::repeat(&true),
99 "",
100 "",
101 )?;
102
103 insert_sql(backend, path, sql, entities).await?;
104 }
105
106 for l in 0..partials.len() {
108 for p in partials.get(l).unwrap() {
109 if merges.contains(p) {
111 continue;
112 }
113
114 let path = FieldPath::from(&p);
115
116 let sql = build_insert_sql(
117 backend,
118 entities,
119 &path,
120 &mut std::iter::repeat(&true),
121 "",
122 "",
123 )?;
124
125 insert_sql(backend, path, sql, entities).await?;
126 }
127 }
128 Ok(())
129}
130
131pub(crate) async fn insert_sql<'a, Q, B, T, R, E>(
132 backend: &mut B,
133 path: FieldPath<'_>,
134 sql: Option<Sql>,
135 entities: &mut [Q],
136) -> std::result::Result<(), E>
137where
138 B: Backend<R, E>,
139 Q: BorrowMut<T>,
140 T: TreeIdentity,
141 E: From<ToqlError>,
142{
143 if sql.is_none() {
144 return Ok(());
145 }
146 let sql = sql.unwrap();
147
148 let descendents = path.children();
149 if <T as TreeIdentity>::auto_id(descendents)? {
150 let ids = backend.insert_sql(sql).await?;
151 set_tree_identity(
152 IdentityAction::Set(RefCell::new(ids)),
153 entities,
154 path.children(),
155 )?;
156 } else {
157 backend.execute_sql(sql).await?;
158 }
159 Ok(())
160}
161
162pub(crate) fn set_tree_identity<'a, T, Q, I>(
163 action: IdentityAction,
164 entities: &mut [Q],
165 descendents: I,
166) -> Result<()>
167where
168 T: TreeIdentity,
169 Q: BorrowMut<T>,
170 I: Iterator<Item = FieldPath<'a>> + Clone,
171{
172 for e in entities.iter_mut() {
173 let e_mut = e.borrow_mut();
174 <T as TreeIdentity>::set_id(e_mut, descendents.clone(), &action)?;
175 }
176
177 Ok(())
178}
179
180pub(crate) fn build_insert_sql<'a, T, Q, B, R, E, J>(
181 backend: &mut B,
182 entities: &[Q],
183 query_path: &FieldPath,
184 inserts: &mut J,
185 _modifier: &str,
186 _extra: &str,
187) -> Result<Option<Sql>>
188where
189 B: Backend<R, E>,
190 T: Mapped + TreeInsert,
191 Q: BorrowMut<T>,
192 E: From<ToqlError>,
193 J: Iterator<Item = &'a bool>,
194{
195 use crate::sql_expr::SqlExpr;
196
197 let ty = <T as Mapped>::type_name();
198
199 let mut values_expr = SqlExpr::new();
200
201 let mut d = query_path.children();
202 let columns_expr = <T as TreeInsert>::columns(&mut d)?;
203 for e in entities {
204 <T as TreeInsert>::values(
206 e.borrow(),
207 query_path.children(),
208 backend.roles(),
209 inserts,
210 &mut values_expr,
211 )?;
212 }
213 if values_expr.is_empty() {
214 return Ok(None);
215 }
216
217 let mut alias_translator = AliasTranslator::new(backend.alias_format());
218
219 let registry = &*backend.registry()?;
220 let sql_builder = SqlBuilder::new(&ty, registry);
221 let mapper = sql_builder.mapper_for_query_path(query_path)?;
222 let canonical_table_alias = &mapper.canonical_table_alias;
223 let table_name = &mapper.table_name;
224
225 let aux_params = [backend.aux_params()];
226 let aux_params_map = ParameterMap::new(&aux_params);
227 let resolver = Resolver::new()
228 .with_aux_params(&aux_params_map)
229 .with_self_alias(&canonical_table_alias);
230 let columns_sql = resolver
231 .to_sql(&columns_expr, &mut alias_translator)
232 .map_err(ToqlError::from)?;
233 let values_sql = resolver
234 .to_sql(&values_expr, &mut alias_translator)
235 .map_err(ToqlError::from)?;
236
237 let mut insert_stmt = String::from("INSERT INTO ");
238 insert_stmt.push_str(&table_name);
239 insert_stmt.push(' ');
240 insert_stmt.push_str(&columns_sql.0);
241 insert_stmt.push_str(" VALUES ");
242 insert_stmt.push_str(&values_sql.0);
243
244 insert_stmt.pop(); insert_stmt.pop();
246
247 Ok(Some(Sql(insert_stmt, values_sql.1)))
248}
249
250pub fn plan_insert_order<T, S: AsRef<str>>(
251 mappers: &HashMap<String, TableMapper>,
252 paths: &[S],
253 joins: &mut Vec<HashSet<String>>,
254 merges: &mut HashSet<String>,
255 partials: &mut Vec<HashSet<String>>,
256) -> Result<()>
257where
258 T: Mapped,
259{
260 let ty = <T as Mapped>::type_name();
261 insert_partial_tables_order(mappers, &ty, 0, &FieldPath::default(), partials)?;
263
264 for path in paths {
265 let field_path = FieldPath::from(path.as_ref().trim_end_matches('_'));
266 let steps = field_path.step_down();
267 let children = field_path.children();
268 let mut level = 0;
269 let mut mapper = mappers
270 .get(&ty)
271 .ok_or_else(|| ToqlError::MapperMissing(ty.to_owned()))?;
272
273 for (d, c) in steps.zip(children) {
274 if let Some(j) = mapper.joined_mapper(c.as_str()) {
275 if joins.len() <= level {
276 joins.push(HashSet::new());
277 }
278 if partials.len() <= level {
279 partials.push(HashSet::new());
280 }
281 if !mapper.is_partial_join(c.as_str()) {
282 joins.get_mut(level).unwrap().insert(d.as_str().to_string());
283 } else {
284 partials
285 .get_mut(level)
286 .unwrap()
287 .insert(d.as_str().to_string());
288 insert_partial_tables_order(mappers, &j, level + 1, &d, partials)?;
289 }
290
291 level += 1;
292 mapper = mappers
293 .get(&j)
294 .ok_or_else(|| ToqlError::MapperMissing(j.to_owned()))?;
295 } else if let Some(m) = mapper.merged_mapper(c.as_str()) {
296 level = 0;
297 merges.insert(d.as_str().to_string());
298 mapper = mappers
299 .get(&m)
300 .ok_or_else(|| ToqlError::MapperMissing(m.to_owned()))?;
301 insert_partial_tables_order(mappers, &m, level, &d, partials)?;
302 } else {
303 return Err(SqlBuilderError::JoinMissing(
304 c.as_str().to_owned(),
305 mapper.table_name.to_string(),
306 )
307 .into());
308 }
309 }
310 }
311
312 Ok(())
313}
314
315fn insert_partial_tables_order(
316 mappers: &HashMap<String, TableMapper>,
317 mapper_name: &str,
318 level: usize,
319 query_path: &FieldPath,
320 joins_or_merges: &mut Vec<HashSet<String>>,
321) -> Result<()> {
322 let mapper = mappers
323 .get(mapper_name)
324 .ok_or_else(|| ToqlError::MapperMissing(mapper_name.to_owned()))?;
325 let partial_joins: Vec<(String, String)> = mapper.joined_partial_mappers();
326
327 for (path, mapper_name) in &partial_joins {
328 let qp = query_path.append(path);
329 if joins_or_merges.len() <= level {
330 joins_or_merges.push(HashSet::new())
331 }
332 insert_partial_tables_order(&mappers, &mapper_name, level + 1, &qp, joins_or_merges)?;
333 joins_or_merges
334 .get_mut(level)
335 .unwrap()
336 .insert(qp.as_str().to_string());
337 }
338
339 Ok(())
340}