Browse Source

Compile where clauses!

main
Dylan Baker 3 years ago
parent
commit
d3a6fb62ed
3 changed files with 132 additions and 32 deletions
  1. 22
    5
      src/ast.rs
  2. 88
    2
      src/compiler.rs
  3. 22
    25
      src/parser.rs

+ 22
- 5
src/ast.rs View File

@@ -12,9 +12,26 @@ pub enum Field {
12 12
 }
13 13
 
14 14
 #[derive(Debug, PartialEq)]
15
-pub enum Where {
16
-    And(Vec<Where>),
17
-    Equals(KValue, KValue),
15
+pub struct Where {
16
+    pub predicates: Vec<Equals>,
17
+}
18
+
19
+impl Where {
20
+    pub fn new(predicates: Vec<Equals>) -> Self {
21
+        Self { predicates }
22
+    }
23
+}
24
+
25
+#[derive(Debug, PartialEq)]
26
+pub struct Equals {
27
+    pub left: KIdentifier,
28
+    pub right: KValue,
29
+}
30
+
31
+impl Equals {
32
+    pub fn new(left: KIdentifier, right: KValue) -> Self {
33
+        Self { left, right }
34
+    }
18 35
 }
19 36
 
20 37
 #[derive(Debug, PartialEq)]
@@ -31,7 +48,7 @@ pub struct KIdentifier {
31 48
 
32 49
 #[derive(Debug, PartialEq)]
33 50
 pub struct KNumber {
34
-    pub value: f32,
51
+    pub value: f64,
35 52
 }
36 53
 
37 54
 #[derive(Debug, PartialEq)]
@@ -48,7 +65,7 @@ impl KIdentifier {
48 65
 }
49 66
 
50 67
 impl KNumber {
51
-    pub fn new(value: f32) -> Self {
68
+    pub fn new(value: f64) -> Self {
52 69
         Self { value }
53 70
     }
54 71
 }

+ 88
- 2
src/compiler.rs View File

@@ -2,7 +2,7 @@ use serde_json::{json, Value};
2 2
 
3 3
 use std::fmt::{Display, Formatter};
4 4
 
5
-use crate::ast::{Field, KIdentifier, Select};
5
+use crate::ast::{Field, KIdentifier, KValue, Select, Where};
6 6
 use crate::error::KappeError;
7 7
 
8 8
 #[derive(Debug, PartialEq)]
@@ -38,14 +38,50 @@ pub fn compile(expr: Select) -> Result<Query, KappeError> {
38 38
         })
39 39
         .collect();
40 40
 
41
+    let query = if let Some(where_clause) = expr.where_clause {
42
+        compile_where_clause(where_clause)
43
+    } else {
44
+        json!({ "match_all":{} })
45
+    };
46
+
41 47
     let body = json!({
42
-        "query": { "match_all":{} },
48
+        "query": query,
43 49
         "_source": Value::Array(field_names)
44 50
     });
45 51
 
46 52
     Ok(Query::new(expr.source, body))
47 53
 }
48 54
 
55
+pub fn compile_where_clause(where_clause: Where) -> Value {
56
+    let terms: Vec<Value> = where_clause
57
+        .predicates
58
+        .iter()
59
+        .map(|predicate| {
60
+            let mut map = serde_json::Map::new();
61
+            let key = predicate.left.name.clone();
62
+            let value = compile_kvalue(&predicate.right);
63
+            map.insert(key, value);
64
+            json!({ "term": Value::Object(map) })
65
+        })
66
+        .collect();
67
+
68
+    json!({
69
+        "bool": {
70
+            "filter": Value::Array(terms)
71
+        }
72
+    })
73
+}
74
+
75
+pub fn compile_kvalue(value: &KValue) -> Value {
76
+    match value {
77
+        KValue::Identifier(identifier) => Value::String(identifier.name.to_string()),
78
+        KValue::Number(number) => {
79
+            Value::Number(serde_json::Number::from_f64(number.value).unwrap())
80
+        }
81
+        KValue::String(string) => Value::String(string.value.to_string()),
82
+    }
83
+}
84
+
49 85
 #[cfg(test)]
50 86
 mod tests {
51 87
     use super::*;
@@ -89,4 +125,54 @@ mod tests {
89 125
             )
90 126
         )
91 127
     }
