Skip to content

Commit 1afc7c1

Browse files
committed
feat: support optional json path as first argument on RadonOpCodes::StringParseJSONArray
1 parent f222ee5 commit 1afc7c1

File tree

2 files changed

+90
-10
lines changed

2 files changed

+90
-10
lines changed

rad/src/operators/string.rs

+89-9
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,87 @@ pub fn parse_json_map(input: &RadonString, args: &Option<Vec<Value>>) -> Result<
179179
},
180180
_ => Err(wrong_args())
181181
}
182+
}
183+
184+
pub fn parse_json_array(input: &RadonString, args: &Option<Vec<Value>>) -> Result<RadonArray, RadError> {
185+
let wrong_args = || RadError::WrongArguments {
186+
input_type: RadonString::radon_type_name(),
187+
operator: "ParseJsonArray".to_string(),
188+
args: args.to_owned().unwrap_or_default(),
189+
};
190+
191+
let json_input: JsonValue = serde_json::from_str(&input.value())
192+
.map_err(|err| RadError::JsonParse {
193+
description: err.to_string(),
194+
})?;
195+
196+
match args.to_owned().unwrap_or_default().get(0) {
197+
Some(Value::Array(values)) => {
198+
let mut items: Vec<RadonTypes> = vec![];
199+
for path in values {
200+
if let Value::Text(json_path) = path {
201+
let selector = Selector::new(json_path.as_str())
202+
.map_err(|err| RadError::JsonPathParse {
203+
description: err.to_string(),
204+
})?;
205+
let mut subitems: Vec<RadonTypes> = selector.find(&json_input)
206+
.map(|item| into_radon_types(item))
207+
.collect();
208+
if subitems.len() > 1 {
209+
items.insert(items.len(), RadonArray::from(subitems).into());
210+
} else {
211+
items.append(subitems.as_mut());
212+
}
213+
} else {
214+
return Err(wrong_args());
215+
}
216+
}
217+
Ok(RadonArray::from(items))
218+
}
219+
Some(Value::Text(json_path)) => {
220+
let selector = Selector::new(json_path.as_str())
221+
.map_err(|err| RadError::JsonPathParse {
222+
description: err.to_string(),
223+
})?;
224+
let items: Vec<RadonTypes> = selector.find(&json_input)
225+
.map(|item| into_radon_types(item))
226+
.collect();
227+
Ok(RadonArray::from(items))
228+
}
229+
None => {
230+
RadonTypes::try_from(json_input)?.try_into()
231+
}
232+
_ => Err(wrong_args())
233+
}
234+
}
182235

236+
fn into_radon_types(value: &serde_json::Value) -> RadonTypes {
237+
match value {
238+
serde_json::Value::Number(value) => {
239+
if value.is_f64() {
240+
RadonTypes::from(RadonFloat::from(value.as_f64().unwrap_or_default()))
241+
} else {
242+
RadonTypes::from(RadonInteger::from(value.as_i64().unwrap_or_default() as i128))
243+
}
244+
},
245+
serde_json::Value::Bool(value) => RadonTypes::from(RadonBoolean::from(*value)),
246+
serde_json::Value::String(value) => RadonTypes::from(RadonString::from(value.clone())),
247+
serde_json::Value::Object(entries) => {
248+
let mut object: BTreeMap<String, RadonTypes> = BTreeMap::new();
249+
for (key, value) in entries {
250+
object.insert(key.clone(), into_radon_types(value));
251+
}
252+
RadonTypes::from(RadonMap::from(object))
253+
}
254+
serde_json::Value::Array(values) => {
255+
let items: Vec<RadonTypes> = values
256+
.iter()
257+
.map(|item| into_radon_types(item))
258+
.collect();
259+
RadonTypes::from(RadonArray::from(items))
260+
}
261+
_ => RadonTypes::from(RadonError::new(RadError::JsonParse { description: value.to_string() }))
262+
}
183263
}
184264

