forked from extern/nushell
Move command changes. Refactorings. (#2683)
Continuing on anchoring and improvements on Nu's overall internal commands (#2635). `move column` sub command has been turned into the command `move` since we use it to move exclusively columns. Examples added as well. Fixed it to carry along any anchor locations that might be in place if table to be moved originates from other sources.
This commit is contained in:
committed by
GitHub
parent
bc6c884a14
commit
b6d19cc9fa
@ -159,7 +159,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
whole_stream_command(Ansi),
|
||||
whole_stream_command(Char),
|
||||
// Column manipulation
|
||||
whole_stream_command(MoveColumn),
|
||||
whole_stream_command(Move),
|
||||
whole_stream_command(Reject),
|
||||
whole_stream_command(Select),
|
||||
whole_stream_command(Get),
|
||||
|
@ -213,7 +213,7 @@ pub(crate) use math::{
|
||||
};
|
||||
pub(crate) use merge::Merge;
|
||||
pub(crate) use mkdir::Mkdir;
|
||||
pub(crate) use move_::{Move, MoveColumn, Mv};
|
||||
pub(crate) use move_::{Move, Mv};
|
||||
pub(crate) use next::Next;
|
||||
pub(crate) use nth::Nth;
|
||||
pub(crate) use open::Open;
|
||||
@ -285,6 +285,7 @@ mod tests {
|
||||
whole_stream_command(Append),
|
||||
whole_stream_command(GroupBy),
|
||||
whole_stream_command(Insert),
|
||||
whole_stream_command(Move),
|
||||
whole_stream_command(Update),
|
||||
whole_stream_command(Empty),
|
||||
]
|
||||
|
@ -175,8 +175,8 @@ async fn from_yaml(
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::*;
|
||||
use nu_plugin::row;
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_protocol::row;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -51,30 +51,30 @@ impl WholeStreamCommand for Command {
|
||||
result: Some(vec![UntaggedValue::row(indexmap! {
|
||||
"File".to_string() => UntaggedValue::Table(vec![
|
||||
UntaggedValue::row(indexmap! {
|
||||
"modified".to_string() => date("2019-07-23".tagged_unknown()).unwrap().into(),
|
||||
"name".to_string() => UntaggedValue::string("Andrés.txt").into(),
|
||||
"type".to_string() => UntaggedValue::string("File").into(),
|
||||
"chickens".to_string() => UntaggedValue::int(10).into(),
|
||||
"modified".to_string() => date("2019-07-23".tagged_unknown()).unwrap().into(),
|
||||
}).into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"modified".to_string() => date("2019-09-24".tagged_unknown()).unwrap().into(),
|
||||
"name".to_string() => UntaggedValue::string("Andrés.txt").into(),
|
||||
"type".to_string() => UntaggedValue::string("File").into(),
|
||||
"chickens".to_string() => UntaggedValue::int(20).into(),
|
||||
"modified".to_string() => date("2019-09-24".tagged_unknown()).unwrap().into(),
|
||||
}).into(),
|
||||
]).into(),
|
||||
"Dir".to_string() => UntaggedValue::Table(vec![
|
||||
UntaggedValue::row(indexmap! {
|
||||
"modified".to_string() => date("2019-07-23".tagged_unknown()).unwrap().into(),
|
||||
"name".to_string() => UntaggedValue::string("Jonathan").into(),
|
||||
"type".to_string() => UntaggedValue::string("Dir").into(),
|
||||
"chickens".to_string() => UntaggedValue::int(5).into(),
|
||||
"modified".to_string() => date("2019-07-23".tagged_unknown()).unwrap().into(),
|
||||
}).into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"modified".to_string() => date("2019-09-24".tagged_unknown()).unwrap().into(),
|
||||
"name".to_string() => UntaggedValue::string("Yehuda").into(),
|
||||
"type".to_string() => UntaggedValue::string("Dir").into(),
|
||||
"chickens".to_string() => UntaggedValue::int(4).into(),
|
||||
"modified".to_string() => date("2019-09-24".tagged_unknown()).unwrap().into(),
|
||||
}).into(),
|
||||
]).into(),
|
||||
})
|
||||
@ -278,9 +278,10 @@ pub fn group(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::group;
|
||||
use nu_data::utils::helpers::{committers, date, int, row, string, table};
|
||||
use nu_data::utils::helpers::committers;
|
||||
use nu_errors::ShellError;
|
||||
use nu_source::*;
|
||||
use nu_test_support::value::{date, int, row, string, table};
|
||||
|
||||
#[test]
|
||||
fn groups_table_by_date_column() -> Result<(), ShellError> {
|
||||
|
@ -38,9 +38,8 @@ mod tests {
|
||||
avg::average, max::maximum, median::median, min::minimum, mode::mode, stddev::stddev,
|
||||
sum::summation, utils::calculate, utils::MathFunction, variance::variance,
|
||||
};
|
||||
use nu_plugin::row;
|
||||
use nu_plugin::test_helpers::value::{decimal, decimal_from_float, int, table};
|
||||
use nu_protocol::Value;
|
||||
use nu_protocol::{row, Value};
|
||||
use nu_test_support::value::{decimal, decimal_from_float, int, table};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
@ -71,14 +70,14 @@ mod tests {
|
||||
values: vec![int(10)],
|
||||
expected_err: None,
|
||||
expected_res: vec![
|
||||
Ok(decimal(10)),
|
||||
Ok(decimal_from_float(10.0)),
|
||||
Ok(int(10)),
|
||||
Ok(int(10)),
|
||||
Ok(int(10)),
|
||||
Ok(table(&[int(10)])),
|
||||
Ok(decimal(0)),
|
||||
Ok(decimal_from_float(0.0)),
|
||||
Ok(int(10)),
|
||||
Ok(decimal(0)),
|
||||
Ok(decimal_from_float(0.0)),
|
||||
],
|
||||
},
|
||||
TestCase {
|
||||
@ -86,7 +85,7 @@ mod tests {
|
||||
values: vec![int(10), int(20), int(30)],
|
||||
expected_err: None,
|
||||
expected_res: vec![
|
||||
Ok(decimal(20)),
|
||||
Ok(decimal_from_float(20.0)),
|
||||
Ok(int(10)),
|
||||
Ok(int(30)),
|
||||
Ok(int(20)),
|
||||
@ -101,13 +100,13 @@ mod tests {
|
||||
values: vec![int(10), decimal_from_float(26.5), decimal_from_float(26.5)],
|
||||
expected_err: None,
|
||||
expected_res: vec![
|
||||
Ok(decimal(21)),
|
||||
Ok(decimal_from_float(21.0)),
|
||||
Ok(int(10)),
|
||||
Ok(decimal_from_float(26.5)),
|
||||
Ok(decimal_from_float(26.5)),
|
||||
Ok(table(&[decimal_from_float(26.5)])),
|
||||
Ok(decimal(BigDecimal::from_str("7.77817459305202276840928798315333943213319531457321440247173855894902863154158871367713143880202865").expect("Could not convert to decimal from string"))),
|
||||
Ok(decimal(63)),
|
||||
Ok(decimal_from_float(63.0)),
|
||||
Ok(decimal_from_float(60.5)),
|
||||
],
|
||||
},
|
||||
@ -116,14 +115,14 @@ mod tests {
|
||||
values: vec![int(-14), int(-11), int(10)],
|
||||
expected_err: None,
|
||||
expected_res: vec![
|
||||
Ok(decimal(-5)),
|
||||
Ok(decimal_from_float(-5.0)),
|
||||
Ok(int(-14)),
|
||||
Ok(int(10)),
|
||||
Ok(int(-11)),
|
||||
Ok(table(&[int(-14), int(-11), int(10)])),
|
||||
Ok(decimal(BigDecimal::from_str("10.67707825203131121081152396559571062628228776946058011397810604284900898365140801704064843595778374").expect("Could not convert to decimal from string"))),
|
||||
Ok(int(-15)),
|
||||
Ok(decimal(114)),
|
||||
Ok(decimal_from_float(114.0)),
|
||||
],
|
||||
},
|
||||
TestCase {
|
||||
@ -131,13 +130,13 @@ mod tests {
|
||||
values: vec![decimal_from_float(-13.5), decimal_from_float(-11.5), int(10)],
|
||||
expected_err: None,
|
||||
expected_res: vec![
|
||||
Ok(decimal(-5)),
|
||||
Ok(decimal_from_float(-5.0)),
|
||||
Ok(decimal_from_float(-13.5)),
|
||||
Ok(int(10)),
|
||||
Ok(decimal_from_float(-11.5)),
|
||||
Ok(table(&[decimal_from_float(-13.5), decimal_from_float(-11.5), int(10)])),
|
||||
Ok(decimal(BigDecimal::from_str("10.63798226482196513098036125801342585449179971588207816421068645273754903468375890632981926875247027").expect("Could not convert to decimal from string"))),
|
||||
Ok(decimal(-15)),
|
||||
Ok(decimal_from_float(-15.0)),
|
||||
Ok(decimal(BigDecimal::from_str("113.1666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667").expect("Could not convert to decimal from string"))),
|
||||
],
|
||||
},
|
||||
|
@ -1,328 +0,0 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_data::base::select_fields;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, Value};
|
||||
use nu_source::HasFallibleSpan;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Arguments {
|
||||
rest: Vec<ColumnPath>,
|
||||
after: Option<ColumnPath>,
|
||||
before: Option<ColumnPath>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"move column"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("move column")
|
||||
.rest(SyntaxShape::ColumnPath, "the columns to move")
|
||||
.named(
|
||||
"after",
|
||||
SyntaxShape::ColumnPath,
|
||||
"the column that will precede the columns moved",
|
||||
None,
|
||||
)
|
||||
.named(
|
||||
"before",
|
||||
SyntaxShape::ColumnPath,
|
||||
"the column that will be next the columns moved",
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Move columns."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
operate(args, registry).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn operate(
|
||||
raw_args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name = raw_args.call_info.name_tag.clone();
|
||||
let registry = registry.clone();
|
||||
let (
|
||||
Arguments {
|
||||
rest: mut columns,
|
||||
before,
|
||||
after,
|
||||
},
|
||||
input,
|
||||
) = raw_args.process(®istry).await?;
|
||||
|
||||
if columns.is_empty() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"expected columns",
|
||||
"expected columns",
|
||||
name,
|
||||
));
|
||||
}
|
||||
|
||||
if columns.iter().any(|c| c.members().len() > 1) {
|
||||
return Err(ShellError::labeled_error(
|
||||
"expected columns",
|
||||
"expected columns",
|
||||
name,
|
||||
));
|
||||
}
|
||||
|
||||
if vec![&after, &before]
|
||||
.iter()
|
||||
.map(|o| if o.is_some() { 1 } else { 0 })
|
||||
.sum::<usize>()
|
||||
> 1
|
||||
{
|
||||
return Err(ShellError::labeled_error(
|
||||
"can't move column(s)",
|
||||
"pick exactly one (before, after)",
|
||||
name,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(after) = after {
|
||||
let member = columns.remove(0);
|
||||
|
||||
Ok(input
|
||||
.map(move |item| {
|
||||
let member = vec![member.clone()];
|
||||
let column_paths = vec![&member, &columns]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<&ColumnPath>>();
|
||||
|
||||
let after_span = after.maybe_span().unwrap_or_else(Span::unknown);
|
||||
|
||||
if after.members().len() == 1 {
|
||||
let keys = column_paths
|
||||
.iter()
|
||||
.filter_map(|c| c.last())
|
||||
.map(|c| c.as_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(column) = after.last() {
|
||||
if !keys.contains(&column.as_string()) {
|
||||
ReturnSuccess::value(move_after(&item, &keys, &after, &name)?)
|
||||
} else {
|
||||
let msg =
|
||||
format!("can't move column {} after itself", column.as_string());
|
||||
Err(ShellError::labeled_error(
|
||||
"can't move column",
|
||||
msg,
|
||||
after_span,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"expected column",
|
||||
"expected column",
|
||||
after_span,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"expected column",
|
||||
"expected column",
|
||||
after_span,
|
||||
))
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
} else if let Some(before) = before {
|
||||
let member = columns.remove(0);
|
||||
|
||||
Ok(input
|
||||
.map(move |item| {
|
||||
let member = vec![member.clone()];
|
||||
let column_paths = vec![&member, &columns]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<&ColumnPath>>();
|
||||
|
||||
let before_span = before.maybe_span().unwrap_or_else(Span::unknown);
|
||||
|
||||
if before.members().len() == 1 {
|
||||
let keys = column_paths
|
||||
.iter()
|
||||
.filter_map(|c| c.last())
|
||||
.map(|c| c.as_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(column) = before.last() {
|
||||
if !keys.contains(&column.as_string()) {
|
||||
ReturnSuccess::value(move_before(&item, &keys, &before, &name)?)
|
||||
} else {
|
||||
let msg =
|
||||
format!("can't move column {} before itself", column.as_string());
|
||||
Err(ShellError::labeled_error(
|
||||
"can't move column",
|
||||
msg,
|
||||
before_span,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"expected column",
|
||||
"expected column",
|
||||
before_span,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"expected column",
|
||||
"expected column",
|
||||
before_span,
|
||||
))
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"no columns given",
|
||||
"no columns given",
|
||||
name,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn move_after(
|
||||
table: &Value,
|
||||
columns: &[String],
|
||||
from: &ColumnPath,
|
||||
tag: impl Into<Tag>,
|
||||
) -> Result<Value, ShellError> {
|
||||
let tag = tag.into();
|
||||
let from_fields = from.maybe_span().unwrap_or_else(Span::unknown);
|
||||
let from = if let Some((last, _)) = from.split_last() {
|
||||
last.as_string()
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"unknown column",
|
||||
"unknown column",
|
||||
from_fields,
|
||||
));
|
||||
};
|
||||
|
||||
let columns_moved = table.data_descriptors().into_iter().map(|name| {
|
||||
if columns.contains(&name) {
|
||||
None
|
||||
} else {
|
||||
Some(name)
|
||||
}
|
||||
});
|
||||
|
||||
let mut reordered_columns = vec![];
|
||||
let mut insert = false;
|
||||
let mut inserted = false;
|
||||
|
||||
for name in columns_moved.into_iter() {
|
||||
if let Some(name) = name {
|
||||
reordered_columns.push(Some(name.clone()));
|
||||
|
||||
if !inserted && name == from {
|
||||
insert = true;
|
||||
}
|
||||
} else {
|
||||
reordered_columns.push(None);
|
||||
}
|
||||
|
||||
if insert {
|
||||
for column in columns {
|
||||
reordered_columns.push(Some(column.clone()));
|
||||
}
|
||||
inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(select_fields(
|
||||
table,
|
||||
&reordered_columns
|
||||
.into_iter()
|
||||
.filter_map(|v| v)
|
||||
.collect::<Vec<_>>(),
|
||||
&tag,
|
||||
))
|
||||
}
|
||||
|
||||
fn move_before(
|
||||
table: &Value,
|
||||
columns: &[String],
|
||||
from: &ColumnPath,
|
||||
tag: impl Into<Tag>,
|
||||
) -> Result<Value, ShellError> {
|
||||
let tag = tag.into();
|
||||
let from_fields = from.maybe_span().unwrap_or_else(Span::unknown);
|
||||
let from = if let Some((last, _)) = from.split_last() {
|
||||
last.as_string()
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"unknown column",
|
||||
"unknown column",
|
||||
from_fields,
|
||||
));
|
||||
};
|
||||
|
||||
let columns_moved = table.data_descriptors().into_iter().map(|name| {
|
||||
if columns.contains(&name) {
|
||||
None
|
||||
} else {
|
||||
Some(name)
|
||||
}
|
||||
});
|
||||
|
||||
let mut reordered_columns = vec![];
|
||||
let mut inserted = false;
|
||||
|
||||
for name in columns_moved.into_iter() {
|
||||
if let Some(name) = name {
|
||||
if !inserted && name == from {
|
||||
for column in columns {
|
||||
reordered_columns.push(Some(column.clone()));
|
||||
}
|
||||
|
||||
inserted = true;
|
||||
}
|
||||
|
||||
reordered_columns.push(Some(name.clone()));
|
||||
} else {
|
||||
reordered_columns.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(select_fields(
|
||||
table,
|
||||
&reordered_columns
|
||||
.into_iter()
|
||||
.filter_map(|v| v)
|
||||
.collect::<Vec<_>>(),
|
||||
&tag,
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::SubCommand;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(SubCommand {})?)
|
||||
}
|
||||
}
|
@ -1,11 +1,20 @@
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_data::base::select_fields;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, Value};
|
||||
use nu_source::HasFallibleSpan;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Command;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Arguments {
|
||||
rest: Vec<ColumnPath>,
|
||||
after: Option<ColumnPath>,
|
||||
before: Option<ColumnPath>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Command {
|
||||
fn name(&self) -> &str {
|
||||
@ -14,34 +23,318 @@ impl WholeStreamCommand for Command {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("move")
|
||||
.rest(SyntaxShape::ColumnPath, "the columns to move")
|
||||
.named(
|
||||
"after",
|
||||
SyntaxShape::ColumnPath,
|
||||
"the column that will precede the columns moved",
|
||||
None,
|
||||
)
|
||||
.named(
|
||||
"before",
|
||||
SyntaxShape::ColumnPath,
|
||||
"the column that will be next the columns moved",
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Moves across desired subcommand."
|
||||
"Move columns."
|
||||
}
|
||||
|
||||
async fn run(
|
||||
&self,
|
||||
_args: CommandArgs,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
|
||||
UntaggedValue::string(crate::commands::help::get_help(&Command, ®istry))
|
||||
.into_value(Tag::unknown()),
|
||||
))))
|
||||
operate(args, registry).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
use nu_test_support::value::*;
|
||||
|
||||
vec![
|
||||
Example {
|
||||
description: "Move the column \"type\" before the column \"name\"",
|
||||
example: r#"ls | move type --before name | first"#,
|
||||
result: Some(vec![row! {
|
||||
"type".into() => string("File"),
|
||||
"name".into() => string("Andrés.txt"),
|
||||
"chickens".into() => int(10),
|
||||
"modified".into() => date("2019-07-23")
|
||||
}]),
|
||||
},
|
||||
Example {
|
||||
description: "or move the column \"chickens\" after \"name\"",
|
||||
example: r#"ls | move chickens --after name | first"#,
|
||||
result: Some(vec![row! {
|
||||
"name".into() => string("Andrés.txt"),
|
||||
"chickens".into() => int(10),
|
||||
"type".into() => string("File"),
|
||||
"modified".into() => date("2019-07-23")
|
||||
}]),
|
||||
},
|
||||
Example {
|
||||
description: "you can selectively move many columns in either direction",
|
||||
example: r#"ls | move name chickens --after type | first"#,
|
||||
result: Some(vec![row! {
|
||||
"type".into() => string("File"),
|
||||
"name".into() => string("Andrés.txt"),
|
||||
"chickens".into() => int(10),
|
||||
"modified".into() => date("2019-07-23")
|
||||
}]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Command;
|
||||
use super::ShellError;
|
||||
async fn operate(
|
||||
raw_args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let name = raw_args.call_info.name_tag.clone();
|
||||
let registry = registry.clone();
|
||||
let (
|
||||
Arguments {
|
||||
rest: mut columns,
|
||||
before,
|
||||
after,
|
||||
},
|
||||
input,
|
||||
) = raw_args.process(®istry).await?;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
if columns.is_empty() {
|
||||
return Err(ShellError::labeled_error(
|
||||
"expected columns",
|
||||
"expected columns",
|
||||
name,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(test_examples(Command {})?)
|
||||
if columns.iter().any(|c| c.members().len() > 1) {
|
||||
return Err(ShellError::labeled_error(
|
||||
"expected columns",
|
||||
"expected columns",
|
||||
name,
|
||||
));
|
||||
}
|
||||
|
||||
if vec![&after, &before]
|
||||
.iter()
|
||||
.map(|o| if o.is_some() { 1 } else { 0 })
|
||||
.sum::<usize>()
|
||||
> 1
|
||||
{
|
||||
return Err(ShellError::labeled_error(
|
||||
"can't move column(s)",
|
||||
"pick exactly one (before, after)",
|
||||
name,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(after) = after {
|
||||
let member = columns.remove(0);
|
||||
|
||||
Ok(input
|
||||
.map(move |item| {
|
||||
let member = vec![member.clone()];
|
||||
let column_paths = vec![&member, &columns]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<&ColumnPath>>();
|
||||
|
||||
let after_span = after.maybe_span().unwrap_or_else(Span::unknown);
|
||||
|
||||
if after.members().len() == 1 {
|
||||
let keys = column_paths
|
||||
.iter()
|
||||
.filter_map(|c| c.last())
|
||||
.map(|c| c.as_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(column) = after.last() {
|
||||
if !keys.contains(&column.as_string()) {
|
||||
ReturnSuccess::value(move_after(&item, &keys, &after)?)
|
||||
} else {
|
||||
let msg =
|
||||
format!("can't move column {} after itself", column.as_string());
|
||||
Err(ShellError::labeled_error(
|
||||
"can't move column",
|
||||
msg,
|
||||
after_span,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"expected column",
|
||||
"expected column",
|
||||
after_span,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"expected column",
|
||||
"expected column",
|
||||
after_span,
|
||||
))
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
} else if let Some(before) = before {
|
||||
let member = columns.remove(0);
|
||||
|
||||
Ok(input
|
||||
.map(move |item| {
|
||||
let member = vec![member.clone()];
|
||||
let column_paths = vec![&member, &columns]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<&ColumnPath>>();
|
||||
|
||||
let before_span = before.maybe_span().unwrap_or_else(Span::unknown);
|
||||
|
||||
if before.members().len() == 1 {
|
||||
let keys = column_paths
|
||||
.iter()
|
||||
.filter_map(|c| c.last())
|
||||
.map(|c| c.as_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(column) = before.last() {
|
||||
if !keys.contains(&column.as_string()) {
|
||||
ReturnSuccess::value(move_before(&item, &keys, &before)?)
|
||||
} else {
|
||||
let msg =
|
||||
format!("can't move column {} before itself", column.as_string());
|
||||
Err(ShellError::labeled_error(
|
||||
"can't move column",
|
||||
msg,
|
||||
before_span,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"expected column",
|
||||
"expected column",
|
||||
before_span,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"expected column",
|
||||
"expected column",
|
||||
before_span,
|
||||
))
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"no columns given",
|
||||
"no columns given",
|
||||
name,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn move_after(table: &Value, columns: &[String], from: &ColumnPath) -> Result<Value, ShellError> {
|
||||
let from_fields = from.maybe_span().unwrap_or_else(Span::unknown);
|
||||
let from = if let Some((last, _)) = from.split_last() {
|
||||
last.as_string()
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"unknown column",
|
||||
"unknown column",
|
||||
from_fields,
|
||||
));
|
||||
};
|
||||
|
||||
let columns_moved = table.data_descriptors().into_iter().map(|name| {
|
||||
if columns.contains(&name) {
|
||||
None
|
||||
} else {
|
||||
Some(name)
|
||||
}
|
||||
});
|
||||
|
||||
let mut reordered_columns = vec![];
|
||||
let mut insert = false;
|
||||
let mut inserted = false;
|
||||
|
||||
for name in columns_moved.into_iter() {
|
||||
if let Some(name) = name {
|
||||
reordered_columns.push(Some(name.clone()));
|
||||
|
||||
if !inserted && name == from {
|
||||
insert = true;
|
||||
}
|
||||
} else {
|
||||
reordered_columns.push(None);
|
||||
}
|
||||
|
||||
if insert {
|
||||
for column in columns {
|
||||
reordered_columns.push(Some(column.clone()));
|
||||
}
|
||||
inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(select_fields(
|
||||
table,
|
||||
&reordered_columns
|
||||
.into_iter()
|
||||
.filter_map(|v| v)
|
||||
.collect::<Vec<_>>(),
|
||||
&table.tag,
|
||||
))
|
||||
}
|
||||
|
||||
fn move_before(table: &Value, columns: &[String], from: &ColumnPath) -> Result<Value, ShellError> {
|
||||
let from_fields = from.maybe_span().unwrap_or_else(Span::unknown);
|
||||
let from = if let Some((last, _)) = from.split_last() {
|
||||
last.as_string()
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"unknown column",
|
||||
"unknown column",
|
||||
from_fields,
|
||||
));
|
||||
};
|
||||
|
||||
let columns_moved = table.data_descriptors().into_iter().map(|name| {
|
||||
if columns.contains(&name) {
|
||||
None
|
||||
} else {
|
||||
Some(name)
|
||||
}
|
||||
});
|
||||
|
||||
let mut reordered_columns = vec![];
|
||||
let mut inserted = false;
|
||||
|
||||
for name in columns_moved.into_iter() {
|
||||
if let Some(name) = name {
|
||||
if !inserted && name == from {
|
||||
for column in columns {
|
||||
reordered_columns.push(Some(column.clone()));
|
||||
}
|
||||
|
||||
inserted = true;
|
||||
}
|
||||
|
||||
reordered_columns.push(Some(name.clone()));
|
||||
} else {
|
||||
reordered_columns.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(select_fields(
|
||||
table,
|
||||
&reordered_columns
|
||||
.into_iter()
|
||||
.filter_map(|v| v)
|
||||
.collect::<Vec<_>>(),
|
||||
&table.tag,
|
||||
))
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
mod column;
|
||||
mod command;
|
||||
pub mod mv;
|
||||
|
||||
pub use column::SubCommand as MoveColumn;
|
||||
pub use command::Command as Move;
|
||||
pub use mv::Mv;
|
||||
|
@ -101,9 +101,10 @@ pub fn split(
|
||||
mod tests {
|
||||
use super::split;
|
||||
use super::ShellError;
|
||||
use nu_data::utils::helpers::{committers_grouped_by_date, date, int, row, string, table};
|
||||
use nu_data::utils::helpers::committers_grouped_by_date;
|
||||
use nu_protocol::UntaggedValue;
|
||||
use nu_source::*;
|
||||
use nu_test_support::value::{date, int, row, string, table};
|
||||
|
||||
#[test]
|
||||
fn splits_inner_tables_by_key() {
|
||||
|
@ -112,8 +112,8 @@ fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -46,8 +46,8 @@ mod tests {
|
||||
use super::ShellError;
|
||||
use super::{to_camel_case, SubCommand};
|
||||
use crate::commands::str_::case::action;
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -46,8 +46,8 @@ mod tests {
|
||||
use super::ShellError;
|
||||
use super::{to_kebab_case, SubCommand};
|
||||
use crate::commands::str_::case::action;
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -46,8 +46,8 @@ mod tests {
|
||||
use super::ShellError;
|
||||
use super::{to_pascal_case, SubCommand};
|
||||
use crate::commands::str_::case::action;
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -46,8 +46,8 @@ mod tests {
|
||||
use super::ShellError;
|
||||
use super::{to_screaming_snake_case, SubCommand};
|
||||
use crate::commands::str_::case::action;
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -46,8 +46,8 @@ mod tests {
|
||||
use super::ShellError;
|
||||
use super::{to_snake_case, SubCommand};
|
||||
use crate::commands::str_::case::action;
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -130,9 +130,9 @@ fn action(
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_protocol::UntaggedValue;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -100,8 +100,8 @@ fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -104,9 +104,9 @@ fn action(input: &Value, pattern: &str, tag: impl Into<Tag>) -> Result<Value, Sh
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_protocol::UntaggedValue;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -149,8 +149,8 @@ fn action(
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, FindReplace, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -248,9 +248,9 @@ fn process_range(input: &Value, range: &Value) -> Result<IndexOfOptionalBounds,
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_protocol::{Primitive, UntaggedValue};
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -145,9 +145,9 @@ fn action(
|
||||
mod tests {
|
||||
use super::{action, SubCommand};
|
||||
use nu_errors::ShellError;
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_protocol::UntaggedValue;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -145,9 +145,9 @@ fn action(
|
||||
mod tests {
|
||||
use super::{action, SubCommand};
|
||||
use nu_errors::ShellError;
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_protocol::UntaggedValue;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -101,8 +101,8 @@ fn action(_input: &Value, options: &Replace, tag: impl Into<Tag>) -> Result<Valu
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, Replace, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -104,9 +104,9 @@ fn action(input: &Value, pattern: &str, tag: impl Into<Tag>) -> Result<Value, Sh
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_protocol::UntaggedValue;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -285,8 +285,8 @@ fn process_arguments(range: Value, name: impl Into<Tag>) -> Result<(isize, isize
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand, Substring};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -176,9 +176,9 @@ fn action(
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, DatetimeFormat, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_protocol::{Primitive, UntaggedValue};
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -114,8 +114,8 @@ fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand};
|
||||
use nu_plugin::test_helpers::value::{decimal_from_float, string};
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::{decimal_from_float, string};
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -114,8 +114,8 @@ fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand};
|
||||
use nu_plugin::test_helpers::value::{int, string};
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::{int, string};
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -65,11 +65,9 @@ mod tests {
|
||||
use super::ShellError;
|
||||
use super::{trim, SubCommand};
|
||||
use crate::commands::str_::trim::{action, ActionMode};
|
||||
use nu_plugin::{
|
||||
row,
|
||||
test_helpers::value::{int, string, table},
|
||||
};
|
||||
use nu_protocol::row;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::{int, string, table};
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -66,11 +66,9 @@ mod tests {
|
||||
use super::ShellError;
|
||||
use super::{trim_left, SubCommand};
|
||||
use crate::commands::str_::trim::{action, ActionMode};
|
||||
use nu_plugin::{
|
||||
row,
|
||||
test_helpers::value::{int, string, table},
|
||||
};
|
||||
use nu_protocol::row;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::{int, string, table};
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -66,11 +66,9 @@ mod tests {
|
||||
use super::ShellError;
|
||||
use super::{trim_right, SubCommand};
|
||||
use crate::commands::str_::trim::{action, ActionMode};
|
||||
use nu_plugin::{
|
||||
row,
|
||||
test_helpers::value::{int, string, table},
|
||||
};
|
||||
use nu_protocol::row;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::{int, string, table};
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -100,8 +100,8 @@ fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::{action, SubCommand};
|
||||
use nu_plugin::test_helpers::value::string;
|
||||
use nu_source::Tag;
|
||||
use nu_test_support::value::string;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
|
@ -7,11 +7,8 @@ use nu_source::{AnchorLocation, TaggedItem};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use indexmap::indexmap;
|
||||
use num_bigint::BigInt;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use crate::command_registry::CommandRegistry;
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::command::CommandArgs;
|
||||
@ -450,10 +447,6 @@ fn string(input: impl Into<String>) -> Value {
|
||||
UntaggedValue::string(input.into()).into_untagged_value()
|
||||
}
|
||||
|
||||
fn row(entries: IndexMap<String, Value>) -> Value {
|
||||
UntaggedValue::row(entries).into_untagged_value()
|
||||
}
|
||||
|
||||
fn date(input: impl Into<String>) -> Value {
|
||||
let key = input.into().tagged_unknown();
|
||||
crate::value::Date::naive_from_str(key.borrow_tagged())
|
||||
@ -463,30 +456,30 @@ fn date(input: impl Into<String>) -> Value {
|
||||
|
||||
fn file_listing() -> Vec<Value> {
|
||||
vec![
|
||||
row(indexmap! {
|
||||
"modified".to_string() => date("2019-07-23"),
|
||||
row! {
|
||||
"name".to_string() => string("Andrés.txt"),
|
||||
"type".to_string() => string("File"),
|
||||
"chickens".to_string() => int(10),
|
||||
}),
|
||||
row(indexmap! {
|
||||
"modified".to_string() => date("2019-07-23"),
|
||||
"modified".to_string() => date("2019-07-23")
|
||||
},
|
||||
row! {
|
||||
"name".to_string() => string("Jonathan"),
|
||||
"type".to_string() => string("Dir"),
|
||||
"chickens".to_string() => int(5),
|
||||
}),
|
||||
row(indexmap! {
|
||||
"modified".to_string() => date("2019-09-24"),
|
||||
"modified".to_string() => date("2019-07-23")
|
||||
},
|
||||
row! {
|
||||
"name".to_string() => string("Andrés.txt"),
|
||||
"type".to_string() => string("File"),
|
||||
"chickens".to_string() => int(20),
|
||||
}),
|
||||
row(indexmap! {
|
||||
"modified".to_string() => date("2019-09-24"),
|
||||
"modified".to_string() => date("2019-09-24")
|
||||
},
|
||||
row! {
|
||||
"name".to_string() => string("Yehuda"),
|
||||
"type".to_string() => string("Dir"),
|
||||
"chickens".to_string() => int(4),
|
||||
}),
|
||||
"modified".to_string() => date("2019-09-24")
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ macro_rules! trace_out_stream {
|
||||
}};
|
||||
}
|
||||
|
||||
pub(crate) use nu_protocol::{errln, out, outln};
|
||||
pub(crate) use nu_protocol::{errln, out, outln, row};
|
||||
use nu_source::HasFallibleSpan;
|
||||
|
||||
pub(crate) use crate::command_registry::CommandRegistry;
|
||||
|
Reference in New Issue
Block a user