forked from extern/nushell
histogram: optionally use a valuator for histogram value.
This commit is contained in:
parent
8ff15c46c1
commit
0db4180cea
@ -1,16 +1,13 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value};
|
use nu_protocol::{
|
||||||
|
ColumnPath, ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value,
|
||||||
|
};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct Histogram;
|
pub struct Histogram;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct HistogramArgs {
|
|
||||||
rest: Vec<Tagged<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl WholeStreamCommand for Histogram {
|
impl WholeStreamCommand for Histogram {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -18,10 +15,17 @@ impl WholeStreamCommand for Histogram {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("histogram").rest(
|
Signature::build("histogram")
|
||||||
SyntaxShape::String,
|
.named(
|
||||||
"column name to give the histogram's frequency column",
|
"use",
|
||||||
)
|
SyntaxShape::ColumnPath,
|
||||||
|
"Use data at the column path given as valuator",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.rest(
|
||||||
|
SyntaxShape::ColumnPath,
|
||||||
|
"column name to give the histogram's frequency column",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -64,22 +68,37 @@ pub async fn histogram(
|
|||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let registry = registry.clone();
|
let registry = registry.clone();
|
||||||
let name = args.call_info.name_tag.clone();
|
let name = args.call_info.name_tag.clone();
|
||||||
|
let (input, args) = args.evaluate_once(®istry).await?.parts();
|
||||||
|
|
||||||
let (HistogramArgs { rest: mut columns }, input) = args.process(®istry).await?;
|
|
||||||
let values: Vec<Value> = input.collect().await;
|
let values: Vec<Value> = input.collect().await;
|
||||||
|
|
||||||
let column_grouper = if !columns.is_empty() {
|
let mut columns = args
|
||||||
Some(columns.remove(0))
|
.positional_iter()
|
||||||
|
.map(|c| c.as_column_path())
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let evaluate_with = if let Some(path) = args.get("use") {
|
||||||
|
Some(evaluator(path.as_column_path()?.item))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let column_names_supplied: Vec<_> = columns.iter().map(|f| f.item.clone()).collect();
|
let column_grouper = if !columns.is_empty() {
|
||||||
|
match columns.remove(0).split_last() {
|
||||||
let frequency_column_name = if column_names_supplied.is_empty() {
|
Some((key, _)) => Some(key.as_string().tagged(&name)),
|
||||||
"frequency".to_string()
|
None => None,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
column_names_supplied[0].clone()
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let frequency_column_name = if columns.is_empty() {
|
||||||
|
"frequency".to_string()
|
||||||
|
} else if let Some((key, _)) = columns[0].split_last() {
|
||||||
|
key.as_string()
|
||||||
|
} else {
|
||||||
|
"frecuency".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let column = if let Some(ref column) = column_grouper {
|
let column = if let Some(ref column) = column_grouper {
|
||||||
@ -94,7 +113,7 @@ pub async fn histogram(
|
|||||||
grouper: Some(Box::new(move |_, _| Ok(String::from("frequencies")))),
|
grouper: Some(Box::new(move |_, _| Ok(String::from("frequencies")))),
|
||||||
splitter: Some(splitter(column_grouper)),
|
splitter: Some(splitter(column_grouper)),
|
||||||
format: None,
|
format: None,
|
||||||
eval: &None,
|
eval: &evaluate_with,
|
||||||
},
|
},
|
||||||
&name,
|
&name,
|
||||||
)?;
|
)?;
|
||||||
@ -155,6 +174,23 @@ pub async fn histogram(
|
|||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn evaluator(by: ColumnPath) -> Box<dyn Fn(usize, &Value) -> Result<Value, ShellError> + Send> {
|
||||||
|
Box::new(move |_: usize, value: &Value| {
|
||||||
|
let path = by.clone();
|
||||||
|
|
||||||
|
let eval = nu_value_ext::get_data_by_column_path(
|
||||||
|
value,
|
||||||
|
&path,
|
||||||
|
Box::new(move |(_, _, error)| error),
|
||||||
|
);
|
||||||
|
|
||||||
|
match eval {
|
||||||
|
Ok(with_value) => Ok(with_value),
|
||||||
|
Err(reason) => Err(reason),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn splitter(
|
fn splitter(
|
||||||
by: Option<Tagged<String>>,
|
by: Option<Tagged<String>>,
|
||||||
) -> Box<dyn Fn(usize, &Value) -> Result<String, ShellError> + Send> {
|
) -> Box<dyn Fn(usize, &Value) -> Result<String, ShellError> + Send> {
|
||||||
|
@ -62,6 +62,43 @@ fn zero_division_error() -> UntaggedValue {
|
|||||||
UntaggedValue::Error(ShellError::untagged_runtime_error("division by zero"))
|
UntaggedValue::Error(ShellError::untagged_runtime_error("division by zero"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unsafe_compute_values(
|
||||||
|
operator: Operator,
|
||||||
|
left: &UntaggedValue,
|
||||||
|
right: &UntaggedValue,
|
||||||
|
) -> Result<UntaggedValue, (&'static str, &'static str)> {
|
||||||
|
let computed = compute_values(operator, left, right);
|
||||||
|
|
||||||
|
if computed.is_ok() {
|
||||||
|
return computed;
|
||||||
|
}
|
||||||
|
|
||||||
|
match (left, right) {
|
||||||
|
(UntaggedValue::Primitive(lhs), UntaggedValue::Primitive(rhs)) => match (lhs, rhs) {
|
||||||
|
(Primitive::Filesize(x), Primitive::Int(y)) => match operator {
|
||||||
|
Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::Int(x + y))),
|
||||||
|
Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Int(x - y))),
|
||||||
|
Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Int(x * y))),
|
||||||
|
Operator::Divide => Ok(UntaggedValue::Primitive(Primitive::Decimal(
|
||||||
|
bigdecimal::BigDecimal::from(*x) / bigdecimal::BigDecimal::from(y.clone()),
|
||||||
|
))),
|
||||||
|
_ => Err((left.type_name(), right.type_name())),
|
||||||
|
},
|
||||||
|
(Primitive::Int(x), Primitive::Filesize(y)) => match operator {
|
||||||
|
Operator::Plus => Ok(UntaggedValue::Primitive(Primitive::Int(x + y))),
|
||||||
|
Operator::Minus => Ok(UntaggedValue::Primitive(Primitive::Int(x - y))),
|
||||||
|
Operator::Multiply => Ok(UntaggedValue::Primitive(Primitive::Int(x * y))),
|
||||||
|
Operator::Divide => Ok(UntaggedValue::Primitive(Primitive::Decimal(
|
||||||
|
bigdecimal::BigDecimal::from(x.clone()) / bigdecimal::BigDecimal::from(*y),
|
||||||
|
))),
|
||||||
|
_ => Err((left.type_name(), right.type_name())),
|
||||||
|
},
|
||||||
|
_ => Err((left.type_name(), right.type_name())),
|
||||||
|
},
|
||||||
|
_ => Err((left.type_name(), right.type_name())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn compute_values(
|
pub fn compute_values(
|
||||||
operator: Operator,
|
operator: Operator,
|
||||||
left: &UntaggedValue,
|
left: &UntaggedValue,
|
||||||
|
Loading…
Reference in New Issue
Block a user