Browse Source

Parse where clauses

main
Dylan Baker 3 years ago
parent
commit
055d94bd01
4 changed files with 186 additions and 35 deletions
  1. 62
    0
      src/ast.rs
  2. 5
    5
      src/compiler.rs
  3. 1
    0
      src/lib.rs
  4. 118
    30
      src/parser.rs

+ 62
- 0
src/ast.rs View File

@@ -0,0 +1,62 @@
1
+#[derive(Debug, PartialEq)]
2
+pub struct Select {
3
+    pub fields: Vec<Field>,
4
+    pub source: KIdentifier,
5
+    pub where_clause: Option<Where>,
6
+}
7
+
8
+#[derive(Debug, PartialEq)]
9
+pub enum Field {
10
+    Named(String),
11
+    Star,
12
+}
13
+
14
+#[derive(Debug, PartialEq)]
15
+pub enum Where {
16
+    And(Vec<Where>),
17
+    Equals(KValue, KValue),
18
+}
19
+
20
+#[derive(Debug, PartialEq)]
21
+pub enum KValue {
22
+    Identifier(KIdentifier),
23
+    Number(KNumber),
24
+    String(KString),
25
+}
26
+
27
+#[derive(Debug, PartialEq)]
28
+pub struct KIdentifier {
29
+    pub name: String,
30
+}
31
+
32
+#[derive(Debug, PartialEq)]
33
+pub struct KNumber {
34
+    pub value: f32,
35
+}
36
+
37
+#[derive(Debug, PartialEq)]
38
+pub struct KString {
39
+    pub value: String,
40
+}
41
+
42
+impl KIdentifier {
43
+    pub fn new(name: &str) -> Self {
44
+        Self {
45
+            name: name.to_string(),
46
+        }
47
+    }
48
+}
49
+
50
+impl KNumber {
51
+    pub fn new(value: f32) -> Self {
52
+        Self { value }
53
+    }
54
+}
55
+
56
+impl KString {
57
+    pub fn new(value: &str) -> Self {
58
+        Self {
59
+            value: value.to_string(),
60
+        }
61
+    }
62
+}

+ 5
- 5
src/compiler.rs View File

@@ -2,17 +2,17 @@ use serde_json::{json, Value};
2 2
 
3 3
 use std::fmt::{Display, Formatter};
4 4
 
5
+use crate::ast::{Field, KIdentifier, Select};
5 6
 use crate::error::KappeError;
6
-use crate::parser::{Field, Identifier, Select};
7 7
 
8 8
 #[derive(Debug, PartialEq)]
9 9
 pub struct Query {
10
-    pub source: Identifier,
10
+    pub source: KIdentifier,
11 11
     pub body: Value,
12 12
 }
13 13
 
