use serde_json::Value;
use std::str::FromStr;
use tokenizer::s;
pub fn calc_from(array_len: usize, args: &Vec<String>) -> Result<usize, String> {
if args.len() < 1 { return Ok(0); }
let mut from: i64 = i64::from_str(args[0].as_str()).unwrap_or(0);
if from < 0 {
from = array_len as i64 + from
}
match from {
_ if from >= 0 => Ok(from as usize),
_ => Err(format!("Error with range: negative bound"))
}
}
pub fn calc_to(array_len: usize, args: &Vec<String>) -> Result<usize, String> {
if args.len() < 2 { return Ok(array_len); }
let mut to: i64 = i64::from_str(args[1].as_str()).unwrap_or(array_len as i64);
if to < 0 {
to = 0
}
match to {
_ if to >= 0 => Ok(to as usize),
_ => Err(format!("Error with range: negative bound"))
}
}
pub fn find_range(json: &Value, args: &Vec<String>) -> Result<Value,String> {
json.as_array()
.ok_or(s("Error with range"))
.and_then(|array| {
calc_from(array.len(), args)
.and_then(|from| {
calc_to(array.len(), args)
.map(|to| array[from..to].to_vec())
})
})
.map(|vec| Value::Array(vec))
}
pub fn search_key(json: &Value, key: &str, res: &Vec<Value>) -> Vec<Value> {
match json.clone() {
Value::Object(obj) => obj.iter().fold(vec![], |mut vect, (k, v)| {
if k == key {
vect.push(v.clone());
vect.append(&mut search_key(v, key, res));
} else {
vect.append(&mut search_key(v, key, res));
}
return vect;
}),
Value::Array(array) => array.iter().fold(vec![], |mut vect, value| {
vect.append(&mut search_key(value, key, res));
return vect;
}),
_ => res.clone()
}
}
pub fn find_key(json: &Value, key: &str) -> Value {
match json.clone() {
Value::Object(obj) => obj.get(key).map(|elem| elem.clone()).unwrap_or(Value::Array(vec![])),
Value::Array(array) => Value::Array(array.iter().map(|obj| {
obj.get(key)
.map(|elem| elem.clone())
.unwrap_or(Value::Null)
})
.filter(|value| !value.is_null())
.collect::<Vec<Value>>()),
_ => Value::Array(vec![])
}
}
pub fn find_indexes(json: &Value, args: &Vec<String>) -> Result<Value,String> {
args.iter().map(|arg| {
arg.parse()
.map_err(|_| s("Err parsing argument"))
.map(|idx| {
json.as_array()
.and_then(|array| {
let length = array.len();
let mut index: i64 = idx;
if index < 0 {
index = length as i64 + index
}
if index >= 0 {
array.get(index as usize)
} else {
None
}
}).map(|elem| elem.clone())
.unwrap_or(Value::Null)
})
}).collect::<Result<Vec<Value>, String>>()
.map(|vec| Value::Array(vec))
}
#[cfg(test)]
mod tests {
extern crate serde_json;
use serde_json::Value;
use tokenizer::s;
use super::*;
#[test]
fn it_request_json_with_key() {
let data: Value = serde_json::from_str(r#" { "authors": [{"name": "John Doe", "age": 43 }]} "#).unwrap();
let res: Value = find_key(&data, "authors");
let expected: Value = serde_json::from_str(r#"[{"name": "John Doe", "age": 43 }]"#).unwrap();
assert_eq!(res, expected);
}
#[test]
fn it_request_json_with_idx() {
let data: Value = serde_json::from_str(r#" [{"name": "John Doe", "age": 43 }, {"name": "Jane Doe", "age": 35 }] "#).unwrap();
let res: Value = find_indexes(&data, &vec![s("1")]).unwrap();
let expected: Value = serde_json::from_str(r#"[{"name": "Jane Doe", "age": 35 }]"#).unwrap();
assert_eq!(res, expected);
}
#[test]
fn it_request_json_with_range_wildcard() {
let data: Value = serde_json::from_str(r#" [{"name": "John Doe", "age": 43 }, {"name": "Jane Doe", "age": 35 }] "#).unwrap();
let res: Value = find_range(&data, &vec![]).unwrap();
let expected: Value = serde_json::from_str(r#"[{"name": "John Doe", "age": 43 }, {"name": "Jane Doe", "age": 35 }]"#).unwrap();
assert_eq!(res, expected);
}
#[test]
fn it_request_json_with_range_from_to() {
let data: Value = serde_json::from_str(r#" [{"name": "John Doe", "age": 43 }, {"name": "Jane Doe", "age": 35 }, {"name": "Jack Doe", "age": 3 }] "#).unwrap();
let res: Value = find_range(&data, &vec![s("1"), s("3")]).unwrap();
let expected: Value = serde_json::from_str(r#"[{"name": "Jane Doe", "age": 35 }, {"name": "Jack Doe", "age": 3 }]"#).unwrap();
assert_eq!(res, expected);
}
#[test]
fn it_search_key() {
let data = r#"
{
"firstName": "John",
"lastName" : "doe",
"age" : 26,
"address" : {
"streetAddress": "naist street",
"city" : "Nara",
"type" : "630-0192"
},
"phoneNumbers": [
{
"type" : {"name": "iPhone", "type":"test"},
"number": "0123-4567-8888"
},
{
"type" : "home",
"number": "0123-4567-8910"
}
]
}
"#;
let data: Value = serde_json::from_str(data).unwrap();
let expected = r#"
[
"630-0192",
{"name": "iPhone", "type":"test"},
"test",
"home"
]
"#;
let res = search_key(&data, "type", &vec![]);
let expected: Value = serde_json::from_str(expected).unwrap();
assert_eq!(Value::Array(res), expected);
}
}