forked from extern/nushell
remove --column
from length
command and remove record
processing (#10091)
# Description This PR removes `record` processing from the `length` command. It just doesn't make sense to try and get the length of a record. This PR also removes the `--column` parameter. If you want to list or count columns, you could use `$table | columns` or `$table | columns | length`. close #10074 ### Before ![image](https://github.com/nushell/nushell/assets/343840/83488316-3ec4-4c32-9583-00341a71f46f) ### After Catches records two different ways now. with the `input_output_types` checker ![image](https://github.com/nushell/nushell/assets/343840/ca67f8b6-359e-4933-ab4d-1b702f8d79cf) and with additional logic in the command for cases like `echo` ![image](https://github.com/nushell/nushell/assets/343840/99064351-b208-4bd3-bab9-535f97cd7ad4) # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # After Submitting <!-- If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. -->
This commit is contained in:
parent
3d698b74d8
commit
af82eeca72
@ -1,9 +1,7 @@
|
|||||||
use nu_engine::column::get_columns;
|
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
|
||||||
Signature, Span, Type, Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -15,7 +13,7 @@ impl Command for Length {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Count the number of elements in the input."
|
"Count the number of items in an input list or rows in a table."
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
@ -24,7 +22,6 @@ impl Command for Length {
|
|||||||
(Type::List(Box::new(Type::Any)), Type::Int),
|
(Type::List(Box::new(Type::Any)), Type::Int),
|
||||||
(Type::Table(vec![]), Type::Int),
|
(Type::Table(vec![]), Type::Int),
|
||||||
])
|
])
|
||||||
.switch("column", "Show the number of columns in a table", Some('c'))
|
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,17 +31,12 @@ impl Command for Length {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let col = call.has_flag("column");
|
length_row(call, input)
|
||||||
if col {
|
|
||||||
length_col(engine_state, call, input)
|
|
||||||
} else {
|
|
||||||
length_row(call, input)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -55,32 +47,29 @@ impl Command for Length {
|
|||||||
result: Some(Value::test_int(5)),
|
result: Some(Value::test_int(5)),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Count the number of columns in a table",
|
description: "Count the number of rows in a table",
|
||||||
example: "[{columnA: A0 columnB: B0}] | length -c",
|
example: "[{a:1 b:2}, {a:2 b:3}] | length",
|
||||||
result: Some(Value::test_int(2)),
|
result: Some(Value::test_int(2)),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this simulates calling input | columns | length
|
|
||||||
fn length_col(
|
|
||||||
engine_state: &EngineState,
|
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
length_row(
|
|
||||||
call,
|
|
||||||
getcol(engine_state, call.head, input)
|
|
||||||
.expect("getcol() should not fail used in column command"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn length_row(call: &Call, input: PipelineData) -> Result<PipelineData, ShellError> {
|
fn length_row(call: &Call, input: PipelineData) -> Result<PipelineData, ShellError> {
|
||||||
match input {
|
match input {
|
||||||
PipelineData::Value(Value::Nothing { .. }, ..) => {
|
PipelineData::Value(Value::Nothing { .. }, ..) => {
|
||||||
Ok(Value::int(0, call.head).into_pipeline_data())
|
Ok(Value::int(0, call.head).into_pipeline_data())
|
||||||
}
|
}
|
||||||
|
// I added this here because input_output_type() wasn't catching a record
|
||||||
|
// being sent in as input from echo. e.g. "echo {a:1 b:2} | length"
|
||||||
|
PipelineData::Value(Value::Record { span, .. }, ..) => {
|
||||||
|
Err(ShellError::OnlySupportsThisInputType {
|
||||||
|
exp_input_type: "list, and table".into(),
|
||||||
|
wrong_type: "record".into(),
|
||||||
|
dst_span: call.head,
|
||||||
|
src_span: span,
|
||||||
|
})
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut count: i64 = 0;
|
let mut count: i64 = 0;
|
||||||
// Check for and propagate errors
|
// Check for and propagate errors
|
||||||
@ -95,43 +84,6 @@ fn length_row(call: &Call, input: PipelineData) -> Result<PipelineData, ShellErr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getcol(
|
|
||||||
engine_state: &EngineState,
|
|
||||||
span: Span,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
match input {
|
|
||||||
PipelineData::Empty => Ok(PipelineData::Empty),
|
|
||||||
PipelineData::Value(
|
|
||||||
Value::List {
|
|
||||||
vals: input_vals,
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
..,
|
|
||||||
) => {
|
|
||||||
let input_cols = get_columns(&input_vals);
|
|
||||||
Ok(input_cols
|
|
||||||
.into_iter()
|
|
||||||
.map(move |x| Value::String { val: x, span })
|
|
||||||
.into_pipeline_data(engine_state.ctrlc.clone()))
|
|
||||||
}
|
|
||||||
PipelineData::ListStream(stream, ..) => {
|
|
||||||
let v: Vec<_> = stream.into_iter().collect();
|
|
||||||
let input_cols = get_columns(&v);
|
|
||||||
|
|
||||||
Ok(input_cols
|
|
||||||
.into_iter()
|
|
||||||
.map(move |x| Value::String { val: x, span })
|
|
||||||
.into_pipeline_data(engine_state.ctrlc.clone()))
|
|
||||||
}
|
|
||||||
PipelineData::Value(..) | PipelineData::ExternalStream { .. } => {
|
|
||||||
let cols = vec![];
|
|
||||||
let vals = vec![];
|
|
||||||
Ok(Value::Record { cols, vals, span }.into_pipeline_data())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -40,9 +40,10 @@ fn gets_first_row_when_no_amount_given() {
|
|||||||
Playground::setup("first_test_3", |dirs, sandbox| {
|
Playground::setup("first_test_3", |dirs, sandbox| {
|
||||||
sandbox.with_files(vec![EmptyFile("caballeros.txt"), EmptyFile("arepas.clu")]);
|
sandbox.with_files(vec![EmptyFile("caballeros.txt"), EmptyFile("arepas.clu")]);
|
||||||
|
|
||||||
let actual = nu!(cwd: dirs.test(), "ls | first | length");
|
// FIXME: We should probably change first to return a one row table instead of a record here
|
||||||
|
let actual = nu!(cwd: dirs.test(), "ls | first | values | length");
|
||||||
|
|
||||||
assert_eq!(actual.out, "1");
|
assert_eq!(actual.out, "4");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,9 +33,10 @@ fn gets_last_row_when_no_amount_given() {
|
|||||||
Playground::setup("last_test_2", |dirs, sandbox| {
|
Playground::setup("last_test_2", |dirs, sandbox| {
|
||||||
sandbox.with_files(vec![EmptyFile("caballeros.txt"), EmptyFile("arepas.clu")]);
|
sandbox.with_files(vec![EmptyFile("caballeros.txt"), EmptyFile("arepas.clu")]);
|
||||||
|
|
||||||
let actual = nu!(cwd: dirs.test(), "ls | last | length");
|
// FIXME: We should probably change last to return a one row table instead of a record here
|
||||||
|
let actual = nu!(cwd: dirs.test(), "ls | last | values | length");
|
||||||
|
|
||||||
assert_eq!(actual.out, "1");
|
assert_eq!(actual.out, "4");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,14 +2,21 @@ use nu_test_support::nu;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn length_columns_in_cal_table() {
|
fn length_columns_in_cal_table() {
|
||||||
let actual = nu!("cal | length -c");
|
let actual = nu!("cal | columns | length");
|
||||||
|
|
||||||
assert_eq!(actual.out, "7");
|
assert_eq!(actual.out, "7");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn length_columns_no_rows() {
|
fn length_columns_no_rows() {
|
||||||
let actual = nu!("echo [] | length -c");
|
let actual = nu!("echo [] | length");
|
||||||
|
|
||||||
assert_eq!(actual.out, "0");
|
assert_eq!(actual.out, "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn length_fails_on_echo_record() {
|
||||||
|
let actual = nu!("echo {a:1 b:2} | length");
|
||||||
|
|
||||||
|
assert_eq!(actual.err.contains("only_supports_this_input_type"), true);
|
||||||
|
}
|
||||||
|
@ -264,7 +264,7 @@ fn update_will_insert() -> TestResult {
|
|||||||
#[test]
|
#[test]
|
||||||
fn length_for_columns() -> TestResult {
|
fn length_for_columns() -> TestResult {
|
||||||
run_test(
|
run_test(
|
||||||
r#"[[name,age,grade]; [bill,20,a] [a b c]] | length -c"#,
|
r#"[[name,age,grade]; [bill,20,a] [a b c]] | columns | length"#,
|
||||||
"3",
|
"3",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user