diff --git a/rad/src/operators/string.rs b/rad/src/operators/string.rs index c766eb88d..58d1faae8 100644 --- a/rad/src/operators/string.rs +++ b/rad/src/operators/string.rs @@ -179,7 +179,87 @@ pub fn parse_json_map(input: &RadonString, args: &Option>) -> Result< }, _ => Err(wrong_args()) } +} + +pub fn parse_json_array(input: &RadonString, args: &Option>) -> Result { + let wrong_args = || RadError::WrongArguments { + input_type: RadonString::radon_type_name(), + operator: "ParseJsonArray".to_string(), + args: args.to_owned().unwrap_or_default(), + }; + + let json_input: JsonValue = serde_json::from_str(&input.value()) + .map_err(|err| RadError::JsonParse { + description: err.to_string(), + })?; + + match args.to_owned().unwrap_or_default().get(0) { + Some(Value::Array(values)) => { + let mut items: Vec = vec![]; + for path in values { + if let Value::Text(json_path) = path { + let selector = Selector::new(json_path.as_str()) + .map_err(|err| RadError::JsonPathParse { + description: err.to_string(), + })?; + let mut subitems: Vec = selector.find(&json_input) + .map(|item| into_radon_types(item)) + .collect(); + if subitems.len() > 1 { + items.insert(items.len(), RadonArray::from(subitems).into()); + } else { + items.append(subitems.as_mut()); + } + } else { + return Err(wrong_args()); + } + } + Ok(RadonArray::from(items)) + } + Some(Value::Text(json_path)) => { + let selector = Selector::new(json_path.as_str()) + .map_err(|err| RadError::JsonPathParse { + description: err.to_string(), + })?; + let items: Vec = selector.find(&json_input) + .map(|item| into_radon_types(item)) + .collect(); + Ok(RadonArray::from(items)) + } + None => { + RadonTypes::try_from(json_input)?.try_into() + } + _ => Err(wrong_args()) + } +} +fn into_radon_types(value: &serde_json::Value) -> RadonTypes { + match value { + serde_json::Value::Number(value) => { + if value.is_f64() { + RadonTypes::from(RadonFloat::from(value.as_f64().unwrap_or_default())) + } else { + RadonTypes::from(RadonInteger::from(value.as_i64().unwrap_or_default() as i128)) + } + }, + serde_json::Value::Bool(value) => RadonTypes::from(RadonBoolean::from(*value)), + serde_json::Value::String(value) => RadonTypes::from(RadonString::from(value.clone())), + serde_json::Value::Object(entries) => { + let mut object: BTreeMap = BTreeMap::new(); + for (key, value) in entries { + object.insert(key.clone(), into_radon_types(value)); + } + RadonTypes::from(RadonMap::from(object)) + } + serde_json::Value::Array(values) => { + let items: Vec = values + .iter() + .map(|item| into_radon_types(item)) + .collect(); + RadonTypes::from(RadonArray::from(items)) + } + _ => RadonTypes::from(RadonError::new(RadError::JsonParse { description: value.to_string() })) + } } fn add_children( @@ -477,7 +557,7 @@ mod tests { #[test] fn test_parse_json_map() { let json_map = RadonString::from(r#"{ "Hello": "world" }"#); - let output = parse_json_map(&json_map).unwrap(); + let output = parse_json_map(&json_map, &None).unwrap(); let key = "Hello"; let value = RadonTypes::String(RadonString::from("world")); @@ -637,7 +717,7 @@ mod tests { fn test_parse_json_map_with_null_entries() { // When parsing a JSON map, any keys with value `null` are ignored let json_map = RadonString::from(r#"{ "Hello": "world", "Bye": null }"#); - let output = parse_json_map(&json_map).unwrap(); + let output = parse_json_map(&json_map, &None).unwrap(); let key = "Hello"; let value = RadonTypes::String(RadonString::from("world")); @@ -651,7 +731,7 @@ mod tests { #[test] fn test_parse_json_map_fail() { let invalid_json = RadonString::from(r#"{ "Hello": }"#); - let output = parse_json_map(&invalid_json).unwrap_err(); + let output = parse_json_map(&invalid_json, &None).unwrap_err(); let expected_err = RadError::JsonParse { description: "expected value at line 1 column 13".to_string(), @@ -659,7 +739,7 @@ mod tests { assert_eq!(output, expected_err); let json_array = RadonString::from(r#"[1,2,3]"#); - let output = parse_json_map(&json_array).unwrap_err(); + let output = parse_json_map(&json_array, &None).unwrap_err(); let expected_err = RadError::Decode { from: "cbor::value::Value", to: RadonMap::radon_type_name(), @@ -670,7 +750,7 @@ mod tests { #[test] fn test_parse_json_array() { let json_array = RadonString::from(r#"[1,2,3]"#); - let output = parse_json_array(&json_array).unwrap(); + let output = parse_json_array(&json_array, &None).unwrap(); let expected_output = RadonArray::from(vec![ RadonTypes::Integer(RadonInteger::from(1)), @@ -685,7 +765,7 @@ mod tests { fn test_parse_json_array_with_null_entries() { // When parsing a JSON array, any elements with value `null` are ignored let json_array = RadonString::from(r#"[null, 1, null, null, 2, 3, null]"#); - let output = parse_json_array(&json_array).unwrap(); + let output = parse_json_array(&json_array, &None).unwrap(); let expected_output = RadonArray::from(vec![ RadonTypes::Integer(RadonInteger::from(1)), @@ -699,7 +779,7 @@ mod tests { #[test] fn test_parse_json_array_fail() { let invalid_json = RadonString::from(r#"{ "Hello": }"#); - let output = parse_json_array(&invalid_json).unwrap_err(); + let output = parse_json_array(&invalid_json, &None).unwrap_err(); let expected_err = RadError::JsonParse { description: "expected value at line 1 column 13".to_string(), @@ -707,7 +787,7 @@ mod tests { assert_eq!(output, expected_err); let json_map = RadonString::from(r#"{ "Hello": "world" }"#); - let output = parse_json_array(&json_map).unwrap_err(); + let output = parse_json_array(&json_map, &None).unwrap_err(); let expected_err = RadError::Decode { from: "cbor::value::Value", to: RadonArray::radon_type_name(), @@ -1235,7 +1315,7 @@ mod tests { let args = vec![Value::Map(map)]; let result = string_match(&input_key, &args); - assert_eq!(result.unwrap_err().to_string(), "Wrong `RadonString::String match()` arguments: `[Map({Text(\"key1\"): Float(1.0), Text(\"key2\"): Float(2.0)})]`"); + assert_eq!(result.unwrap_err().to_string(), "Wrong `RadonString::StringMatch()` arguments: `[Map({Text(\"key1\"): Float(1.0), Text(\"key2\"): Float(2.0)})]`"); } #[test] diff --git a/rad/src/types/string.rs b/rad/src/types/string.rs index 5c3bed08f..ececf939d 100644 --- a/rad/src/types/string.rs +++ b/rad/src/types/string.rs @@ -131,7 +131,7 @@ impl Operable for RadonString { (RadonOpCodes::StringMatch, Some(args)) => { string_operators::string_match(self, args.as_slice()).map(RadonTypes::from) } - (RadonOpCodes::StringParseJSONArray, None) => string_operators::parse_json_array(self) + (RadonOpCodes::StringParseJSONArray, args) => string_operators::parse_json_array(self, &args) .map(RadonTypes::from) .map_err(Into::into), (RadonOpCodes::StringParseJSONMap, args) => string_operators::parse_json_map(self, &args)