1use nom::{
2 branch::alt,
3 bytes::complete::{tag, take_until, take_while1},
4 character::complete::{char, multispace0},
5 combinator::{map, opt, value},
6 multi::{many0, separated_list1},
7 sequence::{delimited, pair, preceded, tuple},
8 IResult,
9};
10
11use crate::ast::*;
12use super::tokens::*;
13
14pub fn parse_columns(input: &str) -> IResult<&str, Vec<Column>> {
16 many0(preceded(ws_or_comment, parse_any_column))(input)
17}
18
19fn parse_any_column(input: &str) -> IResult<&str, Column> {
20 alt((
21 preceded(char('\''), parse_label_column),
23 parse_column_full_def_or_named,
25 ))(input)
26}
27
28fn parse_label_column(input: &str) -> IResult<&str, Column> {
30 alt((
31 value(Column::Star, char('_')),
33 parse_column_full_def_or_named,
35 ))(input)
36}
37
38fn parse_column_full_def_or_named(input: &str) -> IResult<&str, Column> {
39 let (input, name) = parse_identifier(input)?;
41
42 if let Ok((input, Some(func))) = opt(preceded(char('#'), parse_agg_func))(input) {
44 return Ok((input, Column::Aggregate {
45 col: name.to_string(),
46 func
47 }));
48 }
49
50 if let Ok((input, _)) = char::<_, nom::error::Error<&str>>(':')(input) {
52 let (input, type_or_func) = parse_identifier(input)?;
54
55 let (input, _) = ws_or_comment(input)?;
56
57 if let Ok((input, _)) = char::<_, nom::error::Error<&str>>('(')(input) {
59 let (input, _) = ws_or_comment(input)?;
61 let (input, args) = opt(tuple((
62 parse_value,
63 many0(preceded(
64 tuple((ws_or_comment, char(','), ws_or_comment)),
65 parse_value
66 ))
67 )))(input)?;
68 let (input, _) = ws_or_comment(input)?;
69 let (input, _) = char(')')(input)?;
70
71 let params = match args {
72 Some((first, mut rest)) => {
73 let mut v = vec![first];
74 v.append(&mut rest);
75 v
76 },
77 None => vec![],
78 };
79
80 let (input, sorts) = many0(parse_window_sort)(input)?;
82
83 let (input, partitions) = opt(parse_partition_block)(input)?;
85 let partition = partitions.unwrap_or_default();
86
87 return Ok((input, Column::Window {
88 name: name.to_string(),
89 func: type_or_func.to_string(),
90 params,
91 partition,
92 order: sorts,
93 }));
94 } else {
95 let (input, constraints) = parse_constraints(input)?;
97
98 return Ok((input, Column::Def {
99 name: name.to_string(),
100 data_type: type_or_func.to_string(),
101 constraints
102 }));
103 }
104 }
105
106 let (input, constraints) = parse_constraints(input)?;
108 if !constraints.is_empty() {
109 Ok((input, Column::Def {
110 name: name.to_string(),
111 data_type: "str".to_string(),
112 constraints
113 }))
114 } else {
115 Ok((input, Column::Named(name.to_string())))
117 }
118}
119
120fn parse_constraints(input: &str) -> IResult<&str, Vec<Constraint>> {
121 many0(alt((
122 map(
124 tuple((tag("^pk"), nom::combinator::not(char('(')))),
125 |_| Constraint::PrimaryKey
126 ),
127 map(
129 tuple((tag("^uniq"), nom::combinator::not(tag("ue(")))),
130 |_| Constraint::Unique
131 ),
132 value(Constraint::Nullable, char('?')),
133 parse_default_constraint,
134 parse_check_constraint,
135 parse_comment_constraint,
136 )))(input)
137}
138
139fn parse_default_constraint(input: &str) -> IResult<&str, Constraint> {
141 let (input, _) = preceded(multispace0, char('='))(input)?;
142 let (input, _) = multispace0(input)?;
143
144 let (input, value) = alt((
146 map(
148 pair(
149 take_while1(|c: char| c.is_alphanumeric() || c == '_'),
150 tag("()")
151 ),
152 |(name, parens): (&str, &str)| format!("{}{}", name, parens)
153 ),
154 map(
156 take_while1(|c: char| c.is_numeric() || c == '.' || c == '-'),
157 |s: &str| s.to_string()
158 ),
159 map(
161 delimited(char('"'), take_until("\""), char('"')),
162 |s: &str| format!("'{}'", s)
163 ),
164 ))(input)?;
165
166 Ok((input, Constraint::Default(value)))
167}
168
169fn parse_check_constraint(input: &str) -> IResult<&str, Constraint> {
171 let (input, _) = tag("^check(")(input)?;
172 let (input, values) = separated_list1(
173 char(','),
174 delimited(
175 multispace0,
176 delimited(char('"'), take_until("\""), char('"')),
177 multispace0
178 )
179 )(input)?;
180 let (input, _) = char(')')(input)?;
181
182 Ok((input, Constraint::Check(values.into_iter().map(|s| s.to_string()).collect())))
183}
184
185fn parse_comment_constraint(input: &str) -> IResult<&str, Constraint> {
187 let (input, _) = tag("^comment(\"")(input)?;
188 let (input, text) = take_until("\"")(input)?;
189 let (input, _) = tag("\")")(input)?;
190 Ok((input, Constraint::Comment(text.to_string())))
191}
192
193pub fn parse_index_columns(input: &str) -> IResult<&str, Vec<String>> {
195 let (input, _) = char('\'')(input)?;
196 let (input, first) = parse_identifier(input)?;
197 let (input, rest) = many0(preceded(char('-'), parse_identifier))(input)?;
198
199 let mut cols = vec![first.to_string()];
200 cols.extend(rest.iter().map(|s| s.to_string()));
201 Ok((input, cols))
202}
203
204pub fn parse_table_constraints(input: &str) -> IResult<&str, Vec<TableConstraint>> {
206 many0(alt((
207 parse_table_unique,
208 parse_table_pk,
209 )))(input)
210}
211
212fn parse_table_unique(input: &str) -> IResult<&str, TableConstraint> {
214 let (input, _) = tag("^unique(")(input)?;
215 let (input, cols) = parse_constraint_columns(input)?;
216 let (input, _) = char(')')(input)?;
217 Ok((input, TableConstraint::Unique(cols)))
218}
219
220fn parse_table_pk(input: &str) -> IResult<&str, TableConstraint> {
222 let (input, _) = tag("^pk(")(input)?;
223 let (input, cols) = parse_constraint_columns(input)?;
224 let (input, _) = char(')')(input)?;
225 Ok((input, TableConstraint::PrimaryKey(cols)))
226}
227
228fn parse_constraint_columns(input: &str) -> IResult<&str, Vec<String>> {
230 let (input, _) = multispace0(input)?;
231 let (input, first) = parse_identifier(input)?;
232 let (input, rest) = many0(preceded(
233 tuple((multispace0, char(','), multispace0)),
234 parse_identifier
235 ))(input)?;
236 let (input, _) = multispace0(input)?;
237
238 let mut cols = vec![first.to_string()];
239 cols.extend(rest.iter().map(|s| s.to_string()));
240 Ok((input, cols))
241}
242
243fn parse_agg_func(input: &str) -> IResult<&str, AggregateFunc> {
244 alt((
245 value(AggregateFunc::Count, tag("count")),
246 value(AggregateFunc::Sum, tag("sum")),
247 value(AggregateFunc::Avg, tag("avg")),
248 value(AggregateFunc::Min, tag("min")),
249 value(AggregateFunc::Max, tag("max")),
250 ))(input)
251}
252
253fn parse_partition_block(input: &str) -> IResult<&str, Vec<String>> {
254 let (input, _) = char('{')(input)?;
255 let (input, _) = ws_or_comment(input)?;
256 let (input, _) = tag("Part")(input)?;
257 let (input, _) = ws_or_comment(input)?;
258 let (input, _) = char('=')(input)?;
259 let (input, _) = ws_or_comment(input)?;
260
261 let (input, first) = parse_identifier(input)?;
262 let (input, rest) = many0(preceded(
263 tuple((ws_or_comment, char(','), ws_or_comment)),
264 parse_identifier
265 ))(input)?;
266
267 let (input, _) = ws_or_comment(input)?;
268 let (input, _) = char('}')(input)?;
269
270 let mut cols = vec![first.to_string()];
271 cols.append(&mut rest.iter().map(|s| s.to_string()).collect());
272 Ok((input, cols))
273}
274
275fn parse_window_sort(input: &str) -> IResult<&str, Cage> {
277 let (input, _) = char('^')(input)?;
278 let (input, desc) = opt(char('!'))(input)?;
279 let (input, col) = parse_identifier(input)?;
280
281 let order = if desc.is_some() {
282 SortOrder::Desc
283 } else {
284 SortOrder::Asc
285 };
286
287 Ok((
288 input,
289 Cage {
290 kind: CageKind::Sort(order),
291 conditions: vec![Condition {
292 column: col.to_string(),
293 op: Operator::Eq,
294 value: Value::Null,
295 is_array_unnest: false,
296 }],
297 logical_op: LogicalOp::And,
298 },
299 ))
300}