1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
pub mod filter;
pub mod page;
pub mod sort;
use crate::model::error;
use crate::RbhResult;
use crate::query::filter::FilterQuery;
use crate::query::page::PageQuery;
use crate::query::sort::SortQuery;
use percent_encoding::percent_decode_str;
use regex::Regex;
use std::collections::{HashMap, HashSet};
pub type IncludeQuery = HashSet<String>;
pub type FieldsQuery = HashMap<String, HashSet<String>>;
#[derive(Debug, Default)]
pub struct Query {
pub include: Option<IncludeQuery>,
pub fields: FieldsQuery,
pub sort: SortQuery,
pub page: Option<PageQuery>,
pub filter: Option<FilterQuery>,
}
lazy_static! {
static ref KEY_REGEX: Regex = Regex::new(r#"(?P<name>\w+)\[(?P<param>[\w\-_@]+)\]"#).unwrap();
}
impl Query {
pub fn from_uri(uri: &http::Uri) -> RbhResult<Query> {
let mut include_query: IncludeQuery = Default::default();
let mut include_query_exist = false;
let mut sort_query: SortQuery = Default::default();
let mut filter_map: HashMap<String, String> = Default::default();
let mut filter_type: Option<String> = None;
let mut fields_map: FieldsQuery = Default::default();
let mut page_map: HashMap<String, String> = Default::default();
if let Some(query_str) = uri.query() {
let query_str = percent_decode_str(query_str)
.decode_utf8()
.map_err(|err| error::Error::NotUtf8String(query_str, &err, None))?;
for (key, value) in query_str.split('&').filter_map(|s| {
let kv_pair: Vec<&str> = s.splitn(2, '=').collect();
if kv_pair.len() == 2 && !kv_pair[0].is_empty() {
Some((kv_pair[0], kv_pair[1]))
} else {
None
}
}) {
if key == "include" {
include_query_exist = true;
for v in value.split(',').filter(|s| !s.is_empty()).map(ToString::to_string) {
include_query.insert(v);
}
continue;
}
if key == "sort" {
sort_query.insert_raw(value)?;
continue;
}
if let Some(cap) = (&KEY_REGEX as &Regex).captures(key.as_ref()) {
if let (Some(name), Some(param)) = (cap.name("name"), cap.name("param")) {
let name = name.as_str();
let param = param.as_str();
if name == "fields" {
let values: HashSet<String> = value
.split(',')
.filter(|s| !s.is_empty())
.map(ToString::to_string)
.collect();
if let Some(origin_fields) = fields_map.get_mut(param) {
for v in values {
origin_fields.insert(v);
}
} else {
fields_map.insert(param.into(), values);
}
} else if name == "filter" && !value.is_empty() {
if param == "@type" {
filter_type = Some(value.into());
} else {
filter_map.insert(param.into(), value.to_string());
}
} else if name == "page" {
page_map.insert(param.into(), value.to_string());
}
}
}
}
}
let include = if include_query_exist { Some(include_query) } else { None };
let sort = sort_query;
let page = PageQuery::new(&page_map)?;
let filter =
if let Some(ty) = filter_type { FilterQuery::new(&ty, &filter_map)? } else { None };
let query = Query { include, fields: fields_map, sort, page, filter };
Ok(query)
}
}