use std::borrow::Cow;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use crate::config::GroupRollupMode;
use crate::proto::get_features_resp::{AggregateArgs, AggregateOptions, ColumnTypeOptions};
use crate::proto::{ColumnType, GetFeaturesResp};
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct Features<'a> {
#[serde(default)]
pub group_by: bool,
#[serde(default)]
pub group_rollup_mode: Vec<GroupRollupMode>,
#[serde(default)]
pub split_by: bool,
#[serde(default)]
pub filter_ops: IndexMap<ColumnType, Vec<Cow<'a, str>>>,
#[serde(default)]
pub aggregates: IndexMap<ColumnType, Vec<AggSpec<'a>>>,
#[serde(default)]
pub sort: bool,
#[serde(default)]
pub expressions: bool,
#[serde(default)]
pub on_update: bool,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(untagged)]
pub enum AggSpec<'a> {
Single(Cow<'a, str>),
Multiple(Cow<'a, str>, Vec<ColumnType>),
}
impl<'a> From<Features<'a>> for GetFeaturesResp {
fn from(value: Features<'a>) -> GetFeaturesResp {
GetFeaturesResp {
group_by: value.group_by,
group_rollup_mode: value
.group_rollup_mode
.iter()
.map(|x| crate::proto::GroupRollupMode::from(*x) as i32)
.collect(),
split_by: value.split_by,
expressions: value.expressions,
on_update: value.on_update,
sort: value.sort,
aggregates: value
.aggregates
.iter()
.map(|(dtype, aggs)| {
(*dtype as u32, AggregateOptions {
aggregates: aggs
.iter()
.map(|agg| match agg {
AggSpec::Single(cow) => AggregateArgs {
name: cow.to_string(),
args: vec![],
},
AggSpec::Multiple(cow, column_types) => AggregateArgs {
name: cow.to_string(),
args: column_types.iter().map(|x| *x as i32).collect(),
},
})
.collect(),
})
})
.collect(),
filter_ops: value
.filter_ops
.iter()
.map(|(ty, options)| {
(*ty as u32, ColumnTypeOptions {
options: options.iter().map(|x| (*x).to_string()).collect(),
})
})
.collect(),
}
}
}