mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 08:45:45 +02:00
Add insert and update back (#4864)
This commit is contained in:
@ -226,7 +226,7 @@ impl PipelineData {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_cell_path(
|
||||
pub fn upsert_cell_path(
|
||||
&mut self,
|
||||
cell_path: &[PathMember],
|
||||
callback: Box<dyn FnOnce(&Value) -> Value>,
|
||||
@ -238,8 +238,8 @@ impl PipelineData {
|
||||
vals: stream.collect(),
|
||||
span: head,
|
||||
}
|
||||
.update_cell_path(cell_path, callback),
|
||||
PipelineData::Value(v, ..) => v.update_cell_path(cell_path, callback),
|
||||
.upsert_cell_path(cell_path, callback),
|
||||
PipelineData::Value(v, ..) => v.upsert_cell_path(cell_path, callback),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
@ -150,6 +150,13 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE
|
||||
#[label = "value originates here"] Span,
|
||||
),
|
||||
|
||||
#[error("Column already exists")]
|
||||
#[diagnostic(code(nu::shell::column_already_exists), url(docsrs))]
|
||||
ColumnAlreadyExists(
|
||||
#[label = "column already exists"] Span,
|
||||
#[label = "value originates here"] Span,
|
||||
),
|
||||
|
||||
#[error("Not a list value")]
|
||||
#[diagnostic(code(nu::shell::not_a_list), url(docsrs))]
|
||||
NotAList(
|
||||
|
@ -682,7 +682,7 @@ impl Value {
|
||||
}
|
||||
|
||||
/// Follow a given column path into the value: for example accessing select elements in a stream or list
|
||||
pub fn update_cell_path(
|
||||
pub fn upsert_cell_path(
|
||||
&mut self,
|
||||
cell_path: &[PathMember],
|
||||
callback: Box<dyn FnOnce(&Value) -> Value>,
|
||||
@ -693,11 +693,11 @@ impl Value {
|
||||
|
||||
match new_val {
|
||||
Value::Error { error } => Err(error),
|
||||
new_val => self.replace_data_at_cell_path(cell_path, new_val),
|
||||
new_val => self.upsert_data_at_cell_path(cell_path, new_val),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_data_at_cell_path(
|
||||
pub fn upsert_data_at_cell_path(
|
||||
&mut self,
|
||||
cell_path: &[PathMember],
|
||||
new_val: Value,
|
||||
@ -716,7 +716,7 @@ impl Value {
|
||||
for col in cols.iter().zip(vals.iter_mut()) {
|
||||
if col.0 == col_name {
|
||||
found = true;
|
||||
col.1.replace_data_at_cell_path(
|
||||
col.1.upsert_data_at_cell_path(
|
||||
&cell_path[1..],
|
||||
new_val.clone(),
|
||||
)?
|
||||
@ -733,7 +733,7 @@ impl Value {
|
||||
vals: vec![],
|
||||
span: new_val.span()?,
|
||||
};
|
||||
new_col.replace_data_at_cell_path(
|
||||
new_col.upsert_data_at_cell_path(
|
||||
&cell_path[1..],
|
||||
new_val,
|
||||
)?;
|
||||
@ -754,7 +754,7 @@ impl Value {
|
||||
found = true;
|
||||
|
||||
col.1
|
||||
.replace_data_at_cell_path(&cell_path[1..], new_val.clone())?
|
||||
.upsert_data_at_cell_path(&cell_path[1..], new_val.clone())?
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
@ -767,7 +767,7 @@ impl Value {
|
||||
vals: vec![],
|
||||
span: new_val.span()?,
|
||||
};
|
||||
new_col.replace_data_at_cell_path(&cell_path[1..], new_val)?;
|
||||
new_col.upsert_data_at_cell_path(&cell_path[1..], new_val)?;
|
||||
vals.push(new_col);
|
||||
}
|
||||
}
|
||||
@ -777,7 +777,190 @@ impl Value {
|
||||
PathMember::Int { val: row_num, span } => match self {
|
||||
Value::List { vals, .. } => {
|
||||
if let Some(v) = vals.get_mut(*row_num) {
|
||||
v.replace_data_at_cell_path(&cell_path[1..], new_val)?
|
||||
v.upsert_data_at_cell_path(&cell_path[1..], new_val)?
|
||||
} else {
|
||||
return Err(ShellError::AccessBeyondEnd(vals.len(), *span));
|
||||
}
|
||||
}
|
||||
v => return Err(ShellError::NotAList(*span, v.span()?)),
|
||||
},
|
||||
},
|
||||
None => {
|
||||
*self = new_val;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Follow a given column path into the value: for example accessing select elements in a stream or list
|
||||
pub fn update_cell_path(
|
||||
&mut self,
|
||||
cell_path: &[PathMember],
|
||||
callback: Box<dyn FnOnce(&Value) -> Value>,
|
||||
) -> Result<(), ShellError> {
|
||||
let orig = self.clone();
|
||||
|
||||
let new_val = callback(&orig.follow_cell_path(cell_path)?);
|
||||
|
||||
match new_val {
|
||||
Value::Error { error } => Err(error),
|
||||
new_val => self.update_data_at_cell_path(cell_path, new_val),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_data_at_cell_path(
|
||||
&mut self,
|
||||
cell_path: &[PathMember],
|
||||
new_val: Value,
|
||||
) -> Result<(), ShellError> {
|
||||
match cell_path.first() {
|
||||
Some(path_member) => match path_member {
|
||||
PathMember::String {
|
||||
val: col_name,
|
||||
span,
|
||||
} => match self {
|
||||
Value::List { vals, .. } => {
|
||||
for val in vals.iter_mut() {
|
||||
match val {
|
||||
Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: v_span,
|
||||
} => {
|
||||
let mut found = false;
|
||||
for col in cols.iter().zip(vals.iter_mut()) {
|
||||
if col.0 == col_name {
|
||||
found = true;
|
||||
col.1.update_data_at_cell_path(
|
||||
&cell_path[1..],
|
||||
new_val.clone(),
|
||||
)?
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return Err(ShellError::CantFindColumn(*span, *v_span));
|
||||
}
|
||||
}
|
||||
v => return Err(ShellError::CantFindColumn(*span, v.span()?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: v_span,
|
||||
} => {
|
||||
let mut found = false;
|
||||
|
||||
for col in cols.iter().zip(vals.iter_mut()) {
|
||||
if col.0 == col_name {
|
||||
found = true;
|
||||
|
||||
col.1
|
||||
.update_data_at_cell_path(&cell_path[1..], new_val.clone())?
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return Err(ShellError::CantFindColumn(*span, *v_span));
|
||||
}
|
||||
}
|
||||
v => return Err(ShellError::CantFindColumn(*span, v.span()?)),
|
||||
},
|
||||
PathMember::Int { val: row_num, span } => match self {
|
||||
Value::List { vals, .. } => {
|
||||
if let Some(v) = vals.get_mut(*row_num) {
|
||||
v.update_data_at_cell_path(&cell_path[1..], new_val)?
|
||||
} else {
|
||||
return Err(ShellError::AccessBeyondEnd(vals.len(), *span));
|
||||
}
|
||||
}
|
||||
v => return Err(ShellError::NotAList(*span, v.span()?)),
|
||||
},
|
||||
},
|
||||
None => {
|
||||
*self = new_val;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_data_at_cell_path(
|
||||
&mut self,
|
||||
cell_path: &[PathMember],
|
||||
new_val: Value,
|
||||
) -> Result<(), ShellError> {
|
||||
match cell_path.first() {
|
||||
Some(path_member) => match path_member {
|
||||
PathMember::String {
|
||||
val: col_name,
|
||||
span,
|
||||
} => match self {
|
||||
Value::List { vals, .. } => {
|
||||
for val in vals.iter_mut() {
|
||||
match val {
|
||||
Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: v_span,
|
||||
} => {
|
||||
for col in cols.iter().zip(vals.iter_mut()) {
|
||||
if col.0 == col_name {
|
||||
if cell_path.len() == 1 {
|
||||
return Err(ShellError::ColumnAlreadyExists(
|
||||
*span, *v_span,
|
||||
));
|
||||
} else {
|
||||
return col.1.insert_data_at_cell_path(
|
||||
&cell_path[1..],
|
||||
new_val,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cols.push(col_name.clone());
|
||||
vals.push(new_val.clone());
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
"table or record".into(),
|
||||
*span,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: v_span,
|
||||
} => {
|
||||
for col in cols.iter().zip(vals.iter_mut()) {
|
||||
if col.0 == col_name {
|
||||
if cell_path.len() == 1 {
|
||||
return Err(ShellError::ColumnAlreadyExists(*span, *v_span));
|
||||
} else {
|
||||
return col
|
||||
.1
|
||||
.insert_data_at_cell_path(&cell_path[1..], new_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cols.push(col_name.clone());
|
||||
vals.push(new_val);
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
"table or record".into(),
|
||||
*span,
|
||||
))
|
||||
}
|
||||
},
|
||||
PathMember::Int { val: row_num, span } => match self {
|
||||
Value::List { vals, .. } => {
|
||||
if let Some(v) = vals.get_mut(*row_num) {
|
||||
v.insert_data_at_cell_path(&cell_path[1..], new_val)?
|
||||
} else {
|
||||
return Err(ShellError::AccessBeyondEnd(vals.len(), *span));
|
||||
}
|
||||
|
Reference in New Issue
Block a user