mirror of
https://github.com/nushell/nushell
synced 2024-12-26 04:53:09 +00:00
Issue 1787 (#1827)
This commit is contained in:
parent
460daf029b
commit
aadbcf5ce8
6 changed files with 227 additions and 10 deletions
|
@ -2,9 +2,11 @@ use crate::commands::WholeStreamCommand;
|
|||
use crate::prelude::*;
|
||||
use crate::utils::data_processing::{reducer_for, Reduce};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value};
|
||||
use nu_protocol::{Dictionary, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value};
|
||||
use num_traits::identities::Zero;
|
||||
|
||||
use indexmap::map::IndexMap;
|
||||
|
||||
pub struct Sum;
|
||||
|
||||
impl WholeStreamCommand for Sum {
|
||||
|
@ -54,13 +56,40 @@ impl WholeStreamCommand for Sum {
|
|||
|
||||
fn sum(RunnableContext { mut input, .. }: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let stream = async_stream! {
|
||||
let mut values = input.drain_vec().await;
|
||||
|
||||
let mut values: Vec<Value> = input.drain_vec().await;
|
||||
let action = reducer_for(Reduce::Sum);
|
||||
|
||||
match action(Value::zero(), values) {
|
||||
Ok(total) => yield ReturnSuccess::value(total),
|
||||
Err(err) => yield Err(err),
|
||||
if values.iter().all(|v| if let UntaggedValue::Primitive(_) = v.value {true} else {false}) {
|
||||
let total = action(Value::zero(), values)?;
|
||||
yield ReturnSuccess::value(total)
|
||||
} else {
|
||||
let mut column_values = IndexMap::new();
|
||||
for value in values {
|
||||
match value.value {
|
||||
UntaggedValue::Row(row_dict) => {
|
||||
for (key, value) in row_dict.entries.iter() {
|
||||
column_values
|
||||
.entry(key.clone())
|
||||
.and_modify(|v: &mut Vec<Value>| v.push(value.clone()))
|
||||
.or_insert(vec![value.clone()]);
|
||||
}
|
||||
},
|
||||
table => {},
|
||||
};
|
||||
}
|
||||
|
||||
let mut column_totals = IndexMap::new();
|
||||
for (col_name, col_vals) in column_values {
|
||||
let sum = action(Value::zero(), col_vals);
|
||||
match sum {
|
||||
Ok(value) => {
|
||||
column_totals.insert(col_name, value);
|
||||
},
|
||||
Err(err) => yield Err(err),
|
||||
};
|
||||
}
|
||||
yield ReturnSuccess::value(
|
||||
UntaggedValue::Row(Dictionary {entries: column_totals}).into_untagged_value())
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -198,9 +198,20 @@ pub fn evaluate(
|
|||
}
|
||||
|
||||
pub fn sum(data: Vec<Value>) -> Result<Value, ShellError> {
|
||||
Ok(data
|
||||
.into_iter()
|
||||
.fold(Value::zero(), |acc: Value, value| acc + value))
|
||||
let mut acc = Value::zero();
|
||||
for value in data {
|
||||
match value.value {
|
||||
UntaggedValue::Primitive(_) => acc = acc + value,
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Attempted to compute the sum of a value that cannot be summed.",
|
||||
"value appears here",
|
||||
value.tag.span,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(acc)
|
||||
}
|
||||
|
||||
fn formula(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use nu_test_support::fs::Stub::FileWithContentToBeTrimmed;
|
||||
use nu_test_support::playground::Playground;
|
||||
use nu_test_support::{nu, pipeline};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn all() {
|
||||
|
@ -60,3 +61,52 @@ fn outputs_zero_with_no_input() {
|
|||
assert_eq!(actual.out, "0");
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compute_sum_of_individual_row() -> Result<(), String> {
|
||||
let answers_for_columns = [
|
||||
("cpu", 88.257434),
|
||||
("mem", 3032375296.),
|
||||
("virtual", 102579965952.),
|
||||
];
|
||||
for (column_name, expected_value) in answers_for_columns.iter() {
|
||||
let actual = nu!(
|
||||
cwd: "tests/fixtures/formats/",
|
||||
format!("open sample-ps-output.json | select {} | sum | get {}", column_name, column_name)
|
||||
);
|
||||
let result =
|
||||
f64::from_str(&actual.out).map_err(|_| String::from("Failed to parse float."))?;
|
||||
assert_eq!(result, *expected_value);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compute_sum_of_table() -> Result<(), String> {
|
||||
let answers_for_columns = [
|
||||
("cpu", 88.257434),
|
||||
("mem", 3032375296.),
|
||||
("virtual", 102579965952.),
|
||||
];
|
||||
for (column_name, expected_value) in answers_for_columns.iter() {
|
||||
let actual = nu!(
|
||||
cwd: "tests/fixtures/formats/",
|
||||
format!("open sample-ps-output.json | select cpu mem virtual | sum | get {}", column_name)
|
||||
);
|
||||
let result =
|
||||
f64::from_str(&actual.out).map_err(|_| String::from("Failed to parse float."))?;
|
||||
assert_eq!(result, *expected_value);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sum_of_a_row_containing_a_table_is_an_error() {
|
||||
let actual = nu!(
|
||||
cwd: "tests/fixtures/formats/",
|
||||
"open sample-sys-output.json | sum"
|
||||
);
|
||||
assert!(actual
|
||||
.err
|
||||
.contains("Attempted to compute the sum of a value that cannot be summed."));
|
||||
}
|
||||
|
|
|
@ -531,7 +531,8 @@ impl std::ops::Add for Value {
|
|||
|
||||
UntaggedValue::from(left.add(right)).into_value(tag)
|
||||
}
|
||||
(_, _) => unimplemented!("Internal error: can't add non-primitives."),
|
||||
(_, _) => UntaggedValue::Error(ShellError::unimplemented("Can't add non-primitives."))
|
||||
.into_value(tag),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
1
tests/fixtures/formats/sample-ps-output.json
vendored
Normal file
1
tests/fixtures/formats/sample-ps-output.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
[{"pid":10390,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":132112384,"virtual":4989624320},{"pid":10461,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":126992384,"virtual":4995346432},{"pid":10530,"name":"kworker/6:1-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":10593,"name":"kworker/1:1-mm_percpu_wq","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":10650,"name":"chrome","status":"Sleeping","cpu":8.026974,"mem":262434816,"virtual":5217419264},{"pid":10803,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":48173056,"virtual":542531584},{"pid":11191,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":124092416,"virtual":4975763456},{"pid":11210,"name":"kworker/7:0-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":11254,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":113070080,"virtual":4971659264},{"pid":11279,"name":"kworker/u16:0-events_unbound","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":11476,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":88993792,"virtual":4937097216},{"pid":12755,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":163397632,"virtual":5034328064},{"pid":12772,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":113561600,"virtual":4985073664},{"pid":14351,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":111861760,"virtual":4962754560},{"pid":17818,"name":"udisksd","status":"Sleeping","cpu":0.0,"mem":14409728,"virtual":402935808},{"pid":17815,"name":".gvfs-udisks2-v","status":"Sleeping","cpu":0.0,"mem":16199680,"virtual":585306112},{"pid":17831,"name":".gvfs-mtp-volum","status":"Sleeping","cpu":0.0,"mem":6393856,"virtual":454680576},{"pid":17836,"name":".gvfs-gphoto2-v","status":"Sleeping","cpu":0.0,"mem":7110656,"virtual":456966144},{"pid":17841,"name":".gvfs-afc-volum","status":"Sleeping","cpu":0.0,"mem":8585216,"virtual":537448448},{"pid":17846,"name":".gvfsd-trash-wr","status":"Sleeping","cpu":0.0,"mem":12767232,"virtual":577998848},{"pid":17856,"name":".gvfsd-network-","status":"Sleeping","cpu":0.0,"mem":13295616,"virtual":654110720},{"pid":17862,"name":".gvfsd-dnssd-wr","status":"Sleeping","cpu":0.0,"mem":7639040,"virtual":533233664},{"pid":17869,"name":"dconf-service","status":"Sleeping","cpu":0.0,"mem":5365760,"virtual":158957568},{"pid":18153,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":183738368,"virtual":5128962048},{"pid":23033,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":166035456,"virtual":5074878464},{"pid":24101,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":101224448,"virtual":4956262400},{"pid":24832,"name":"kworker/7:2-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":24912,"name":"kworker/5:2-events_power_efficient","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":25228,"name":"kworker/4:3-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":25678,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":117522432,"virtual":4970983424},{"pid":25706,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":30760960,"virtual":528375808},{"pid":26080,"name":"kworker/1:0-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":26818,"name":"kworker/2:0-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":26827,"name":"kworker/6:2-mm_percpu_wq","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":26832,"name":"kworker/0:2-mm_percpu_wq","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":26843,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":116621312,"virtual":4982403072},{"pid":27163,"name":"kworker/3:2-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":27800,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":128200704,"virtual":4965363712},{"pid":27820,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":54960128,"virtual":4895596544},{"pid":27898,"name":"kworker/3:0-mm_percpu_wq","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":27977,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":141930496,"virtual":4982546432},{"pid":28035,"name":"kworker/u16:1-events_unbound","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":28104,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":126853120,"virtual":5003902976},{"pid":28158,"name":"nu","status":"Sleeping","cpu":0.0,"mem":27344896,"virtual":870764544},{"pid":28236,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":450560000,"virtual":5389582336},{"pid":29186,"name":"kworker/5:0-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":30140,"name":"kworker/u16:2-events_unbound","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":30142,"name":"nu_plugin_core_","status":"Zombie","cpu":0.0,"mem":0,"virtual":0},{"pid":30356,"name":"sh","status":"Sleeping","cpu":0.0,"mem":3743744,"virtual":224092160},{"pid":30360,"name":"nu_plugin_core_ps","status":"Sleeping","cpu":80.23046000000001,"mem":6422528,"virtual":633016320}]
|
125
tests/fixtures/formats/sample-sys-output.json
vendored
Normal file
125
tests/fixtures/formats/sample-sys-output.json
vendored
Normal file
|
@ -0,0 +1,125 @@
|
|||
{
|
||||
"host": {
|
||||
"name": "Linux",
|
||||
"release": "5.4.33",
|
||||
"version": "#1-NixOS SMP Fri Apr 17 08:50:26 UTC 2020",
|
||||
"hostname": "nixos",
|
||||
"arch": "x86_64",
|
||||
"uptime": 105126,
|
||||
"sessions": [
|
||||
"alexj"
|
||||
]
|
||||
},
|
||||
"cpu": {
|
||||
"cores": 8,
|
||||
"current ghz": 2.4200000000000004,
|
||||
"min ghz": 0.39999999999999997,
|
||||
"max ghz": 3.4000000000000004
|
||||
},
|
||||
"disks": [
|
||||
{
|
||||
"device": "/dev/disk/by-uuid/e9adff48-c37b-4631-b98b-eaec9b410ba3",
|
||||
"type": "ext4",
|
||||
"mount": "/",
|
||||
"total": 483445473280,
|
||||
"used": 121866776576,
|
||||
"free": 336949624832
|
||||
},
|
||||
{
|
||||
"device": "/dev/disk/by-uuid/e9adff48-c37b-4631-b98b-eaec9b410ba3",
|
||||
"type": "ext4",
|
||||
"mount": "/nix/store",
|
||||
"total": 483445473280,
|
||||
"used": 121866776576,
|
||||
"free": 336949624832
|
||||
},
|
||||
{
|
||||
"device": "/dev/sda3",
|
||||
"type": "vfat",
|
||||
"mount": "/boot",
|
||||
"total": 534757376,
|
||||
"used": 72650752,
|
||||
"free": 462106624
|
||||
}
|
||||
],
|
||||
"mem": {
|
||||
"total": 16256524000,
|
||||
"free": 3082268000,
|
||||
"swap total": 18874344000,
|
||||
"swap free": 18874344000
|
||||
},
|
||||
"temp": [
|
||||
{
|
||||
"unit": "iwlwifi_1",
|
||||
"temp": 42.0
|
||||
},
|
||||
{
|
||||
"unit": "acpitz",
|
||||
"temp": 53.00000000000001,
|
||||
"critical": 103.0
|
||||
},
|
||||
{
|
||||
"unit": "coretemp",
|
||||
"label": "Core 1",
|
||||
"temp": 52.00000000000001,
|
||||
"high": 100.0,
|
||||
"critical": 100.0
|
||||
},
|
||||
{
|
||||
"unit": "coretemp",
|
||||
"label": "Core 2",
|
||||
"temp": 52.00000000000001,
|
||||
"high": 100.0,
|
||||
"critical": 100.0
|
||||
},
|
||||
{
|
||||
"unit": "coretemp",
|
||||
"label": "Package id 0",
|
||||
"temp": 52.00000000000001,
|
||||
"high": 100.0,
|
||||
"critical": 100.0
|
||||
},
|
||||
{
|
||||
"unit": "coretemp",
|
||||
"label": "Core 3",
|
||||
"temp": 51.00000000000001,
|
||||
"high": 100.0,
|
||||
"critical": 100.0
|
||||
},
|
||||
{
|
||||
"unit": "coretemp",
|
||||
"label": "Core 0",
|
||||
"temp": 51.00000000000001,
|
||||
"high": 100.0,
|
||||
"critical": 100.0
|
||||
},
|
||||
{
|
||||
"unit": "pch_skylake",
|
||||
"temp": 48.00000000000001
|
||||
}
|
||||
],
|
||||
"net": [
|
||||
{
|
||||
"name": "wlp2s0",
|
||||
"sent": 387642399,
|
||||
"recv": 15324719784
|
||||
},
|
||||
{
|
||||
"name": "lo",
|
||||
"sent": 2667,
|
||||
"recv": 2667
|
||||
},
|
||||
{
|
||||
"name": "vboxnet0",
|
||||
"sent": 0,
|
||||
"recv": 0
|
||||
}
|
||||
],
|
||||
"battery": [
|
||||
{
|
||||
"vendor": "ASUSTeK",
|
||||
"model": "ASUS Battery",
|
||||
"cycles": 445
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue