reject multiple row args support (#10163)

# Description
This PR fixes `reject` failing when providing row items in ascending
order.


# User-Facing Changes
users can now `reject` multiple rows independently of each other.
```nushell
let foo = [[a b]; [ 1 2] [3 4] [ 5 6]]
# this will work independant of the order
print ($foo | reject 2 1)
print ($foo | reject 1 2)
```

---------

Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com>
This commit is contained in:
Tilen Gimpelj 2023-09-09 20:59:31 +02:00 committed by GitHub
parent 17abbdf6e0
commit 248aca7a44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 7 deletions

View file

@ -1,10 +1,12 @@
use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath};
use nu_protocol::ast::{Call, CellPath, PathMember};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, Record, ShellError, Signature, Span,
SyntaxShape, Type, Value,
};
use std::cmp::Reverse;
use std::collections::HashSet;
#[derive(Clone)]
pub struct Reject;
@ -70,6 +72,17 @@ impl Command for Reject {
Span::test_data(),
)),
},
Example {
description: "Reject a row in a table",
example: "[[a, b]; [1, 2] [3, 4]] | reject 1",
result: Some(Value::List {
vals: vec![Value::test_record(Record {
cols: vec!["a".to_string(), "b".to_string()],
vals: vec![Value::test_int(1), Value::test_int(2)],
})],
span: Span::test_data(),
}),
},
Example {
description: "Reject the specified field in a record",
example: "{a: 1, b: 2} | reject a",
@ -99,15 +112,47 @@ fn reject(
input: PipelineData,
cell_paths: Vec<CellPath>,
) -> Result<PipelineData, ShellError> {
let mut unique_rows: HashSet<usize> = HashSet::new();
let val = input.into_value(span);
let mut val = val;
let mut columns = vec![];
for c in cell_paths {
if !columns.contains(&c) {
columns.push(c);
let mut new_columns = vec![];
let mut new_rows = vec![];
for column in cell_paths {
let CellPath { ref members } = column;
match members.get(0) {
Some(PathMember::Int { val, span, .. }) => {
if members.len() > 1 {
return Err(ShellError::GenericError(
"Reject only allows row numbers for rows".into(),
"extra after row number".into(),
Some(*span),
None,
Vec::new(),
));
}
if !unique_rows.contains(val) {
unique_rows.insert(*val);
new_rows.push(column);
}
}
for cell_path in columns {
_ => {
if !new_columns.contains(&column) {
new_columns.push(column)
}
}
};
}
new_rows.sort_unstable_by_key(|k| {
Reverse({
match k.members[0] {
PathMember::Int { val, .. } => val,
PathMember::String { .. } => usize::MIN,
}
})
});
new_columns.append(&mut new_rows);
for cell_path in new_columns {
val.remove_data_at_cell_path(&cell_path.members)?;
}
Ok(val.into_pipeline_data())

View file

@ -79,6 +79,12 @@ fn ignores_duplicate_columns_rejected() {
assert_eq!(actual.out, "last name");
}
#[test]
fn ignores_duplicate_rows_rejected() {
let actual = nu!("[[a,b];[1 2] [3 4] [5 6]] | reject 2 2 | to nuon");
assert_eq!(actual.out, "[[a, b]; [1, 2], [3, 4]]");
}
#[test]
fn reject_record_from_raw_eval() {
let actual = nu!(r#"{"a": 3} | reject a | describe"#);
@ -143,3 +149,15 @@ fn reject_optional_row() {
let actual = nu!("[{foo: 'bar'}] | reject 3? | to nuon");
assert_eq!(actual.out, "[[foo]; [bar]]");
}
#[test]
fn reject_multiple_rows_ascending() {
let actual = nu!("[[a,b];[1 2] [3 4] [5 6]] | reject 1 2 | to nuon");
assert_eq!(actual.out, "[[a, b]; [1, 2]]");
}
#[test]
fn reject_multiple_rows_descending() {
let actual = nu!("[[a,b];[1 2] [3 4] [5 6]] | reject 2 1 | to nuon");
assert_eq!(actual.out, "[[a, b]; [1, 2]]");
}