nushell/crates/nu-cli/src/commands/is_empty.rs
Jonathan Turner 076fde16dd
Evaluation of command arguments (#1801)
* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Finish adding the baseline refactors for argument invocation

* Finish cleanup and add test

* Add missing plugin references
2020-05-16 15:18:24 +12:00

199 lines
7.7 KiB
Rust

use crate::commands::WholeStreamCommand;
use crate::context::CommandRegistry;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
use nu_value_ext::ValueExt;
enum IsEmptyFor {
Value,
RowWithFieldsAndFallback(Vec<Tagged<ColumnPath>>, Value),
RowWithField(Tagged<ColumnPath>),
RowWithFieldAndFallback(Box<Tagged<ColumnPath>>, Value),
}
pub struct IsEmpty;
#[derive(Deserialize)]
pub struct IsEmptyArgs {
rest: Vec<Value>,
}
impl WholeStreamCommand for IsEmpty {
fn name(&self) -> &str {
"empty?"
}
fn signature(&self) -> Signature {
Signature::build("empty?").rest(
SyntaxShape::Any,
"the names of the columns to check emptiness followed by the replacement value.",
)
}
fn usage(&self) -> &str {
"Checks emptiness. The last value is the replacement value for any empty column(s) given to check against the table."
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
is_empty(args, registry)
}
}
fn is_empty(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let stream = async_stream! {
let (IsEmptyArgs { rest }, mut input) = args.process(&registry).await?;
while let Some(value) = input.next().await {
let value_tag = value.tag();
let action = if rest.len() <= 2 {
let field = rest.get(0);
let replacement_if_true = rest.get(1);
match (field, replacement_if_true) {
(Some(field), Some(replacement_if_true)) => {
IsEmptyFor::RowWithFieldAndFallback(
Box::new(field.as_column_path()?),
replacement_if_true.clone(),
)
}
(Some(field), None) => IsEmptyFor::RowWithField(field.as_column_path()?),
(_, _) => IsEmptyFor::Value,
}
} else {
// let no_args = vec![];
let mut arguments = rest.iter().rev();
let replacement_if_true = match arguments.next() {
Some(arg) => arg.clone(),
None => UntaggedValue::boolean(value.is_empty()).into_value(&value_tag),
};
IsEmptyFor::RowWithFieldsAndFallback(
arguments
.map(|a| a.as_column_path())
.filter_map(Result::ok)
.collect(),
replacement_if_true,
)
};
match action {
IsEmptyFor::Value => yield Ok(ReturnSuccess::Value(
UntaggedValue::boolean(value.is_empty()).into_value(value_tag),
)),
IsEmptyFor::RowWithFieldsAndFallback(fields, default) => {
let mut out = value;
for field in fields.iter() {
let val =
crate::commands::get::get_column_path(&field, &out)?;
let emptiness_value = match out {
obj
@
Value {
value: UntaggedValue::Row(_),
..
} => {
if val.is_empty() {
match obj.replace_data_at_column_path(&field, default.clone()) {
Some(v) => Ok(v),
None => Err(ShellError::labeled_error(
"empty? could not find place to check emptiness",
"column name",
&field.tag,
)),
}
} else {
Ok(obj)
}
}
_ => Err(ShellError::labeled_error(
"Unrecognized type in stream",
"original value",
&value_tag,
)),
};
out = emptiness_value?;
}
yield Ok(ReturnSuccess::Value(out))
}
IsEmptyFor::RowWithField(field) => {
let val =
crate::commands::get::get_column_path(&field, &value)?;
match &value {
obj
@
Value {
value: UntaggedValue::Row(_),
..
} => {
if val.is_empty() {
match obj.replace_data_at_column_path(
&field,
UntaggedValue::boolean(true).into_value(&value_tag),
) {
Some(v) => yield Ok(ReturnSuccess::Value(v)),
None => yield Err(ShellError::labeled_error(
"empty? could not find place to check emptiness",
"column name",
&field.tag,
)),
}
} else {
yield Ok(ReturnSuccess::Value(value))
}
}
_ => yield Err(ShellError::labeled_error(
"Unrecognized type in stream",
"original value",
&value_tag,
)),
}
}
IsEmptyFor::RowWithFieldAndFallback(field, default) => {
let val =
crate::commands::get::get_column_path(&field, &value)?;
match &value {
obj
@
Value {
value: UntaggedValue::Row(_),
..
} => {
if val.is_empty() {
match obj.replace_data_at_column_path(&field, default) {
Some(v) => yield Ok(ReturnSuccess::Value(v)),
None => yield Err(ShellError::labeled_error(
"empty? could not find place to check emptiness",
"column name",
&field.tag,
)),
}
} else {
yield Ok(ReturnSuccess::Value(value))
}
}
_ => yield Err(ShellError::labeled_error(
"Unrecognized type in stream",
"original value",
&value_tag,
)),
}
}
}
}
};
Ok(stream.to_output_stream())
}