128
+
129
+    #[test]
130
+    fn it_compiles_a_select_with_a_single_predicate_where_clause() {
131
+        let mut map: serde_json::Map<String, Value> = serde_json::Map::new();
132
+        map.insert("baz".to_string(), Value::String("quux".to_string()));
133
+        assert_eq!(
134
+            _compile("SELECT * FROM bar WHERE baz = \"quux\"").unwrap(),
135
+            Query::new(
136
+                KIdentifier::new("bar"),
137
+                json!({
138
+                    "query": {
139
+                        "bool": {
140
+                            "filter": [
141
+                                json!({ "term": Value::Object(map) })
142
+                            ]
143
+                        }
144
+                    },
145
+                    "_source": ["*"]
146
+                })
147
+            )
148
+        )
149
+    }
150
+
151
+    #[test]
152
+    fn it_compiles_a_select_with_a_multiple_predicate_where_claus() {
153
+        let mut map_one: serde_json::Map<String, Value> = serde_json::Map::new();
154
+        map_one.insert("baz".to_string(), Value::String("quux".to_string()));
155
+        let mut map_two: serde_json::Map<String, Value> = serde_json::Map::new();
156
+        map_two.insert(
157
+            "bop".to_string(),
158
+            Value::Number(serde_json::Number::from_f64(5.0).unwrap()),
159
+        );
160
+        assert_eq!(
161
+            _compile("SELECT * FROM bar WHERE baz = \"quux\", bop = 5").unwrap(),
162
+            Query::new(
163
+                KIdentifier::new("bar"),
164
+                json!({
165
+                    "query": {
166
+                        "bool": {
167
+                            "filter": [
168
+                                json!({ "term": Value::Object(map_one) }),
169
+                                json!({ "term": Value::Object(map_two) }),
170
+                            ]
171
+                        }
172
+                    },
173
+                    "_source": ["*"]
174
+                })
175
+            )
176
+        )
177
+    }
92 178
 }

+ 22
- 25
src/parser.rs View File

@@ -1,6 +1,6 @@
1 1
 use std::{iter::Peekable, slice::Iter};
2 2
 
3
-use crate::ast::{Field, KIdentifier, KNumber, KString, KValue, Select, Where};
3
+use crate::ast::{Equals, Field, KIdentifier, KNumber, KString, KValue, Select, Where};
4 4
 use crate::error::KappeError;
5 5
 use crate::token::{Token, TokenType};
6 6
 
@@ -45,25 +45,22 @@ fn parse_fields(tokens: &mut Peekable<Iter<Token>>) -> Result<Vec<Field>, KappeE
45 45
 }
46 46
 
47 47
 fn parse_where_clause(tokens: &mut Peekable<Iter<Token>>) -> Result<Option<Where>, KappeError> {
48
+    let mut predicates: Vec<Equals> = vec![];
48 49
     let where_clause = if current_token_is(tokens, TokenType::Where) {
49 50
         eat(tokens, TokenType::Where)?;
50 51
 
51 52
         let predicate = parse_predicate(tokens)?;
53
+        predicates.push(predicate);
52 54
 
53 55
         if current_token_is(tokens, TokenType::Comma) {
54
-            let mut predicates: Vec<Where> = vec![];
55
-            predicates.push(predicate);
56
-
57 56
             while current_token_is(tokens, TokenType::Comma) {
58 57
                 eat(tokens, TokenType::Comma)?;
59 58
                 let predicate = parse_predicate(tokens)?;
60 59
                 predicates.push(predicate);
61 60
             }
62
-
63
-            Some(Where::And(predicates))
64
-        } else {
65
-            Some(predicate)
66 61
         }
62
+
63
+        Some(Where::new(predicates))
67 64
     } else {
68 65
         None
69 66
     };
@@ -71,9 +68,9 @@ fn parse_where_clause(tokens: &mut Peekable<Iter<Token>>) -> Result<Option<Where
71 68
     Ok(where_clause)
72 69
 }
