From d0eb0f08a90f4243e84160c364507c36265e6f84 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Fri, 22 Dec 2023 17:50:07 +0300 Subject: [PATCH] fix: Refactored Serializer --- server/src/lang/serializer.rs | 134 ++++++++++++------ server/src/lang/tests/helpers.rs | 6 +- server/src/lang/tests/sql/mod.rs | 1 + server/src/lang/tests/sql/select_from.rs | 45 ++++++ server/src/lang/tests/sql/select_limit.rs | 30 ++++ server/src/lang/tests/sql/select_order.rs | 50 +++++++ .../src/lang/tests/sql/select_projection.rs | 58 +++++++- server/src/runtime/mod.rs | 10 +- 8 files changed, 286 insertions(+), 48 deletions(-) create mode 100644 server/src/lang/tests/sql/select_from.rs diff --git a/server/src/lang/serializer.rs b/server/src/lang/serializer.rs index 6a4936c8..5aea6b1e 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, SqlProjection, SqlSelect, SqlSelectCore}, + sql::{SqlCollectionSubquery, SqlExpr, SqlProjection, SqlSelect, SqlSelectCore}, stmt::{Stmt, StmtId}, ImmutableVisitor, }, @@ -11,60 +11,112 @@ use super::{ }; use std::rc::Rc; -impl Program { +pub struct ProgramSerializer<'a> { + pub program: &'a Program, +} + +impl<'a> ProgramSerializer<'a> { + pub fn new(program: &'a Program) -> ProgramSerializer<'a> { + ProgramSerializer { program } + } pub fn to_json(&self) -> Value { - json!(self.visit_stmt(self.root).unwrap()) + json!(self.visit_stmt(self.program.root).unwrap()) } pub fn serialize(&self) -> String { serde_json::to_string_pretty(&self.to_json()).unwrap() } } -impl ToString for Program { +impl<'a> ToString for ProgramSerializer<'a> { fn to_string(&self) -> String { self.serialize().clone() } } -impl ImmutableVisitor for Program { - fn visit_select(&self, select: &SqlSelect) -> Result { - let serialize_sql_expr = |sql_expr: &SqlExpr| { - if let SqlExpr::Default(eidx) = sql_expr { - self.visit_expr(*eidx).unwrap() - } else { - panic!("Not implemented"); - } - }; +impl<'a> ProgramSerializer<'a> { + fn serialize_sql_expr(&self, sql_expr: &SqlExpr) -> Value { + if let SqlExpr::Default(eidx) = sql_expr { + self.visit_expr(*eidx).unwrap() + } else { + panic!("Not implemented"); + } + } - 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": serialize_sql_expr(&expr), - "alias": alias.as_ref().map(|token| token.lexeme.to_owned()) - }) - } - }) - .collect(); - json!({ - "projection": core_projection + fn serialize_sql_select_core(&self, core: &SqlSelectCore) -> Value { + let core_projection: Value = core + .projection + .iter() + .map(|x| match x { + SqlProjection::All { collection } => { + json!({ + "type": "All", + "collection": collection.as_ref().map(|token| token.lexeme.to_owned()) + }) + } + SqlProjection::Expr { expr, alias } => { + json!({ + "type": "Expr", + "expr": self.serialize_sql_expr(&expr), + "alias": alias.as_ref().map(|token| token.lexeme.to_owned()) + }) + } }) - }; + .collect(); + + json!({ + "projection": core_projection, + "from": core.from.as_ref().map(|x| self.serialize_sql_subquery(&x)) + }) + } + + fn serialize_sql_subquery(&self, subquery: &SqlCollectionSubquery) -> Value { + match subquery { + SqlCollectionSubquery::Collection { + namespace, + name, + alias, + } => { + json!({ + "type": "Collection", + "namespace": namespace.as_ref().map(|token| token.lexeme.to_owned()), + "name": name.lexeme, + "alias": alias.as_ref().map(|token| token.lexeme.to_owned()) + }) + } + SqlCollectionSubquery::Group(groups) => { + let subqueries: Value = groups + .iter() + .map(|x| self.serialize_sql_subquery(x)) + .collect(); + json!({ + "type": "Group", + "subqueries": subqueries + }) + } + SqlCollectionSubquery::Select { expr, alias } => { + json!({ + "type": "Select", + "expr": self.visit_expr(*expr), + "alias": alias.as_ref().map(|token| token.lexeme.to_owned()) + }) + } + SqlCollectionSubquery::Join(_, _) => { + json!({}) + } + } + } +} + +impl<'a> ImmutableVisitor for ProgramSerializer<'a> { + fn visit_select(&self, select: &SqlSelect) -> Result { + let core = self.serialize_sql_select_core(&select.core); let compound: Value = select .compound .iter() .map(|x| { json!({ - "core": serialize_sql_core(&x.core), + "core": self.serialize_sql_select_core(&x.core), "operator": format!("{:?}", x.operator), }) }) @@ -73,7 +125,7 @@ impl ImmutableVisitor for Program { let order_by: Option = select.order_by.as_ref().map(|x| { x.iter() .map(|order| { - let expr = serialize_sql_expr(&order.expr); + let expr = self.serialize_sql_expr(&order.expr); let val = json!({ "expr": expr, "ordering": format!("{:?}", order.ordering), @@ -84,10 +136,10 @@ impl ImmutableVisitor for Program { }); let limit: Option = select.limit.as_ref().map(|x| { - let count_part = serialize_sql_expr(&x.count); + let count_part = self.serialize_sql_expr(&x.count); let offset_part = if x.offset.is_some() { - serialize_sql_expr(&x.offset.as_ref().unwrap()) + self.serialize_sql_expr(&x.offset.as_ref().unwrap()) } else { json!(serde_json::Value::Null) }; @@ -99,7 +151,7 @@ impl ImmutableVisitor for Program { }); Ok(json!({ - "core": serialize_sql_core(&select.core), + "core": core, "compound": compound, "order_by": order_by, "limit": limit @@ -108,7 +160,7 @@ impl ImmutableVisitor for Program { fn visit_expr(&self, eidx: ExprId) -> Result { // TODO: Remove clone here - let a = Rc::clone(&self.arena); + let a = Rc::clone(&self.program.arena); let e = a.get_expression(eidx); let matched: Value = match e { @@ -244,7 +296,7 @@ impl ImmutableVisitor for Program { fn visit_stmt(&self, sidx: StmtId) -> Result { // TODO: Remove clone here - let a = Rc::clone(&self.arena); + let a = Rc::clone(&self.program.arena); let s = a.get_statement(sidx); let matched: Value = match s { Stmt::Program { body, span: _ } => { diff --git a/server/src/lang/tests/helpers.rs b/server/src/lang/tests/helpers.rs index fe08697f..674877e7 100644 --- a/server/src/lang/tests/helpers.rs +++ b/server/src/lang/tests/helpers.rs @@ -21,9 +21,11 @@ pub fn get_tokens(source: &str) -> Vec { #[cfg(test)] pub fn compare_parsed_to_expected(source: &str, expected: Value) { + use crate::lang::serializer::ProgramSerializer; + let tokens = get_tokens(source); - let mut parsed = Parser::parse(&tokens).unwrap(); - let actual = parsed.to_json(); + let parsed = Parser::parse(&tokens).unwrap(); + let actual = ProgramSerializer::new(&parsed).to_json(); assert_json_eq!(actual, expected); } diff --git a/server/src/lang/tests/sql/mod.rs b/server/src/lang/tests/sql/mod.rs index 40571c0a..ae096ae9 100644 --- a/server/src/lang/tests/sql/mod.rs +++ b/server/src/lang/tests/sql/mod.rs @@ -1,3 +1,4 @@ +pub mod select_from; pub mod select_limit; pub mod select_order; pub mod select_projection; diff --git a/server/src/lang/tests/sql/select_from.rs b/server/src/lang/tests/sql/select_from.rs new file mode 100644 index 00000000..0de70c3f --- /dev/null +++ b/server/src/lang/tests/sql/select_from.rs @@ -0,0 +1,45 @@ +#[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": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, + "projection": [{ + "type": "All", + "collection": null + }] + }, + "compound": [], + "limit": null, + "order_by": null + } + } + } + ] + } + } +} diff --git a/server/src/lang/tests/sql/select_limit.rs b/server/src/lang/tests/sql/select_limit.rs index 09cf97d6..403d7bec 100644 --- a/server/src/lang/tests/sql/select_limit.rs +++ b/server/src/lang/tests/sql/select_limit.rs @@ -19,7 +19,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": null }] }, @@ -49,7 +59,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": null }] }, @@ -83,7 +103,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": null }] }, diff --git a/server/src/lang/tests/sql/select_order.rs b/server/src/lang/tests/sql/select_order.rs index 6fb1a4f3..d4f170db 100644 --- a/server/src/lang/tests/sql/select_order.rs +++ b/server/src/lang/tests/sql/select_order.rs @@ -19,7 +19,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": null }] }, @@ -42,7 +52,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": null }] }, @@ -71,7 +91,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": null }] }, @@ -107,7 +137,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": null }] }, @@ -143,7 +183,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": null }] }, diff --git a/server/src/lang/tests/sql/select_projection.rs b/server/src/lang/tests/sql/select_projection.rs index 7509d78e..4486c687 100644 --- a/server/src/lang/tests/sql/select_projection.rs +++ b/server/src/lang/tests/sql/select_projection.rs @@ -19,7 +19,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": null }] }, @@ -43,7 +53,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "All", "collection": "users" }] }, @@ -66,7 +86,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "Expr", "expr": { "type": "Expr::Variable", "name": "id" @@ -74,6 +104,7 @@ assert_parsing! { "alias": null }, { + "type": "Expr", "expr": { "type": "Expr::Get", "object": { @@ -95,7 +126,7 @@ assert_parsing! { } }, mixed_1: { - "SELECT 5 as five, \"text\" as some_text from users;" => { + "SELECT 5 as five, \"text\" as some_text from users;" => { "type": "Stmt::Program", "body": [ { @@ -104,7 +135,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "Expr", "expr": { "type": "Expr::Literal", "value": "Num(5.0)", @@ -113,6 +154,7 @@ assert_parsing! { "alias": "five" }, { + "type": "Expr", "expr": { "type": "Expr::Literal", "value": "Str(\"text\")", @@ -140,7 +182,17 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": { + "type": "Group", + "subqueries": [{ + "type": "Collection", + "alias": null, + "name": "users", + "namespace": null, + }], + }, "projection": [{ + "type": "Expr", "expr": { "type": "Expr::Binary", "left": { @@ -160,6 +212,7 @@ assert_parsing! { "alias": "addition" }, { + "type": "Expr", "expr": { "type": "Expr::Binary", "left": { @@ -198,7 +251,9 @@ assert_parsing! { "type": "Expr::Select", "value": { "core": { + "from": null, "projection": [{ + "type": "Expr", "expr": { "type": "Expr::Binary", "left": { @@ -218,6 +273,7 @@ assert_parsing! { "alias": "addition" }, { + "type": "Expr", "expr": { "type": "Expr::Binary", "left": { diff --git a/server/src/runtime/mod.rs b/server/src/runtime/mod.rs index c68842cf..66ef5bbc 100644 --- a/server/src/runtime/mod.rs +++ b/server/src/runtime/mod.rs @@ -3,8 +3,9 @@ use self::interpreter::HaltReason; use self::resolver::Resolver; use self::std::stdlib; use crate::lang::ast::Visitor; -use crate::lang::parser::Parser; +use crate::lang::parser::{ParseError, Parser}; use crate::lang::scanner::Scanner; +use crate::lang::serializer::ProgramSerializer; use crate::runtime::environment::Environment; use crate::runtime::interpreter::Interpreter; use crate::runtime::types::RV; @@ -44,10 +45,11 @@ impl Runtime { Runtime { env, mode } } - pub fn print_ast(&mut self, source: &str) { + pub fn print_ast(&mut self, source: &str) -> Result<(), ParseError> { let tokens = Scanner::scan(source).unwrap(); - let program = Parser::parse(&tokens); - println!("{}", program.unwrap().serialize()); + let program = Parser::parse(&tokens)?; + println!("{}", ProgramSerializer::new(&program).to_string()); + Ok(()) } pub fn interpret(&mut self, source: &str) -> Result {