1use std::cmp::Ordering;
2use std::fmt::{self, Display};
3use std::str;
4use std::str::FromStr;
5
6use nom::branch::alt;
7use nom::bytes::complete::{tag, tag_no_case, take_until};
8use nom::character::complete::{alphanumeric1, digit1, multispace0, multispace1};
9use nom::combinator::{map, opt};
10use nom::multi::{many0, separated_list0};
11use nom::sequence::{delimited, pair, preceded, terminated, tuple};
12use nom::IResult;
13
14use base::error::ParseSQLErrorKind;
15use base::{CaseWhenExpression, CommonParser, DataType, DisplayUtil, Literal, ParseSQLError, Real};
16
17#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
18pub enum FunctionExpression {
19 Avg(FunctionArgument, bool),
20 Count(FunctionArgument, bool),
21 CountStar,
22 Sum(FunctionArgument, bool),
23 Max(FunctionArgument),
24 Min(FunctionArgument),
25 GroupConcat(FunctionArgument, String),
26 Generic(String, FunctionArguments),
27}
28
29impl FunctionExpression {
30 pub fn parse(i: &str) -> IResult<&str, FunctionExpression, ParseSQLError<&str>> {
31 let delim_group_concat_fx = delimited(tag("("), Self::group_concat_fx, tag(")"));
32 alt((
33 map(tag_no_case("COUNT(*)"), |_| FunctionExpression::CountStar),
34 map(
35 preceded(tag_no_case("COUNT"), FunctionArgument::delim_fx_args),
36 |args| FunctionExpression::Count(args.0.clone(), args.1),
37 ),
38 map(
39 preceded(tag_no_case("SUM"), FunctionArgument::delim_fx_args),
40 |args| FunctionExpression::Sum(args.0.clone(), args.1),
41 ),
42 map(
43 preceded(tag_no_case("AVG"), FunctionArgument::delim_fx_args),
44 |args| FunctionExpression::Avg(args.0.clone(), args.1),
45 ),
46 map(
47 preceded(tag_no_case("MAX"), FunctionArgument::delim_fx_args),
48 |args| FunctionExpression::Max(args.0.clone()),
49 ),
50 map(
51 preceded(tag_no_case("MIN"), FunctionArgument::delim_fx_args),
52 |args| FunctionExpression::Min(args.0.clone()),
53 ),
54 map(
55 preceded(tag_no_case("GROUP_CONCAT"), delim_group_concat_fx),
56 |spec| {
57 let (ref col, ref sep) = spec;
58 let sep = match *sep {
59 None => String::from(","),
61 Some(s) => String::from(s),
62 };
63 FunctionExpression::GroupConcat(FunctionArgument::Column(col.clone()), sep)
64 },
65 ),
66 map(
67 tuple((
68 CommonParser::sql_identifier,
69 multispace0,
70 tag("("),
71 separated_list0(
72 tag(","),
73 delimited(multispace0, FunctionArgument::parse, multispace0),
74 ),
75 tag(")"),
76 )),
77 |tuple| {
78 let (name, _, _, arguments, _) = tuple;
79 FunctionExpression::Generic(
80 name.to_string(),
81 FunctionArguments::from(arguments),
82 )
83 },
84 ),
85 ))(i)
86 }
87
88 fn group_concat_fx_helper(i: &str) -> IResult<&str, &str, ParseSQLError<&str>> {
89 let ws_sep = preceded(multispace0, tag_no_case("separator"));
90 let (remaining_input, sep) = delimited(
91 ws_sep,
92 delimited(tag("'"), opt(alphanumeric1), tag("'")),
93 multispace0,
94 )(i)?;
95
96 Ok((remaining_input, sep.unwrap_or("")))
97 }
98
99 fn group_concat_fx(i: &str) -> IResult<&str, (Column, Option<&str>), ParseSQLError<&str>> {
100 pair(Column::without_alias, opt(Self::group_concat_fx_helper))(i)
101 }
102}
103
104impl Display for FunctionExpression {
105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106 match *self {
107 FunctionExpression::Avg(ref col, d) if d => write!(f, "avg(distinct {})", col),
108 FunctionExpression::Count(ref col, d) if d => write!(f, "count(distinct {})", col),
109 FunctionExpression::Sum(ref col, d) if d => write!(f, "sum(distinct {})", col),
110 FunctionExpression::Avg(ref col, _) => write!(f, "avg({})", col),
111 FunctionExpression::Count(ref col, _) => write!(f, "count({})", col),
112 FunctionExpression::CountStar => write!(f, "count(*)"),
113 FunctionExpression::Sum(ref col, _) => write!(f, "sum({})", col),
114 FunctionExpression::Max(ref col) => write!(f, "max({})", col),
115 FunctionExpression::Min(ref col) => write!(f, "min({})", col),
116 FunctionExpression::GroupConcat(ref col, ref s) => {
117 write!(f, "group_concat({}, {})", col, s)
118 }
119 FunctionExpression::Generic(ref name, ref args) => write!(f, "{}({})", name, args),
120 }
121 }
122}
123
124#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
125pub struct FunctionArguments {
126 pub arguments: Vec<FunctionArgument>,
127}
128
129impl Display for FunctionArguments {
130 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131 write!(
132 f,
133 "{}",
134 self.arguments
135 .iter()
136 .map(|arg| format!("{}", arg))
137 .collect::<Vec<String>>()
138 .join(",")
139 )?;
140 Ok(())
141 }
142}
143
144impl From<Vec<FunctionArgument>> for FunctionArguments {
145 fn from(args: Vec<FunctionArgument>) -> FunctionArguments {
146 FunctionArguments { arguments: args }
147 }
148}
149
150#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
151pub enum FunctionArgument {
152 Column(Column),
153 Conditional(CaseWhenExpression),
154}
155
156impl FunctionArgument {
157 pub fn parse(i: &str) -> IResult<&str, FunctionArgument, ParseSQLError<&str>> {
159 alt((
160 map(CaseWhenExpression::parse, FunctionArgument::Conditional),
161 map(Column::without_alias, FunctionArgument::Column),
162 ))(i)
163 }
164
165 fn function_arguments(i: &str) -> IResult<&str, (FunctionArgument, bool), ParseSQLError<&str>> {
168 let distinct_parser = opt(tuple((tag_no_case("distinct"), multispace1)));
169 let (remaining_input, (distinct, args)) =
170 tuple((distinct_parser, FunctionArgument::parse))(i)?;
171 Ok((remaining_input, (args, distinct.is_some())))
172 }
173
174 pub fn delim_fx_args(i: &str) -> IResult<&str, (FunctionArgument, bool), ParseSQLError<&str>> {
175 delimited(tag("("), Self::function_arguments, tag(")"))(i)
176 }
177}
178
179impl Display for FunctionArgument {
180 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181 match *self {
182 FunctionArgument::Column(ref col) => write!(f, "{}", col)?,
183 FunctionArgument::Conditional(ref e) => {
184 write!(f, "{}", e)?;
185 }
186 }
187 Ok(())
188 }
189}
190
191#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
192pub struct Column {
193 pub name: String,
194 pub alias: Option<String>,
195 pub table: Option<String>,
196 pub function: Option<Box<FunctionExpression>>,
197}
198
199impl Column {
200 pub fn index_col_list(i: &str) -> IResult<&str, Vec<Column>, ParseSQLError<&str>> {
201 many0(map(
202 terminated(
203 CommonParser::index_col_name,
204 opt(CommonParser::ws_sep_comma),
205 ),
206 |e| e.0,
208 ))(i)
209 }
210
211 pub fn field_list(i: &str) -> IResult<&str, Vec<Column>, ParseSQLError<&str>> {
213 many0(terminated(
214 Column::without_alias,
215 opt(CommonParser::ws_sep_comma),
216 ))(i)
217 }
218
219 pub fn without_alias(i: &str) -> IResult<&str, Column, ParseSQLError<&str>> {
221 let table_parser = pair(
222 opt(terminated(CommonParser::sql_identifier, tag("."))),
223 CommonParser::sql_identifier,
224 );
225 alt((
226 map(FunctionExpression::parse, |f| Column {
227 name: format!("{}", f),
228 alias: None,
229 table: None,
230 function: Some(Box::new(f)),
231 }),
232 map(table_parser, |tup| Column {
233 name: tup.1.to_string(),
234 alias: None,
235 table: tup.0.map(|t| t.to_string()),
236 function: None,
237 }),
238 ))(i)
239 }
240
241 pub fn parse(i: &str) -> IResult<&str, Column, ParseSQLError<&str>> {
243 let col_func_no_table = map(
244 pair(FunctionExpression::parse, opt(CommonParser::as_alias)),
245 |tup| Column {
246 name: match tup.1 {
247 None => format!("{}", tup.0),
248 Some(a) => String::from(a),
249 },
250 alias: tup.1.map(String::from),
251 table: None,
252 function: Some(Box::new(tup.0)),
253 },
254 );
255 let col_w_table = map(
256 tuple((
257 opt(terminated(CommonParser::sql_identifier, tag("."))),
258 CommonParser::sql_identifier,
259 opt(CommonParser::as_alias),
260 )),
261 |tup| Column {
262 name: tup.1.to_string(),
263 alias: tup.2.map(String::from),
264 table: tup.0.map(|t| t.to_string()),
265 function: None,
266 },
267 );
268 alt((col_func_no_table, col_w_table))(i)
269 }
270}
271
272impl fmt::Display for Column {
273 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
274 if let Some(ref table) = self.table {
275 write!(
276 f,
277 "{}.{}",
278 DisplayUtil::escape_if_keyword(table),
279 DisplayUtil::escape_if_keyword(&self.name)
280 )?;
281 } else if let Some(ref function) = self.function {
282 write!(f, "{}", *function)?;
283 } else {
284 write!(f, "{}", DisplayUtil::escape_if_keyword(&self.name))?;
285 }
286 if let Some(ref alias) = self.alias {
287 write!(f, " AS {}", DisplayUtil::escape_if_keyword(alias))?;
288 }
289 Ok(())
290 }
291}
292
293impl From<String> for Column {
294 fn from(value: String) -> Self {
295 match value.find('.') {
296 None => Column {
297 name: value,
298 alias: None,
299 table: None,
300 function: None,
301 },
302 Some(i) => Column {
303 name: String::from(&value[i + 1..]),
304 alias: None,
305 table: Some(String::from(&value[0..i])),
306 function: None,
307 },
308 }
309 }
310}
311
312impl<'a> From<&'a str> for Column {
313 fn from(c: &str) -> Column {
314 match c.find('.') {
315 None => Column {
316 name: String::from(c),
317 alias: None,
318 table: None,
319 function: None,
320 },
321 Some(i) => Column {
322 name: String::from(&c[i + 1..]),
323 alias: None,
324 table: Some(String::from(&c[0..i])),
325 function: None,
326 },
327 }
328 }
329}
330
331impl Ord for Column {
332 fn cmp(&self, other: &Column) -> Ordering {
333 if self.table.is_some() && other.table.is_some() {
334 match self.table.cmp(&other.table) {
335 Ordering::Equal => self.name.cmp(&other.name),
336 x => x,
337 }
338 } else {
339 self.name.cmp(&other.name)
340 }
341 }
342}
343
344#[allow(clippy::non_canonical_partial_ord_impl)]
345impl PartialOrd for Column {
346 fn partial_cmp(&self, other: &Column) -> Option<Ordering> {
347 if self.table.is_some() && other.table.is_some() {
348 match self.table.cmp(&other.table) {
349 Ordering::Equal => Some(self.name.cmp(&other.name)),
350 x => Some(x),
351 }
352 } else if self.table.is_none() && other.table.is_none() {
353 Some(self.name.cmp(&other.name))
354 } else {
355 None
356 }
357 }
358}
359
360#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
361pub enum ColumnConstraint {
362 NotNull,
363 Null,
364 CharacterSet(String),
365 Collation(String),
366 DefaultValue(Literal),
367 AutoIncrement,
368 PrimaryKey,
369 Unique,
370 OnUpdate(Literal),
371}
372
373impl ColumnConstraint {
374 pub fn parse(i: &str) -> IResult<&str, Option<ColumnConstraint>, ParseSQLError<&str>> {
375 let not_null = map(
376 delimited(
377 multispace0,
378 tuple((tag_no_case("NOT"), multispace1, tag_no_case("NULL"))),
379 multispace0,
380 ),
381 |_| Some(ColumnConstraint::NotNull),
382 );
383 let null = map(
384 delimited(multispace0, tag_no_case("NULL"), multispace0),
385 |_| Some(ColumnConstraint::Null),
386 );
387 let auto_increment = map(
388 delimited(multispace0, tag_no_case("AUTO_INCREMENT"), multispace0),
389 |_| Some(ColumnConstraint::AutoIncrement),
390 );
391 let primary_key = map(
392 delimited(
393 multispace0,
394 tuple((tag_no_case("PRIMARY"), multispace1, tag_no_case("KEY"))),
395 multispace0,
396 ),
397 |_| Some(ColumnConstraint::PrimaryKey),
398 );
399 let unique = map(
400 delimited(multispace0, tag_no_case("UNIQUE"), multispace0),
401 |_| Some(ColumnConstraint::Unique),
402 );
403 let character_set = map(
404 preceded(
405 delimited(
406 multispace0,
407 tuple((tag_no_case("CHARACTER"), multispace1, tag_no_case("SET"))),
408 multispace1,
409 ),
410 alt((
411 CommonParser::sql_identifier,
412 delimited(tag("'"), CommonParser::sql_identifier, tag("'")),
413 delimited(tag("\""), CommonParser::sql_identifier, tag("\"")),
414 )),
415 ),
416 |cs| {
417 let char_set = cs.to_owned();
418 Some(ColumnConstraint::CharacterSet(char_set))
419 },
420 );
421 let charset = map(
422 preceded(
423 delimited(multispace0, tag_no_case("CHARSET"), multispace1),
424 alt((
425 CommonParser::sql_identifier,
426 delimited(tag("'"), CommonParser::sql_identifier, tag("'")),
427 delimited(tag("\""), CommonParser::sql_identifier, tag("\"")),
428 )),
429 ),
430 |cs| {
431 let char_set = cs.to_owned();
432 Some(ColumnConstraint::CharacterSet(char_set))
433 },
434 );
435 let collate = map(
436 preceded(
437 delimited(multispace0, tag_no_case("COLLATE"), multispace1),
438 alt((
439 CommonParser::sql_identifier,
440 delimited(tag("'"), CommonParser::sql_identifier, tag("'")),
441 delimited(tag("\""), CommonParser::sql_identifier, tag("\"")),
442 )),
443 ),
444 |c| {
445 let collation = c.to_owned();
446 Some(ColumnConstraint::Collation(collation))
447 },
448 );
449 let on_update = map(
452 tuple((
453 tag_no_case("ON"),
454 multispace1,
455 tag_no_case("UPDATE"),
456 multispace1,
457 tag_no_case("CURRENT_TIMESTAMP"),
458 opt(CommonParser::delim_digit),
459 )),
460 |_| Some(ColumnConstraint::OnUpdate(Literal::CurrentTimestamp)),
461 );
462
463 alt((
464 not_null,
465 null,
466 auto_increment,
467 Self::default,
468 primary_key,
469 unique,
470 character_set,
471 charset,
472 collate,
473 on_update,
474 ))(i)
475 }
476
477 fn default(i: &str) -> IResult<&str, Option<ColumnConstraint>, ParseSQLError<&str>> {
478 let (remaining_input, (_, _, _, def, _)) = tuple((
479 multispace0,
480 tag_no_case("DEFAULT"),
481 multispace1,
482 alt((
483 map(delimited(tag("'"), take_until("'"), tag("'")), |s| {
484 Literal::String(String::from(s))
485 }),
486 map(delimited(tag("\""), take_until("\""), tag("\"")), |s| {
487 Literal::String(String::from(s))
488 }),
489 map(tuple((digit1, tag("."), digit1)), |(i, _, f)| {
490 Literal::FixedPoint(Real {
491 integral: i32::from_str(i).unwrap(),
492 fractional: i32::from_str(f).unwrap(),
493 })
494 }),
495 map(tuple((opt(tag("-")), digit1)), |d: (Option<&str>, &str)| {
496 let d_i64: i64 = d.1.parse().unwrap();
497 if d.0.is_some() {
498 Literal::Integer(-d_i64)
499 } else {
500 Literal::Integer(d_i64)
501 }
502 }),
503 map(tag("''"), |_| Literal::String(String::from(""))),
504 map(tag_no_case("NULL"), |_| Literal::Null),
505 map(tag_no_case("FALSE"), |_| Literal::Bool(false)),
506 map(tag_no_case("TRUE"), |_| Literal::Bool(true)),
507 map(
508 tuple((
509 tag_no_case("CURRENT_TIMESTAMP"),
510 opt(CommonParser::delim_digit),
511 )),
512 |_| Literal::CurrentTimestamp,
513 ),
514 )),
515 multispace0,
516 ))(i)?;
517
518 Ok((remaining_input, Some(ColumnConstraint::DefaultValue(def))))
519 }
520}
521
522impl fmt::Display for ColumnConstraint {
523 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
524 match *self {
525 ColumnConstraint::NotNull => write!(f, "NOT NULL"),
526 ColumnConstraint::Null => write!(f, "NULL"),
527 ColumnConstraint::CharacterSet(ref charset) => write!(f, "CHARACTER SET {}", charset),
528 ColumnConstraint::Collation(ref collation) => write!(f, "COLLATE {}", collation),
529 ColumnConstraint::DefaultValue(ref literal) => {
530 write!(f, "DEFAULT {}", literal)
531 }
532 ColumnConstraint::AutoIncrement => write!(f, "AutoIncrement"),
533 ColumnConstraint::PrimaryKey => write!(f, "PRIMARY KEY"),
534 ColumnConstraint::Unique => write!(f, "UNIQUE"),
535 ColumnConstraint::OnUpdate(ref ts) => write!(f, "ON UPDATE CURRENT_TIMESTAMP"),
536 }
537 }
538}
539
540#[derive(Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize)]
541pub enum ColumnPosition {
542 First,
543 After(Column),
544}
545
546impl ColumnPosition {
547 pub fn parse(i: &str) -> IResult<&str, ColumnPosition, ParseSQLError<&str>> {
548 alt((
549 map(
550 tuple((multispace0, tag_no_case("FIRST"), multispace0)),
551 |_| ColumnPosition::First,
552 ),
553 map(
554 tuple((
555 multispace0,
556 tag_no_case("AFTER"),
557 multispace1,
558 CommonParser::sql_identifier,
559 )),
560 |(_, _, _, identifier)| ColumnPosition::After(String::from(identifier).into()),
561 ),
562 ))(i)
563 }
564}
565
566impl Display for ColumnPosition {
567 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
568 match self {
569 ColumnPosition::First => Ok(write!(f, "FIRST")?),
570 ColumnPosition::After(column) => {
571 let column_name = match &column.table {
572 Some(table) => format!("{}.{}", table, &column.name),
573 None => column.name.to_string(),
574 };
575 Ok(write!(f, "AFTER {column_name}")?)
576 }
577 }
578 }
579}
580
581#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
588pub struct ColumnSpecification {
589 pub column: Column,
590 pub data_type: DataType,
591 pub constraints: Vec<ColumnConstraint>,
592 pub comment: Option<String>,
593 pub position: Option<ColumnPosition>,
594}
595
596impl ColumnSpecification {
597 pub fn parse(i: &str) -> IResult<&str, ColumnSpecification, ParseSQLError<&str>> {
598 let mut parser = tuple((
599 Column::without_alias,
600 opt(delimited(
601 multispace1,
602 DataType::type_identifier,
603 multispace0,
604 )),
605 many0(ColumnConstraint::parse),
606 opt(CommonParser::parse_comment),
607 opt(ColumnPosition::parse),
608 opt(CommonParser::ws_sep_comma),
609 ));
610
611 match parser(i) {
612 Ok((input, (column, field_type, constraints, comment, position, _))) => {
613 if field_type.is_none() {
614 let error = ParseSQLError {
615 errors: vec![(i, ParseSQLErrorKind::Context("data type is empty"))],
616 };
617 return Err(nom::Err::Error(error));
618 }
619
620 let sql_type = field_type.unwrap();
621 Ok((
622 input,
623 ColumnSpecification {
624 column,
625 data_type: sql_type,
626 constraints: constraints.into_iter().flatten().collect(),
627 comment,
628 position,
629 },
630 ))
631 }
632 Err(err) => Err(err),
633 }
634 }
635
636 pub fn new(column: Column, sql_type: DataType) -> ColumnSpecification {
637 ColumnSpecification {
638 column,
639 data_type: sql_type,
640 constraints: vec![],
641 comment: None,
642 position: None,
643 }
644 }
645
646 pub fn with_constraints(
647 column: Column,
648 sql_type: DataType,
649 constraints: Vec<ColumnConstraint>,
650 ) -> ColumnSpecification {
651 ColumnSpecification {
652 column,
653 data_type: sql_type,
654 constraints,
655 comment: None,
656 position: None,
657 }
658 }
659}
660
661impl fmt::Display for ColumnSpecification {
662 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
663 write!(
664 f,
665 "{} {}",
666 DisplayUtil::escape_if_keyword(&self.column.name),
667 self.data_type
668 )?;
669 for constraint in self.constraints.iter() {
670 write!(f, " {}", constraint)?;
671 }
672 if let Some(ref comment) = self.comment {
673 write!(f, " COMMENT '{}'", comment)?;
674 }
675 if let Some(ref position) = self.position {
676 write!(f, " {}", position)?;
677 }
678 Ok(())
679 }
680}
681
682#[cfg(test)]
683mod tests {
684 use super::*;
685
686 #[test]
687 fn column_from_str() {
688 let s = "table.col";
689 let c = Column::from(s);
690
691 assert_eq!(
692 c,
693 Column {
694 name: String::from("col"),
695 alias: None,
696 table: Some(String::from("table")),
697 function: None,
698 }
699 );
700 }
701
702 #[test]
703 fn print_function_column() {
704 let c1 = Column {
705 name: "".into(), alias: Some("foo".into()),
707 table: None,
708 function: Some(Box::new(FunctionExpression::CountStar)),
709 };
710 let c2 = Column {
711 name: "".into(), alias: None,
713 table: None,
714 function: Some(Box::new(FunctionExpression::CountStar)),
715 };
716 let c3 = Column {
717 name: "".into(), alias: None,
719 table: None,
720 function: Some(Box::new(FunctionExpression::Sum(
721 FunctionArgument::Column(Column::from("mytab.foo")),
722 false,
723 ))),
724 };
725
726 assert_eq!(format!("{}", c1), "count(*) AS foo");
727 assert_eq!(format!("{}", c2), "count(*)");
728 assert_eq!(format!("{}", c3), "sum(mytab.foo)");
729 }
730
731 #[test]
732 fn simple_generic_function() {
733 let list = [
734 "coalesce(a,b,c)",
735 "coalesce (a,b,c)",
736 "coalesce(a ,b,c)",
737 "coalesce(a, b,c)",
738 ];
739 for part in list.iter() {
740 let res = FunctionExpression::parse(part);
741 let expected = FunctionExpression::Generic(
742 "coalesce".to_string(),
743 FunctionArguments::from(vec![
744 FunctionArgument::Column(Column::from("a")),
745 FunctionArgument::Column(Column::from("b")),
746 FunctionArgument::Column(Column::from("c")),
747 ]),
748 );
749 assert_eq!(res, Ok(("", expected)));
750 }
751 }
752
753 #[test]
754 fn parse_function_expression() {
755 let str1 = "count(*)";
756 let res1 = FunctionExpression::parse(str1);
757 assert!(res1.is_ok());
758 assert_eq!(res1.unwrap().1, FunctionExpression::CountStar);
759
760 let str2 = "max(addr_id)";
761 let res2 = FunctionExpression::parse(str2);
762 let expected = FunctionExpression::Max(FunctionArgument::Column(Column::from("addr_id")));
763 assert_eq!(res2.unwrap().1, expected);
764
765 let str3 = "count(num)";
766 let res3 = FunctionExpression::parse(str3);
767 assert!(res3.is_ok());
768 let expected =
769 FunctionExpression::Count(FunctionArgument::Column(Column::from("num")), false);
770 assert_eq!(res3.unwrap().1, expected);
771 }
772
773 #[test]
774 fn parse_column_constraint() {
775 let str1 = "NOT null ";
776 let res1 = ColumnConstraint::parse(str1);
777 assert!(res1.is_ok());
778 assert_eq!(res1.unwrap().1.unwrap(), ColumnConstraint::NotNull);
779
780 let str2 = "AUTO_INCREMENT";
781 let res2 = ColumnConstraint::parse(str2);
782 assert!(res2.is_ok());
783 assert_eq!(res2.unwrap().1.unwrap(), ColumnConstraint::AutoIncrement);
784
785 let str3 = "CHARACTER SET utf8";
786 let res3 = ColumnConstraint::parse(str3);
787 assert!(res3.is_ok());
788 assert_eq!(
789 res3.unwrap().1.unwrap(),
790 ColumnConstraint::CharacterSet("utf8".to_string())
791 );
792 }
793
794 #[test]
795 fn parse_column_position() {
796 let parts = [
797 "FIRST",
798 " FIRST",
799 " FIRST ",
800 "AFTER foo",
801 " AFTER foo ",
802 " AFTER foo ",
803 ];
804 let positions = vec![
805 ColumnPosition::First,
806 ColumnPosition::First,
807 ColumnPosition::First,
808 ColumnPosition::After("foo".into()),
809 ColumnPosition::After("foo".into()),
810 ColumnPosition::After("foo".into()),
811 ];
812 for i in 0..parts.len() {
813 let res = ColumnPosition::parse(parts[i]);
814 assert!(res.is_ok());
815 assert_eq!(res.unwrap().1, positions[i])
816 }
817 }
818
819 #[test]
820 fn parse_column() {
821 let str1 = "some_column VARCHAR(255) FIRST;";
822 let res1 = ColumnSpecification::parse(str1);
823 let expected = ColumnSpecification {
824 column: "some_column".into(),
825 data_type: DataType::Varchar(255),
826 constraints: vec![],
827 comment: None,
828 position: Some(ColumnPosition::First),
829 };
830 assert!(res1.is_ok());
831 assert_eq!(res1.unwrap().1, expected);
832
833 let str2 = "another_column int not null auto_increment primary key After age;";
834 let res2 = ColumnSpecification::parse(str2);
835 let expected = ColumnSpecification {
836 column: "another_column".into(),
837 data_type: DataType::Int(32),
838 constraints: vec![
839 ColumnConstraint::NotNull,
840 ColumnConstraint::AutoIncrement,
841 ColumnConstraint::PrimaryKey,
842 ],
843 comment: None,
844 position: Some(ColumnPosition::After("age".into())),
845 };
846 assert!(res2.is_ok());
847 assert_eq!(res2.unwrap().1, expected);
848 }
849}