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 syn::parse::{Parse, ParseStream, Result};
use syn::punctuated::Punctuated;
use syn::token::Comma;
use syn::{parenthesized, Ident, LitInt, LitStr};

use deprecated::utils::parse_eq_and_lit_str;
use parsers::PostgresType;
use util::{unknown_attribute, POSTGRES_TYPE_NOTE};

enum Attr {
    Oid(Ident, LitInt),
    ArrayOid(Ident, LitInt),
    TypeName(Ident, LitStr),
}

impl Parse for Attr {
    fn parse(input: ParseStream) -> Result<Self> {
        let name: Ident = input.parse()?;
        let name_str = name.to_string();

        match &*name_str {
            "oid" => Ok(Attr::Oid(name.clone(), {
                let lit_str = parse_eq_and_lit_str(name, input, POSTGRES_TYPE_NOTE)?;
                lit_str.parse()?
            })),
            "array_oid" => Ok(Attr::ArrayOid(name.clone(), {
                let lit_str = parse_eq_and_lit_str(name, input, POSTGRES_TYPE_NOTE)?;
                lit_str.parse()?
            })),
            "type_name" => Ok(Attr::TypeName(
                name.clone(),
                parse_eq_and_lit_str(name, input, POSTGRES_TYPE_NOTE)?,
            )),

            _ => unknown_attribute(&name, &["oid", "array_oid", "type_name"]),
        }
    }
}

pub fn parse_postgres_type(name: Ident, input: ParseStream) -> Result<PostgresType> {
    if input.is_empty() {
        abort!(
            name.span(),
            "unexpected end of input, expected parentheses";
            help = "The correct format looks like `#[diesel({})]`", POSTGRES_TYPE_NOTE
        );
    }

    let content;
    parenthesized!(content in input);

    let mut oid = None;
    let mut array_oid = None;
    let mut type_name = None;

    for attr in Punctuated::<Attr, Comma>::parse_terminated(&content)? {
        match attr {
            Attr::Oid(ident, value) => oid = Some((ident, value)),
            Attr::ArrayOid(ident, value) => array_oid = Some((ident, value)),
            Attr::TypeName(ident, value) => type_name = Some((ident, value)),
        }
    }

    PostgresType::validate_and_build(&content, oid, array_oid, type_name, None)
}