faucet_stream/extract/
jsonpath.rs1use crate::error::FaucetError;
4use jsonpath_rust::JsonPath;
5use serde_json::Value;
6
7pub fn extract_records(body: &Value, path: Option<&str>) -> Result<Vec<Value>, FaucetError> {
9 match path {
10 Some(p) => {
11 let results = body
12 .query(p)
13 .map_err(|e| FaucetError::JsonPath(format!("invalid JSONPath '{p}': {e}")))?;
14 Ok(results.into_iter().cloned().collect())
15 }
16 None => match body {
17 Value::Array(arr) => Ok(arr.clone()),
18 other => Ok(vec![other.clone()]),
19 },
20 }
21}
22
23#[cfg(test)]
24mod tests {
25 use super::*;
26 use serde_json::json;
27
28 #[test]
29 fn test_extract_nested_records() {
30 let body = json!({
31 "data": [
32 {"id": 1, "name": "Alice"},
33 {"id": 2, "name": "Bob"},
34 ],
35 "meta": {"total": 2}
36 });
37 let records = extract_records(&body, Some("$.data[*]")).unwrap();
38 assert_eq!(records.len(), 2);
39 assert_eq!(records[0]["name"], "Alice");
40 }
41
42 #[test]
43 fn test_extract_no_path_array() {
44 let body = json!([{"id": 1}, {"id": 2}]);
45 let records = extract_records(&body, None).unwrap();
46 assert_eq!(records.len(), 2);
47 }
48
49 #[test]
50 fn test_extract_no_path_object() {
51 let body = json!({"id": 1, "name": "Alice"});
52 let records = extract_records(&body, None).unwrap();
53 assert_eq!(records.len(), 1);
54 assert_eq!(records[0]["name"], "Alice");
55 }
56
57 #[test]
58 fn test_extract_empty_result() {
59 let body = json!({"data": []});
60 let records = extract_records(&body, Some("$.data[*]")).unwrap();
61 assert!(records.is_empty());
62 }
63}