From b99ac59df43fff6df3e066e617253aca8d97e76f Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Thu, 21 Dec 2023 18:15:56 +0300 Subject: [PATCH] fix: Minimal order by tests --- server/src/lang/ast/sql.rs | 25 +++++- server/src/lang/parser.rs | 15 ++-- server/src/lang/serializer.rs | 21 +++-- server/src/lang/tests/sql/select_order.rs | 102 +++++++++++++++++++++- 4 files changed, 141 insertions(+), 22 deletions(-) diff --git a/server/src/lang/ast/sql.rs b/server/src/lang/ast/sql.rs index b7a84ec2..c0894979 100644 --- a/server/src/lang/ast/sql.rs +++ b/server/src/lang/ast/sql.rs @@ -45,6 +45,25 @@ pub enum SqlProjection { Expr { expr: SqlExpr, alias: Option }, } + +#[derive(Debug, Eq, PartialEq)] +pub struct SqlLimitClause { + pub limit: SqlExpr, + pub offset: Option +} + +#[derive(Debug, Eq, PartialEq)] +pub struct SqlOrderByClause { + pub expr: SqlExpr, + pub ordering: SqlOrdering +} + +#[derive(Debug, Eq, PartialEq)] +pub struct SqlSelectCompound { + pub operator: SqlCompoundOperator, + pub core: SqlSelectCore +} + #[derive(Debug, Eq, PartialEq)] pub struct SqlJoin { pub join_type: SqlJoinType, @@ -80,7 +99,7 @@ pub struct SqlSelectCore { #[derive(Debug, Eq, PartialEq)] pub struct SqlSelect { pub core: SqlSelectCore, - pub compound: Vec<(SqlCompoundOperator, SqlSelectCore)>, - pub order_by: Option>, - pub limit: Option<(SqlExpr, Option)>, + pub compound: Vec, + pub order_by: Option>, + pub limit: Option, } diff --git a/server/src/lang/parser.rs b/server/src/lang/parser.rs index 0e4966c4..43c8952f 100644 --- a/server/src/lang/parser.rs +++ b/server/src/lang/parser.rs @@ -1,7 +1,7 @@ use super::ast::expr::{Expr, ExprId}; use super::ast::sql::{ SqlCollectionSubquery, SqlCompoundOperator, SqlDistinct, SqlExpr, SqlJoin, SqlJoinType, - SqlOrdering, SqlProjection, SqlSelect, SqlSelectCore, + SqlOrdering, SqlProjection, SqlSelect, SqlSelectCore, SqlOrderByClause, SqlSelectCompound, SqlLimitClause, }; use super::ast::stmt::{Stmt, StmtId}; use super::ast::{Literal, ParserArena}; @@ -481,7 +481,7 @@ impl<'a> Parser<'a> { return self.call(); } let core = self.sql_select_core()?; - let mut compounds: Vec<(SqlCompoundOperator, SqlSelectCore)> = vec![]; + let mut compounds: Vec = vec![]; while self.match_next_one_of(&[skw!(Union), skw!(Intersect), skw!(Except)]) { let op = self.peek_bw(1); let compound_op = if op.tok_type == skw!(Union) && self.match_next(skw!(All)) { @@ -497,20 +497,21 @@ impl<'a> Parser<'a> { } }; let secondary_core = self.sql_select_core()?; - compounds.push((compound_op, secondary_core)) + compounds.push(SqlSelectCompound { operator: compound_op, core: secondary_core }) } let order_by = if self.match_next(skw!(Order)) { self.expected(skw!(By))?; - let mut ordering: Vec<(SqlExpr, SqlOrdering)> = vec![]; + let mut ordering: Vec = vec![]; loop { let order_expr = self.expression()?; let order = if self.match_next(skw!(Desc)) { Some(SqlOrdering::Desc) } else { + self.match_next(skw!(Asc)); Some(SqlOrdering::Asc) }; - ordering.push((SqlExpr::Default(order_expr), order.unwrap())); + ordering.push(SqlOrderByClause { expr: SqlExpr::Default(order_expr), ordering: order.unwrap() }); if !self.match_next(sym!(Comma)) { break; } @@ -532,9 +533,9 @@ impl<'a> Parser<'a> { }; if second_expr.is_some() && reverse { - Some((second_expr.unwrap(), Some(first_expr))) + Some(SqlLimitClause { limit: second_expr.unwrap(), offset: Some(first_expr) }) } else { - Some((first_expr, second_expr)) + Some(SqlLimitClause { limit: first_expr, offset: second_expr }) } } else { None diff --git a/server/src/lang/serializer.rs b/server/src/lang/serializer.rs index 85e5128b..b94019d8 100644 --- a/server/src/lang/serializer.rs +++ b/server/src/lang/serializer.rs @@ -9,7 +9,7 @@ use super::{ }, parser::Program, }; -use std::{borrow::BorrowMut, rc::Rc}; +use std::rc::Rc; impl Program { pub fn to_json(&self) -> Value { @@ -28,36 +28,35 @@ impl ToString for Program { impl ImmutableVisitor for Program { fn visit_select(&self, select: &SqlSelect) -> Result { - let order_by: Value = select + let order_by: Option = select .order_by .as_ref() .map(|x| { x.iter() .map(|order| { - let expr = if let SqlExpr::Default(eidx) = order.0 { + let expr = if let SqlExpr::Default(eidx) = order.expr { self.visit_expr(eidx).unwrap() } else { panic!("Not implemented"); }; let val = json!({ "expr": expr, - "ordering": format!("{:?}", order.1), + "ordering": format!("{:?}", order.ordering), }); val }) .collect() - }) - .unwrap(); + }); let limit: Option = select.limit.as_ref().map(|x| { - let limit_part = if let SqlExpr::Default(eidx) = x.0 { + let limit_part = if let SqlExpr::Default(eidx) = x.limit { self.visit_expr(eidx).unwrap() } else { panic!("Not implemented"); }; - let offset_part = if x.1.is_some() { - if let SqlExpr::Default(eidx) = x.1.as_ref().unwrap() { + let offset_part = if x.offset.is_some() { + if let SqlExpr::Default(eidx) = x.offset.as_ref().unwrap() { self.visit_expr(*eidx).unwrap() } else { panic!("Not implemented"); @@ -67,8 +66,8 @@ impl ImmutableVisitor for Program { }; json!({ - "limit_part": limit_part, - "offset_part": offset_part + "limit": limit_part, + "offset": offset_part }) }); /* diff --git a/server/src/lang/tests/sql/select_order.rs b/server/src/lang/tests/sql/select_order.rs index d355506e..f9e6f850 100644 --- a/server/src/lang/tests/sql/select_order.rs +++ b/server/src/lang/tests/sql/select_order.rs @@ -9,7 +9,107 @@ use crate::assert_parsing; #[cfg(test)] assert_parsing! { - multiple_order: { + no_order: { + "SELECT * from users;" => { + "type": "Stmt::Program", + "body": [ + { + "type": "Stmt::Expression", + "expr": { + "type": "Expr::Select", + "value": { + "limit": null, + "order_by": null + } + } + } + ] + } + }, + single_order: { + "SELECT * from users order by id desc;" => { + "type": "Stmt::Program", + "body": [ + { + "type": "Stmt::Expression", + "expr": { + "type": "Expr::Select", + "value": { + "limit": null, + "order_by": [{ + "expr": { + "name": "id", + "type": "Expr::Variable" + }, + "ordering": "Desc" + }] + } + } + } + ] + } + }, + multiple_order_0: { + "SELECT * from users order by id, name;" => { + "type": "Stmt::Program", + "body": [ + { + "type": "Stmt::Expression", + "expr": { + "type": "Expr::Select", + "value": { + "limit": null, + "order_by": [{ + "expr": { + "name": "id", + "type": "Expr::Variable" + }, + "ordering": "Asc" + }, + { + "expr": { + "name": "name", + "type": "Expr::Variable" + }, + "ordering": "Asc" + }] + } + } + } + ] + } + }, + multiple_order_1: { + "SELECT * from users order by id asc, name;" => { + "type": "Stmt::Program", + "body": [ + { + "type": "Stmt::Expression", + "expr": { + "type": "Expr::Select", + "value": { + "limit": null, + "order_by": [{ + "expr": { + "name": "id", + "type": "Expr::Variable" + }, + "ordering": "Asc" + }, + { + "expr": { + "name": "name", + "type": "Expr::Variable" + }, + "ordering": "Asc" + }] + } + } + } + ] + } + }, + multiple_order_2: { "SELECT * from users order by id, name desc;" => { "type": "Stmt::Program", "body": [