mirror of
https://github.com/nushell/nushell
synced 2024-12-27 13:33:16 +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> {
|
fn follow_path_int(&self, count: usize, span: Span) -> Result<Value, ShellError> {
|
||||||
let path = PathMember::Int { val: count, span };
|
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> {
|
fn follow_path_string(&self, column_name: String, span: Span) -> Result<Value, ShellError> {
|
||||||
|
@ -61,7 +61,7 @@ impl CustomValue for ExprDb {
|
||||||
span,
|
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 {
|
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> {
|
fn follow_path_int(&self, count: usize, span: Span) -> Result<Value, ShellError> {
|
||||||
let path = PathMember::Int { val: count, span };
|
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> {
|
fn follow_path_string(&self, column_name: String, span: Span) -> Result<Value, ShellError> {
|
||||||
|
@ -64,7 +64,7 @@ impl CustomValue for SelectDb {
|
||||||
val: column_name,
|
val: column_name,
|
||||||
span,
|
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 {
|
fn typetag_name(&self) -> &'static str {
|
||||||
|
|
|
@ -101,7 +101,7 @@ fn dropcol(
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
for path in &keep_columns {
|
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());
|
cols.push(path.into_string());
|
||||||
vals.push(fetcher);
|
vals.push(fetcher);
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ fn dropcol(
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
for path in &keep_columns {
|
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());
|
cols.push(path.into_string());
|
||||||
vals.push(fetcher);
|
vals.push(fetcher);
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ fn dropcol(
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
for cell_path in &keep_columns {
|
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());
|
cols.push(cell_path.into_string());
|
||||||
vals.push(result);
|
vals.push(result);
|
||||||
|
|
|
@ -81,7 +81,7 @@ fn empty(
|
||||||
for val in input {
|
for val in input {
|
||||||
for column in &columns {
|
for column in &columns {
|
||||||
let val = val.clone();
|
let val = val.clone();
|
||||||
match val.follow_cell_path(&column.members) {
|
match val.follow_cell_path(&column.members, false) {
|
||||||
Ok(Value::Nothing { .. }) => {}
|
Ok(Value::Nothing { .. }) => {}
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
return Ok(Value::Bool {
|
return Ok(Value::Bool {
|
||||||
|
|
|
@ -31,6 +31,11 @@ impl Command for Get {
|
||||||
"return nothing if path can't be found",
|
"return nothing if path can't be found",
|
||||||
Some('i'),
|
Some('i'),
|
||||||
)
|
)
|
||||||
|
.switch(
|
||||||
|
"sensitive",
|
||||||
|
"get path in a case sensitive manner",
|
||||||
|
Some('s'),
|
||||||
|
)
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,13 +49,14 @@ impl Command for Get {
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
let cell_path: CellPath = call.req(engine_state, stack, 0)?;
|
||||||
let rest: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
|
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 ignore_errors = call.has_flag("ignore-errors");
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let metadata = input.metadata();
|
let metadata = input.metadata();
|
||||||
|
|
||||||
if rest.is_empty() {
|
if rest.is_empty() {
|
||||||
let output = input
|
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());
|
.map(|x| x.into_pipeline_data());
|
||||||
|
|
||||||
if ignore_errors {
|
if ignore_errors {
|
||||||
|
@ -69,7 +75,7 @@ impl Command for Get {
|
||||||
let input = input.into_value(span);
|
let input = input.into_value(span);
|
||||||
|
|
||||||
for path in paths {
|
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 ignore_errors {
|
||||||
if let Ok(val) = val {
|
if let Ok(val) = val {
|
||||||
|
@ -106,6 +112,16 @@ impl Command for Get {
|
||||||
example: "sys | get cpu",
|
example: "sys | get cpu",
|
||||||
result: None,
|
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![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
for path in &keep_columns {
|
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 {
|
if let Ok(value) = fetcher {
|
||||||
cols.push(path.into_string());
|
cols.push(path.into_string());
|
||||||
|
@ -135,7 +135,7 @@ fn reject(
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
for path in &keep_columns {
|
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());
|
cols.push(path.into_string());
|
||||||
vals.push(fetcher);
|
vals.push(fetcher);
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ fn reject(
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
for cell_path in &keep_columns {
|
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());
|
cols.push(cell_path.into_string());
|
||||||
vals.push(result);
|
vals.push(result);
|
||||||
|
|
|
@ -124,7 +124,7 @@ fn select(
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
for path in &columns {
|
for path in &columns {
|
||||||
//FIXME: improve implementation to not clone
|
//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('.', "_"));
|
cols.push(path.into_string().replace('.', "_"));
|
||||||
vals.push(fetcher);
|
vals.push(fetcher);
|
||||||
|
@ -148,7 +148,7 @@ fn select(
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
for path in &columns {
|
for path in &columns {
|
||||||
//FIXME: improve implementation to not clone
|
//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) => {
|
Ok(value) => {
|
||||||
cols.push(path.into_string().replace('.', "_"));
|
cols.push(path.into_string().replace('.', "_"));
|
||||||
vals.push(value);
|
vals.push(value);
|
||||||
|
@ -173,7 +173,7 @@ fn select(
|
||||||
|
|
||||||
for cell_path in columns {
|
for cell_path in columns {
|
||||||
// FIXME: remove clone
|
// 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('.', "_"));
|
cols.push(cell_path.into_string().replace('.', "_"));
|
||||||
vals.push(result);
|
vals.push(result);
|
||||||
|
|
|
@ -261,7 +261,7 @@ fn format_record(
|
||||||
span: *span,
|
span: *span,
|
||||||
})
|
})
|
||||||
.collect();
|
.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) => {
|
Ok(value_at_column) => {
|
||||||
output.push_str(value_at_column.into_string(", ", config).as_str())
|
output.push_str(value_at_column.into_string(", ", config).as_str())
|
||||||
}
|
}
|
||||||
|
|
|
@ -310,12 +310,13 @@ fn convert_to_list(
|
||||||
} else {
|
} else {
|
||||||
for header in headers.iter().skip(1) {
|
for header in headers.iter().skip(1) {
|
||||||
let result = match item {
|
let result = match item {
|
||||||
Value::Record { .. } => {
|
Value::Record { .. } => item.clone().follow_cell_path(
|
||||||
item.clone().follow_cell_path(&[PathMember::String {
|
&[PathMember::String {
|
||||||
val: header.into(),
|
val: header.into(),
|
||||||
span: head,
|
span: head,
|
||||||
}])
|
}],
|
||||||
}
|
false,
|
||||||
|
),
|
||||||
_ => Ok(item.clone()),
|
_ => Ok(item.clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -386,12 +386,13 @@ fn convert_to_table(
|
||||||
let skip_num = if !disable_index { 1 } else { 0 };
|
let skip_num = if !disable_index { 1 } else { 0 };
|
||||||
for header in headers.iter().skip(skip_num) {
|
for header in headers.iter().skip(skip_num) {
|
||||||
let result = match item {
|
let result = match item {
|
||||||
Value::Record { .. } => {
|
Value::Record { .. } => item.clone().follow_cell_path(
|
||||||
item.clone().follow_cell_path(&[PathMember::String {
|
&[PathMember::String {
|
||||||
val: header.into(),
|
val: header.into(),
|
||||||
span: head,
|
span: head,
|
||||||
}])
|
}],
|
||||||
}
|
false,
|
||||||
|
),
|
||||||
_ => Ok(item.clone()),
|
_ => Ok(item.clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ fn get_converted_value(
|
||||||
val: block_id,
|
val: block_id,
|
||||||
span: from_span,
|
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);
|
let block = engine_state.get_block(block_id);
|
||||||
|
|
||||||
|
|
|
@ -295,7 +295,7 @@ pub fn eval_expression(
|
||||||
Expr::FullCellPath(cell_path) => {
|
Expr::FullCellPath(cell_path) => {
|
||||||
let value = eval_expression(engine_state, stack, &cell_path.head)?;
|
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::ImportPattern(_) => Ok(Value::Nothing { span: expr.span }),
|
||||||
Expr::Call(call) => {
|
Expr::Call(call) => {
|
||||||
|
|
|
@ -217,6 +217,7 @@ impl PipelineData {
|
||||||
self,
|
self,
|
||||||
cell_path: &[PathMember],
|
cell_path: &[PathMember],
|
||||||
head: Span,
|
head: Span,
|
||||||
|
insensitive: bool,
|
||||||
) -> Result<Value, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
// FIXME: there are probably better ways of doing this
|
// FIXME: there are probably better ways of doing this
|
||||||
|
@ -224,8 +225,8 @@ impl PipelineData {
|
||||||
vals: stream.collect(),
|
vals: stream.collect(),
|
||||||
span: head,
|
span: head,
|
||||||
}
|
}
|
||||||
.follow_cell_path(cell_path),
|
.follow_cell_path(cell_path, insensitive),
|
||||||
PipelineData::Value(v, ..) => v.follow_cell_path(cell_path),
|
PipelineData::Value(v, ..) => v.follow_cell_path(cell_path, insensitive),
|
||||||
_ => Err(ShellError::IOError("can't follow stream paths".into())),
|
_ => 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
|
/// 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;
|
let mut current = self;
|
||||||
for member in cell_path {
|
for member in cell_path {
|
||||||
// FIXME: this uses a few extra clones for simplicity, but there may be a way
|
// FIXME: this uses a few extra clones for simplicity, but there may be a way
|
||||||
|
@ -661,12 +665,13 @@ impl Value {
|
||||||
let span = *span;
|
let span = *span;
|
||||||
|
|
||||||
// Make reverse iterate to avoid duplicate column leads to first value, actuall last value is expected.
|
// Make reverse iterate to avoid duplicate column leads to first value, actuall last value is expected.
|
||||||
if let Some(found) = cols
|
if let Some(found) = cols.iter().zip(vals.iter()).rev().find(|x| {
|
||||||
.iter()
|
if insensitive {
|
||||||
.zip(vals.iter())
|
x.0.to_lowercase() == column_name.to_lowercase()
|
||||||
.rev()
|
} else {
|
||||||
.find(|x| x.0 == column_name)
|
x.0 == column_name
|
||||||
{
|
}
|
||||||
|
}) {
|
||||||
current = found.1.clone();
|
current = found.1.clone();
|
||||||
} else if let Some(suggestion) = did_you_mean(&cols, column_name) {
|
} else if let Some(suggestion) = did_you_mean(&cols, column_name) {
|
||||||
return Err(ShellError::DidYouMean(suggestion, *origin_span));
|
return Err(ShellError::DidYouMean(suggestion, *origin_span));
|
||||||
|
@ -679,10 +684,13 @@ impl Value {
|
||||||
let mut hasvalue = false;
|
let mut hasvalue = false;
|
||||||
let mut temp: Result<Value, ShellError> = Err(ShellError::NotFound(*span));
|
let mut temp: Result<Value, ShellError> = Err(ShellError::NotFound(*span));
|
||||||
for val in vals {
|
for val in vals {
|
||||||
temp = val.clone().follow_cell_path(&[PathMember::String {
|
temp = val.clone().follow_cell_path(
|
||||||
val: column_name.clone(),
|
&[PathMember::String {
|
||||||
span: *origin_span,
|
val: column_name.clone(),
|
||||||
}]);
|
span: *origin_span,
|
||||||
|
}],
|
||||||
|
insensitive,
|
||||||
|
);
|
||||||
if let Ok(result) = temp.clone() {
|
if let Ok(result) = temp.clone() {
|
||||||
hasvalue = true;
|
hasvalue = true;
|
||||||
output.push(result);
|
output.push(result);
|
||||||
|
@ -723,7 +731,7 @@ impl Value {
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
let orig = self.clone();
|
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 {
|
match new_val {
|
||||||
Value::Error { error } => Err(error),
|
Value::Error { error } => Err(error),
|
||||||
|
@ -834,7 +842,7 @@ impl Value {
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
let orig = self.clone();
|
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 {
|
match new_val {
|
||||||
Value::Error { error } => Err(error),
|
Value::Error { error } => Err(error),
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl Inc {
|
||||||
pub fn inc(&self, head: Span, value: &Value) -> Result<Value, LabeledError> {
|
pub fn inc(&self, head: Span, value: &Value) -> Result<Value, LabeledError> {
|
||||||
if let Some(cell_path) = &self.cell_path {
|
if let Some(cell_path) = &self.cell_path {
|
||||||
let working_value = value.clone();
|
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)?;
|
let cell_value = self.inc_value(head, &cell_value)?;
|
||||||
|
|
||||||
|
|
|
@ -260,3 +260,11 @@ fn length_defaulted_columns() -> TestResult {
|
||||||
fn get_fuzzy() -> TestResult {
|
fn get_fuzzy() -> TestResult {
|
||||||
run_test("(ls | get -i foo) == $nothing", "true")
|
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