1use std::collections::BTreeMap;
10
11use crate::entry::Entry;
12use crate::validator::Validator;
13use crate::{
14 de::FogDeserializer,
15 element::Parser,
16 error::{Error, Result},
17 ser::FogSerializer,
18 validator::{Checklist, DataChecklist},
19 value_ref::ValueRef,
20 MAX_QUERY_SIZE,
21};
22use fog_crypto::hash::Hash;
23use serde::{Deserialize, Serialize};
24
25#[derive(Clone, Debug, Serialize, Deserialize)]
26#[serde(deny_unknown_fields)]
27struct InnerQuery {
28 key: String,
29 query: Validator,
30}
31
32#[derive(Clone, Debug)]
43pub struct NewQuery {
44 inner: InnerQuery,
45}
46
47impl NewQuery {
48 pub fn new(key: &str, query: Validator) -> Self {
51 Self {
52 inner: InnerQuery {
53 key: key.to_owned(),
54 query,
55 },
56 }
57 }
58
59 pub fn validator(&self) -> &Validator {
61 &self.inner.query
62 }
63
64 pub fn key(&self) -> &str {
66 &self.inner.key
67 }
68
69 pub(crate) fn complete(self, max_regex: u8) -> Result<Vec<u8>> {
70 fn parse_validator(v: &Validator) -> usize {
71 match v {
72 Validator::Str(val) => val.matches.is_some() as usize,
73 Validator::Map(val) => {
74 let key_matches = if let Some(s) = val.keys.as_ref() {
75 s.matches.is_some() as usize
76 } else {
77 0
78 };
79 key_matches
80 + val
81 .req
82 .values()
83 .fold(0, |acc, val| acc + parse_validator(val))
84 + val
85 .opt
86 .values()
87 .fold(0, |acc, val| acc + parse_validator(val))
88 + val.values.as_ref().map_or(0, |val| parse_validator(val))
89 }
90 Validator::Array(val) => {
91 val.contains
92 .iter()
93 .fold(0, |acc, val| acc + parse_validator(val))
94 + parse_validator(val.items.as_ref())
95 + val
96 .prefix
97 .iter()
98 .fold(0, |acc, val| acc + parse_validator(val))
99 }
100 Validator::Hash(val) => val.link.as_ref().map_or(0, |val| parse_validator(val)),
101 Validator::Enum(val) => val
102 .values()
103 .fold(0, |acc, val| acc + val.as_ref().map_or(0, parse_validator)),
104 Validator::Multi(val) => val.iter().fold(0, |acc, val| acc + parse_validator(val)),
105 _ => 0,
106 }
107 }
108 let regexes = parse_validator(&self.inner.query);
109 if regexes > (max_regex as usize) {
110 return Err(Error::FailValidate(format!(
111 "Found {} regexes in query, only {} allowed",
112 regexes, max_regex
113 )));
114 }
115 let mut ser = FogSerializer::default();
116 self.inner.serialize(&mut ser)?;
117 let buf = ser.finish();
118 if buf.len() > MAX_QUERY_SIZE {
119 Err(Error::LengthTooLong {
120 max: MAX_QUERY_SIZE,
121 actual: buf.len(),
122 })
123 } else {
124 Ok(buf)
125 }
126 }
127}
128
129#[derive(Clone, Debug)]
137pub struct Query {
138 inner: InnerQuery,
139 schema: Hash,
140 types: BTreeMap<String, Validator>,
141}
142
143impl Query {
144 pub(crate) fn new(buf: Vec<u8>, max_regex: u8) -> Result<Self> {
145 let mut de = FogDeserializer::new(&buf);
147 let regex_check = ValueRef::deserialize(&mut de)?;
148 let regexes = crate::count_regexes(®ex_check["query"]);
149 if regexes > (max_regex as usize) {
150 return Err(Error::FailValidate(format!(
151 "Found {} regexes in query, only {} allowed",
152 regexes, max_regex
153 )));
154 }
155
156 let mut de = FogDeserializer::new(&buf);
158 let inner = InnerQuery::deserialize(&mut de)?;
159 Ok(Self {
160 inner,
161 schema: Hash::new([]),
162 types: BTreeMap::new(),
163 })
164 }
165
166 pub fn validator(&self) -> &Validator {
168 &self.inner.query
169 }
170
171 pub fn key(&self) -> &str {
173 &self.inner.key
174 }
175
176 pub fn query(&self, entry: &Entry) -> Result<DataChecklist<()>> {
182 let parser = Parser::new(entry.data());
183 let checklist = Some(Checklist::new(&self.schema, &self.types));
184 let (_, checklist) = self.inner.query.validate(&self.types, parser, checklist)?;
185 Ok(DataChecklist::from_checklist(checklist.unwrap(), ()))
186 }
187}
188
189#[cfg(test)]
190mod test {
191 use regex::Regex;
192
193 use crate::validator::{MapValidator, StrValidator};
194
195 use super::*;
196
197 #[test]
198 fn max_regex_in_key() {
199 let validator = MapValidator {
200 keys: Some(Box::new(StrValidator {
201 matches: Some(Box::new(Regex::new("[a-z]").unwrap())),
202 ..Default::default()
203 })),
204 ..Default::default()
205 }
206 .build();
207
208 NewQuery::new("test", validator.clone())
209 .complete(0)
210 .unwrap_err();
211 let enc_query = NewQuery::new("test", validator).complete(1).unwrap();
212 assert!(Query::new(enc_query.clone(), 0).is_err());
213 assert!(Query::new(enc_query.clone(), 1).is_ok());
214 assert!(Query::new(enc_query, 2).is_ok());
215 }
216
217 #[test]
218 fn max_regex_in_str() {
219 let matches = Some(Box::new(Regex::new("[a-z]").unwrap()));
220 let validator = StrValidator {
221 matches,
222 ..Default::default()
223 }
224 .build();
225 NewQuery::new("test", validator.clone())
226 .complete(0)
227 .unwrap_err();
228 let enc_query = NewQuery::new("test", validator).complete(1).unwrap();
229 assert!(Query::new(enc_query.clone(), 0).is_err());
230 assert!(Query::new(enc_query.clone(), 1).is_ok());
231 assert!(Query::new(enc_query, 2).is_ok());
232 }
233}