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
use super::{super::combinator::*, *};
use crate::ast::*;

/// 301 select_list = `(` [named_types] { `,` [named_types] } `)` .
pub fn select_list(input: &str) -> ParseResult<Vec<String>> {
    tuple((char('('), comma_separated(named_types), char(')')))
        .map(|(_start, ids, _end)| ids)
        .parse(input)
}

/// 300 select_extension = BASED_ON [type_ref] \[ WITH [select_list] \] .
pub fn select_extension(input: &str) -> ParseResult<(String, Vec<String>)> {
    let with = tuple((tag("WITH"), select_list)).map(|(_with, list)| list);
    tuple((tag("BASED_ON"), type_ref, opt(with)))
        .map(|(_based_on, id, opt)| (id, opt.unwrap_or_default()))
        .parse(input)
}

/// 302 select_type = \[ EXTENSIBLE \[ GENERIC_ENTITY \] \] SELECT \[ [select_list] | [select_extension] \] .
pub fn select_type(input: &str) -> ParseResult<Type> {
    // FIXME support select_extension

    // `GENERIC_ENTITY` only appears in `select_type` declaration.
    let extensibility = tuple((
        tag("EXTENSIBLE"),
        opt(tuple((spaces, tag("GENERIC_ENTITY")))),
    ))
    .map(|(_extensible, opt)| {
        if opt.is_some() {
            Extensibility::GenericEntity
        } else {
            Extensibility::Extensible
        }
    });

    tuple((
        opt(tuple((extensibility, spaces))),
        tag("SELECT"),
        select_list,
    ))
    .map(|(opt, _select, types)| {
        if let Some((extensibility, _spaces)) = opt {
            Type::Select {
                extensibility,
                types,
            }
        } else {
            Type::Select {
                extensibility: Extensibility::None,
                types,
            }
        }
    })
    .parse(input)
}

#[cfg(test)]
mod tests {
    use super::*;
    use nom::Finish;

    #[test]
    fn select() {
        let (res, (s, _remarks)) = super::select_type("SELECT (a, b)").finish().unwrap();
        assert_eq!(res, "");
        if let Type::Select {
            extensibility,
            types,
        } = s
        {
            assert_eq!(extensibility, Extensibility::None);
            assert_eq!(types[0], "a");
            assert_eq!(types[1], "b");
        } else {
            panic!()
        }
    }
}