1
2use std::iter::Peekable;
3
4use logos::{Lexer, Logos};
5
6use crate::{error::{PakResult, PqlError, PqlResult}, 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(source : &str) -> PakResult<Box<dyn PakQueryExpression>> {
80 let mut lexer = Lexer::new(source).peekable();
81 match PqlQuery::parse(&mut lexer) {
82 Ok(query) => {Ok(query.eval())},
83 Err(error) => Err(error.into()),
84 }
85}
86
87type TokenResult = Result<PqlToken, ()>;
92
93fn next_is<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>, token : &PqlToken) -> PqlResult<bool> {
94 let Some(Ok(t)) = lexer.peek() else { return Err(PqlError::EndOfFile.into()) };
95 Ok(token == t)
96}
97
98fn next_is_or_end<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>, token : &PqlToken) -> PqlResult<bool> {
99 let Some(Ok(t)) = lexer.peek() else { return Ok(false) };
100 Ok(token == t)
101}
102
103#[derive(Debug, Clone)]
108enum PqlQuery {
109 Expression(Box<PqlExpression>),
110 Group(Box<PqlGroup>)
111}
112
113impl PqlQuery {
114 fn parse<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlQuery> {
115 let group = PqlGroup::parse(lexer);
116 match group {
117 Ok(group) => return Ok(PqlQuery::Group(Box::new(group))),
118 Err(PqlError::NoMatch) => {},
119 Err(err) => return Err(err),
120 };
121 let expression = PqlExpression::parse(lexer);
122 match expression {
123 Ok(expression) => Ok(PqlQuery::Expression(Box::new(expression))),
124 Err(err) => Err(err),
125 }
126 }
127
128 fn eval(self) -> Box<dyn PakQueryExpression> {
129 match self {
130 PqlQuery::Expression(pql_expression) => pql_expression.eval(),
131 PqlQuery::Group(pql_group) => pql_group.eval(),
132 }
133 }
134}
135
136
137#[derive(Debug, Clone)]
142struct PqlGroup(PqlQuery);
143
144impl PqlGroup {
145 fn parse<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlGroup> {
146 if !next_is_or_end(lexer, &PqlToken::GroupStart)? { return Err(PqlError::NoMatch) }
147 lexer.next();
148 let query = PqlQuery::parse(lexer)?;
149 if !next_is(lexer, &PqlToken::GroupEnd)? { return Err(PqlError::UnexpectedToken(lexer.next().unwrap().unwrap(), ")".to_string())) }
150 lexer.next();
151 Ok(PqlGroup(query))
152 }
153
154 fn eval(self) -> Box<dyn PakQueryExpression> {
155 self.0.eval()
156 }
157}
158
159
160#[derive(Debug, Clone)]
165struct PqlExpression {
166 first : PqlStatement,
167 second : Option<(PqlToken, PqlQuery)>
168}
169
170impl PqlExpression {
171 fn parse<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlExpression> {
172 let first = PqlStatement::parse(lexer)?;
173 if !(next_is_or_end(lexer, &PqlToken::Or)? || next_is_or_end(lexer, &PqlToken::And)?) { return Ok(PqlExpression { first, second: None }) }
174 let Some(Ok(op)) = lexer.next() else { return Ok(PqlExpression { first, second: None })};
175 let second = PqlQuery::parse(lexer)?;
176 Ok(PqlExpression { first, second : Some((op, second)) })
177 }
178
179 fn eval(self) -> Box<dyn PakQueryExpression> {
180 let first = self.first.eval();
181 if let Some((op, second)) = self.second {
182 let second = second.eval();
183 match op {
184 PqlToken::And => Box::new(PakQueryIntersection::new(first, second)),
185 PqlToken::Or => Box::new(PakQueryUnion::new(first, second)),
186 _ => unreachable!()
187 }
188 } else {
189 Box::new(first)
190 }
191 }
192}
193
194
195#[derive(Debug, Clone)]
200struct PqlStatement {
201 key : String,
202 op : PqlToken,
203 value : PakValue
204}
205
206impl PqlStatement {
207 fn parse<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlStatement> {
208 let key = parse_text(lexer)?;
209 let op = parse_statement_op(lexer)?;
210 let value = parse_value(lexer)?;
211 Ok(PqlStatement { key, op, value })
212 }
213
214 fn eval(self) -> Box<dyn PakQueryExpression> {
215 let query = match self.op {
216 PqlToken::Eq => PakQuery::Equal(self.key, self.value),
217 PqlToken::Less => PakQuery::LessThan(self.key, self.value),
218 PqlToken::LessEq => PakQuery::LessThanEqual(self.key, self.value),
219 PqlToken::Greater => PakQuery::GreaterThan(self.key, self.value),
220 PqlToken::GreaterEq => PakQuery::GreaterThanEqual(self.key, self.value),
221 PqlToken::Contains => PakQuery::Contains(self.key, self.value),
222 _ => unreachable!()
223 };
224 Box::new(query)
225 }
226}
227
228
229fn parse_value<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PakValue> {
234 if !check_value(lexer)? { return Err(PqlError::NoMatch) }
235 let Some(Ok(first_text)) = lexer.next() else { return Err(PqlError::EndOfFile) };
236 let value = match first_text {
237 PqlToken::Text(value) => PakValue::String(value),
238 PqlToken::Int(value) => PakValue::Int(value),
239 PqlToken::Uint(value) => PakValue::Uint(value),
240 PqlToken::Float(value) => PakValue::Float(value.to_bits()),
241 _ => { unreachable!() }
242 };
243 Ok(value)
244}
245
246fn check_value<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<bool> {
247 let Some(Ok(next)) = lexer.peek() else { return Err(PqlError::EndOfFile) };
248 Ok(matches!(next, PqlToken::Text(_) | PqlToken::Float(_) | PqlToken::Int(_) | PqlToken::Uint(_)))
249}
250
251fn parse_text<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<String> {
256 if !check_text(lexer)? { return Err(PqlError::NoMatch) }
257 let Some(Ok(first_text)) = lexer.next() else { return Err(PqlError::EndOfFile) };
258 let Some(text) = first_text.get_text() else { return Err(PqlError::NoMatch) };
259 Ok(text.clone())
260}
261
262fn check_text<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<bool> {
263 let Some(Ok(next)) = lexer.peek() else { return Err(PqlError::EndOfFile) };
264 Ok(matches!(next, PqlToken::Text(_)))
265}
266
267fn parse_statement_op<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<PqlToken> {
272 if !check_statement_op(lexer)? { return Err(PqlError::NoMatch) }
273 Ok(lexer.next().unwrap().unwrap())
274}
275
276fn check_statement_op<I : Iterator<Item =TokenResult>>(lexer : &mut Peekable<I>) -> PqlResult<bool> {
277 let Some(Ok(next)) = lexer.peek() else { return Err(PqlError::EndOfFile) };
278 Ok(matches!(next, PqlToken::Eq | PqlToken::Less | PqlToken::Greater | PqlToken::LessEq | PqlToken::GreaterEq | PqlToken::Contains))
279}
280
281
282#[cfg(test)]
283mod test {
284 use logos::Lexer;
285
286 use crate::{index::PakIndexIdentifier, query::pql::{PqlExpression, PqlGroup, PqlQuery, PqlStatement, PqlToken}, test::{Person, build_data_base}, value::PakValue};
287
288 #[test]
289 fn pql_parse_query() {
290 let pql = "(age >= 25 | name = John) & last_name = Doe & personallity_traits <- Patient";
291 let mut lexer = Lexer::<PqlToken>::new(pql).peekable();
292 let query = PqlQuery::parse(&mut lexer);
293 assert!(query.is_ok())
294 }
295
296 #[test]
297 fn pql_parse_statement() {
298 let pql = "age <= 25";
299 let mut lexer = Lexer::<PqlToken>::new(pql).peekable();
300 let stmt = PqlStatement::parse(&mut lexer).unwrap();
301 assert_eq!(stmt.key, "age");
302 assert_eq!(stmt.op, PqlToken::LessEq);
303 assert_eq!(stmt.value, PakValue::Int(25));
304 }
305
306 #[test]
307 fn pql_parse_expression() {
308 let pql = "age <= 20 | name >= J";
309 let mut lexer = Lexer::<PqlToken>::new(pql).peekable();
310 let expr = PqlExpression::parse(&mut lexer).unwrap();
311 assert_eq!(expr.first.key, "age");
312 assert_eq!(expr.first.op, PqlToken::LessEq);
313 assert_eq!(expr.first.value, PakValue::Int(20));
314 }
315
316 #[test]
317 fn pql_parse_group() {
318 let pql = "(age <= 20 | name >= J)";
319 let mut lexer = Lexer::<PqlToken>::new(pql).peekable();
320 let expr = PqlGroup::parse(&mut lexer).unwrap();
321 assert!(matches!(expr, PqlGroup(PqlQuery::Expression(_))));
322 }
323
324 #[test]
325 fn pql_compare() {
326 let (pak, _, _) = build_data_base();
327 let pql = "personallity_traits <- Patient";
328 let query = "personallity_traits".contains_value("Patient");
329 let people = pak.query_sql::<(Person,)>(pql).unwrap();
330 let other_people = pak.query::<(Person,)>(query).unwrap();
331 assert_eq!(people.len(), other_people.len());
332 assert!(people.iter().all(|person| person.personallity_traits.contains(&crate::test::PersonalityTrait::Patient)));
333 assert!(other_people.iter().all(|person| person.personallity_traits.contains(&crate::test::PersonalityTrait::Patient)));
334 }
335}