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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use {
    super::ExprNode,
    crate::{
        ast::{Assignment, Expr},
        parse_sql::parse_assignment,
        result::{Error, Result},
        translate::translate_assignment,
    },
};

#[derive(Clone, Debug)]
pub enum AssignmentNode<'a> {
    Expr(String, ExprNode<'a>),
    Text(String),
}

impl<'a> From<&str> for AssignmentNode<'a> {
    fn from(expr: &str) -> Self {
        Self::Text(expr.to_owned())
    }
}

impl<'a> TryFrom<AssignmentNode<'a>> for Assignment {
    type Error = Error;

    fn try_from(node: AssignmentNode<'a>) -> Result<Self> {
        match node {
            AssignmentNode::Text(expr) => {
                let expr = parse_assignment(expr)
                    .and_then(|assignment| translate_assignment(&assignment))?;
                Ok(expr)
            }
            AssignmentNode::Expr(col, expr_node) => {
                let value = Expr::try_from(expr_node)?;
                let id = col;
                Ok(Assignment { id, value })
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        ast_builder::AssignmentNode, parse_sql::parse_assignment, translate::translate_assignment,
    };

    fn test(actual: AssignmentNode, expected: &str) {
        let parsed = &parse_assignment(expected).expect(expected);
        let expected = translate_assignment(parsed);
        assert_eq!(actual.try_into(), expected);
    }

    #[test]
    fn assignment() {
        let actual = "foo = 1".into();
        let expected = "foo = 1";
        test(actual, expected);

        let actual = r#"foo = "choco""#.into();
        let expected = r#"foo = "choco""#;
        test(actual, expected);

        let actual = r#"Bar = mild"#.into();
        let expected = r#"Bar = mild"#;
        test(actual, expected);

        let actual = AssignmentNode::Expr("foo".into(), "1".into());
        let expected = "foo = 1";
        test(actual, expected);

        let actual = AssignmentNode::Expr("foo".into(), r#""cocoa""#.into());
        let expected = r#"foo = "cocoa""#;
        test(actual, expected);

        let actual = AssignmentNode::Expr("Bar".into(), "mild".into());
        let expected = "Bar = mild";
        test(actual, expected);
    }
}