1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
extern crate serde_json;

use std::io;
use serde_json::Value;

/// Trait used to remove Json Value's element
pub trait Remove {
    /// Method use to remove element in Json Values
    fn remove(&mut self, json_pointer: &str) -> io::Result<Option<Value>>;
}

impl Remove for serde_json::Value {
    /// # Examples: Remove an element in a table
    /// ```
    /// use serde_json::Value;
    /// use json_value_remove::Remove;
    ///
    /// let mut array1: Value = serde_json::from_str(r#"{"my_table":["a","b","c"]}"#).unwrap();
    /// assert_eq!(Some(Value::String("a".to_string())), array1.remove("/my_table/0").unwrap());
    /// assert_eq!(r#"{"my_table":["b","c"]}"#, array1.to_string());
    /// ```
    /// # Examples: Remove a field from an object
    /// ```
    /// use serde_json::Value;
    /// use json_value_remove::Remove;
    ///
    /// let mut object1: Value = serde_json::from_str(r#"{"field1.0":{"field1.1":"value1.1","field1.2":"value1.2"},"field2.0":"value2.0"}"#).unwrap();
    /// assert_eq!(Some(Value::String("value1.2".to_string())), object1.remove("/field1.0/field1.2").unwrap());
    /// assert_eq!(r#"{"field1.0":{"field1.1":"value1.1"},"field2.0":"value2.0"}"#,object1.to_string());
    /// ```
    fn remove(&mut self, json_pointer: &str) -> io::Result<Option<Value>> {
        let fields: Vec<&str> = json_pointer.split("/").skip(1).collect();

        remove(self, fields)
    }
}

fn remove(json_value: &mut Value, fields: Vec<&str>) -> io::Result<Option<Value>> {
    if fields.is_empty() {
        return Ok(None);
    }

    let mut fields = fields.clone();
    let field = fields.remove(0);

    if field.is_empty() {
        return Ok(None);
    }

    match fields.is_empty() {
        true => match json_value {
            Value::Array(vec) => {
                let index = match field.parse::<usize>() {
                    Ok(index) => index,
                    Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidInput, format!("{}. Can't find the field '{}' in {}.", e, field, json_value.to_string())))
                };
                let len = vec.len();
                if index >= len {
                    return Err(io::Error::new(io::ErrorKind::InvalidInput, format!("removal index (is {}) should be < len (is {}) from {}", index, len, json_value.to_string())))
                }
                Ok(Some(vec.remove(index)))
            },
            Value::Object(map) => Ok(map.remove(field)),
            _ => Ok(None)
        },
        false => match json_value.pointer_mut(format!("/{}", field).as_str()) {
            Some(json_targeted) => remove(json_targeted, fields),
            None => Ok(None)
        }
    }
}

#[cfg(test)]
mod serde_json_value_remove_test {
    use super::*;
    #[test]
    fn it_should_remove_element_in_array() {
        let mut array1: Value = serde_json::from_str(r#"{"my_table":["a","b","c"]}"#).unwrap();
        assert_eq!(Some(Value::String("a".to_string())), array1.remove("/my_table/0").unwrap());
        assert_eq!(r#"{"my_table":["b","c"]}"#, array1.to_string());
    }
    #[test]
    fn it_should_remove_element_in_object() {
        let mut object1: Value = serde_json::from_str(r#"{"field1.0":{"field1.1":"value1.1","field1.2":"value1.2"},"field2.0":"value2.0"}"#).unwrap();
        assert_eq!(Some(Value::String("value1.2".to_string())), object1.remove("/field1.0/field1.2").unwrap());
        assert_eq!(r#"{"field1.0":{"field1.1":"value1.1"},"field2.0":"value2.0"}"#,object1.to_string());
    }
    #[test]
    fn it_should_raise_exception_in_array_with_unavailable_index() {
        let mut array1: Value = serde_json::from_str(r#"{"my_table":["a","b"]}"#).unwrap();
        match array1.remove("/my_table/3") {
            Ok(_) => assert!(false, "Should raise an error because the element not exist"),
            Err(e) =>  assert_eq!("removal index (is 3) should be < len (is 2) from [\"a\",\"b\"]".to_string(), e.to_string())
        };
    }
    #[test]
    fn it_should_raise_exception_in_array_with_unavailable_field() {
        let mut array1: Value = serde_json::from_str(r#"{"my_table":["a","b"]}"#).unwrap();
        match array1.remove("/my_table/a") {
            Ok(_) => assert!(false, "Should raise an error because the element not exist"),
            Err(e) =>  assert_eq!("invalid digit found in string. Can't find the field 'a' in [\"a\",\"b\"].".to_string(), e.to_string())
        };
    }
    #[test]
    fn it_should_return_empty_if_field_not_exist() {
        let mut object1: Value = serde_json::from_str(r#"{"field1.0":{"field1.1":"value1.1","field1.2":"value1.2"}}"#).unwrap();
        assert_eq!(None, object1.remove("/field1.0/field1.3").unwrap());
    }
    #[test]
    fn it_should_return_empty_if_field_is_empty() {
        let mut object1: Value = serde_json::from_str(r#"{"field1.0":{"field1.1":"value1.1","field1.2":"value1.2"}}"#).unwrap();
        assert_eq!(None, object1.remove("/field1.0/").unwrap());
        assert_eq!(None, object1.remove("/field1.0/ ").unwrap());
        assert_eq!(None, object1.remove("/field1.0/ /field1.1").unwrap());
    }
}