mirror of
https://github.com/nushell/nushell
synced 2024-12-26 13:03:07 +00:00
* feat: Add insensitive flag to get, fix #4295 * add get insensitive example * Fix get flags * Update get examples
This commit is contained in:
parent
b79abdb2a5
commit
d44059c36b
16 changed files with 78 additions and 43 deletions
|
@ -52,7 +52,7 @@ impl CustomValue for ExprDb {
|
|||
fn follow_path_int(&self, count: usize, span: Span) -> Result<Value, ShellError> {
|
||||
let path = PathMember::Int { val: count, span };
|
||||
|
||||
ExprDb::expr_to_value(self.as_ref(), span).follow_cell_path(&[path])
|
||||
ExprDb::expr_to_value(self.as_ref(), span).follow_cell_path(&[path], false)
|
||||
}
|
||||
|
||||
fn follow_path_string(&self, column_name: String, span: Span) -> Result<Value, ShellError> {
|
||||
|
@ -61,7 +61,7 @@ impl CustomValue for ExprDb {
|
|||
span,
|
||||
};
|
||||
|
||||
ExprDb::expr_to_value(self.as_ref(), span).follow_cell_path(&[path])
|
||||
ExprDb::expr_to_value(self.as_ref(), span).follow_cell_path(&[path], false)
|
||||
}
|
||||
|
||||
fn typetag_name(&self) -> &'static str {
|
||||
|
|
|
@ -56,7 +56,7 @@ impl CustomValue for SelectDb {
|
|||
fn follow_path_int(&self, count: usize, span: Span) -> Result<Value, ShellError> {
|
||||
let path = PathMember::Int { val: count, span };
|
||||
|
||||
SelectDb::select_to_value(self.as_ref(), span).follow_cell_path(&[path])
|
||||
SelectDb::select_to_value(self.as_ref(), span).follow_cell_path(&[path], false)
|
||||
}
|
||||
|
||||
fn follow_path_string(&self, column_name: String, span: Span) -> Result<Value, ShellError> {
|
||||
|
@ -64,7 +64,7 @@ impl CustomValue for SelectDb {
|
|||
val: column_name,
|
||||
span,
|
||||
};
|
||||
SelectDb::select_to_value(self.as_ref(), span).follow_cell_path(&[path])
|
||||
SelectDb::select_to_value(self.as_ref(), span).follow_cell_path(&[path], false)
|
||||
}
|
||||
|
||||
fn typetag_name(&self) -> &'static str {
|
||||
|
|
|
@ -101,7 +101,7 @@ fn dropcol(
|
|||
let mut vals = vec![];
|
||||
|
||||
for path in &keep_columns {
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members)?;
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members, false)?;
|
||||
cols.push(path.into_string());
|
||||
vals.push(fetcher);
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ fn dropcol(
|
|||
let mut vals = vec![];
|
||||
|
||||
for path in &keep_columns {
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members)?;
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members, false)?;
|
||||
cols.push(path.into_string());
|
||||
vals.push(fetcher);
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ fn dropcol(
|
|||
let mut vals = vec![];
|
||||
|
||||
for cell_path in &keep_columns {
|
||||
let result = v.clone().follow_cell_path(&cell_path.members)?;
|
||||
let result = v.clone().follow_cell_path(&cell_path.members, false)?;
|
||||
|
||||
cols.push(cell_path.into_string());
|
||||
vals.push(result);
|
||||
|
|
|
@ -81,7 +81,7 @@ fn empty(
|
|||
for val in input {
|
||||
for column in &columns {
|
||||
let val = val.clone();
|
||||
match val.follow_cell_path(&column.members) {
|
||||
match val.follow_cell_path(&column.members, false) {
|
||||
Ok(Value::Nothing { .. }) => {}
|
||||
Ok(_) => {
|
||||
return Ok(Value::Bool {
|
||||
|
|
|
@ -31,6 +31,11 @@ impl Command for Get {
|
|||
"return nothing if path can't be found",
|
||||
Some('i'),
|
||||
)
|
||||
.switch(
|
||||
"sensitive",
|
||||
"get path in a case sensitive manner",
|
||||
Some('s'),
|
||||
)
|
||||
.category(Category::Filters)
|
||||
}
|
||||
|
||||
|
@ -44,13 +49,14 @@ impl Command for Get {
|
|||
let span = call.head;
|
||||
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
||||
let rest: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
|
||||
let sensitive = call.has_flag("sensitive");
|
||||
let ignore_errors = call.has_flag("ignore-errors");
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
let metadata = input.metadata();
|
||||
|
||||
if rest.is_empty() {
|
||||
let output = input
|
||||
.follow_cell_path(&cell_path.members, call.head)
|
||||
.follow_cell_path(&cell_path.members, call.head, !sensitive)
|
||||
.map(|x| x.into_pipeline_data());
|
||||
|
||||
if ignore_errors {
|
||||
|
@ -69,7 +75,7 @@ impl Command for Get {
|
|||
let input = input.into_value(span);
|
||||
|
||||
for path in paths {
|
||||
let val = input.clone().follow_cell_path(&path.members);
|
||||
let val = input.clone().follow_cell_path(&path.members, !sensitive);
|
||||
|
||||
if ignore_errors {
|
||||
if let Ok(val) = val {
|
||||
|
@ -106,6 +112,16 @@ impl Command for Get {
|
|||
example: "sys | get cpu",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Getting Path/PATH in a case insensitive way",
|
||||
example: "$env | get paTH",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Getting Path in a case sensitive way, won't work for 'PATH'",
|
||||
example: "$env | get -s Path",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ fn reject(
|
|||
let mut vals = vec![];
|
||||
|
||||
for path in &keep_columns {
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members);
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members, false);
|
||||
|
||||
if let Ok(value) = fetcher {
|
||||
cols.push(path.into_string());
|
||||
|
@ -135,7 +135,7 @@ fn reject(
|
|||
let mut vals = vec![];
|
||||
|
||||
for path in &keep_columns {
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members)?;
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members, false)?;
|
||||
cols.push(path.into_string());
|
||||
vals.push(fetcher);
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ fn reject(
|
|||
let mut vals = vec![];
|
||||
|
||||
for cell_path in &keep_columns {
|
||||
let result = v.clone().follow_cell_path(&cell_path.members)?;
|
||||
let result = v.clone().follow_cell_path(&cell_path.members, false)?;
|
||||
|
||||
cols.push(cell_path.into_string());
|
||||
vals.push(result);
|
||||
|
|
|
@ -124,7 +124,7 @@ fn select(
|
|||
let mut vals = vec![];
|
||||
for path in &columns {
|
||||
//FIXME: improve implementation to not clone
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members)?;
|
||||
let fetcher = input_val.clone().follow_cell_path(&path.members, false)?;
|
||||
|
||||
cols.push(path.into_string().replace('.', "_"));
|
||||
vals.push(fetcher);
|
||||
|
@ -148,7 +148,7 @@ fn select(
|
|||
let mut vals = vec![];
|
||||
for path in &columns {
|
||||
//FIXME: improve implementation to not clone
|
||||
match x.clone().follow_cell_path(&path.members) {
|
||||
match x.clone().follow_cell_path(&path.members, false) {
|
||||
Ok(value) => {
|
||||
cols.push(path.into_string().replace('.', "_"));
|
||||
vals.push(value);
|
||||
|
@ -173,7 +173,7 @@ fn select(
|
|||
|
||||
for cell_path in columns {
|
||||
// FIXME: remove clone
|
||||
let result = v.clone().follow_cell_path(&cell_path.members)?;
|
||||
let result = v.clone().follow_cell_path(&cell_path.members, false)?;
|
||||
|
||||
cols.push(cell_path.into_string().replace('.', "_"));
|
||||
vals.push(result);
|
||||
|
|
|
@ -261,7 +261,7 @@ fn format_record(
|
|||
span: *span,
|
||||
})
|
||||
.collect();
|
||||
match data_as_value.clone().follow_cell_path(&path_members) {
|
||||
match data_as_value.clone().follow_cell_path(&path_members, false) {
|
||||
Ok(value_at_column) => {
|
||||
output.push_str(value_at_column.into_string(", ", config).as_str())
|
||||
}
|
||||
|
|
|
@ -310,12 +310,13 @@ fn convert_to_list(
|
|||
} else {
|
||||
for header in headers.iter().skip(1) {
|
||||
let result = match item {
|
||||
Value::Record { .. } => {
|
||||
item.clone().follow_cell_path(&[PathMember::String {
|
||||
Value::Record { .. } => item.clone().follow_cell_path(
|
||||
&[PathMember::String {
|
||||
val: header.into(),
|
||||
span: head,
|
||||
}])
|
||||
}
|
||||
}],
|
||||
false,
|
||||
),
|
||||
_ => Ok(item.clone()),
|
||||
};
|
||||
|
||||
|
|
|
@ -386,12 +386,13 @@ fn convert_to_table(
|
|||
let skip_num = if !disable_index { 1 } else { 0 };
|
||||
for header in headers.iter().skip(skip_num) {
|
||||
let result = match item {
|
||||
Value::Record { .. } => {
|
||||
item.clone().follow_cell_path(&[PathMember::String {
|
||||
Value::Record { .. } => item.clone().follow_cell_path(
|
||||
&[PathMember::String {
|
||||
val: header.into(),
|
||||
span: head,
|
||||
}])
|
||||
}
|
||||
}],
|
||||
false,
|
||||
),
|
||||
_ => Ok(item.clone()),
|
||||
};
|
||||
|
||||
|
|
|
@ -262,7 +262,7 @@ fn get_converted_value(
|
|||
val: block_id,
|
||||
span: from_span,
|
||||
..
|
||||
}) = env_conversions.follow_cell_path(path_members)
|
||||
}) = env_conversions.follow_cell_path(path_members, false)
|
||||
{
|
||||
let block = engine_state.get_block(block_id);
|
||||
|
||||
|
|
|
@ -295,7 +295,7 @@ pub fn eval_expression(
|
|||
Expr::FullCellPath(cell_path) => {
|
||||
let value = eval_expression(engine_state, stack, &cell_path.head)?;
|
||||
|
||||
value.follow_cell_path(&cell_path.tail)
|
||||
value.follow_cell_path(&cell_path.tail, false)
|
||||
}
|
||||
Expr::ImportPattern(_) => Ok(Value::Nothing { span: expr.span }),
|
||||
Expr::Call(call) => {
|
||||
|
|
|
@ -217,6 +217,7 @@ impl PipelineData {
|
|||
self,
|
||||
cell_path: &[PathMember],
|
||||
head: Span,
|
||||
insensitive: bool,
|
||||
) -> Result<Value, ShellError> {
|
||||
match self {
|
||||
// FIXME: there are probably better ways of doing this
|
||||
|
@ -224,8 +225,8 @@ impl PipelineData {
|
|||
vals: stream.collect(),
|
||||
span: head,
|
||||
}
|
||||
.follow_cell_path(cell_path),
|
||||
PipelineData::Value(v, ..) => v.follow_cell_path(cell_path),
|
||||
.follow_cell_path(cell_path, insensitive),
|
||||
PipelineData::Value(v, ..) => v.follow_cell_path(cell_path, insensitive),
|
||||
_ => Err(ShellError::IOError("can't follow stream paths".into())),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -605,7 +605,11 @@ impl Value {
|
|||
}
|
||||
|
||||
/// Follow a given column path into the value: for example accessing select elements in a stream or list
|
||||
pub fn follow_cell_path(self, cell_path: &[PathMember]) -> Result<Value, ShellError> {
|
||||
pub fn follow_cell_path(
|
||||
self,
|
||||
cell_path: &[PathMember],
|
||||
insensitive: bool,
|
||||
) -> Result<Value, ShellError> {
|
||||
let mut current = self;
|
||||
for member in cell_path {
|
||||
// FIXME: this uses a few extra clones for simplicity, but there may be a way
|
||||
|
@ -661,12 +665,13 @@ impl Value {
|
|||
let span = *span;
|
||||
|
||||
// Make reverse iterate to avoid duplicate column leads to first value, actuall last value is expected.
|
||||
if let Some(found) = cols
|
||||
.iter()
|
||||
.zip(vals.iter())
|
||||
.rev()
|
||||
.find(|x| x.0 == column_name)
|
||||
{
|
||||
if let Some(found) = cols.iter().zip(vals.iter()).rev().find(|x| {
|
||||
if insensitive {
|
||||
x.0.to_lowercase() == column_name.to_lowercase()
|
||||
} else {
|
||||
x.0 == column_name
|
||||
}
|
||||
}) {
|
||||
current = found.1.clone();
|
||||
} else if let Some(suggestion) = did_you_mean(&cols, column_name) {
|
||||
return Err(ShellError::DidYouMean(suggestion, *origin_span));
|
||||
|
@ -679,10 +684,13 @@ impl Value {
|
|||
let mut hasvalue = false;
|
||||
let mut temp: Result<Value, ShellError> = Err(ShellError::NotFound(*span));
|
||||
for val in vals {
|
||||
temp = val.clone().follow_cell_path(&[PathMember::String {
|
||||
val: column_name.clone(),
|
||||
span: *origin_span,
|
||||
}]);
|
||||
temp = val.clone().follow_cell_path(
|
||||
&[PathMember::String {
|
||||
val: column_name.clone(),
|
||||
span: *origin_span,
|
||||
}],
|
||||
insensitive,
|
||||
);
|
||||
if let Ok(result) = temp.clone() {
|
||||
hasvalue = true;
|
||||
output.push(result);
|
||||
|
@ -723,7 +731,7 @@ impl Value {
|
|||
) -> Result<(), ShellError> {
|
||||
let orig = self.clone();
|
||||
|
||||
let new_val = callback(&orig.follow_cell_path(cell_path)?);
|
||||
let new_val = callback(&orig.follow_cell_path(cell_path, false)?);
|
||||
|
||||
match new_val {
|
||||
Value::Error { error } => Err(error),
|
||||
|
@ -834,7 +842,7 @@ impl Value {
|
|||
) -> Result<(), ShellError> {
|
||||
let orig = self.clone();
|
||||
|
||||
let new_val = callback(&orig.follow_cell_path(cell_path)?);
|
||||
let new_val = callback(&orig.follow_cell_path(cell_path, false)?);
|
||||
|
||||
match new_val {
|
||||
Value::Error { error } => Err(error),
|
||||
|
|
|
@ -86,7 +86,7 @@ impl Inc {
|
|||
pub fn inc(&self, head: Span, value: &Value) -> Result<Value, LabeledError> {
|
||||
if let Some(cell_path) = &self.cell_path {
|
||||
let working_value = value.clone();
|
||||
let cell_value = working_value.follow_cell_path(&cell_path.members)?;
|
||||
let cell_value = working_value.follow_cell_path(&cell_path.members, false)?;
|
||||
|
||||
let cell_value = self.inc_value(head, &cell_value)?;
|
||||
|
||||
|
|
|
@ -260,3 +260,11 @@ fn length_defaulted_columns() -> TestResult {
|
|||
fn get_fuzzy() -> TestResult {
|
||||
run_test("(ls | get -i foo) == $nothing", "true")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_insensitive() -> TestResult {
|
||||
run_test(
|
||||
r#"[[name, age]; [a, 1] [b, 2]] | get NAmE | select 0 | get 0"#,
|
||||
"a",
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue