modelvault_core/sql/
mod.rs1mod lexer;
6mod parser;
7
8use crate::error::DbError;
9use crate::query::OrderBy;
10use crate::schema::FieldPath;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct SqlSelect {
14 pub columns: SqlColumns,
15 pub collection: String,
16 pub predicate: Option<SqlPredicate>,
17 pub order_by: Option<OrderBy>,
18 pub limit: Option<usize>,
19 pub param_count: usize,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum SqlColumns {
24 Star,
25 Paths(Vec<FieldPath>),
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum SqlValue {
30 Param(usize),
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub enum SqlPredicate {
35 Eq { path: FieldPath, value: SqlValue },
36 Lt { path: FieldPath, value: SqlValue },
37 Lte { path: FieldPath, value: SqlValue },
38 Gt { path: FieldPath, value: SqlValue },
39 Gte { path: FieldPath, value: SqlValue },
40 And(Vec<SqlPredicate>),
41 Or(Vec<SqlPredicate>),
42}
43
44pub fn parse_select(sql: &str) -> Result<SqlSelect, DbError> {
50 parser::parse_select_tokens(lexer::lex(sql)?)
51}
52
53#[cfg(test)]
54mod parse_select_token_tests {
55 use super::parser::parse_select_tokens;
56 use crate::error::DbError;
57 use crate::sql::lexer::Tok;
58
59 #[test]
62 fn limit_accepts_ident_that_parses_as_usize() {
63 let toks = vec![
64 Tok::Ident("select".into()),
65 Tok::Star,
66 Tok::Ident("from".into()),
67 Tok::Ident("t".into()),
68 Tok::Ident("limit".into()),
69 Tok::Ident("42".into()),
70 ];
71 let s = parse_select_tokens(toks).unwrap();
72 assert_eq!(s.limit, Some(42));
73 }
74
75 #[test]
76 fn parse_errors_when_where_clause_ends_after_path() {
77 let toks = vec![
78 Tok::Ident("select".into()),
79 Tok::Star,
80 Tok::Ident("from".into()),
81 Tok::Ident("t".into()),
82 Tok::Ident("where".into()),
83 Tok::Ident("x".into()),
84 ];
85 let e = parse_select_tokens(toks).unwrap_err();
86 assert!(matches!(e, DbError::Query(_)));
87 }
88}