14 14
 impl Query {
15
-    pub fn new(source: Identifier, body: Value) -> Self {
15
+    pub fn new(source: KIdentifier, body: Value) -> Self {
16 16
         Self { source, body }
17 17
     }
18 18
 }
@@ -63,7 +63,7 @@ mod tests {
63 63
         assert_eq!(
64 64
             _compile("SELECT * FROM bar").unwrap(),
65 65
             Query::new(
66
-                Identifier::new("bar"),
66
+                KIdentifier::new("bar"),
67 67
                 json!({
68 68
                     "query": {
69 69
                         "match_all": {}
@@ -79,7 +79,7 @@ mod tests {
79 79
         assert_eq!(
80 80
             _compile("SELECT foo FROM bar").unwrap(),
81 81
             Query::new(
82
-                Identifier::new("bar"),
82
+                KIdentifier::new("bar"),
83 83
                 json!({
84 84
                     "query": {
85 85
                         "match_all": {}

+ 1
- 0
src/lib.rs View File

@@ -1,3 +1,4 @@
1
+pub mod ast;
1 2
 pub mod compiler;
2 3
 pub mod error;
3 4
 pub mod lexer;

+ 118
- 30
src/parser.rs View File

@@ -1,33 +1,9 @@
1 1
 use std::{iter::Peekable, slice::Iter};
2 2
 
3
+use crate::ast::{Field, KIdentifier, KNumber, KString, KValue, Select, Where};
3 4
 use crate::error::KappeError;
4 5
 use crate::token::{Token, TokenType};
5 6
 
6
-#[derive(Debug, PartialEq)]
7
-pub struct Select {
8
-    pub fields: Vec<Field>,
9
-    pub source: Identifier,
10
-}
11
-
12
-#[derive(Debug, PartialEq)]
13
-pub struct Identifier {
14
-    pub name: String,
15
-}
16
-
17
-#[derive(Debug, PartialEq)]
18
-pub enum Field {
19
-    Named(String),
20
-    Star,
21
-}
22
-
23
-impl Identifier {
24
-    pub fn new(name: &str) -> Self {
25
-        Self {
26
-            name: name.to_string(),
27
-        }
28
-    }
29
-}
30
-
31 7
 pub fn parse(tokens: Vec<Token>) -> Result<Select, KappeError> {
32 8
     parse_select_expression(&mut tokens.iter().peekable())
33 9
 }
@@ -36,9 +12,15 @@ fn parse_select_expression(tokens: &mut Peekable<Iter<Token>>) -> Result<Select,
36 12
     eat(tokens, TokenType::Select)?;
37 13
     let fields = parse_fields(tokens)?;
38 14
     eat(tokens, TokenType::From)?;
39
-    let source = eat(tokens, TokenType::Identfiier).and_then(|t| Ok(Identifier::new(&t.value)))?;
15
+    let source = eat(tokens, TokenType::Identfiier).and_then(|t| Ok(KIdentifier::new(&t.value)))?;
16
+
17
+    let where_clause = parse_where_clause(tokens)?;
40 18
 
41
-    Ok(Select { fields, source })
19
+    Ok(Select {
20
+        fields,
21
+        source,
22
+        where_clause,
23
+    })
42 24
 }
43 25
 
44 26
 fn parse_fields(tokens: &mut Peekable<Iter<Token>>) -> Result<Vec<Field>, KappeError> {
@@ -62,6 +44,57 @@ fn parse_fields(tokens: &mut Peekable<Iter<Token>>) -> Result<Vec<Field>, KappeE
62 44
     }
63 45
 }
64 46
 
47
+fn parse_where_clause(tokens: &mut Peekable<Iter<Token>>) -> Result<Option<Where>, KappeError> {
48
+    let where_clause = if current_token_is(tokens, TokenType::Where) {
49
+        eat(tokens, TokenType::Where)?;
50
+
51
+        let predicate = parse_predicate(tokens)?;
52
+
53
+        if current_token_is(tokens, TokenType::Comma) {
54
+            let mut predicates: Vec<Where> = vec![];
55
+            predicates.push(predicate);
56
+
57
+            while current_token_is(tokens, TokenType::Comma) {
58
+                eat(tokens, TokenType::Comma)?;
59
+                let predicate = parse_predicate(tokens)?;
60
+                predicates.push(predicate);
61
+            }
62
+
63
+            Some(Where::And(predicates))
64
+        } else {
65
+            Some(predicate)
66
+        }
67
+    } else {
68
+        None
69
+    };
70
+
71
+    Ok(where_clause)
72
+}
73
+
74
+fn parse_predicate(tokens: &mut Peekable<Iter<Token>>) -> Result<Where, KappeError> {
75
+    let field = eat(tokens, TokenType::Identfiier)?;
76
+    let field = KValue::Identifier(KIdentifier::new(&field.value));
77
+
78
+    eat(tokens, TokenType::Equals)?;
79
+
80
+    let value: KValue = if current_token_is(tokens, TokenType::String) {
81
+        let token = eat(tokens, TokenType::String)?;
82
+        Ok(KValue::String(KString::new(&token.value)))
83
+    } else if current_token_is(tokens, TokenType::Number) {
84
+        let token = eat(tokens, TokenType::Number)?;
85
+        match token.value.parse::<f32>() {
86
+            Ok(n) => Ok(KValue::Number(KNumber::new(n))),
87
+            Err(_) => Err(KappeError::new("Error converting number to f32")),
88
+        }
89
+    } else {
90
+        Err(KappeError::new(
91
+            "Invalid token on right-hand side of equals sign",
92
+        ))
93
+    }?;
94
+
95
+    Ok(Where::Equals(field, value))
96
+}
97
+
65 98
 fn current_token_is(tokens: &mut Peekable<Iter<Token>>, token_type: TokenType) -> bool {
66 99
     match tokens.peek() {
67 100
         Some(t) => t.token_type == token_type,
@@ -104,7 +137,8 @@ mod tests {
104 137
             _parse("SELECT * FROM index").unwrap(),
105 138
             Select {
106 139
                 fields: vec![Field::Star],
107
-                source: Identifier::new("index")
140
+                source: KIdentifier::new("index"),
141
+                where_clause: None
108 142
             },
109 143
         )
110 144
     }
@@ -115,7 +149,8 @@ mod tests {
115 149
             _parse("SELECT field FROM index").unwrap(),
116 150
             Select {
117 151
                 fields: vec![Field::Named("field".to_string())],
118
-                source: Identifier::new("index")
152
+                source: KIdentifier::new("index"),
153
+                where_clause: None
119 154
             },
120 155
         )
121 156
     }
@@ -129,7 +164,60 @@ mod tests {
129 164
                     Field::Named("field_one".to_string()),
130 165
                     Field::Named("field_two".to_string())
131 166
                 ],
132
-                source: Identifier::new("index")
167
+                source: KIdentifier::new("index"),
168
+                where_clause: None
169
+            },
170
+        )
171
+    }
172
+
173
+    #[test]
174
+    fn it_parses_a_select_with_a_single_predicate_where_clause() {
175
+        assert_eq!(
176
+            _parse("SELECT * FROM index WHERE field = \"hello\"").unwrap(),
177
+            Select {
178
+                fields: vec![Field::Star],
179
+                source: KIdentifier::new("index"),
180
+                where_clause: Some(Where::Equals(
181
+                    KValue::Identifier(KIdentifier::new("field")),
182
+                    KValue::String(KString::new("hello")),
183
+                ))
184
+            },
185
+        )
186
+    }
187
+
188
+    #[test]
189
+    fn it_parses_a_select_with_a_numeric_predicate() {
190
+        assert_eq!(
191
+            _parse("SELECT * FROM index WHERE field = 123").unwrap(),
192
+            Select {
193
+                fields: vec![Field::Star],
194
+                source: KIdentifier::new("index"),
195
+                where_clause: Some(Where::Equals(
196
+                    KValue::Identifier(KIdentifier::new("field")),
197
+                    KValue::Number(KNumber::new(123.0)),
198
+                ))
199
+            },
200
+        )
201
+    }
202
+
203
+    #[test]
204
+    fn it_parses_a_select_with_a_multiple_predicate_where_clause() {
205
+        assert_eq!(
206
+            _parse("SELECT * FROM index WHERE field_one = \"hello\", field_two = \"world\"")
207
+                .unwrap(),
208
+            Select {
209
+                fields: vec![Field::Star],
210
+                source: KIdentifier::new("index"),
211
+                where_clause: Some(Where::And(vec![
212
+                    Where::Equals(
213
+                        KValue::Identifier(KIdentifier::new("field_one")),
214
+                        KValue::String(KString::new("hello")),
215
+                    ),
216
+                    Where::Equals(
217
+                        KValue::Identifier(KIdentifier::new("field_two")),
218
+                        KValue::String(KString::new("world")),
219
+                    )
220
+                ]))
133 221
             },
134 222
         )
135 223
     }

Loading…
Cancel
Save