1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use crate::errors::*;

use crate::{proto, base, Warnable};

use crate::components::{Component, Named};
use crate::base::{Value, ValueProperties, IndexKey, DataframeProperties};
use crate::utilities::{prepend, get_argument};
use indexmap::map::IndexMap;
use crate::utilities::properties::select_properties;

impl Component for proto::ToDataframe {
    fn propagate_property(
        &self,
        _privacy_definition: &Option<proto::PrivacyDefinition>,
        public_arguments: IndexMap<base::IndexKey, &Value>,
        properties: base::NodeProperties,
        _node_id: u32
    ) -> Result<Warnable<ValueProperties>> {

        let data_property = properties.get::<IndexKey>(&"data".into())
            .ok_or("data: missing")?.array()
            .map_err(prepend("data:"))?;

        if !data_property.releasable {
            data_property.assert_is_not_aggregated()?;
        }

        let column_names = self.get_names(
            public_arguments, IndexMap::new(), None)?;

        if column_names.len() != data_property.num_columns()? as usize {
            return Err("Column names must be the same length as the number of columns.".into())
        }

        Ok(ValueProperties::Dataframe(DataframeProperties {
            children: column_names.into_iter().enumerate()
                .map(|(idx, name)| Ok((
                    name,
                    select_properties(data_property, idx)?
                )))
                .collect::<Result<IndexMap<IndexKey, ValueProperties>>>()?,
        }).into())
    }
}

impl Named for proto::ToDataframe {
    fn get_names(
        &self,
        public_arguments: IndexMap<base::IndexKey, &Value>,
        _argument_variables: IndexMap<base::IndexKey, Vec<IndexKey>>,
        _release: Option<&Value>
    ) -> Result<Vec<IndexKey>> {
        Ok(match get_argument(&public_arguments, "names")?.ref_array()? {
            base::Array::Str(names) =>
                names.iter().map(|v| IndexKey::from(v.to_string())).collect(),
            base::Array::Bool(names) =>
                names.iter().map(|v| IndexKey::from(*v)).collect(),
            base::Array::Int(names) =>
                names.iter().map(|v| IndexKey::from(*v)).collect(),
            _ => return Err("floats may not be used for column names".into())
        })
    }
}