nodedb_sql/parser/preprocess/
function_args.rs1use crate::parser::object_literal::parse_object_literal;
5
6pub(super) fn rewrite_object_literal_args(sql: &str) -> Option<String> {
10 let mut result = String::with_capacity(sql.len());
11 let chars: Vec<char> = sql.chars().collect();
12 let mut i = 0;
13 let mut found = false;
14 let mut paren_depth: i32 = 0;
15
16 while i < chars.len() {
17 match chars[i] {
18 '(' => {
19 paren_depth += 1;
20 result.push('(');
21 i += 1;
22 }
23 ')' => {
24 paren_depth = paren_depth.saturating_sub(1);
25 result.push(')');
26 i += 1;
27 }
28 '\'' => {
29 result.push('\'');
30 i += 1;
31 while i < chars.len() {
32 result.push(chars[i]);
33 if chars[i] == '\'' {
34 if i + 1 < chars.len() && chars[i + 1] == '\'' {
35 i += 1;
36 result.push(chars[i]);
37 } else {
38 break;
39 }
40 }
41 i += 1;
42 }
43 i += 1;
44 }
45 '{' if paren_depth > 0 => {
46 let remaining: String = chars[i..].iter().collect();
47 if let Some(Ok(fields)) = parse_object_literal(&remaining)
48 && let Some(end) = find_matching_brace(&chars, i)
49 {
50 let json = value_map_to_json(&fields);
51 result.push('\'');
52 result.push_str(&json);
53 result.push('\'');
54 i = end + 1;
55 found = true;
56 continue;
57 }
58 result.push('{');
59 i += 1;
60 }
61 _ => {
62 result.push(chars[i]);
63 i += 1;
64 }
65 }
66 }
67
68 if found { Some(result) } else { None }
69}
70
71fn value_map_to_json(fields: &std::collections::HashMap<String, nodedb_types::Value>) -> String {
73 let mut parts = Vec::with_capacity(fields.len());
74 let mut entries: Vec<_> = fields.iter().collect();
75 entries.sort_by_key(|(k, _)| k.as_str());
76 for (key, val) in entries {
77 parts.push(format!("\"{}\":{}", key, value_to_json(val)));
78 }
79 format!("{{{}}}", parts.join(","))
80}
81
82fn value_to_json(value: &nodedb_types::Value) -> String {
84 match value {
85 nodedb_types::Value::String(s) => {
86 format!("\"{}\"", s.replace('\\', "\\\\").replace('"', "\\\""))
87 }
88 nodedb_types::Value::Integer(n) => n.to_string(),
89 nodedb_types::Value::Float(f) => {
90 if f.is_finite() {
91 format!("{f}")
92 } else {
93 "null".to_string()
96 }
97 }
98 nodedb_types::Value::Bool(b) => if *b { "true" } else { "false" }.to_string(),
99 nodedb_types::Value::Null => "null".to_string(),
100 nodedb_types::Value::Array(items) => {
101 let inner: Vec<String> = items.iter().map(value_to_json).collect();
102 format!("[{}]", inner.join(","))
103 }
104 nodedb_types::Value::Object(map) => value_map_to_json(map),
105 _ => format!("\"{}\"", format!("{value:?}").replace('"', "\\\"")),
106 }
107}
108
109fn find_matching_brace(chars: &[char], start: usize) -> Option<usize> {
111 let mut depth = 0;
112 let mut in_string = false;
113 let mut i = start;
114 while i < chars.len() {
115 match chars[i] {
116 '\'' if !in_string => in_string = true,
117 '\'' if in_string => {
118 if i + 1 < chars.len() && chars[i + 1] == '\'' {
119 i += 2;
120 continue;
121 }
122 in_string = false;
123 }
124 '{' if !in_string => depth += 1,
125 '}' if !in_string => {
126 depth -= 1;
127 if depth == 0 {
128 return Some(i);
129 }
130 }
131 _ => {}
132 }
133 i += 1;
134 }
135 None
136}