From b6d19cc9fa39fd8844deeea4f70c11a6b6374ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20N=2E=20Robalino?= Date: Tue, 20 Oct 2020 04:07:13 -0500 Subject: [PATCH] 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. --- Cargo.lock | 3 + crates/nu-cli/src/cli.rs | 2 +- crates/nu-cli/src/commands.rs | 3 +- crates/nu-cli/src/commands/from_yaml.rs | 4 +- crates/nu-cli/src/commands/group_by.rs | 11 +- crates/nu-cli/src/commands/math/command.rs | 25 +- crates/nu-cli/src/commands/move_/column.rs | 328 ------------------ crates/nu-cli/src/commands/move_/command.rs | 327 ++++++++++++++++- crates/nu-cli/src/commands/move_/mod.rs | 2 - crates/nu-cli/src/commands/split_by.rs | 3 +- crates/nu-cli/src/commands/str_/capitalize.rs | 2 +- .../src/commands/str_/case/camel_case.rs | 2 +- .../src/commands/str_/case/kebab_case.rs | 2 +- .../src/commands/str_/case/pascal_case.rs | 2 +- .../str_/case/screaming_snake_case.rs | 2 +- .../src/commands/str_/case/snake_case.rs | 2 +- crates/nu-cli/src/commands/str_/contains.rs | 2 +- crates/nu-cli/src/commands/str_/downcase.rs | 2 +- crates/nu-cli/src/commands/str_/ends_with.rs | 2 +- .../nu-cli/src/commands/str_/find_replace.rs | 2 +- crates/nu-cli/src/commands/str_/index_of.rs | 2 +- crates/nu-cli/src/commands/str_/lpad.rs | 2 +- crates/nu-cli/src/commands/str_/rpad.rs | 2 +- crates/nu-cli/src/commands/str_/set.rs | 2 +- .../nu-cli/src/commands/str_/starts_with.rs | 2 +- crates/nu-cli/src/commands/str_/substring.rs | 2 +- .../nu-cli/src/commands/str_/to_datetime.rs | 2 +- crates/nu-cli/src/commands/str_/to_decimal.rs | 2 +- crates/nu-cli/src/commands/str_/to_integer.rs | 2 +- .../src/commands/str_/trim/trim_both_ends.rs | 6 +- .../src/commands/str_/trim/trim_left.rs | 6 +- .../src/commands/str_/trim/trim_right.rs | 6 +- crates/nu-cli/src/commands/str_/upcase.rs | 2 +- crates/nu-cli/src/examples.rs | 31 +- crates/nu-cli/src/prelude.rs | 2 +- crates/nu-cli/tests/commands/move_/column.rs | 10 +- crates/nu-data/src/base.rs | 29 +- crates/nu-data/src/utils/mod.rs | 133 +++---- crates/nu-plugin/Cargo.toml | 3 +- crates/nu-plugin/src/test_helpers.rs | 75 +--- crates/nu-protocol/src/macros.rs | 9 + crates/nu-protocol/src/value.rs | 8 +- crates/nu-test-support/Cargo.toml | 1 + crates/nu-test-support/src/value.rs | 18 +- crates/nu-value-ext/src/tests.rs | 18 +- crates/nu_plugin_inc/Cargo.toml | 1 + crates/nu_plugin_inc/src/inc.rs | 2 +- crates/nu_plugin_inc/src/nu/tests.rs | 25 +- crates/nu_plugin_xpath/src/xpath.rs | 10 +- 49 files changed, 516 insertions(+), 625 deletions(-) delete mode 100644 crates/nu-cli/src/commands/move_/column.rs diff --git a/Cargo.lock b/Cargo.lock index 2674dc5cb6..86d1d36bda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3067,6 +3067,7 @@ dependencies = [ "nu-errors", "nu-protocol", "nu-source", + "nu-test-support", "nu-value-ext", "num-bigint 0.3.0", "serde 1.0.115", @@ -3119,6 +3120,7 @@ dependencies = [ name = "nu-test-support" version = "0.21.0" dependencies = [ + "bigdecimal", "chrono", "dunce", "getset", @@ -3227,6 +3229,7 @@ dependencies = [ "nu-plugin", "nu-protocol", "nu-source", + "nu-test-support", "nu-value-ext", "semver 0.10.0", ] diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index e3c5d2d478..e29c6c3082 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -159,7 +159,7 @@ pub fn create_default_context(interactive: bool) -> Result Result<(), ShellError> { diff --git a/crates/nu-cli/src/commands/group_by.rs b/crates/nu-cli/src/commands/group_by.rs index 9f8f10a3c4..89bc38b884 100644 --- a/crates/nu-cli/src/commands/group_by.rs +++ b/crates/nu-cli/src/commands/group_by.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/math/command.rs b/crates/nu-cli/src/commands/math/command.rs index 1a0dc4310d..3bd6556fd3 100644 --- a/crates/nu-cli/src/commands/math/command.rs +++ b/crates/nu-cli/src/commands/math/command.rs @@ -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"))), ], }, diff --git a/crates/nu-cli/src/commands/move_/column.rs b/crates/nu-cli/src/commands/move_/column.rs deleted file mode 100644 index 4151098a57..0000000000 --- a/crates/nu-cli/src/commands/move_/column.rs +++ /dev/null @@ -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, - after: Option, - before: Option, -} - -#[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 { - operate(args, registry).await - } -} - -async fn operate( - raw_args: CommandArgs, - registry: &CommandRegistry, -) -> Result { - 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::() - > 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::>(); - - 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::>(); - - 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::>(); - - 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::>(); - - 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, -) -> Result { - 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::>(), - &tag, - )) -} - -fn move_before( - table: &Value, - columns: &[String], - from: &ColumnPath, - tag: impl Into, -) -> Result { - 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::>(), - &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 {})?) - } -} diff --git a/crates/nu-cli/src/commands/move_/command.rs b/crates/nu-cli/src/commands/move_/command.rs index d71ccde0e0..46bb3da50a 100644 --- a/crates/nu-cli/src/commands/move_/command.rs +++ b/crates/nu-cli/src/commands/move_/command.rs @@ -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, + after: Option, + before: Option, +} + #[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 { - 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 { + 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 { + 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::() + > 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::>(); + + 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::>(); + + 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::>(); + + 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::>(); + + 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 { + 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::>(), + &table.tag, + )) +} + +fn move_before(table: &Value, columns: &[String], from: &ColumnPath) -> Result { + 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::>(), + &table.tag, + )) +} diff --git a/crates/nu-cli/src/commands/move_/mod.rs b/crates/nu-cli/src/commands/move_/mod.rs index 62269546b6..c9c70b9fdd 100644 --- a/crates/nu-cli/src/commands/move_/mod.rs +++ b/crates/nu-cli/src/commands/move_/mod.rs @@ -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; diff --git a/crates/nu-cli/src/commands/split_by.rs b/crates/nu-cli/src/commands/split_by.rs index c73daa076e..4595e424e2 100644 --- a/crates/nu-cli/src/commands/split_by.rs +++ b/crates/nu-cli/src/commands/split_by.rs @@ -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() { diff --git a/crates/nu-cli/src/commands/str_/capitalize.rs b/crates/nu-cli/src/commands/str_/capitalize.rs index aea8bcb5e0..e894e9a606 100644 --- a/crates/nu-cli/src/commands/str_/capitalize.rs +++ b/crates/nu-cli/src/commands/str_/capitalize.rs @@ -112,8 +112,8 @@ fn action(input: &Value, tag: impl Into) -> Result { 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> { diff --git a/crates/nu-cli/src/commands/str_/case/camel_case.rs b/crates/nu-cli/src/commands/str_/case/camel_case.rs index c10d9c1c84..ac2bb06aaa 100644 --- a/crates/nu-cli/src/commands/str_/case/camel_case.rs +++ b/crates/nu-cli/src/commands/str_/case/camel_case.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/case/kebab_case.rs b/crates/nu-cli/src/commands/str_/case/kebab_case.rs index 4688704dfc..b6ee390cc6 100644 --- a/crates/nu-cli/src/commands/str_/case/kebab_case.rs +++ b/crates/nu-cli/src/commands/str_/case/kebab_case.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/case/pascal_case.rs b/crates/nu-cli/src/commands/str_/case/pascal_case.rs index fe25f7a7ff..cb6b202ba7 100644 --- a/crates/nu-cli/src/commands/str_/case/pascal_case.rs +++ b/crates/nu-cli/src/commands/str_/case/pascal_case.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/case/screaming_snake_case.rs b/crates/nu-cli/src/commands/str_/case/screaming_snake_case.rs index afb76c525b..5976303dfa 100644 --- a/crates/nu-cli/src/commands/str_/case/screaming_snake_case.rs +++ b/crates/nu-cli/src/commands/str_/case/screaming_snake_case.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/case/snake_case.rs b/crates/nu-cli/src/commands/str_/case/snake_case.rs index 849691fcbd..751eda9a42 100644 --- a/crates/nu-cli/src/commands/str_/case/snake_case.rs +++ b/crates/nu-cli/src/commands/str_/case/snake_case.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/contains.rs b/crates/nu-cli/src/commands/str_/contains.rs index 74b011ba4b..5a5b63ab70 100644 --- a/crates/nu-cli/src/commands/str_/contains.rs +++ b/crates/nu-cli/src/commands/str_/contains.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/downcase.rs b/crates/nu-cli/src/commands/str_/downcase.rs index 8986218c80..30b6c954c1 100644 --- a/crates/nu-cli/src/commands/str_/downcase.rs +++ b/crates/nu-cli/src/commands/str_/downcase.rs @@ -100,8 +100,8 @@ fn action(input: &Value, tag: impl Into) -> Result { 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> { diff --git a/crates/nu-cli/src/commands/str_/ends_with.rs b/crates/nu-cli/src/commands/str_/ends_with.rs index 65a405fee8..b0415596ec 100644 --- a/crates/nu-cli/src/commands/str_/ends_with.rs +++ b/crates/nu-cli/src/commands/str_/ends_with.rs @@ -104,9 +104,9 @@ fn action(input: &Value, pattern: &str, tag: impl Into) -> Result Result<(), ShellError> { diff --git a/crates/nu-cli/src/commands/str_/find_replace.rs b/crates/nu-cli/src/commands/str_/find_replace.rs index e229e4e990..6a66161fa1 100644 --- a/crates/nu-cli/src/commands/str_/find_replace.rs +++ b/crates/nu-cli/src/commands/str_/find_replace.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/index_of.rs b/crates/nu-cli/src/commands/str_/index_of.rs index 1f1b7e8c84..e8760e5462 100644 --- a/crates/nu-cli/src/commands/str_/index_of.rs +++ b/crates/nu-cli/src/commands/str_/index_of.rs @@ -248,9 +248,9 @@ fn process_range(input: &Value, range: &Value) -> Result Result<(), ShellError> { diff --git a/crates/nu-cli/src/commands/str_/lpad.rs b/crates/nu-cli/src/commands/str_/lpad.rs index 9db60c1192..1a436a79cc 100644 --- a/crates/nu-cli/src/commands/str_/lpad.rs +++ b/crates/nu-cli/src/commands/str_/lpad.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/rpad.rs b/crates/nu-cli/src/commands/str_/rpad.rs index 85c13f0993..1db83c7818 100644 --- a/crates/nu-cli/src/commands/str_/rpad.rs +++ b/crates/nu-cli/src/commands/str_/rpad.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/set.rs b/crates/nu-cli/src/commands/str_/set.rs index 576209d764..6da5a4d472 100644 --- a/crates/nu-cli/src/commands/str_/set.rs +++ b/crates/nu-cli/src/commands/str_/set.rs @@ -101,8 +101,8 @@ fn action(_input: &Value, options: &Replace, tag: impl Into) -> Result Result<(), ShellError> { diff --git a/crates/nu-cli/src/commands/str_/starts_with.rs b/crates/nu-cli/src/commands/str_/starts_with.rs index 5eacdfb00e..a771ed48df 100644 --- a/crates/nu-cli/src/commands/str_/starts_with.rs +++ b/crates/nu-cli/src/commands/str_/starts_with.rs @@ -104,9 +104,9 @@ fn action(input: &Value, pattern: &str, tag: impl Into) -> Result Result<(), ShellError> { diff --git a/crates/nu-cli/src/commands/str_/substring.rs b/crates/nu-cli/src/commands/str_/substring.rs index c4113e9b7f..cbfa4a4b36 100644 --- a/crates/nu-cli/src/commands/str_/substring.rs +++ b/crates/nu-cli/src/commands/str_/substring.rs @@ -285,8 +285,8 @@ fn process_arguments(range: Value, name: impl Into) -> 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> { diff --git a/crates/nu-cli/src/commands/str_/to_datetime.rs b/crates/nu-cli/src/commands/str_/to_datetime.rs index ef871082de..60f65552d3 100644 --- a/crates/nu-cli/src/commands/str_/to_datetime.rs +++ b/crates/nu-cli/src/commands/str_/to_datetime.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/to_decimal.rs b/crates/nu-cli/src/commands/str_/to_decimal.rs index 9ad4b2fc5d..847ec76fbf 100644 --- a/crates/nu-cli/src/commands/str_/to_decimal.rs +++ b/crates/nu-cli/src/commands/str_/to_decimal.rs @@ -114,8 +114,8 @@ fn action(input: &Value, tag: impl Into) -> Result { 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> { diff --git a/crates/nu-cli/src/commands/str_/to_integer.rs b/crates/nu-cli/src/commands/str_/to_integer.rs index 86af40c3e4..ed1da07832 100644 --- a/crates/nu-cli/src/commands/str_/to_integer.rs +++ b/crates/nu-cli/src/commands/str_/to_integer.rs @@ -114,8 +114,8 @@ fn action(input: &Value, tag: impl Into) -> Result { 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> { diff --git a/crates/nu-cli/src/commands/str_/trim/trim_both_ends.rs b/crates/nu-cli/src/commands/str_/trim/trim_both_ends.rs index a47ac1d33d..3ab3e3251d 100644 --- a/crates/nu-cli/src/commands/str_/trim/trim_both_ends.rs +++ b/crates/nu-cli/src/commands/str_/trim/trim_both_ends.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/trim/trim_left.rs b/crates/nu-cli/src/commands/str_/trim/trim_left.rs index 34147cff34..308c5c47c9 100644 --- a/crates/nu-cli/src/commands/str_/trim/trim_left.rs +++ b/crates/nu-cli/src/commands/str_/trim/trim_left.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/trim/trim_right.rs b/crates/nu-cli/src/commands/str_/trim/trim_right.rs index 3cb22d606e..1cf002cddc 100644 --- a/crates/nu-cli/src/commands/str_/trim/trim_right.rs +++ b/crates/nu-cli/src/commands/str_/trim/trim_right.rs @@ -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> { diff --git a/crates/nu-cli/src/commands/str_/upcase.rs b/crates/nu-cli/src/commands/str_/upcase.rs index 37d812c74f..6ecf392d6a 100644 --- a/crates/nu-cli/src/commands/str_/upcase.rs +++ b/crates/nu-cli/src/commands/str_/upcase.rs @@ -100,8 +100,8 @@ fn action(input: &Value, tag: impl Into) -> Result { 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> { diff --git a/crates/nu-cli/src/examples.rs b/crates/nu-cli/src/examples.rs index cca869249c..2c3ff9ba52 100644 --- a/crates/nu-cli/src/examples.rs +++ b/crates/nu-cli/src/examples.rs @@ -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) -> Value { UntaggedValue::string(input.into()).into_untagged_value() } -fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() -} - fn date(input: impl Into) -> 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) -> Value { fn file_listing() -> Vec { 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") + }, ] } diff --git a/crates/nu-cli/src/prelude.rs b/crates/nu-cli/src/prelude.rs index 7c8d21f6b9..4d40975bbb 100644 --- a/crates/nu-cli/src/prelude.rs +++ b/crates/nu-cli/src/prelude.rs @@ -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; diff --git a/crates/nu-cli/tests/commands/move_/column.rs b/crates/nu-cli/tests/commands/move_/column.rs index 88ee8e6c12..36fba36c82 100644 --- a/crates/nu-cli/tests/commands/move_/column.rs +++ b/crates/nu-cli/tests/commands/move_/column.rs @@ -22,7 +22,7 @@ fn moves_a_column_before() { cwd: dirs.test(), pipeline( r#" open sample.csv - | move column column99 --before column1 + | move column99 --before column1 | rename chars | get chars | str trim @@ -57,7 +57,7 @@ fn moves_columns_before() { cwd: dirs.test(), pipeline( r#" open sample.csv - | move column column99 column3 --before column2 + | move column99 column3 --before column2 | rename _ chars_1 chars_2 | get chars_2 chars_1 | str trim @@ -92,8 +92,8 @@ fn moves_a_column_after() { cwd: dirs.test(), pipeline( r#" open sample.csv - | move column letters --after and_more - | move column letters and_more --before column2 + | move letters --after and_more + | move letters and_more --before column2 | rename _ chars_1 chars_2 | get chars_1 chars_2 | str trim @@ -128,7 +128,7 @@ fn moves_columns_after() { cwd: dirs.test(), pipeline( r#" open sample.csv - | move column letters and_more --after column1 + | move letters and_more --after column1 | get | nth 1 2 | str collect diff --git a/crates/nu-data/src/base.rs b/crates/nu-data/src/base.rs index 4042c3f646..97836060ce 100644 --- a/crates/nu-data/src/base.rs +++ b/crates/nu-data/src/base.rs @@ -191,7 +191,7 @@ mod tests { #[test] fn gets_matching_field_from_nested_rows_inside_a_row() -> Result<(), ShellError> { - let field_path = column_path("package.version"); + let field_path = column_path("package.version").as_column_path()?; let (version, tag) = string("0.4.0").into_parts(); @@ -205,7 +205,7 @@ mod tests { assert_eq!( *value.into_value(tag).get_data_by_column_path( - &field_path?.item, + &field_path.item, Box::new(error_callback("package.version")) )?, version @@ -217,7 +217,7 @@ mod tests { #[test] fn gets_first_matching_field_from_rows_with_same_field_inside_a_table() -> Result<(), ShellError> { - let field_path = column_path("package.authors.name"); + let field_path = column_path("package.authors.name").as_column_path()?; let (_, tag) = string("Andrés N. Robalino").into_parts(); @@ -235,7 +235,7 @@ mod tests { assert_eq!( value.into_value(tag).get_data_by_column_path( - &field_path?.item, + &field_path.item, Box::new(error_callback("package.authors.name")) )?, table(&[ @@ -250,7 +250,7 @@ mod tests { #[test] fn column_path_that_contains_just_a_number_gets_a_row_from_a_table() -> Result<(), ShellError> { - let field_path = column_path("package.authors.0"); + let field_path = column_path("package.authors.0").as_column_path()?; let (_, tag) = string("Andrés N. Robalino").into_parts(); @@ -268,7 +268,7 @@ mod tests { assert_eq!( *value.into_value(tag).get_data_by_column_path( - &field_path?.item, + &field_path.item, Box::new(error_callback("package.authors.0")) )?, UntaggedValue::row(indexmap! { @@ -281,7 +281,7 @@ mod tests { #[test] fn column_path_that_contains_just_a_number_gets_a_row_from_a_row() -> Result<(), ShellError> { - let field_path = column_path(r#"package.authors."0""#); + let field_path = column_path(r#"package.authors."0""#).as_column_path()?; let (_, tag) = string("Andrés N. Robalino").into_parts(); @@ -299,7 +299,7 @@ mod tests { assert_eq!( *value.into_value(tag).get_data_by_column_path( - &field_path?.item, + &field_path.item, Box::new(error_callback("package.authors.\"0\"")) )?, UntaggedValue::row(indexmap! { @@ -312,7 +312,7 @@ mod tests { #[test] fn replaces_matching_field_from_a_row() -> Result<(), ShellError> { - let field_path = column_path("amigos"); + let field_path = column_path("amigos").as_column_path()?; let sample = UntaggedValue::row(indexmap! { "amigos".into() => table(&[ @@ -326,7 +326,7 @@ mod tests { let actual = sample .into_untagged_value() - .replace_data_at_column_path(&field_path?.item, replacement) + .replace_data_at_column_path(&field_path.item, replacement) .ok_or_else(|| ShellError::untagged_runtime_error("Could not replace column"))?; assert_eq!(actual, row(indexmap! {"amigos".into() => string("jonas")})); @@ -336,7 +336,7 @@ mod tests { #[test] fn replaces_matching_field_from_nested_rows_inside_a_row() -> Result<(), ShellError> { - let field_path = column_path(r#"package.authors."los.3.caballeros""#); + let field_path = column_path(r#"package.authors."los.3.caballeros""#).as_column_path()?; let sample = UntaggedValue::row(indexmap! { "package".into() => row(indexmap! { @@ -353,7 +353,7 @@ mod tests { let actual = sample .into_value(&tag) - .replace_data_at_column_path(&field_path?.item, replacement.clone()) + .replace_data_at_column_path(&field_path.item, replacement.clone()) .ok_or_else(|| { ShellError::labeled_error( "Could not replace column", @@ -377,7 +377,8 @@ mod tests { } #[test] fn replaces_matching_field_from_rows_inside_a_table() -> Result<(), ShellError> { - let field_path = column_path(r#"shell_policy.releases."nu.version.arepa""#); + let field_path = + column_path(r#"shell_policy.releases."nu.version.arepa""#).as_column_path()?; let sample = UntaggedValue::row(indexmap! { "shell_policy".into() => row(indexmap! { @@ -409,7 +410,7 @@ mod tests { let actual = sample .into_value(tag.clone()) - .replace_data_at_column_path(&field_path?.item, replacement.clone()) + .replace_data_at_column_path(&field_path.item, replacement.clone()) .ok_or_else(|| { ShellError::labeled_error( "Could not replace column", diff --git a/crates/nu-data/src/utils/mod.rs b/crates/nu-data/src/utils/mod.rs index 69cb79429f..a8be47418f 100644 --- a/crates/nu-data/src/utils/mod.rs +++ b/crates/nu-data/src/utils/mod.rs @@ -97,99 +97,68 @@ pub fn report( } pub mod helpers { - use super::Model; - use indexmap::indexmap; use nu_errors::ShellError; - use nu_protocol::{UntaggedValue, Value}; - use nu_source::{Span, Tag, TaggedItem}; + use nu_protocol::{row, Value}; + use nu_source::{Tag, TaggedItem}; + use nu_test_support::value::{date, int, string, table}; use nu_value_ext::ValueExt; - use num_bigint::BigInt; - - use indexmap::IndexMap; - - pub fn int(s: impl Into) -> Value { - UntaggedValue::int(s).into_untagged_value() - } - - pub fn decimal_from_float(f: f64, span: Span) -> Value { - UntaggedValue::decimal_from_float(f, span).into_untagged_value() - } - - pub fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() - } - - pub fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() - } - - pub fn table(list: &[Value]) -> Value { - UntaggedValue::table(list).into_untagged_value() - } - - pub fn date(input: impl Into) -> Value { - let key = input.into().tagged_unknown(); - crate::value::Date::naive_from_str(key.borrow_tagged()) - .expect("date from string failed") - .into_untagged_value() - } pub fn committers() -> Vec { vec![ - row(indexmap! { + row! { "date".into() => date("2019-07-23"), "name".into() => string("AR"), "country".into() => string("EC"), - "chickens".into() => int(10), - }), - row(indexmap! { + "chickens".into() => int(10) + }, + row! { "date".into() => date("2019-07-23"), "name".into() => string("JT"), "country".into() => string("NZ"), - "chickens".into() => int(5), - }), - row(indexmap! { + "chickens".into() => int(5) + }, + row! { "date".into() => date("2019-10-10"), "name".into() => string("YK"), "country".into() => string("US"), - "chickens".into() => int(6), - }), - row(indexmap! { + "chickens".into() => int(6) + }, + row! { "date".into() => date("2019-09-24"), "name".into() => string("AR"), "country".into() => string("EC"), - "chickens".into() => int(20), - }), - row(indexmap! { + "chickens".into() => int(20) + }, + row! { "date".into() => date("2019-10-10"), "name".into() => string("JT"), "country".into() => string("NZ"), - "chickens".into() => int(15), - }), - row(indexmap! { + "chickens".into() => int(15) + }, + row! { "date".into() => date("2019-09-24"), "name".into() => string("YK"), "country".into() => string("US"), - "chickens".into() => int(4), - }), - row(indexmap! { + "chickens".into() => int(4) + }, + row! { "date".into() => date("2019-10-10"), "name".into() => string("AR"), "country".into() => string("EC"), - "chickens".into() => int(30), - }), - row(indexmap! { + "chickens".into() => int(30) + }, + row! { "date".into() => date("2019-09-24"), "name".into() => string("JT"), "country".into() => string("NZ"), - "chickens".into() => int(10), - }), - row(indexmap! { + "chickens".into() => int(10) + }, + row! { "date".into() => date("2019-07-23"), "name".into() => string("YK"), "country".into() => string("US"), - "chickens".into() => int(2), - }), + "chickens".into() => int(2) + }, ] } @@ -217,6 +186,17 @@ pub mod helpers { date.format(&fmt) }) } +} + +#[cfg(test)] +mod tests { + use super::helpers::{committers, date_formatter}; + use super::{report, Labels, Model, Operation, Range, Reduction}; + use nu_errors::ShellError; + use nu_protocol::Value; + use nu_source::{Tag, TaggedItem}; + use nu_test_support::value::{decimal_from_float, int, table}; + use nu_value_ext::ValueExt; pub fn assert_without_checking_percentages(report_a: Model, report_b: Model) { assert_eq!(report_a.labels.x, report_b.labels.x); @@ -224,19 +204,6 @@ pub mod helpers { assert_eq!(report_a.ranges, report_b.ranges); assert_eq!(report_a.data, report_b.data); } -} - -#[cfg(test)] -mod tests { - use super::helpers::{ - assert_without_checking_percentages, committers, date_formatter, decimal_from_float, int, - table, - }; - use super::{report, Labels, Model, Operation, Range, Reduction}; - use nu_errors::ShellError; - use nu_protocol::Value; - use nu_source::{Span, Tag, TaggedItem}; - use nu_value_ext::ValueExt; #[test] fn prepares_report_using_counting_value() { @@ -304,19 +271,19 @@ mod tests { ]), percentages: table(&[ table(&[ - decimal_from_float(33.33, Span::unknown()), - decimal_from_float(66.66, Span::unknown()), - decimal_from_float(99.99, Span::unknown()), + decimal_from_float(33.33), + decimal_from_float(66.66), + decimal_from_float(99.99), ]), table(&[ - decimal_from_float(16.66, Span::unknown()), - decimal_from_float(33.33, Span::unknown()), - decimal_from_float(49.99, Span::unknown()), + decimal_from_float(16.66), + decimal_from_float(33.33), + decimal_from_float(49.99), ]), table(&[ - decimal_from_float(6.66, Span::unknown()), - decimal_from_float(13.33, Span::unknown()), - decimal_from_float(19.99, Span::unknown()), + decimal_from_float(6.66), + decimal_from_float(13.33), + decimal_from_float(19.99), ]), ]), }, diff --git a/crates/nu-plugin/Cargo.toml b/crates/nu-plugin/Cargo.toml index 36b702c357..bf5a6fefc8 100644 --- a/crates/nu-plugin/Cargo.toml +++ b/crates/nu-plugin/Cargo.toml @@ -14,6 +14,7 @@ nu-errors = {path = "../nu-errors", version = "0.21.0"} nu-protocol = {path = "../nu-protocol", version = "0.21.0"} nu-source = {path = "../nu-source", version = "0.21.0"} nu-value-ext = {path = "../nu-value-ext", version = "0.21.0"} +nu-test-support = {path = "../nu-test-support", version = "0.21.0"} bigdecimal = {version = "0.2.0", features = ["serde"]} indexmap = {version = "1.6.0", features = ["serde-1"]} @@ -21,4 +22,4 @@ num-bigint = {version = "0.3.0", features = ["serde"]} serde = {version = "1.0.115", features = ["derive"]} serde_json = "1.0.57" -[build-dependencies] +[build-dependencies] \ No newline at end of file diff --git a/crates/nu-plugin/src/test_helpers.rs b/crates/nu-plugin/src/test_helpers.rs index 6a9071093a..bf3b2bf480 100644 --- a/crates/nu-plugin/src/test_helpers.rs +++ b/crates/nu-plugin/src/test_helpers.rs @@ -1,8 +1,12 @@ use crate::Plugin; use indexmap::IndexMap; use nu_errors::ShellError; -use nu_protocol::{CallInfo, EvaluatedArgs, ReturnSuccess, ReturnValue, UntaggedValue, Value}; +use nu_protocol::{ + CallInfo, EvaluatedArgs, Primitive, ReturnSuccess, ReturnValue, UntaggedValue, Value, +}; use nu_source::Tag; +use nu_test_support::value::column_path; +use nu_value_ext::ValueExt; pub struct PluginTest<'a, T: Plugin> { plugin: &'a mut T, @@ -112,12 +116,12 @@ impl CallStub { } pub fn with_parameter(&mut self, name: &str) -> Result<&mut Self, ShellError> { - let fields: Vec = name - .split('.') - .map(|s| UntaggedValue::string(s.to_string()).into_value(Tag::unknown())) - .collect(); + let cp = column_path(&name) + .as_column_path() + .expect("Failed! Expected valid column path."); + let cp = UntaggedValue::Primitive(Primitive::ColumnPath(cp.item)).into_value(cp.tag); - self.positionals.push(value::column_path(&fields)?); + self.positionals.push(cp); Ok(self) } @@ -157,62 +161,3 @@ pub fn expect_return_value_at( return_values.len() - 1 )) } - -pub mod value { - use bigdecimal::BigDecimal; - use nu_errors::ShellError; - use nu_protocol::{Primitive, TaggedDictBuilder, UntaggedValue, Value}; - use nu_source::{Span, Tag}; - use nu_value_ext::ValueExt; - use num_bigint::BigInt; - - pub fn get_data(for_value: Value, key: &str) -> Value { - for_value.get_data(&key.to_string()).borrow().clone() - } - - pub fn int(i: impl Into) -> Value { - UntaggedValue::Primitive(Primitive::Int(i.into())).into_untagged_value() - } - - pub fn decimal(f: impl Into) -> Value { - UntaggedValue::decimal(f.into()).into_untagged_value() - } - - pub fn decimal_from_float(f: f64) -> Value { - UntaggedValue::decimal_from_float(f, Span::unknown()).into_untagged_value() - } - - pub fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() - } - - pub fn structured_sample_record(key: &str, value: &str) -> Value { - let mut record = TaggedDictBuilder::new(Tag::unknown()); - record.insert_untagged(key, UntaggedValue::string(value)); - record.into_value() - } - - pub fn unstructured_sample_record(value: &str) -> Value { - UntaggedValue::string(value).into_value(Tag::unknown()) - } - - pub fn table(list: &[Value]) -> Value { - UntaggedValue::table(list).into_untagged_value() - } - - pub fn column_path(paths: &[Value]) -> Result { - Ok(UntaggedValue::Primitive(Primitive::ColumnPath( - table(&paths.to_vec()).as_column_path()?.item, - )) - .into_untagged_value()) - } - - #[macro_export] - macro_rules! row { - ($( $key: expr => $val: expr ),*) => {{ - let mut map = ::indexmap::IndexMap::new(); - $( map.insert($key, $val); )* - ::nu_protocol::UntaggedValue::row(map).into_untagged_value() - }} - } -} diff --git a/crates/nu-protocol/src/macros.rs b/crates/nu-protocol/src/macros.rs index cfc4cd43e7..4b7eb81a69 100644 --- a/crates/nu-protocol/src/macros.rs +++ b/crates/nu-protocol/src/macros.rs @@ -24,3 +24,12 @@ macro_rules! outln { macro_rules! errln { ($($tokens:tt)*) => { eprintln!($($tokens)*) } } + +#[macro_export] +macro_rules! row { + ($( $key: expr => $val: expr ),*) => {{ + let mut map = ::indexmap::IndexMap::new(); + $( map.insert($key, $val); )* + ::nu_protocol::UntaggedValue::row(map).into_untagged_value() + }} +} diff --git a/crates/nu-protocol/src/value.rs b/crates/nu-protocol/src/value.rs index 87003df1a6..13a9e11c73 100644 --- a/crates/nu-protocol/src/value.rs +++ b/crates/nu-protocol/src/value.rs @@ -169,8 +169,8 @@ impl UntaggedValue { } /// Helper for creating column-path values - pub fn column_path(s: &str) -> UntaggedValue { - let s = s.to_string().spanned_unknown(); + pub fn column_path(s: &str, span: Span) -> UntaggedValue { + let s = s.to_string().spanned(span); UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::build(&s))) } @@ -196,8 +196,8 @@ impl UntaggedValue { } /// Helper for creating decimal values - pub fn decimal(s: BigDecimal) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Decimal(s)) + pub fn decimal(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Decimal(s.into())) } /// Helper for creating decimal values diff --git a/crates/nu-test-support/Cargo.toml b/crates/nu-test-support/Cargo.toml index a46d64a0a3..061783ec26 100644 --- a/crates/nu-test-support/Cargo.toml +++ b/crates/nu-test-support/Cargo.toml @@ -21,6 +21,7 @@ getset = "0.1.1" glob = "0.3.0" indexmap = {version = "1.6.0", features = ["serde-1"]} num-bigint = {version = "0.3.0", features = ["serde"]} +bigdecimal = {version = "0.2.0", features = ["serde"]} tempfile = "3.1.0" [build-dependencies] diff --git a/crates/nu-test-support/src/value.rs b/crates/nu-test-support/src/value.rs index ddc3afb073..000fe16044 100644 --- a/crates/nu-test-support/src/value.rs +++ b/crates/nu-test-support/src/value.rs @@ -1,16 +1,21 @@ +use bigdecimal::BigDecimal; use chrono::{DateTime, NaiveDate, Utc}; use indexmap::IndexMap; use nu_errors::ShellError; -use nu_protocol::{ColumnPath, PathMember, Primitive, UntaggedValue, Value}; -use nu_source::{Span, SpannedItem, Tagged, TaggedItem}; +use nu_protocol::{PathMember, Primitive, UntaggedValue, Value}; +use nu_source::{Span, TaggedItem}; use num_bigint::BigInt; pub fn int(s: impl Into) -> Value { UntaggedValue::int(s).into_untagged_value() } -pub fn decimal_from_float(f: f64, span: Span) -> Value { - UntaggedValue::decimal_from_float(f, span).into_untagged_value() +pub fn decimal(s: BigDecimal) -> Value { + UntaggedValue::Primitive(Primitive::Decimal(s)).into_untagged_value() +} + +pub fn decimal_from_float(f: f64) -> Value { + UntaggedValue::decimal_from_float(f, Span::unknown()).into_untagged_value() } pub fn string(input: impl Into) -> Value { @@ -42,9 +47,8 @@ pub fn date(input: impl Into) -> Value { .into_untagged_value() } -pub fn column_path(paths: &str) -> Result, ShellError> { - let paths = paths.to_string().spanned_unknown(); - Ok(ColumnPath::build(&paths).tagged_unknown()) +pub fn column_path(paths: &str) -> Value { + UntaggedValue::column_path(paths, Span::unknown()).into_untagged_value() } pub fn error_callback( diff --git a/crates/nu-value-ext/src/tests.rs b/crates/nu-value-ext/src/tests.rs index 86d6000811..db40e313e3 100644 --- a/crates/nu-value-ext/src/tests.rs +++ b/crates/nu-value-ext/src/tests.rs @@ -5,7 +5,7 @@ use indexmap::indexmap; #[test] fn forgiving_insertion_test_1() { - let field_path = column_path("crate.version").unwrap(); + let field_path = column_path("crate.version").as_column_path().unwrap(); let version = string("nuno"); @@ -20,7 +20,7 @@ fn forgiving_insertion_test_1() { assert_eq!( *value .into_untagged_value() - .forgiving_insert_data_at_column_path(&field_path, version) + .forgiving_insert_data_at_column_path(&field_path.item, version) .unwrap() .get_data_by_column_path(&field_path, Box::new(error_callback("crate.version"))) .unwrap(), @@ -30,7 +30,7 @@ fn forgiving_insertion_test_1() { #[test] fn forgiving_insertion_test_2() { - let field_path = column_path("things.0").unwrap(); + let field_path = column_path("things.0").as_column_path().unwrap(); let version = string("arepas"); @@ -47,7 +47,7 @@ fn forgiving_insertion_test_2() { assert_eq!( *value .into_untagged_value() - .forgiving_insert_data_at_column_path(&field_path, version) + .forgiving_insert_data_at_column_path(&field_path.item, version) .unwrap() .get_data_by_column_path(&field_path, Box::new(error_callback("things.0"))) .unwrap(), @@ -57,8 +57,10 @@ fn forgiving_insertion_test_2() { #[test] fn forgiving_insertion_test_3() { - let field_path = column_path("color_config.arepa_color").unwrap(); - let pizza_path = column_path("things.0").unwrap(); + let field_path = column_path("color_config.arepa_color") + .as_column_path() + .unwrap(); + let pizza_path = column_path("things.0").as_column_path().unwrap(); let entry = string("amarillo"); @@ -79,7 +81,7 @@ fn forgiving_insertion_test_3() { .forgiving_insert_data_at_column_path(&field_path, entry.clone()) .unwrap() .get_data_by_column_path( - &field_path, + &field_path.item, Box::new(error_callback("color_config.arepa_color")) ) .unwrap(), @@ -89,7 +91,7 @@ fn forgiving_insertion_test_3() { assert_eq!( *value .into_untagged_value() - .forgiving_insert_data_at_column_path(&field_path, entry) + .forgiving_insert_data_at_column_path(&field_path.item, entry) .unwrap() .get_data_by_column_path(&pizza_path, Box::new(error_callback("things.0"))) .unwrap(), diff --git a/crates/nu_plugin_inc/Cargo.toml b/crates/nu_plugin_inc/Cargo.toml index d9fb145d80..fdf4e70a7f 100644 --- a/crates/nu_plugin_inc/Cargo.toml +++ b/crates/nu_plugin_inc/Cargo.toml @@ -15,6 +15,7 @@ nu-plugin = {path = "../nu-plugin", version = "0.21.0"} nu-protocol = {path = "../nu-protocol", version = "0.21.0"} nu-source = {path = "../nu-source", version = "0.21.0"} nu-value-ext = {path = "../nu-value-ext", version = "0.21.0"} +nu-test-support = {path = "../nu-test-support", version = "0.21.0"} semver = "0.10.0" diff --git a/crates/nu_plugin_inc/src/inc.rs b/crates/nu_plugin_inc/src/inc.rs index 1ef26b4ec9..6599734535 100644 --- a/crates/nu_plugin_inc/src/inc.rs +++ b/crates/nu_plugin_inc/src/inc.rs @@ -150,7 +150,7 @@ mod tests { mod semver { use crate::inc::SemVerAction; use crate::Inc; - use nu_plugin::test_helpers::value::string; + use nu_test_support::value::string; #[test] fn major() -> Result<(), Box> { diff --git a/crates/nu_plugin_inc/src/nu/tests.rs b/crates/nu_plugin_inc/src/nu/tests.rs index 391e00e73d..afc6b54541 100644 --- a/crates/nu_plugin_inc/src/nu/tests.rs +++ b/crates/nu_plugin_inc/src/nu/tests.rs @@ -2,8 +2,10 @@ mod integration { use crate::inc::{Action, SemVerAction}; use crate::Inc; use nu_errors::ShellError; - use nu_plugin::test_helpers::value::{column_path, string}; use nu_plugin::test_helpers::{plugin, CallStub}; + use nu_protocol::{Primitive, UntaggedValue}; + use nu_test_support::value::column_path; + use nu_value_ext::ValueExt; #[test] fn picks_up_one_action_flag_only() { @@ -58,21 +60,28 @@ mod integration { .args(CallStub::new().with_parameter("package.version")?.create()) .setup(|plugin, _| { //FIXME: this will need to be updated - if let Ok(column_path) = column_path(&[string("package"), string("version")]) { + if let Ok(column_path) = column_path("package.version").as_column_path() { + let column_path = + UntaggedValue::Primitive(Primitive::ColumnPath(column_path.item)) + .into_value(column_path.tag); plugin.expect_field(column_path) } }); Ok(()) } - mod sem_ver { use crate::Inc; use nu_errors::ShellError; - use nu_plugin::test_helpers::value::{get_data, string, structured_sample_record}; use nu_plugin::test_helpers::{expect_return_value_at, plugin, CallStub}; + use nu_protocol::TaggedDictBuilder; + use nu_source::Tag; + use nu_test_support::value::string; + use nu_value_ext::get_data; fn cargo_sample_record(with_version: &str) -> nu_protocol::Value { - structured_sample_record("version", with_version) + TaggedDictBuilder::build(Tag::unknown(), |row| { + row.insert_value("version".to_string(), string(with_version)); + }) } #[test] @@ -90,7 +99,7 @@ mod integration { let actual = expect_return_value_at(run, 0); - assert_eq!(get_data(actual, "version"), string("1.0.0")); + assert_eq!(get_data(&actual, "version").borrow(), &string("1.0.0")); Ok(()) } @@ -109,7 +118,7 @@ mod integration { let actual = expect_return_value_at(run, 0); - assert_eq!(get_data(actual, "version"), string("0.2.0")); + assert_eq!(get_data(&actual, "version").borrow(), &string("0.2.0")); Ok(()) } @@ -128,7 +137,7 @@ mod integration { let actual = expect_return_value_at(run, 0); - assert_eq!(get_data(actual, "version"), string("0.1.4")); + assert_eq!(get_data(&actual, "version").borrow(), &string("0.1.4")); Ok(()) } } diff --git a/crates/nu_plugin_xpath/src/xpath.rs b/crates/nu_plugin_xpath/src/xpath.rs index 857a8a770a..17e469541c 100644 --- a/crates/nu_plugin_xpath/src/xpath.rs +++ b/crates/nu_plugin_xpath/src/xpath.rs @@ -127,7 +127,7 @@ fn build_xpath(xpath_str: &str) -> Result { mod tests { use super::string_to_value as query; use nu_errors::ShellError; - use nu_source::{Span, TaggedItem}; + use nu_source::TaggedItem; use nu_test_support::value::{decimal_from_float, row}; use indexmap::indexmap; @@ -140,9 +140,7 @@ mod tests { assert_eq!( actual[0], - row( - indexmap! { "count(//a/*[posit...".into() => decimal_from_float(1.0, Span::unknown()) } - ) + row(indexmap! { "count(//a/*[posit...".into() => decimal_from_float(1.0) }) ); Ok(()) @@ -156,9 +154,7 @@ mod tests { assert_eq!( actual[0], - row( - indexmap! { "count(//*[contain...".into() => decimal_from_float(1.0, Span::unknown()) } - ) + row(indexmap! { "count(//*[contain...".into() => decimal_from_float(1.0) }) ); Ok(())