nu_data/utils/
split.rs

1use nu_errors::ShellError;
2use nu_protocol::{SpannedTypeName, TaggedDictBuilder, UntaggedValue, Value};
3use nu_source::Tag;
4
5use crate::utils::group;
6
7#[allow(clippy::type_complexity)]
8pub fn split(
9    value: &Value,
10    splitter: &Option<Box<dyn Fn(usize, &Value) -> Result<String, ShellError> + Send>>,
11    tag: impl Into<Tag>,
12) -> Result<Value, ShellError> {
13    let tag = tag.into();
14
15    let mut splits = indexmap::IndexMap::new();
16    let mut out = TaggedDictBuilder::new(&tag);
17
18    if splitter.is_none() {
19        out.insert_untagged("table", value.clone());
20        return Ok(out.into_value());
21    }
22
23    for (column, value) in value.row_entries() {
24        if !&value.is_table() {
25            return Err(ShellError::type_error(
26                "a table value",
27                value.spanned_type_name(),
28            ));
29        }
30
31        match group(value, splitter, &tag) {
32            Ok(grouped) => {
33                for (split_label, subset) in grouped.row_entries() {
34                    let s = splits
35                        .entry(split_label.clone())
36                        .or_insert(indexmap::IndexMap::new());
37
38                    if !&subset.is_table() {
39                        return Err(ShellError::type_error(
40                            "a table value",
41                            subset.spanned_type_name(),
42                        ));
43                    }
44
45                    s.insert(column.clone(), subset.clone());
46                }
47            }
48            Err(err) => return Err(err),
49        }
50    }
51
52    let mut out = TaggedDictBuilder::new(&tag);
53
54    for (k, v) in splits {
55        out.insert_untagged(k, UntaggedValue::row(v));
56    }
57
58    Ok(out.into_value())
59}