feat(get,select,reject): add --ignore-case which interprets cell-paths case insensitively, analogous to --optional (#16401)

# Description
Follow up to #16007

Also added some examples for existing flags which were previously
missing.

After the deprecation period of `--ignore-errors (-i)`, `-i` will be
used as the short form of this flag.

# User-Facing Changes
`get`, `select`, `reject` commands now have a `--ignore-case` flag,
which makes the commands interpret all cell-path arguments as completely
case insensitive.

# Tests + Formatting
+1

# After Submitting
Set a reminder for the `--ignore-errors` deprecation and using `-i` as
the short flag. Maybe we can make PRs in advance for future versions and
mark them with GitHub's milestones.
This commit is contained in:
Bahex
2025-08-13 23:45:33 +03:00
committed by GitHub
parent 3fe9c7c00c
commit ee7334a772
4 changed files with 115 additions and 3 deletions

View File

@@ -45,6 +45,11 @@ If multiple cell paths are given, this will produce a list of values."#
"make all cell path members optional (returns `null` for missing values)",
Some('o'),
)
.switch(
"ignore-case",
"make all cell path members case insensitive",
None,
)
.switch(
"ignore-errors",
"ignore missing data (make all cell path members optional) (deprecated)",
@@ -74,6 +79,30 @@ If multiple cell paths are given, this will produce a list of values."#
Span::test_data(),
)),
},
Example {
description: "Get a column from a table where some rows don't have that column, using optional cell-path syntax",
example: "[{A: A0, B: B0}, {B: B1}, {A: A2, B: B2}] | get A?",
result: Some(Value::list(
vec![
Value::test_string("A0"),
Value::test_nothing(),
Value::test_string("A2"),
],
Span::test_data(),
)),
},
Example {
description: "Get a column from a table where some rows don't have that column, using the optional flag",
example: "[{A: A0, B: B0}, {B: B1}, {A: A2, B: B2}] | get -o A",
result: Some(Value::list(
vec![
Value::test_string("A0"),
Value::test_nothing(),
Value::test_string("A2"),
],
Span::test_data(),
)),
},
Example {
description: "Get a cell from a table",
example: "[{A: A0}] | get 0.A",
@@ -90,8 +119,13 @@ If multiple cell paths are given, this will produce a list of values."#
result: None,
},
Example {
description: "Getting Path/PATH in a case insensitive way",
example: "$env | get paTH!",
description: "Getting environment variables in a case insensitive way, using case insensitive cell-path syntax",
example: "$env | get home! path!",
result: None,
},
Example {
description: "Getting environment variables in a case insensitive way, using the '--ignore-case' flag",
example: "$env | get --ignore-case home path",
result: None,
},
Example {
@@ -116,12 +150,14 @@ If multiple cell paths are given, this will produce a list of values."#
let rest: Vec<CellPath> = call.rest_const(working_set, 1)?;
let optional = call.has_flag_const(working_set, "optional")?
|| call.has_flag_const(working_set, "ignore-errors")?;
let ignore_case = call.has_flag_const(working_set, "ignore-case")?;
let metadata = input.metadata();
action(
input,
cell_path,
rest,
optional,
ignore_case,
working_set.permanent().signals().clone(),
call.head,
)
@@ -139,12 +175,14 @@ If multiple cell paths are given, this will produce a list of values."#
let rest: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let optional = call.has_flag(engine_state, stack, "optional")?
|| call.has_flag(engine_state, stack, "ignore-errors")?;
let ignore_case = call.has_flag(engine_state, stack, "ignore-case")?;
let metadata = input.metadata();
action(
input,
cell_path,
rest,
optional,
ignore_case,
engine_state.signals().clone(),
call.head,
)
@@ -176,6 +214,7 @@ fn action(
mut cell_path: CellPath,
mut rest: Vec<CellPath>,
optional: bool,
ignore_case: bool,
signals: Signals,
span: Span,
) -> Result<PipelineData, ShellError> {
@@ -186,6 +225,13 @@ fn action(
}
}
if ignore_case {
cell_path.make_insensitive();
for path in &mut rest {
path.make_insensitive();
}
}
if let PipelineData::Empty = input {
return Err(ShellError::PipelineEmpty { dst_span: span });
}

View File

@@ -18,6 +18,11 @@ impl Command for Reject {
(Type::list(Type::Any), Type::list(Type::Any)),
])
.switch("optional", "make all cell path members optional", Some('o'))
.switch(
"ignore-case",
"make all cell path members case insensitive",
None,
)
.switch(
"ignore-errors",
"ignore missing data (make all cell path members optional) (deprecated)",
@@ -93,12 +98,20 @@ impl Command for Reject {
let optional = call.has_flag(engine_state, stack, "optional")?
|| call.has_flag(engine_state, stack, "ignore-errors")?;
let ignore_case = call.has_flag(engine_state, stack, "ignore-case")?;
if optional {
for cell_path in &mut new_columns {
cell_path.make_optional();
}
}
if ignore_case {
for cell_path in &mut new_columns {
cell_path.make_insensitive();
}
}
reject(engine_state, span, input, new_columns)
}

View File

@@ -26,6 +26,11 @@ impl Command for Select {
"make all cell path members optional (returns `null` for missing values)",
Some('o'),
)
.switch(
"ignore-case",
"make all cell path members case insensitive",
None,
)
.switch(
"ignore-errors",
"ignore missing data (make all cell path members optional) (deprecated)",
@@ -110,6 +115,7 @@ produce a table, a list will produce a list, and a record will produce a record.
}
let optional = call.has_flag(engine_state, stack, "optional")?
|| call.has_flag(engine_state, stack, "ignore-errors")?;
let ignore_case = call.has_flag(engine_state, stack, "ignore-case")?;
let span = call.head;
if optional {
@@ -118,6 +124,12 @@ produce a table, a list will produce a list, and a record will produce a record.
}
}
if ignore_case {
for cell_path in &mut new_columns {
cell_path.make_insensitive();
}
}
select(engine_state, span, new_columns, input)
}
@@ -143,6 +155,18 @@ produce a table, a list will produce a list, and a record will produce a record.
"a" => Value::test_string("a")
})])),
},
Example {
description: "Select a column even if some rows are missing that column",
example: "[{a: a0 b: b0} {b: b1}] | select -o a",
result: Some(Value::test_list(vec![
Value::test_record(record! {
"a" => Value::test_string("a0")
}),
Value::test_record(record! {
"a" => Value::test_nothing()
}),
])),
},
Example {
description: "Select a field in a record",
example: "{a: a b: b} | select a",