1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use nom::types::CompleteByteSlice;
use std::fmt;

use column::Column;
use common::{column_identifier_no_alias, literal, opt_multispace, Literal};
use condition::{condition_expr, ConditionExpression};

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum ColumnOrLiteral {
    Column(Column),
    Literal(Literal),
}

impl fmt::Display for ColumnOrLiteral {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ColumnOrLiteral::Column(ref c) => write!(f, "{}", c)?,
            ColumnOrLiteral::Literal(ref l) => write!(f, "{}", l.to_string())?,
        }
        Ok(())
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct CaseWhenExpression {
    pub condition: ConditionExpression,
    pub then_expr: ColumnOrLiteral,
    pub else_expr: Option<ColumnOrLiteral>,
}

impl fmt::Display for CaseWhenExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CASE WHEN {} THEN {}", self.condition, self.then_expr)?;
        if let Some(ref expr) = self.else_expr {
            write!(f, " ELSE {}", expr)?;
        }
        Ok(())
    }
}

named!(pub case_when_column<CompleteByteSlice, CaseWhenExpression>,
       do_parse!(
           tag_no_case!("case when") >>
           opt_multispace >>
           cond: condition_expr >>
           opt_multispace >>
           tag_no_case!("then") >>
           opt_multispace >>
           column: column_identifier_no_alias >>
           opt_multispace >>
           else_value: opt!(do_parse!(
               tag_no_case!("else") >>
               opt_multispace >>
               else_val: literal >>
               opt_multispace >>
               (else_val)
           )) >>
           tag_no_case!("end") >>
           (CaseWhenExpression {
               condition: cond,
               then_expr: ColumnOrLiteral::Column(column),
               else_expr: else_value.map(|v| ColumnOrLiteral::Literal(v)),
           })
       )
);