From cea19d466668754cb2eeb72253c603e0ca5e5f6d Mon Sep 17 00:00:00 2001 From: myyrakle Date: Tue, 30 Jul 2024 00:04:23 +0900 Subject: [PATCH] =?UTF-8?q?[#142]=20parse=5Fjoin=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ast/dml/parts/join.rs | 8 ++- src/parser/test/select.rs | 120 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/src/ast/dml/parts/join.rs b/src/ast/dml/parts/join.rs index 2d8d3bdb..43a892f0 100644 --- a/src/ast/dml/parts/join.rs +++ b/src/ast/dml/parts/join.rs @@ -2,7 +2,7 @@ use crate::ast::types::{SQLExpression, TableName}; use serde::{Deserialize, Serialize}; -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Default)] pub struct JoinClause { pub join_type: JoinType, pub right: TableName, @@ -19,3 +19,9 @@ pub enum JoinType { RightOuterJoin, FullOuterJoin, } + +impl Default for JoinType { + fn default() -> Self { + JoinType::InnerJoin + } +} diff --git a/src/parser/test/select.rs b/src/parser/test/select.rs index e067e0de..2600c248 100644 --- a/src/parser/test/select.rs +++ b/src/parser/test/select.rs @@ -2046,3 +2046,123 @@ fn test_parse_group_by_item() { } } } + +#[test] +fn test_parse_join() { + struct TestCase { + name: String, + input: Vec, + expected: JoinClause, + want_error: bool, + } + + let test_cases = vec![ + TestCase { + name: "foo.bar as fb ON p.id = fb.id".into(), + input: vec![ + Token::Identifier("foo".into()), + Token::Period, + Token::Identifier("bar".into()), + Token::As, + Token::Identifier("fb".into()), + Token::On, + Token::Identifier("p".into()), + Token::Period, + Token::Identifier("id".into()), + Token::Operator(OperatorToken::Eq), + Token::Identifier("fb".into()), + Token::Period, + Token::Identifier("id".into()), + ], + expected: JoinClause { + join_type: JoinType::InnerJoin, + right: TableName { + database_name: Some("foo".into()), + table_name: "bar".into(), + }, + right_alias: Some("fb".into()), + on: BinaryOperatorExpression { + operator: BinaryOperator::Eq, + lhs: SelectColumn::new(Some("p".into()), "id".into()).into(), + rhs: SelectColumn::new(Some("fb".into()), "id".into()).into(), + } + .into(), + }, + want_error: false, + }, + TestCase { + name: "foo.bar ON p.id = fb.id".into(), + input: vec![ + Token::Identifier("foo".into()), + Token::Period, + Token::Identifier("bar".into()), + Token::On, + Token::Identifier("p".into()), + Token::Period, + Token::Identifier("id".into()), + Token::Operator(OperatorToken::Eq), + Token::Identifier("fb".into()), + Token::Period, + Token::Identifier("id".into()), + ], + expected: JoinClause { + join_type: JoinType::InnerJoin, + right: TableName { + database_name: Some("foo".into()), + table_name: "bar".into(), + }, + right_alias: None, + on: BinaryOperatorExpression { + operator: BinaryOperator::Eq, + lhs: SelectColumn::new(Some("p".into()), "id".into()).into(), + rhs: SelectColumn::new(Some("fb".into()), "id".into()).into(), + } + .into(), + }, + want_error: false, + }, + TestCase { + name: "foo.bar".into(), + input: vec![ + Token::Identifier("foo".into()), + Token::Period, + Token::Identifier("bar".into()), + ], + expected: JoinClause { + join_type: JoinType::InnerJoin, + right: TableName { + database_name: Some("foo".into()), + table_name: "bar".into(), + }, + right_alias: None, + on: None, + }, + want_error: false, + }, + TestCase { + name: "실패: 빈 토큰".into(), + input: vec![], + expected: Default::default(), + want_error: true, + }, + ]; + + for t in test_cases { + let mut parser = Parser::new(t.input); + + let got = parser.parse_join(JoinType::InnerJoin, Default::default()); + + assert_eq!( + got.is_err(), + t.want_error, + "{}: want_error: {}, error: {:?}", + t.name, + t.want_error, + got.err() + ); + + if let Ok(statements) = got { + assert_eq!(statements, t.expected, "TC: {}", t.name); + } + } +}