diff --git a/server/src/lang/ast/sql.rs b/server/src/lang/ast/sql.rs index 0aa93db3..7a976bb0 100644 --- a/server/src/lang/ast/sql.rs +++ b/server/src/lang/ast/sql.rs @@ -45,23 +45,22 @@ pub enum SqlProjection { Expr { expr: SqlExpr, alias: Option }, } - #[derive(Debug, Eq, PartialEq)] pub struct SqlLimitClause { pub count: SqlExpr, - pub offset: Option + pub offset: Option, } #[derive(Debug, Eq, PartialEq)] pub struct SqlOrderByClause { pub expr: SqlExpr, - pub ordering: SqlOrdering + pub ordering: SqlOrdering, } #[derive(Debug, Eq, PartialEq)] pub struct SqlSelectCompound { pub operator: SqlCompoundOperator, - pub core: SqlSelectCore + pub core: SqlSelectCore, } #[derive(Debug, Eq, PartialEq)] diff --git a/server/src/lang/parser.rs b/server/src/lang/parser.rs index beda4745..a051896b 100644 --- a/server/src/lang/parser.rs +++ b/server/src/lang/parser.rs @@ -1,7 +1,8 @@ use super::ast::expr::{Expr, ExprId}; use super::ast::sql::{ SqlCollectionSubquery, SqlCompoundOperator, SqlDistinct, SqlExpr, SqlJoin, SqlJoinType, - SqlOrdering, SqlProjection, SqlSelect, SqlSelectCore, SqlOrderByClause, SqlSelectCompound, SqlLimitClause, + SqlLimitClause, SqlOrderByClause, SqlOrdering, SqlProjection, SqlSelect, SqlSelectCompound, + SqlSelectCore, }; use super::ast::stmt::{Stmt, StmtId}; use super::ast::{Literal, ParserArena}; @@ -497,7 +498,10 @@ impl<'a> Parser<'a> { } }; let secondary_core = self.sql_select_core()?; - compounds.push(SqlSelectCompound { operator: compound_op, core: secondary_core }) + compounds.push(SqlSelectCompound { + operator: compound_op, + core: secondary_core, + }) } let order_by = if self.match_next(skw!(Order)) { self.expected(skw!(By))?; @@ -511,7 +515,10 @@ impl<'a> Parser<'a> { self.match_next(skw!(Asc)); Some(SqlOrdering::Asc) }; - ordering.push(SqlOrderByClause { expr: SqlExpr::Default(order_expr), ordering: order.unwrap() }); + ordering.push(SqlOrderByClause { + expr: SqlExpr::Default(order_expr), + ordering: order.unwrap(), + }); if !self.match_next(sym!(Comma)) { break; } @@ -533,9 +540,15 @@ impl<'a> Parser<'a> { }; if second_expr.is_some() && reverse { - Some(SqlLimitClause { count: second_expr.unwrap(), offset: Some(first_expr) }) + Some(SqlLimitClause { + count: second_expr.unwrap(), + offset: Some(first_expr), + }) } else { - Some(SqlLimitClause { count: first_expr, offset: second_expr }) + Some(SqlLimitClause { + count: first_expr, + offset: second_expr, + }) } } else { None diff --git a/server/src/lang/serializer.rs b/server/src/lang/serializer.rs index f3afde62..e31512ff 100644 --- a/server/src/lang/serializer.rs +++ b/server/src/lang/serializer.rs @@ -3,7 +3,7 @@ use serde_json::{json, Value}; use super::{ ast::{ expr::{Expr, ExprId}, - sql::{SqlExpr, SqlSelect}, + sql::{SqlExpr, SqlProjection, SqlSelect, SqlSelectCore}, stmt::{Stmt, StmtId}, ImmutableVisitor, }, @@ -28,25 +28,22 @@ impl ToString for Program { impl ImmutableVisitor for Program { fn visit_select(&self, select: &SqlSelect) -> Result { - let order_by: Option = select - .order_by - .as_ref() - .map(|x| { - x.iter() - .map(|order| { - 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.ordering), - }); - val - }) - .collect() - }); + let order_by: Option = select.order_by.as_ref().map(|x| { + x.iter() + .map(|order| { + 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.ordering), + }); + val + }) + .collect() + }); let limit: Option = select.limit.as_ref().map(|x| { let count_part = if let SqlExpr::Default(eidx) = x.count { @@ -70,6 +67,34 @@ impl ImmutableVisitor for Program { "offset": offset_part }) }); + + let serialize_sql_core = + |core: &SqlSelectCore| { + let core_projection: Value = core.projection.iter().map(|x| { + match x { + SqlProjection::All { collection } => { + json!({ + "collection": collection.as_ref().map(|token| token.lexeme.to_owned()) + }) + }, + SqlProjection::Expr { expr, alias } => { + json!({ + "expr": if let SqlExpr::Default(eidx) = expr { + self.visit_expr(*eidx).unwrap() + } else { + panic!("Not implemented"); + }, + "alias": alias.as_ref().map(|token| token.lexeme.to_owned()) + }) + } + } + }).collect(); + + json!({ + "projection": core_projection + }) + }; + /* { pub core: SqlSelectCore, @@ -79,6 +104,7 @@ impl ImmutableVisitor for Program { } */ Ok(json!({ + "core": serialize_sql_core(&select.core), "order_by": order_by, "limit": limit })) diff --git a/server/src/lang/tests/sql/mod.rs b/server/src/lang/tests/sql/mod.rs index f17e470f..40571c0a 100644 --- a/server/src/lang/tests/sql/mod.rs +++ b/server/src/lang/tests/sql/mod.rs @@ -1,2 +1,3 @@ +pub mod select_limit; pub mod select_order; -pub mod select_limit; \ No newline at end of file +pub mod select_projection; diff --git a/server/src/lang/tests/sql/select_limit.rs b/server/src/lang/tests/sql/select_limit.rs index 11f97d5d..defebc00 100644 --- a/server/src/lang/tests/sql/select_limit.rs +++ b/server/src/lang/tests/sql/select_limit.rs @@ -18,6 +18,11 @@ assert_parsing! { "expr": { "type": "Expr::Select", "value": { + "core": { + "projection": [{ + "collection": null + }] + }, "limit": { "count": { "type": "Expr::Literal", @@ -42,6 +47,11 @@ assert_parsing! { "expr": { "type": "Expr::Select", "value": { + "core": { + "projection": [{ + "collection": null + }] + }, "limit": { "count": { "type": "Expr::Literal", @@ -70,6 +80,11 @@ assert_parsing! { "expr": { "type": "Expr::Select", "value": { + "core": { + "projection": [{ + "collection": null + }] + }, "limit": { "count": { "type": "Expr::Literal", diff --git a/server/src/lang/tests/sql/select_order.rs b/server/src/lang/tests/sql/select_order.rs index f9e6f850..8f909b6f 100644 --- a/server/src/lang/tests/sql/select_order.rs +++ b/server/src/lang/tests/sql/select_order.rs @@ -18,6 +18,11 @@ assert_parsing! { "expr": { "type": "Expr::Select", "value": { + "core": { + "projection": [{ + "collection": null + }] + }, "limit": null, "order_by": null } @@ -35,6 +40,11 @@ assert_parsing! { "expr": { "type": "Expr::Select", "value": { + "core": { + "projection": [{ + "collection": null + }] + }, "limit": null, "order_by": [{ "expr": { @@ -58,6 +68,11 @@ assert_parsing! { "expr": { "type": "Expr::Select", "value": { + "core": { + "projection": [{ + "collection": null + }] + }, "limit": null, "order_by": [{ "expr": { @@ -88,6 +103,11 @@ assert_parsing! { "expr": { "type": "Expr::Select", "value": { + "core": { + "projection": [{ + "collection": null + }] + }, "limit": null, "order_by": [{ "expr": { @@ -118,6 +138,11 @@ assert_parsing! { "expr": { "type": "Expr::Select", "value": { + "core": { + "projection": [{ + "collection": null + }] + }, "limit": null, "order_by": [{ "expr": { diff --git a/server/src/lang/tests/sql/select_projection.rs b/server/src/lang/tests/sql/select_projection.rs new file mode 100644 index 00000000..6d51ab0f --- /dev/null +++ b/server/src/lang/tests/sql/select_projection.rs @@ -0,0 +1,94 @@ +#[cfg(test)] +use crate::lang::tests::helpers::compare_parsed_to_expected; + +#[cfg(test)] +use serde_json::json; + +#[cfg(test)] +use crate::assert_parsing; + +#[cfg(test)] +assert_parsing! { + plain: { + "SELECT * from users;" => { + "type": "Stmt::Program", + "body": [ + { + "type": "Stmt::Expression", + "expr": { + "type": "Expr::Select", + "value": { + "core": { + "projection": [{ + "collection": null + }] + }, + "limit": null, + "order_by": null + } + } + } + ] + } + }, + + collection: { + "SELECT users.* from users;" => { + "type": "Stmt::Program", + "body": [ + { + "type": "Stmt::Expression", + "expr": { + "type": "Expr::Select", + "value": { + "core": { + "projection": [{ + "collection": "users" + }] + }, + "limit": null, + "order_by": null + } + } + } + ] + } + }, + mixed_0: { + "SELECT id, users.name as username from users;" => { + "type": "Stmt::Program", + "body": [ + { + "type": "Stmt::Expression", + "expr": { + "type": "Expr::Select", + "value": { + "core": { + "projection": [{ + "expr": { + "type": "Expr::Variable", + "name": "id" + }, + "alias": null + }, + { + "expr": { + "type": "Expr::Get", + "object": { + "type": "Expr::Variable", + "name": "users" + }, + "name": "name" + }, + "alias": "username" + }] + }, + "limit": null, + "order_by": null + } + } + } + ] + } + } +}