mirror of
https://github.com/nushell/nushell.git
synced 2025-05-29 14:21:45 +02:00
feat(cell-path): opt-in case insensitivity for cell-path members
- Add `CellPath::String::insensitive: bool`, represented with an exclamation mark in `Display` - Update `into cell-path` and `split cell-path` to take case insensitivity into account while constructing and splitting cell-paths
This commit is contained in:
parent
39b95fc59e
commit
0294419c76
@ -17,7 +17,12 @@ impl Command for IntoCellPath {
|
||||
(Type::List(Box::new(Type::Any)), Type::CellPath),
|
||||
(
|
||||
Type::List(Box::new(Type::Record(
|
||||
[("value".into(), Type::Any), ("optional".into(), Type::Bool)].into(),
|
||||
[
|
||||
("value".into(), Type::Any),
|
||||
("optional".into(), Type::Bool),
|
||||
("insensitive".into(), Type::Bool),
|
||||
]
|
||||
.into(),
|
||||
))),
|
||||
Type::CellPath,
|
||||
),
|
||||
@ -69,8 +74,8 @@ impl Command for IntoCellPath {
|
||||
example: "'some.path' | split row '.' | into cell-path",
|
||||
result: Some(Value::test_cell_path(CellPath {
|
||||
members: vec![
|
||||
PathMember::test_string("some".into(), false),
|
||||
PathMember::test_string("path".into(), false),
|
||||
PathMember::test_string("some".into(), false, false),
|
||||
PathMember::test_string("path".into(), false, false),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -80,9 +85,9 @@ impl Command for IntoCellPath {
|
||||
result: Some(Value::test_cell_path(CellPath {
|
||||
members: vec![
|
||||
PathMember::test_int(5, false),
|
||||
PathMember::test_string("c".into(), false),
|
||||
PathMember::test_string("c".into(), false, false),
|
||||
PathMember::test_int(7, false),
|
||||
PathMember::test_string("h".into(), false),
|
||||
PathMember::test_string("h".into(), false, false),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -92,7 +97,7 @@ impl Command for IntoCellPath {
|
||||
result: Some(Value::test_cell_path(CellPath {
|
||||
members: vec![
|
||||
PathMember::test_int(5, true),
|
||||
PathMember::test_string("c".into(), false),
|
||||
PathMember::test_string("c".into(), false, false),
|
||||
],
|
||||
})),
|
||||
},
|
||||
@ -175,6 +180,12 @@ fn record_to_path_member(
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(insensitive) = record.get("insensitive") {
|
||||
if insensitive.as_bool()? {
|
||||
member.make_insensitive();
|
||||
}
|
||||
};
|
||||
|
||||
Ok(member)
|
||||
}
|
||||
|
||||
@ -196,7 +207,7 @@ fn value_to_path_member(val: &Value, span: Span) -> Result<PathMember, ShellErro
|
||||
let val_span = val.span();
|
||||
let member = match val {
|
||||
Value::Int { val, .. } => int_to_path_member(*val, val_span)?,
|
||||
Value::String { val, .. } => PathMember::string(val.into(), false, val_span),
|
||||
Value::String { val, .. } => PathMember::string(val.into(), false, false, val_span),
|
||||
Value::Record { val, .. } => record_to_path_member(val, val_span, span)?,
|
||||
other => {
|
||||
return Err(ShellError::CantConvert {
|
||||
|
@ -16,7 +16,12 @@ impl Command for SplitCellPath {
|
||||
(
|
||||
Type::CellPath,
|
||||
Type::List(Box::new(Type::Record(
|
||||
[("value".into(), Type::Any), ("optional".into(), Type::Bool)].into(),
|
||||
[
|
||||
("value".into(), Type::Any),
|
||||
("optional".into(), Type::Bool),
|
||||
("insensitive".into(), Type::Bool),
|
||||
]
|
||||
.into(),
|
||||
))),
|
||||
),
|
||||
])
|
||||
@ -114,19 +119,29 @@ fn split_cell_path(val: CellPath, span: Span) -> Result<Value, ShellError> {
|
||||
struct PathMemberRecord {
|
||||
value: Value,
|
||||
optional: bool,
|
||||
insensitive: bool,
|
||||
}
|
||||
|
||||
impl PathMemberRecord {
|
||||
fn from_path_member(pm: PathMember) -> Self {
|
||||
let (optional, internal_span) = match pm {
|
||||
PathMember::String { optional, span, .. }
|
||||
| PathMember::Int { optional, span, .. } => (optional, span),
|
||||
let (optional, insensitive, internal_span) = match pm {
|
||||
PathMember::String {
|
||||
optional,
|
||||
insensitive,
|
||||
span,
|
||||
..
|
||||
} => (optional, insensitive, span),
|
||||
PathMember::Int { optional, span, .. } => (optional, false, span),
|
||||
};
|
||||
let value = match pm {
|
||||
PathMember::String { val, .. } => Value::string(val, internal_span),
|
||||
PathMember::Int { val, .. } => Value::int(val as i64, internal_span),
|
||||
};
|
||||
Self { value, optional }
|
||||
Self {
|
||||
value,
|
||||
optional,
|
||||
insensitive,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ pub fn empty(
|
||||
if !columns.is_empty() {
|
||||
for val in input {
|
||||
for column in &columns {
|
||||
if !val.follow_cell_path(&column.members, false)?.is_nothing() {
|
||||
if !val.follow_cell_path(&column.members)?.is_nothing() {
|
||||
return Ok(Value::bool(negate, head).into_pipeline_data());
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ pub enum PathMember {
|
||||
/// If marked as optional don't throw an error if not found but perform default handling
|
||||
/// (e.g. return `Value::Nothing`)
|
||||
optional: bool,
|
||||
/// If marked as insensitive, column lookup happens case insensitively
|
||||
insensitive: bool,
|
||||
},
|
||||
/// Accessing a member by index (i.e. row of a table or item in a list)
|
||||
Int {
|
||||
@ -34,11 +36,12 @@ impl PathMember {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string(val: String, optional: bool, span: Span) -> Self {
|
||||
pub fn string(val: String, optional: bool, insensitive: bool, span: Span) -> Self {
|
||||
PathMember::String {
|
||||
val,
|
||||
span,
|
||||
optional,
|
||||
insensitive,
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,10 +53,11 @@ impl PathMember {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_string(val: String, optional: bool) -> Self {
|
||||
pub fn test_string(val: String, optional: bool, insensitive: bool) -> Self {
|
||||
PathMember::String {
|
||||
val,
|
||||
optional,
|
||||
insensitive,
|
||||
span: Span::test_data(),
|
||||
}
|
||||
}
|
||||
@ -69,6 +73,16 @@ impl PathMember {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_insensitive(&mut self) {
|
||||
match self {
|
||||
PathMember::String {
|
||||
ref mut insensitive,
|
||||
..
|
||||
} => *insensitive = true,
|
||||
PathMember::Int { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
PathMember::String { span, .. } => *span,
|
||||
@ -182,6 +196,12 @@ impl CellPath {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_insensitive(&mut self) {
|
||||
for member in &mut self.members {
|
||||
member.make_insensitive();
|
||||
}
|
||||
}
|
||||
|
||||
// Formats the cell-path as a column name, i.e. without quoting and optional markers ('?').
|
||||
pub fn to_column_name(&self) -> String {
|
||||
let mut s = String::new();
|
||||
@ -213,14 +233,20 @@ impl Display for CellPath {
|
||||
let question_mark = if *optional { "?" } else { "" };
|
||||
write!(f, ".{val}{question_mark}")?
|
||||
}
|
||||
PathMember::String { val, optional, .. } => {
|
||||
PathMember::String {
|
||||
val,
|
||||
optional,
|
||||
insensitive,
|
||||
..
|
||||
} => {
|
||||
let question_mark = if *optional { "?" } else { "" };
|
||||
let exclamation_mark = if *insensitive { "!" } else { "" };
|
||||
let val = if needs_quoting(val) {
|
||||
&escape_quote_string(val)
|
||||
} else {
|
||||
val
|
||||
};
|
||||
write!(f, ".{val}{question_mark}")?
|
||||
write!(f, ".{val}{exclamation_mark}{question_mark}")?
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,7 +269,11 @@ mod test {
|
||||
fn path_member_partial_ord() {
|
||||
assert_eq!(
|
||||
Some(Greater),
|
||||
PathMember::test_int(5, true).partial_cmp(&PathMember::test_string("e".into(), true))
|
||||
PathMember::test_int(5, true).partial_cmp(&PathMember::test_string(
|
||||
"e".into(),
|
||||
true,
|
||||
false
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@ -258,14 +288,20 @@ mod test {
|
||||
|
||||
assert_eq!(
|
||||
Some(Greater),
|
||||
PathMember::test_string("e".into(), true)
|
||||
.partial_cmp(&PathMember::test_string("e".into(), false))
|
||||
PathMember::test_string("e".into(), true, false).partial_cmp(&PathMember::test_string(
|
||||
"e".into(),
|
||||
false,
|
||||
false
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Some(Greater),
|
||||
PathMember::test_string("f".into(), true)
|
||||
.partial_cmp(&PathMember::test_string("e".into(), true))
|
||||
PathMember::test_string("f".into(), true, false).partial_cmp(&PathMember::test_string(
|
||||
"e".into(),
|
||||
true,
|
||||
false
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user