1use std::collections::HashMap;
4
5use serde_json::{Map, Value};
6
7use super::ir::{RowCol, RowShape};
8
9pub fn restore_rows(shape: &RowShape, rows: &[Value]) -> Value {
16 let mut index: HashMap<Value, usize> = HashMap::new();
20 let mut buckets: Vec<Vec<&Value>> = Vec::new();
21 for (i, row) in rows.iter().enumerate() {
22 let key = root_key(shape, row).unwrap_or_else(|| Value::from(i as u64));
23 match index.get(&key) {
24 Some(&idx) => buckets[idx].push(row),
25 None => {
26 index.insert(key, buckets.len());
27 buckets.push(vec![row]);
28 }
29 }
30 }
31
32 let cols: Vec<&RowCol> = shape.columns.iter().collect();
33 let docs: Vec<Value> = buckets
34 .into_iter()
35 .map(|group| {
36 let present = shape
39 .present_alias
40 .as_deref()
41 .and_then(|a| row_val(group[0], a).as_str())
42 .map(|s| s.to_owned());
43 Value::Object(build_object(&cols, &group, 0, present.as_deref()))
44 })
45 .collect();
46 Value::Array(docs)
47}
48
49fn build_object(
55 cols: &[&RowCol],
56 rows: &[&Value],
57 path_len: usize,
58 present: Option<&str>,
59) -> Map<String, Value> {
60 let mut obj = Map::new();
61 for c in cols {
62 if c.json_path.len() == path_len + 1 || (!c.is_array && c.json_path.len() > path_len + 1) {
63 let val = row_val(rows[0], &c.alias).clone();
64 merge_path(
65 &mut obj,
66 &c.json_path[path_len..],
67 val,
68 present,
69 c.always,
70 c.is_bool,
71 );
72 }
73 }
74 let mut rels: Vec<String> = Vec::new();
76 for c in cols {
77 if c.is_array && c.json_path.len() > path_len + 1 {
78 let r = &c.json_path[path_len];
79 if !rels.iter().any(|x| x == r) {
80 rels.push(r.clone());
81 }
82 }
83 }
84 for r in rels {
85 let sub: Vec<&RowCol> = cols
86 .iter()
87 .copied()
88 .filter(|c| {
89 c.is_array && c.json_path.len() > path_len + 1 && c.json_path[path_len] == r
90 })
91 .collect();
92 obj.insert(r.clone(), relation_value(&sub, rows, path_len));
93 }
94 obj
95}
96
97fn relation_value(cols: &[&RowCol], rows: &[&Value], path_len: usize) -> Value {
100 let one = cols
101 .first()
102 .and_then(|c| c.ones.get(path_len).copied())
103 .unwrap_or_else(|| cols.first().map(|c| c.one).unwrap_or(false));
104 let id_col = cols
105 .iter()
106 .find(|c| c.json_path.len() == path_len + 2 && c.json_path[path_len + 1] == "_id");
107 let mut order: Vec<String> = Vec::new();
110 let mut groups: HashMap<String, Vec<&Value>> = HashMap::new();
111 for row in rows {
112 if cols.iter().all(|c| row_val(row, &c.alias).is_null()) {
114 continue;
115 }
116 let key = match id_col.map(|c| row_val(row, &c.alias)) {
117 Some(v) if !v.is_null() => v.to_string(),
118 _ => format!("\u{0}{}", order.len()),
119 };
120 if !groups.contains_key(&key) {
121 order.push(key.clone());
122 }
123 groups.entry(key).or_default().push(row);
124 }
125 let docs: Vec<Value> = order
126 .into_iter()
127 .map(|k| Value::Object(build_object(cols, &groups[&k], path_len + 1, None)))
128 .collect();
129 if one {
130 docs.into_iter().next().unwrap_or(Value::Null)
131 } else {
132 Value::Array(docs)
133 }
134}
135
136fn row_val<'a>(row: &'a Value, alias: &str) -> &'a Value {
138 match row {
139 Value::Object(map) => map.get(alias).unwrap_or(&Value::Null),
140 _ => &Value::Null,
141 }
142}
143
144fn root_key(shape: &RowShape, row: &Value) -> Option<Value> {
147 let id_alias = shape
148 .columns
149 .iter()
150 .find(|c| !c.is_array && c.json_path.len() == 1 && c.json_path[0] == "_id")?
151 .alias
152 .clone();
153 row.get(&id_alias).cloned()
154}
155
156fn merge_path(
170 obj: &mut Map<String, Value>,
171 path: &[String],
172 val: Value,
173 present: Option<&str>,
174 always: bool,
175 is_bool: bool,
176) {
177 let val = if is_bool { to_json_bool(val) } else { val };
178 if path.len() <= 1 {
179 if let Some(k) = path.first() {
180 if always || !val.is_null() || present_contains(present, k) {
181 obj.insert(k.clone(), val);
182 }
183 }
184 return;
185 }
186 let head = path[0].clone();
187 let entry = obj
188 .entry(head.clone())
189 .or_insert_with(|| Value::Object(Map::new()));
190 if let Value::Object(m) = entry {
191 merge_path(m, &path[1..], val, present, always, false);
192 }
193}
194
195fn to_json_bool(v: Value) -> Value {
198 let as_num = match &v {
199 Value::Number(n) => n.as_f64(),
200 Value::String(s) => s.parse::<f64>().ok(),
201 _ => None,
202 };
203 match as_num {
204 Some(1.0) => Value::Bool(true),
205 Some(0.0) => Value::Bool(false),
206 _ => v,
207 }
208}
209
210fn present_contains(present: Option<&str>, key: &str) -> bool {
212 match present {
213 Some(s) => s.contains(&format!(",{},", key)),
214 None => false,
215 }
216}
217
218pub fn restore_rows_json(shape: &Value, rows: &Value) -> Result<Value, String> {
220 let shape = RowShape::from_value(shape)?;
221 let rows = match rows {
222 Value::Array(a) => a.clone(),
223 _ => Vec::new(),
224 };
225 Ok(restore_rows(&shape, &rows))
226}
227
228impl RowShape {
229 pub fn from_value(v: &Value) -> Result<RowShape, String> {
231 let obj = v
232 .get("columns")
233 .and_then(|c| c.as_array())
234 .ok_or("rowShape 缺少 columns")?;
235 let mut columns = Vec::new();
236 for c in obj {
237 let alias = c
238 .get("alias")
239 .and_then(|a| a.as_str())
240 .ok_or("列缺 alias")?
241 .to_string();
242 let path: Vec<String> = c
243 .get("path")
244 .and_then(|p| p.as_array())
245 .map(|arr| {
246 arr.iter()
247 .filter_map(|s| s.as_str().map(String::from))
248 .collect()
249 })
250 .unwrap_or_default();
251 let is_array = c.get("isArray").and_then(|b| b.as_bool()).unwrap_or(false);
252 let one = c.get("one").and_then(|b| b.as_bool()).unwrap_or(false);
253 let ones: Vec<bool> = match c.get("ones").and_then(|o| o.as_array()) {
255 Some(a) => a.iter().map(|b| b.as_bool().unwrap_or(false)).collect(),
256 None if is_array => vec![one],
257 None => Vec::new(),
258 };
259 let sub_shape = c
260 .get("subShape")
261 .and_then(|s| {
262 if s.is_null() {
263 None
264 } else {
265 Some(RowShape::from_value(s))
266 }
267 })
268 .transpose()?;
269 let always = c.get("always").and_then(|b| b.as_bool()).unwrap_or(false);
270 let is_bool = c.get("bool").and_then(|b| b.as_bool()).unwrap_or(false);
271 columns.push(RowCol {
272 alias,
273 json_path: path,
274 is_array,
275 one,
276 ones,
277 sub_shape,
278 always,
279 is_bool,
280 });
281 }
282 let present_alias = v
283 .get("present")
284 .and_then(|p| p.as_str())
285 .filter(|s| !s.is_empty())
286 .map(|s| s.to_string());
287 Ok(RowShape {
288 columns,
289 present_alias,
290 })
291 }
292}