250 lines
7.8 KiB
Rust
250 lines
7.8 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use axum::extract::{Request, FromRequest};
|
|
use axum::response::{Response, IntoResponse};
|
|
use axum::http::StatusCode;
|
|
use axum::Form;
|
|
|
|
impl<S> FromRequest<S> for Node
|
|
where
|
|
S: Send + Sync,
|
|
{
|
|
type Rejection = Response;
|
|
|
|
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
|
|
let Form(data): Form<Vec<(String, String)>> = Form::from_request(req, state)
|
|
.await
|
|
.map_err(IntoResponse::into_response)?;
|
|
|
|
let node = Node::from_key_value(data)
|
|
.map_err(|_| StatusCode::UNPROCESSABLE_ENTITY.into_response())?;
|
|
|
|
Ok(node)
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug)]
|
|
pub enum FormError {
|
|
MismatchedType
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
pub enum Node {
|
|
Value(String),
|
|
Map(HashMap<String, Node>),
|
|
Sequence(Sequence)
|
|
}
|
|
|
|
impl Node {
|
|
pub fn from_key_value(data: Vec<(String, String)>) -> Result<Node, FormError> {
|
|
let mut form = Node::Map(HashMap::new());
|
|
for (key, value) in data {
|
|
|
|
// Consider empty value not filled and remove them
|
|
if value.is_empty() {
|
|
continue;
|
|
}
|
|
|
|
let path = Self::parse_key(&key);
|
|
let mut parent_node = &mut form;
|
|
|
|
for window in path.windows(2) {
|
|
let parent_key = &window[0];
|
|
let child_key = &window[1];
|
|
|
|
parent_node = match (parent_node, parent_key) {
|
|
(&mut Node::Map(ref mut map), Key::Attribute(key)) => {
|
|
map.entry(key.clone()).or_insert_with(|| child_key.new_node())
|
|
},
|
|
(&mut Node::Sequence(Sequence::ImplicitIndex(ref mut list)), Key::ImplicitIndex) => {
|
|
list.push(child_key.new_node());
|
|
list.last_mut().unwrap()
|
|
},
|
|
(&mut Node::Sequence(Sequence::ExplicitIndex(ref mut list)), Key::ExplicitIndex(index)) => {
|
|
list.entry(*index).or_insert_with(|| child_key.new_node())
|
|
},
|
|
_ => {
|
|
return Err(FormError::MismatchedType);
|
|
}
|
|
};
|
|
}
|
|
|
|
let last_key = path.last().unwrap();
|
|
match (parent_node, last_key) {
|
|
(&mut Node::Map(ref mut map), Key::Attribute(key)) => {
|
|
map.insert(key.clone(), Node::Value(value));
|
|
},
|
|
(&mut Node::Sequence(Sequence::ImplicitIndex(ref mut list)), Key::ImplicitIndex) => {
|
|
list.push(Node::Value(value))
|
|
},
|
|
(&mut Node::Sequence(Sequence::ExplicitIndex(ref mut list)), Key::ExplicitIndex(index)) => {
|
|
list.insert(*index, Node::Value(value));
|
|
},
|
|
_ => {
|
|
return Err(FormError::MismatchedType);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(form)
|
|
|
|
}
|
|
|
|
pub fn parse_key(key: &str) -> Vec<Key> {
|
|
let keys = if let Some((head, tail)) = key.split_once('[') {
|
|
let mut keys = vec![head];
|
|
keys.extend(tail.trim_end_matches(']').split("]["));
|
|
keys
|
|
} else {
|
|
vec![key]
|
|
};
|
|
|
|
keys.iter().map(|key| {
|
|
if key.is_empty() {
|
|
Key::ImplicitIndex
|
|
} else if let Ok(index) = key.parse::<usize>() {
|
|
Key::ExplicitIndex(index)
|
|
} else {
|
|
Key::Attribute(key.to_string())
|
|
}
|
|
}).collect()
|
|
}
|
|
|
|
pub fn into_json_value(self) -> serde_json::Value {
|
|
match self {
|
|
Node::Value(value) => serde_json::Value::String(value),
|
|
Node::Map(map) => {
|
|
let map = map.into_iter()
|
|
.map(|(key, node)| (key, node.into_json_value()))
|
|
.collect();
|
|
serde_json::Value::Object(map)
|
|
},
|
|
Node::Sequence(list) => {
|
|
let array = list.to_vec()
|
|
.into_iter()
|
|
.map(|node| node.into_json_value())
|
|
.collect();
|
|
|
|
serde_json::Value::Array(array)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
pub enum Sequence {
|
|
ImplicitIndex(Vec<Node>),
|
|
ExplicitIndex(HashMap<usize, Node>),
|
|
}
|
|
|
|
impl Sequence {
|
|
pub fn to_vec(self) -> Vec<Node> {
|
|
match self {
|
|
Sequence::ImplicitIndex(list) => list,
|
|
Sequence::ExplicitIndex(map) => {
|
|
let mut key_values: Vec<(usize, Node)> = map.into_iter().collect();
|
|
key_values.sort_by_key(|(k, _)| *k);
|
|
key_values.into_iter().map(|(_, v)| v).collect()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
pub enum Key {
|
|
ExplicitIndex(usize),
|
|
ImplicitIndex,
|
|
Attribute(String),
|
|
}
|
|
|
|
impl Key {
|
|
pub fn new_node(&self) -> Node {
|
|
match self {
|
|
Key::ExplicitIndex(_) => Node::Sequence(Sequence::ExplicitIndex(HashMap::new())),
|
|
Key::ImplicitIndex => Node::Sequence(Sequence::ImplicitIndex(Vec::new())),
|
|
Key::Attribute(_) => Node::Map(HashMap::new()),
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
pub fn test_parse_key() {
|
|
let key = "records[0][addresses][][address]".to_string();
|
|
let parsed_key = vec![
|
|
Key::Attribute("records".to_string()),
|
|
Key::ExplicitIndex(0),
|
|
Key::Attribute("addresses".to_string()),
|
|
Key::ImplicitIndex,
|
|
Key::Attribute("address".to_string()),
|
|
];
|
|
assert_eq!(Node::parse_key(&key), parsed_key);
|
|
}
|
|
|
|
#[test]
|
|
pub fn test_parse_key_value() {
|
|
let form_data = vec![
|
|
("records[0][addresses][][address]".to_string(), "123".to_string()),
|
|
("records[0][addresses][][address]".to_string(), "abc".to_string()),
|
|
];
|
|
let mut address1 = HashMap::new();
|
|
address1.insert("address".to_string(), Node::Value("123".to_string()));
|
|
let mut address2 = HashMap::new();
|
|
address2.insert("address".to_string(), Node::Value("abc".to_string()));
|
|
|
|
let addresses = vec![Node::Map(address1), Node::Map(address2)];
|
|
|
|
let mut record = HashMap::new();
|
|
record.insert("addresses".to_string(), Node::Sequence(Sequence::ImplicitIndex(addresses)));
|
|
|
|
let mut record_list = HashMap::new();
|
|
record_list.insert(0, Node::Map(record));
|
|
|
|
let mut form = HashMap::new();
|
|
form.insert("records".to_string(), Node::Sequence(Sequence::ExplicitIndex(record_list)));
|
|
|
|
let parsed_form = Node::Map(form);
|
|
|
|
assert_eq!(Node::from_key_value(form_data).unwrap(), parsed_form);
|
|
}
|
|
|
|
#[test]
|
|
pub fn test_json_value() {
|
|
let mut address1 = HashMap::new();
|
|
address1.insert("address".to_string(), Node::Value("123".to_string()));
|
|
let mut address2 = HashMap::new();
|
|
address2.insert("address".to_string(), Node::Value("abc".to_string()));
|
|
|
|
let addresses = vec![Node::Map(address1), Node::Map(address2)];
|
|
|
|
let mut record = HashMap::new();
|
|
record.insert("addresses".to_string(), Node::Sequence(Sequence::ImplicitIndex(addresses)));
|
|
|
|
let mut record_list = HashMap::new();
|
|
record_list.insert(0, Node::Map(record));
|
|
|
|
let mut form = HashMap::new();
|
|
form.insert("records".to_string(), Node::Sequence(Sequence::ExplicitIndex(record_list)));
|
|
|
|
let parsed_form = Node::Map(form);
|
|
|
|
let json_value = json!({
|
|
"records": [
|
|
{
|
|
"addresses": [
|
|
{ "address": "123" },
|
|
{ "address": "abc" },
|
|
]
|
|
}
|
|
]
|
|
});
|
|
|
|
assert_eq!(parsed_form.into_json_value(), json_value);
|
|
}
|
|
}
|