mirror of
https://github.com/nushell/nushell.git
synced 2024-12-12 18:20:55 +01:00
076fde16dd
* 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
199 lines
7.7 KiB
Rust
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(®istry).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())
|
|
}
|