pak_db/query/
pql.rs

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//==============================================================================================
9//        PQL Tokens
10//==============================================================================================
11
12#[derive(Logos, Debug, PartialEq, PartialOrd, Clone)]
13#[logos(skip r"[ \t\n\f]+")] // Ignore this regex pattern between tokens
14pub 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
75//==============================================================================================
76//        Parse Function
77//==============================================================================================
78
79pub 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
87//==============================================================================================
88//        Pql parsing Common
89//==============================================================================================
90
91type 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//==============================================================================================
104//        Query
105//==============================================================================================
106
107#[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//==============================================================================================
138//        PqlGroup
139//==============================================================================================
140
141#[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//==============================================================================================
161//        Expression
162//==============================================================================================
163
164#[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//==============================================================================================
196//        Statement
197//==============================================================================================
198
199#[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
229//==============================================================================================
230//        Value Parse
231//==============================================================================================
232
233fn 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
251//==============================================================================================
252//        Text
253//==============================================================================================
254
255fn 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
267//==============================================================================================
268//        Statement Op
269//==============================================================================================
270
271fn 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}