From 8d10d866602e25f078801e07158bea97fdde0506 Mon Sep 17 00:00:00 2001 From: myyrakle Date: Sun, 28 Jul 2024 23:44:50 +0900 Subject: [PATCH] =?UTF-8?q?[#142]=20group=20by=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parser/implements/dml/select.rs | 7 +- src/parser/test/select.rs | 151 +++++++++++++++++++++++++++- 2 files changed, 154 insertions(+), 4 deletions(-) diff --git a/src/parser/implements/dml/select.rs b/src/parser/implements/dml/select.rs index e13bf44..f3c31db 100644 --- a/src/parser/implements/dml/select.rs +++ b/src/parser/implements/dml/select.rs @@ -92,10 +92,11 @@ impl Parser { } } _ => { - return Err(ParsingError::wrap(format!( - "E0304 expected 'FROM' clause. but your input word is '{:?}'", + // From이어야만 이전 루프를 탈출하기 때문에, From이 아닐 수 없음 + unreachable!( + "expected 'FROM' clause. but your input word is '{:?}'", current_token - ))); + ); } } diff --git a/src/parser/test/select.rs b/src/parser/test/select.rs index 06fcb7b..aaead41 100644 --- a/src/parser/test/select.rs +++ b/src/parser/test/select.rs @@ -1,6 +1,7 @@ #![cfg(test)] use crate::ast::dml::expressions::binary::BinaryOperatorExpression; +use crate::ast::dml::expressions::call::CallExpression; use crate::ast::dml::expressions::operators::BinaryOperator; use crate::ast::dml::parts::_where::WhereClause; use crate::ast::dml::parts::group_by::GroupByItem; @@ -8,7 +9,9 @@ use crate::ast::dml::parts::join::{JoinClause, JoinType}; use crate::ast::dml::parts::order_by::{OrderByItem, OrderByNulls, OrderByType}; use crate::ast::dml::parts::select_item::{SelectItem, SelectWildCard}; use crate::ast::dml::select::SelectQuery; -use crate::ast::types::{SQLExpression, SelectColumn, TableName}; +use crate::ast::types::{ + AggregateFunction, BuiltInFunction, Function, SQLExpression, SelectColumn, TableName, +}; use crate::lexer::predule::OperatorToken; use crate::lexer::tokens::Token; use crate::parser::predule::Parser; @@ -1078,6 +1081,81 @@ fn test_select_query() { .build(), want_error: false, }, + TestCase { + name: r#" + SELECT + p.content as post + FROM post as p + GROUP BY SELECT; + "# + .into(), + input: vec![ + Token::Select, + Token::Identifier("p".into()), + Token::Period, + Token::Identifier("content".into()), + Token::As, + Token::Identifier("post".into()), + Token::From, + Token::Identifier("post".into()), + Token::As, + Token::Identifier("p".into()), + Token::Group, + Token::By, + Token::Select, + Token::SemiColon, + ], + expected: Default::default(), + want_error: true, + }, + TestCase { + name: r#" + SELECT + p.content as post + FROM post as p + GROUP BY p.content + LIMIT 5; + "# + .into(), + input: vec![ + Token::Select, + Token::Identifier("p".into()), + Token::Period, + Token::Identifier("content".into()), + Token::As, + Token::Identifier("post".into()), + Token::From, + Token::Identifier("post".into()), + Token::As, + Token::Identifier("p".into()), + Token::Group, + Token::By, + Token::Identifier("p".into()), + Token::Period, + Token::Identifier("content".into()), + Token::Limit, + Token::Integer(5), + Token::SemiColon, + ], + expected: SelectQuery::builder() + .add_select_item( + SelectItem::builder() + .set_item(SelectColumn::new(Some("p".into()), "content".into()).into()) + .set_alias("post".into()) + .build(), + ) + .set_from_table(TableName { + database_name: None, + table_name: "post".into(), + }) + .set_from_alias("p".into()) + .add_group_by(GroupByItem { + item: SelectColumn::new(Some("p".into()), "content".into()), + }) + .set_limit(5) + .build(), + want_error: false, + }, TestCase { name: r#" SELECT @@ -1168,6 +1246,46 @@ fn test_select_query() { expected: Default::default(), want_error: true, }, + TestCase { + name: r#" + SELECT + COUNT(p.a) + FROM post as p + "# + .into(), + input: vec![ + Token::Select, + Token::Identifier("count".into()), + Token::LeftParentheses, + Token::Identifier("p".into()), + Token::Period, + Token::Identifier("a".into()), + Token::RightParentheses, + Token::From, + Token::Identifier("post".into()), + Token::As, + Token::Identifier("p".into()), + ], + expected: SelectQuery::builder() + .add_select_item( + SelectItem::builder() + .set_item(SQLExpression::FunctionCall(CallExpression { + function: Function::BuiltIn(BuiltInFunction::Aggregate( + AggregateFunction::Count, + )), + arguments: vec![SelectColumn::new(Some("p".into()), "a".into()).into()], + })) + .build(), + ) + .set_has_aggregate(true) + .set_from_table(TableName { + database_name: None, + table_name: "post".into(), + }) + .set_from_alias("p".into()) + .build(), + want_error: false, + }, TestCase { name: r#" SELECT @@ -1444,6 +1562,37 @@ fn test_select_query() { .build(), want_error: false, }, + TestCase { + name: r#" + 집계함수가 사용된 컬럼이 group by에 있다면 오류 + + SELECT + COUNT(p.a) + FROM post as p + GROUP BY p.a + "# + .into(), + input: vec![ + Token::Select, + Token::Identifier("count".into()), + Token::LeftParentheses, + Token::Identifier("p".into()), + Token::Period, + Token::Identifier("a".into()), + Token::RightParentheses, + Token::From, + Token::Identifier("post".into()), + Token::As, + Token::Identifier("p".into()), + Token::Group, + Token::By, + Token::Identifier("p".into()), + Token::Period, + Token::Identifier("a".into()), + ], + expected: Default::default(), + want_error: true, + }, ]; for t in test_cases {