nodedb_sql/parser/preprocess/
object_literal_stmt.rs1use super::literal::value_to_sql_literal;
5use crate::parser::object_literal::{parse_object_literal, parse_object_literal_array};
6
7pub(super) fn try_rewrite_object_literal(sql: &str) -> Option<String> {
12 let after_into = sql["INSERT INTO ".len()..].trim_start();
13 let coll_end = after_into.find(|c: char| c.is_whitespace())?;
14 let coll_name = &after_into[..coll_end];
15 let rest = after_into[coll_end..].trim_start();
16
17 let obj_str = rest.trim_end_matches(';').trim_end();
19
20 if obj_str.starts_with('[') {
21 return rewrite_array_form(coll_name, obj_str);
22 }
23
24 if !obj_str.starts_with('{') {
25 return None;
26 }
27
28 let fields = parse_object_literal(obj_str)?.ok()?;
29 if fields.is_empty() {
30 return None;
31 }
32 Some(fields_to_values_sql(coll_name, &[fields]))
33}
34
35fn rewrite_array_form(coll_name: &str, obj_str: &str) -> Option<String> {
37 let objects = parse_object_literal_array(obj_str)?.ok()?;
38 if objects.is_empty() {
39 return None;
40 }
41 Some(fields_to_values_sql(coll_name, &objects))
42}
43
44fn fields_to_values_sql(
48 coll_name: &str,
49 rows: &[std::collections::HashMap<String, nodedb_types::Value>],
50) -> String {
51 let mut all_keys: Vec<String> = rows
52 .iter()
53 .flat_map(|r| r.keys().cloned())
54 .collect::<std::collections::BTreeSet<_>>()
55 .into_iter()
56 .collect();
57 all_keys.sort();
58
59 let col_list = all_keys.join(", ");
60
61 let row_strs: Vec<String> = rows
62 .iter()
63 .map(|row| {
64 let vals: Vec<String> = all_keys
65 .iter()
66 .map(|k| match row.get(k) {
67 Some(v) => value_to_sql_literal(v),
68 None => "NULL".to_string(),
69 })
70 .collect();
71 format!("({})", vals.join(", "))
72 })
73 .collect();
74
75 format!(
76 "INSERT INTO {} ({}) VALUES {}",
77 coll_name,
78 col_list,
79 row_strs.join(", ")
80 )
81}