73 70
 
74
-fn parse_predicate(tokens: &mut Peekable<Iter<Token>>) -> Result<Where, KappeError> {
71
+fn parse_predicate(tokens: &mut Peekable<Iter<Token>>) -> Result<Equals, KappeError> {
75 72
     let field = eat(tokens, TokenType::Identfiier)?;
76
-    let field = KValue::Identifier(KIdentifier::new(&field.value));
73
+    let field = KIdentifier::new(&field.value);
77 74
 
78 75
     eat(tokens, TokenType::Equals)?;
79 76
 
@@ -82,9 +79,9 @@ fn parse_predicate(tokens: &mut Peekable<Iter<Token>>) -> Result<Where, KappeErr
82 79
         Ok(KValue::String(KString::new(&token.value)))
83 80
     } else if current_token_is(tokens, TokenType::Number) {
84 81
         let token = eat(tokens, TokenType::Number)?;
85
-        match token.value.parse::<f32>() {
82
+        match token.value.parse::<f64>() {
86 83
             Ok(n) => Ok(KValue::Number(KNumber::new(n))),
87
-            Err(_) => Err(KappeError::new("Error converting number to f32")),
84
+            Err(_) => Err(KappeError::new("Error converting number to f64")),
88 85
         }
89 86
     } else {
90 87
         Err(KappeError::new(
@@ -92,7 +89,7 @@ fn parse_predicate(tokens: &mut Peekable<Iter<Token>>) -> Result<Where, KappeErr
92 89
         ))
93 90
     }?;
94 91
 
95
-    Ok(Where::Equals(field, value))
92
+    Ok(Equals::new(field, value))
96 93
 }
97 94
 
98 95
 fn current_token_is(tokens: &mut Peekable<Iter<Token>>, token_type: TokenType) -> bool {
@@ -177,10 +174,10 @@ mod tests {
177 174
             Select {
178 175
                 fields: vec![Field::Star],
179 176
                 source: KIdentifier::new("index"),
180
-                where_clause: Some(Where::Equals(
181
-                    KValue::Identifier(KIdentifier::new("field")),
177
+                where_clause: Some(Where::new(vec![Equals::new(
178
+                    KIdentifier::new("field"),
182 179
                     KValue::String(KString::new("hello")),
183
-                ))
180
+                )]))
184 181
             },
185 182
         )
186 183
     }
@@ -192,10 +189,10 @@ mod tests {
192 189
             Select {
193 190
                 fields: vec![Field::Star],
194 191
                 source: KIdentifier::new("index"),
195
-                where_clause: Some(Where::Equals(
196
-                    KValue::Identifier(KIdentifier::new("field")),
197
-                    KValue::Number(KNumber::new(123.0)),
198
-                ))
192
+                where_clause: Some(Where::new(vec![Equals::new(
193
+                    KIdentifier::new("field"),
194
+                    KValue::Number(KNumber::new(123.0))
195
+                ),]))
199 196
             },
200 197
         )
201 198
     }
@@ -208,13 +205,13 @@ mod tests {
208 205
             Select {
209 206
                 fields: vec![Field::Star],
210 207
                 source: KIdentifier::new("index"),
211
-                where_clause: Some(Where::And(vec![
212
-                    Where::Equals(
213
-                        KValue::Identifier(KIdentifier::new("field_one")),
208
+                where_clause: Some(Where::new(vec![
209
+                    Equals::new(
210
+                        KIdentifier::new("field_one"),
214 211
                         KValue::String(KString::new("hello")),
215 212
                     ),
216
-                    Where::Equals(
217
-                        KValue::Identifier(KIdentifier::new("field_two")),
213
+                    Equals::new(
214
+                        KIdentifier::new("field_two"),
218 215
                         KValue::String(KString::new("world")),
219 216
                     )
220 217
                 ]))

Loading…
Cancel
Save