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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! ddl parser contains algorithmn for parsing restq DDL syntax
//! into an DDL AST.
use super::*;
use crate::{
    ast::{
        ddl::Foreign,
        parser::{utils::end_or_ln, *},
        Value,
    },
    data_type::data_type,
    data_value,
};
use either::Either;
use pom::parser::{sym, tag, Parser};

pub(crate) fn column_attribute<'a>() -> Parser<'a, char, ColumnAttribute> {
    sym('*').map(|_| ColumnAttribute::Primary)
        | sym('&').map(|_| ColumnAttribute::Unique)
        | sym('@').map(|_| ColumnAttribute::Index)
}

pub(crate) fn column_attributes<'a>() -> Parser<'a, char, Vec<ColumnAttribute>>
{
    column_attribute().repeat(1..)
}

/// foreign = "(", table, ")"
///     = "(", table, ["::", ",", column] )
pub(crate) fn foreign<'a>() -> Parser<'a, char, Foreign> {
    (sym('(') * table() + (tag("::") * column()).opt() - sym(')'))
        .map(|(table, column)| Foreign { table, column })
}

/// parse column definition with the format
/// column_def  = [column_attribute], column, [foreign] [":" data_type];
/// example:
///     &*product_id(product):u32
pub(crate) fn column_def<'a>() -> Parser<'a, char, ColumnDef> {
    ((column_attributes().opt() + column() + foreign().opt() - sym(':')
        + data_type_def())
    .map(|(((attributes, column), foreign), data_type)| ColumnDef {
        column,
        attributes,
        data_type_def: data_type,
        foreign,
    }))
    .name("column_def")
}

pub(crate) fn column_def_list<'a>() -> Parser<'a, char, Vec<ColumnDef>> {
    list_fail(column_def(), sym(',')).name("column_def_list")
}

pub(crate) fn enclosed_column_def_list<'a>() -> Parser<'a, char, Vec<ColumnDef>>
{
    sym('{') * column_def_list() - sym('}')
}

/// example:
///   product{*product_id:s32,@name:text,description:text,updated:utc,created_by(users):u32,@is_active:bool}
///
///  or
///
///   product(*product_id:s32,@name:text,description:text,updated:utc,created_by(users):u32,@is_active:bool)
///
/// Note: that braces `{}` are invalid when used in the path part, but can be valid when used in
/// query part.
/// So it is safe to use the parenthesis `()` when used in actual rest api request.
pub fn table_def<'a>() -> Parser<'a, char, TableDef> {
    (table() + enclosed_column_def_list() - end_or_ln())
        .map(|(table, columns)| TableDef { table, columns })
}

pub fn default_value<'a>() -> Parser<'a, char, Either<Function, Value>> {
    function().map(Either::Left) | value().map(Either::Right)
}

/// data_type_def = data_type ["?"] "(" value ")"
/// example:
///     u32?(0.0)
pub fn data_type_def<'a>() -> Parser<'a, char, DataTypeDef> {
    (data_type()
        + sym('?').opt()
        + (sym('(') * default_value() - sym(')')).opt())
    .map(|((data_type, optional), default_value)| {
        let default = default_value.map(|d| match d {
            Either::Left(df) => DefaultValue::Function(df),
            Either::Right(dv) => DefaultValue::DataValue(
                data_value::cast_data_value(&dv, &data_type),
            ),
        });

        DataTypeDef {
            data_type,
            is_optional: if let Some(_) = optional { true } else { false },
            default,
        }
    })
    .name("data_type_def")
}

pub fn drop_table<'a>() -> Parser<'a, char, DropTable> {
    (sym('-') * table() - end_or_ln()).map(|table| DropTable { table })
}

fn drop_column<'a>() -> Parser<'a, char, AlterOperation> {
    (sym('-') * column()).map(AlterOperation::DropColumn)
}

fn add_column<'a>() -> Parser<'a, char, AlterOperation> {
    (sym('+') * column_def()).map(AlterOperation::AddColumn)
}

fn alter_column<'a>() -> Parser<'a, char, AlterOperation> {
    (column() - sym('=') + column_def()).map(|(column, column_def)| {
        AlterOperation::AlterColumn(column, column_def)
    })
}

fn alter_operation<'a>() -> Parser<'a, char, AlterOperation> {
    alter_column() | drop_column() | add_column()
}

fn alter_operations<'a>() -> Parser<'a, char, Vec<AlterOperation>> {
    sym('{') * list_fail(alter_operation(), sym(',')) - sym('}')
}

pub fn alter_table<'a>() -> Parser<'a, char, AlterTable> {
    (table() + alter_operations() - end_or_ln()).map(
        |(table, alter_operations)| AlterTable {
            table,
            alter_operations,
        },
    )
}