1
2use std::{iter::Peekable, marker::PhantomData};
3
4use logos::{Lexer, Logos};
5
6use crate::{error::{PakResult, PqlError, PqlResult}, group::DeserializeGroup, query::{PakQuery, PakQueryExpression, PakQueryIntersection, PakQueryUnion}, value::PakValue};
7
8#[derive(Logos, Debug, PartialEq, PartialOrd, Clone)]
13#[logos(skip r"[ \t\n\f]+")] pub enum PqlToken {
15 #[token("=")]
16 Eq,
17 #[token("<")]
18 Less,
19 #[token("<=")]
20 LessEq,
21 #[token(">")]
22 Greater,
23 #[token(">=")]
24 GreaterEq,
25 #[token("<-")]
26 Contains,
27 #[token("|")]
28 Or,
29 #[token("&")]
30 And,
31 #[regex("|[ ]+\\(")]
32 GroupStartOr,
33 #[regex("&[ ]+\\(")]
34 GroupStartAnd,
35 #[token("(")]
36 GroupStart,
37 #[token(")")]
38 GroupEnd,
39 #[regex("[a-zA-Z_]([a-zA-Z0-9_-]+)?", text)]
40 Text(String),
41 #[regex("[0-9]+", int)]
42 #[regex("[0-9]+i", int)]
43 Int(i64),
44 #[regex("[0-9]+u", uint)]
45 Uint(u64),
46 #[regex("[0-9]+.[0-9]+", float)]
47 #[regex("[0-9]+f", float)]
48 Float(f64),
49}
50
51impl PqlToken {
52 pub fn get_text(&self) -> Option<&String> {
53 let PqlToken::Text(text) = self else { return None };
54 Some(text)
55 }
56}
57
58fn text(lex : &mut Lexer<PqlToken>) -> Option<String> {
59 Some(lex.slice().to_string())
60}
61
62fn int(lex : &mut Lexer<PqlToken>) -> Option<i64> {
63 lex.slice().parse().ok()
64}
65
66fn uint(lex : &mut Lexer<PqlToken>) -> Option<u64> {
67 lex.slice().parse().ok()
68}
69
70fn float(lex : &mut Lexer<PqlToken>) -> Option<f64> {
71 lex.slice().parse().ok()
72}
73
74
75pub fn pql<T : DeserializeGroup + 'static>(source : &str) -> PakResult<Box<dyn PakQueryExpression<T>>> {
80 if source.starts_with("all") || source.is_empty() {
81 return Ok(Box::new(PakQuery::All));
82 }
83 let mut lexer = Lexer::new(source).peekable();
84 match PqlQuery::parse(&mut lexer) {
85 Ok(query) => {Ok(query.eval())},
86 Err(error) => Err(error.into()),
87 }
88}
89
90type TokenResult = Result<PqlToken, ()>;
95
96fn next_is<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>, token : &PqlToken) -> PqlResult<bool> {
97 let Some(Ok(t)) = lexer.peek() else { return Err(PqlError::EndOfFile.into()) };
98 Ok(token == t)
99}
100
101fn next_is_or_end<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>, token : &PqlToken) -> PqlResult<bool> {
102 let Some(Ok(t)) = lexer.peek() else { return Ok(false) };
103 Ok(token == t)
104}
105
106#[derive(Debug, Clone)]
111enum PqlQuery {
112 Expression(Box<PqlExpression>),
113 Group(Box<PqlGroup>)
114}
115
116impl PqlQuery {
117 fn parse<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlQuery> {
118 let group = PqlGroup::parse(lexer);
119 match group {
120 Ok(group) => return Ok(PqlQuery::Group(Box::new(group))),
121 Err(PqlError::NoMatch) => {},
122 Err(err) => return Err(err),
123 };
124 let expression = PqlExpression::parse(lexer);
125 match expression {
126 Ok(expression) => Ok(PqlQuery::Expression(Box::new(expression))),
127 Err(err) => Err(err),
128 }
129 }
130
131 fn eval<T : DeserializeGroup + 'static>(self) -> Box<dyn PakQueryExpression<T>> {
132 match self {
133 PqlQuery::Expression(pql_expression) => pql_expression.eval(),
134 PqlQuery::Group(pql_group) => pql_group.eval(),
135 }
136 }
137}
138
139
140#[derive(Debug, Clone)]
145struct PqlGroup(PqlQuery);
146
147impl PqlGroup {
148 fn parse<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlGroup> {
149 if !next_is_or_end(lexer, &PqlToken::GroupStart)? { return Err(PqlError::NoMatch) }
150 lexer.next();
151 let query = PqlQuery::parse(lexer)?;
152 if !next_is(lexer, &PqlToken::GroupEnd)? { return Err(PqlError::UnexpectedToken(lexer.next().unwrap().unwrap(), ")".to_string())) }
153 lexer.next();
154 Ok(PqlGroup(query))
155 }
156
157 fn eval<T : DeserializeGroup + 'static>(self) -> Box<dyn PakQueryExpression<T>> {
158 self.0.eval()
159 }
160}
161
162
163#[derive(Debug, Clone)]
168struct PqlExpression {
169 first : PqlStatement,
170 second : Option<(PqlToken, PqlQuery)>
171}
172
173impl PqlExpression {
174 fn parse<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlExpression> {
175 let first = PqlStatement::parse(lexer)?;
176 if !(next_is_or_end(lexer, &PqlToken::Or)? || next_is_or_end(lexer, &PqlToken::And)?) { return Ok(PqlExpression { first, second: None }) }
177 let Some(Ok(op)) = lexer.next() else { return Ok(PqlExpression { first, second: None })};
178 let second = PqlQuery::parse(lexer)?;
179 Ok(PqlExpression { first, second : Some((op, second)) })
180 }
181
182 fn eval<T : DeserializeGroup + 'static>(self) -> Box<dyn PakQueryExpression<T>> {
183 let first = self.first.eval::<T>();
184 if let Some((op, second)) = self.second {
185 let second = second.eval();
186 match op {
187 PqlToken::And => Box::new(PakQueryIntersection::new(first, second)),
188 PqlToken::Or => Box::new(PakQueryUnion::new(first, second)),
189 _ => unreachable!()
190 }
191 } else {
192 Box::new(first)
193 }
194 }
195}
196
197
198#[derive(Debug, Clone)]
203struct PqlStatement {
204 key : String,
205 op : PqlToken,
206 value : PakValue
207}
208
209impl PqlStatement {
210 fn parse<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlStatement> {
211 let key = parse_text(lexer)?;
212 let op = parse_statement_op(lexer)?;
213 let value = parse_value(lexer)?;
214 Ok(PqlStatement { key, op, value })
215 }
216
217 fn eval<T : DeserializeGroup + 'static>(self) -> Box<dyn PakQueryExpression<T>> {
218 let query = match self.op {
219 PqlToken::Eq => PakQuery::Equal(self.key, self.value, PhantomData),
220 PqlToken::Less => PakQuery::LessThan(self.key, self.value),
221 PqlToken::LessEq => PakQuery::LessThanEqual(self.key, self.value),
222 PqlToken::Greater => PakQuery::GreaterThan(self.key, self.value),
223 PqlToken::GreaterEq => PakQuery::GreaterThanEqual(self.key, self.value),
224 PqlToken::Contains => PakQuery::Contains(self.key, self.value),
225 _ => unreachable!()
226 };
227 Box::new(query)
228 }
229}
230
231
232fn parse_value<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PakValue> {
237 if !check_value(lexer)? { return Err(PqlError::NoMatch) }
238 let Some(Ok(first_text)) = lexer.next() else { return Err(PqlError::EndOfFile) };
239 let value = match first_text {
240 PqlToken::Text(value) => PakValue::String(value),
241 PqlToken::Int(value) => PakValue::Int(value),
242 PqlToken::Uint(value) => PakValue::Uint(value),
243 PqlToken::Float(value) => PakValue::Float(value.to_bits()),
244 _ => { unreachable!() }
245 };
246 Ok(value)
247}
248
249fn check_value<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<bool> {
250 let Some(Ok(next)) = lexer.peek() else { return Err(PqlError::EndOfFile) };
251 Ok(matches!(next, PqlToken::Text(_) | PqlToken::Float(_) | PqlToken::Int(_) | PqlToken::Uint(_)))
252}
253
254fn parse_text<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<String> {
259 if !check_text(lexer)? { return Err(PqlError::NoMatch) }
260 let Some(Ok(first_text)) = lexer.next() else { return Err(PqlError::EndOfFile) };
261 let Some(text) = first_text.get_text() else { return Err(PqlError::NoMatch) };
262 Ok(text.clone())
263}
264
265fn check_text<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<bool> {
266 let Some(Ok(next)) = lexer.peek() else { return Err(PqlError::EndOfFile) };
267 Ok(matches!(next, PqlToken::Text(_)))
268}
269
270fn parse_statement_op<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlToken> {
275 if !check_statement_op(lexer)? { return Err(PqlError::NoMatch) }
276 Ok(lexer.next().unwrap().unwrap())
277}
278
279fn check_statement_op<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<bool> {
280 let Some(Ok(next)) = lexer.peek() else { return Err(PqlError::EndOfFile) };
281 Ok(matches!(next, PqlToken::Eq | PqlToken::Less | PqlToken::Greater | PqlToken::LessEq | PqlToken::GreaterEq | PqlToken::Contains))
282}
283
284
285#[cfg(test)]
286mod test {
287 use logos::Lexer;
288
289 use crate::{index::PakIndexIdentifier, query::pql::{PqlExpression, PqlGroup, PqlQuery, PqlStatement, PqlToken}, test::{Person, Pet, alice_smith, bob_johnson, build_data_base, jane_doe, john_doe, john_jacob}, value::PakValue};
290
291 #[test]
292 fn pql_parse_query() {
293 let pql = "(age >= 25 | name = John) & last_name = Doe & personallity_traits <- Patient";
294 let mut lexer = Lexer::<PqlToken>::new(pql).peekable();
295 let query = PqlQuery::parse(&mut lexer);
296 assert!(query.is_ok())
297 }
298
299 #[test]
300 fn pql_parse_statement() {
301 let pql = "age <= 25";
302 let mut lexer = Lexer::<PqlToken>::new(pql).peekable();
303 let stmt = PqlStatement::parse(&mut lexer).unwrap();
304 assert_eq!(stmt.key, "age");
305 assert_eq!(stmt.op, PqlToken::LessEq);
306 assert_eq!(stmt.value, PakValue::Int(25));
307 }
308
309 #[test]
310 fn pql_parse_expression() {
311 let pql = "age <= 20 | name >= J";
312 let mut lexer = Lexer::<PqlToken>::new(pql).peekable();
313 let expr = PqlExpression::parse(&mut lexer).unwrap();
314 assert_eq!(expr.first.key, "age");
315 assert_eq!(expr.first.op, PqlToken::LessEq);
316 assert_eq!(expr.first.value, PakValue::Int(20));
317 }
318
319 #[test]
320 fn pql_parse_group() {
321 let pql = "(age <= 20 | name >= J)";
322 let mut lexer = Lexer::<PqlToken>::new(pql).peekable();
323 let expr = PqlGroup::parse(&mut lexer).unwrap();
324 assert!(matches!(expr, PqlGroup(PqlQuery::Expression(_))));
325 }
326
327 #[test]
328 fn pql_compare() {
329 let (pak, _, _) = build_data_base();
330 let pql = "personallity_traits <- Patient";
331 let query = "personallity_traits".contains_value("Patient");
332 let people = pak.query_pql::<(Person,)>(pql).unwrap();
333 let other_people = pak.query::<(Person,)>(query).unwrap();
334 assert_eq!(people.len(), other_people.len());
335 assert!(people.iter().all(|person| person.personallity_traits.contains(&crate::test::PersonalityTrait::Patient)));
336 assert!(other_people.iter().all(|person| person.personallity_traits.contains(&crate::test::PersonalityTrait::Patient)));
337 }
338
339 #[test]
340 fn pql_all() {
341 let (pak, _, _) = build_data_base();
342 let pql = "all";
343 let (people, pets) = pak.query_pql::<(Person, Pet)>(pql).unwrap();
344
345 assert_eq!(people.len(), 7);
346 assert_eq!(pets.len(), 3);
347
348 assert!(people.contains(&john_doe()));
349 assert!(people.contains(&jane_doe()));
350 assert!(people.contains(&alice_smith()));
351 assert!(people.contains(&john_jacob()));
352 assert!(people.contains(&bob_johnson()));
353 }
354}