185265
fn add_children(
@@ -477,7 +557,7 @@ mod tests {
477557
#[test]
478558
fn test_parse_json_map() {
479559
let json_map = RadonString::from(r#"{ "Hello": "world" }"#);
480-
let output = parse_json_map(&json_map).unwrap();
560+
let output = parse_json_map(&json_map, &None).unwrap();
481561

482562
let key = "Hello";
483563
let value = RadonTypes::String(RadonString::from("world"));
@@ -637,7 +717,7 @@ mod tests {
637717
fn test_parse_json_map_with_null_entries() {
638718
// When parsing a JSON map, any keys with value `null` are ignored
639719
let json_map = RadonString::from(r#"{ "Hello": "world", "Bye": null }"#);
640-
let output = parse_json_map(&json_map).unwrap();
720+
let output = parse_json_map(&json_map, &None).unwrap();
641721

642722
let key = "Hello";
643723
let value = RadonTypes::String(RadonString::from("world"));
@@ -651,15 +731,15 @@ mod tests {
651731
#[test]
652732
fn test_parse_json_map_fail() {
653733
let invalid_json = RadonString::from(r#"{ "Hello": }"#);
654-
let output = parse_json_map(&invalid_json).unwrap_err();
734+
let output = parse_json_map(&invalid_json, &None).unwrap_err();
655735

656736
let expected_err = RadError::JsonParse {
657737
description: "expected value at line 1 column 13".to_string(),
658738
};
659739
assert_eq!(output, expected_err);
660740

661741
let json_array = RadonString::from(r#"[1,2,3]"#);
662-
let output = parse_json_map(&json_array).unwrap_err();
742+
let output = parse_json_map(&json_array, &None).unwrap_err();
663743
let expected_err = RadError::Decode {
664744
from: "cbor::value::Value",
665745
to: RadonMap::radon_type_name(),
@@ -670,7 +750,7 @@ mod tests {
670750
#[test]
671751
fn test_parse_json_array() {
672752
let json_array = RadonString::from(r#"[1,2,3]"#);
673-
let output = parse_json_array(&json_array).unwrap();
753+
let output = parse_json_array(&json_array, &None).unwrap();
674754

675755
let expected_output = RadonArray::from(vec![
676756
RadonTypes::Integer(RadonInteger::from(1)),
@@ -685,7 +765,7 @@ mod tests {
685765
fn test_parse_json_array_with_null_entries() {
686766
// When parsing a JSON array, any elements with value `null` are ignored
687767
let json_array = RadonString::from(r#"[null, 1, null, null, 2, 3, null]"#);
688-
let output = parse_json_array(&json_array).unwrap();
768+
let output = parse_json_array(&json_array, &None).unwrap();
689769

690770
let expected_output = RadonArray::from(vec![
691771
RadonTypes::Integer(RadonInteger::from(1)),
@@ -699,15 +779,15 @@ mod tests {
699779
#[test]
700780
fn test_parse_json_array_fail() {
701781
let invalid_json = RadonString::from(r#"{ "Hello": }"#);
702-
let output = parse_json_array(&invalid_json).unwrap_err();
782+
let output = parse_json_array(&invalid_json, &None).unwrap_err();
703783

704784
let expected_err = RadError::JsonParse {
705785
description: "expected value at line 1 column 13".to_string(),
706786
};
707787
assert_eq!(output, expected_err);
708788

709789
let json_map = RadonString::from(r#"{ "Hello": "world" }"#);
710-
let output = parse_json_array(&json_map).unwrap_err();
790+
let output = parse_json_array(&json_map, &None).unwrap_err();
711791
let expected_err = RadError::Decode {
712792
from: "cbor::value::Value",
713793
to: RadonArray::radon_type_name(),
@@ -1235,7 +1315,7 @@ mod tests {
12351315
let args = vec![Value::Map(map)];
12361316

12371317
let result = string_match(&input_key, &args);
1238-
assert_eq!(result.unwrap_err().to_string(), "Wrong `RadonString::String match()` arguments: `[Map({Text(\"key1\"): Float(1.0), Text(\"key2\"): Float(2.0)})]`");
1318+
assert_eq!(result.unwrap_err().to_string(), "Wrong `RadonString::StringMatch()` arguments: `[Map({Text(\"key1\"): Float(1.0), Text(\"key2\"): Float(2.0)})]`");
12391319
}
12401320

12411321
#[test]

rad/src/types/string.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl Operable for RadonString {
131131
(RadonOpCodes::StringMatch, Some(args)) => {
132132
string_operators::string_match(self, args.as_slice()).map(RadonTypes::from)
133133
}
134-
(RadonOpCodes::StringParseJSONArray, None) => string_operators::parse_json_array(self)
134+
(RadonOpCodes::StringParseJSONArray, args) => string_operators::parse_json_array(self, &args)
135135
.map(RadonTypes::from)
136136
.map_err(Into::into),
137137
(RadonOpCodes::StringParseJSONMap, args) => string_operators::parse_json_map(self, &args)

0 commit comments

Comments
 (0)