Browse Source

Parse fields in SELECT

main
Dylan Baker 3 years ago
parent
commit
bb6fb86440
1 changed files with 62 additions and 5 deletions
  1. 62
    5
      src/parser.rs

+ 62
- 5
src/parser.rs View File

@@ -1,4 +1,4 @@
1
-use std::slice::Iter;
1
+use std::{iter::Peekable, slice::Iter};
2 2
 
3 3
 use crate::error::ParserError;
4 4
 use crate::token::{Token, TokenType};
@@ -16,6 +16,7 @@ pub struct Identifier {
16 16
 
17 17
 #[derive(Debug, PartialEq)]
18 18
 pub enum Field {
19
+    Named(String),
19 20
     Star,
20 21
 }
21 22
 
@@ -28,19 +29,50 @@ impl Identifier {
28 29
 }
29 30
 
30 31
 pub fn parse(tokens: Vec<Token>) -> Result<Select, ParserError> {
31
-    select_expression(&mut tokens.iter())
32
+    parse_select_expression(&mut tokens.iter().peekable())
32 33
 }
33 34
 
34
-fn select_expression(tokens: &mut Iter<Token>) -> Result<Select, ParserError> {
35
+fn parse_select_expression(tokens: &mut Peekable<Iter<Token>>) -> Result<Select, ParserError> {
35 36
     eat(tokens, TokenType::Select)?;
36
-    let fields = eat(tokens, TokenType::Star).and_then(|_| Ok(vec![Field::Star]))?;
37
+    let fields = parse_fields(tokens)?;
37 38
     eat(tokens, TokenType::From)?;
38 39
     let source = eat(tokens, TokenType::Identfiier).and_then(|t| Ok(Identifier::new(&t.value)))?;
39 40
 
40 41
     Ok(Select { fields, source })
41 42
 }
42 43
 
43
-fn eat<'a>(tokens: &'a mut Iter<Token>, token_type: TokenType) -> Result<&'a Token, ParserError> {
44
+fn parse_fields(tokens: &mut Peekable<Iter<Token>>) -> Result<Vec<Field>, ParserError> {
45
+    if current_token_is(tokens, TokenType::Star) {
46
+        eat(tokens, TokenType::Star).and_then(|_| Ok(vec![Field::Star]))
47
+    } else {
48
+        let mut fields: Vec<Field> = vec![];
49
+
50
+        loop {
51
+            let field = eat(tokens, TokenType::Identfiier)?;
52
+            fields.push(Field::Named(field.value.clone()));
53
+
54
+            if current_token_is(tokens, TokenType::Comma) {
55
+                eat(tokens, TokenType::Comma)?;
56
+            } else {
57
+                break;
58
+            }
59
+        }
60
+
61
+        Ok(fields)
62
+    }
63
+}
64
+
65
+fn current_token_is(tokens: &mut Peekable<Iter<Token>>, token_type: TokenType) -> bool {
66
+    match tokens.peek() {
67
+        Some(t) => t.token_type == token_type,
68
+        None => false,
69
+    }
70
+}
71
+
72
+fn eat<'a>(
73
+    tokens: &'a mut Peekable<Iter<Token>>,
74
+    token_type: TokenType,
75
+) -> Result<&'a Token, ParserError> {
44 76
     match tokens.next() {
45 77
         Some(token) => {
46 78
             if token.token_type == token_type {
@@ -76,4 +108,29 @@ mod tests {
76 108
             },
77 109
         )
78 110
     }
111
+
112
+    #[test]
113
+    fn it_parses_a_select_with_field() {
114
+        assert_eq!(
115
+            _parse("SELECT field FROM index").unwrap(),
116
+            Select {
117
+                fields: vec![Field::Named("field".to_string())],
118
+                source: Identifier::new("index")
119
+            },
120
+        )
121
+    }
122
+
123
+    #[test]
124
+    fn it_parses_a_select_with_multiple_fields() {
125
+        assert_eq!(
126
+            _parse("SELECT field_one, field_two FROM index").unwrap(),
127
+            Select {
128
+                fields: vec![
129
+                    Field::Named("field_one".to_string()),
130
+                    Field::Named("field_two".to_string())
131
+                ],
132
+                source: Identifier::new("index")
133
+            },
134
+        )
135
+    }
79 136
 }

Loading…
Cancel
Save