From af82b8bb7959d1d98df53128fae8556e51ac8367 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Sat, 28 Sep 2024 16:55:47 +0300 Subject: [PATCH 1/7] fix: New join test --- lykiadb-server/tests/planner/join.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lykiadb-server/tests/planner/join.rs b/lykiadb-server/tests/planner/join.rs index 0638b191..c9f8fb6f 100644 --- a/lykiadb-server/tests/planner/join.rs +++ b/lykiadb-server/tests/planner/join.rs @@ -2,6 +2,17 @@ use lykiadb_server::{assert_plan, plan::planner::test_helpers::expect_plan}; assert_plan! { + two_way_simple: { + "SELECT * FROM books b + INNER JOIN categories c ON b.category_id = c.id + WHERE c.name = 'Science';" => + +"- filter (c.name IsEqual Str(\"Science\")): + - join [Inner, (b.category_id IsEqual c.id)]: + - scan [books as b] + - scan [categories as c] +" +}, three_way_simple: { "SELECT * FROM books b INNER JOIN categories c ON b.category_id = c.id From fb66d9fce3365f888c08e67623b73f02e8721def Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Sun, 29 Sep 2024 14:17:00 +0300 Subject: [PATCH 2/7] fix: Value reorg --- lykiadb-server/src/comm/mod.rs | 2 +- lykiadb-server/src/engine/interpreter.rs | 6 +++--- lykiadb-server/src/engine/mod.rs | 2 +- lykiadb-server/src/engine/stdlib/fib.rs | 2 +- lykiadb-server/src/engine/stdlib/json.rs | 2 +- lykiadb-server/src/engine/stdlib/mod.rs | 2 +- lykiadb-server/src/engine/stdlib/out.rs | 2 +- lykiadb-server/src/engine/stdlib/time.rs | 2 +- lykiadb-server/src/value/callable.rs | 2 +- lykiadb-server/src/value/environment.rs | 4 ++-- lykiadb-server/src/value/mod.rs | 21 ++++++++++++++++++++- lykiadb-server/src/value/types.rs | 20 ++------------------ lykiadb-server/tests/runtime/blocks.rs | 2 +- lykiadb-server/tests/runtime/functions.rs | 2 +- lykiadb-server/tests/runtime/ifs.rs | 2 +- lykiadb-server/tests/runtime/loops.rs | 2 +- 16 files changed, 39 insertions(+), 36 deletions(-) diff --git a/lykiadb-server/src/comm/mod.rs b/lykiadb-server/src/comm/mod.rs index 6002ce91..513ec498 100644 --- a/lykiadb-server/src/comm/mod.rs +++ b/lykiadb-server/src/comm/mod.rs @@ -1,5 +1,5 @@ use crate::engine::{Runtime, RuntimeMode}; -use crate::value::types::RV; +use crate::value::RV; use ::std::time::Instant; use tcp::TcpConnection; use tokio::net::TcpStream; diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index 0d7b6964..7869d8fe 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -17,7 +17,7 @@ use crate::plan::planner::Planner; use crate::util::{alloc_shared, Shared}; use crate::value::callable::{Callable, CallableKind, Function, Stateful}; use crate::value::environment::{EnvId, Environment}; -use crate::value::types::{eval_binary, RV}; +use crate::value::{RV, types::eval_binary}; use std::sync::Arc; use std::vec; @@ -706,7 +706,7 @@ impl Stateful for Output { pub mod test_helpers { use crate::engine::{Runtime, RuntimeMode}; use crate::util::{alloc_shared, Shared}; - use crate::value::types::RV; + use crate::value::RV; use super::Output; @@ -725,7 +725,7 @@ pub mod test_helpers { #[cfg(test)] mod test { - use crate::value::types::RV; + use crate::value::RV; use super::test_helpers::get_runtime; diff --git a/lykiadb-server/src/engine/mod.rs b/lykiadb-server/src/engine/mod.rs index 03f0d165..e8021478 100644 --- a/lykiadb-server/src/engine/mod.rs +++ b/lykiadb-server/src/engine/mod.rs @@ -4,7 +4,7 @@ use self::stdlib::stdlib; use crate::engine::interpreter::Interpreter; use crate::util::{alloc_shared, Shared}; use crate::value::environment::Environment; -use crate::value::types::RV; +use crate::value::RV; use lykiadb_lang::parser::Parser; use lykiadb_lang::tokenizer::scanner::Scanner; use serde_json::Value; diff --git a/lykiadb-server/src/engine/stdlib/fib.rs b/lykiadb-server/src/engine/stdlib/fib.rs index 9c73b078..5eb6658e 100644 --- a/lykiadb-server/src/engine/stdlib/fib.rs +++ b/lykiadb-server/src/engine/stdlib/fib.rs @@ -1,6 +1,6 @@ use crate::{ engine::interpreter::{HaltReason, InterpretError, Interpreter}, - value::types::RV, + value::RV, }; fn _calculate(n: f64) -> f64 { diff --git a/lykiadb-server/src/engine/stdlib/json.rs b/lykiadb-server/src/engine/stdlib/json.rs index 63df62d5..222d2a32 100644 --- a/lykiadb-server/src/engine/stdlib/json.rs +++ b/lykiadb-server/src/engine/stdlib/json.rs @@ -1,6 +1,6 @@ use crate::{ engine::interpreter::{HaltReason, InterpretError, Interpreter}, - value::types::RV, + value::RV, }; use serde_json::json; use std::sync::Arc; diff --git a/lykiadb-server/src/engine/stdlib/mod.rs b/lykiadb-server/src/engine/stdlib/mod.rs index 908b7323..8722b807 100644 --- a/lykiadb-server/src/engine/stdlib/mod.rs +++ b/lykiadb-server/src/engine/stdlib/mod.rs @@ -2,7 +2,7 @@ use rustc_hash::FxHashMap; use crate::{ util::{alloc_shared, Shared}, - value::{callable::{Callable, CallableKind, Function}, types::RV}, + value::{callable::{Callable, CallableKind, Function}, RV}, }; use self::{ diff --git a/lykiadb-server/src/engine/stdlib/out.rs b/lykiadb-server/src/engine/stdlib/out.rs index e9ff7157..73994d0c 100644 --- a/lykiadb-server/src/engine/stdlib/out.rs +++ b/lykiadb-server/src/engine/stdlib/out.rs @@ -1,6 +1,6 @@ use crate::{ engine::interpreter::{HaltReason, Interpreter}, - value::types::RV, + value::RV, }; pub fn nt_print(_interpreter: &mut Interpreter, args: &[RV]) -> Result { diff --git a/lykiadb-server/src/engine/stdlib/time.rs b/lykiadb-server/src/engine/stdlib/time.rs index cf38773f..c8dbec0f 100644 --- a/lykiadb-server/src/engine/stdlib/time.rs +++ b/lykiadb-server/src/engine/stdlib/time.rs @@ -1,5 +1,5 @@ use crate::engine::interpreter::{HaltReason, Interpreter}; -use crate::value::types::RV; +use crate::value::RV; use std::time; pub fn nt_clock(_interpreter: &mut Interpreter, _args: &[RV]) -> Result { diff --git a/lykiadb-server/src/value/callable.rs b/lykiadb-server/src/value/callable.rs index 65137f31..88a7a8a0 100644 --- a/lykiadb-server/src/value/callable.rs +++ b/lykiadb-server/src/value/callable.rs @@ -3,7 +3,7 @@ use std::fmt::{Debug, Display, Formatter}; use lykiadb_lang::ast::stmt::Stmt; use crate::{engine::interpreter::{HaltReason, Interpreter}, util::Shared}; use super::environment::EnvId; -use super::types::RV; +use super::RV; #[derive(Debug, Clone)] pub enum CallableKind { diff --git a/lykiadb-server/src/value/environment.rs b/lykiadb-server/src/value/environment.rs index 2d510c6c..4fdd2a05 100644 --- a/lykiadb-server/src/value/environment.rs +++ b/lykiadb-server/src/value/environment.rs @@ -4,7 +4,7 @@ use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use std::borrow::{Borrow, BorrowMut}; -use super::types::RV; +use super::RV; #[repr(transparent)] #[derive(Debug, Eq, PartialEq, Clone, Copy)] @@ -169,7 +169,7 @@ impl Environment { #[cfg(test)] mod test { - use crate::value::types::RV; + use crate::value::RV; #[test] fn test_read_basic() { diff --git a/lykiadb-server/src/value/mod.rs b/lykiadb-server/src/value/mod.rs index bf7d3a44..eb7d8a89 100644 --- a/lykiadb-server/src/value/mod.rs +++ b/lykiadb-server/src/value/mod.rs @@ -1,3 +1,22 @@ +use std::sync::Arc; + +use callable::Callable; +use rustc_hash::FxHashMap; + +use crate::util::Shared; + pub mod environment; pub mod types; -pub mod callable; \ No newline at end of file +pub mod callable; +#[derive(Debug, Clone)] +pub enum RV { + Str(Arc), + Num(f64), + Bool(bool), + Object(Shared>), + Array(Shared>), + Callable(Callable), + Undefined, + NaN, + Null, +} \ No newline at end of file diff --git a/lykiadb-server/src/value/types.rs b/lykiadb-server/src/value/types.rs index ffe5ce38..524bc4c1 100644 --- a/lykiadb-server/src/value/types.rs +++ b/lykiadb-server/src/value/types.rs @@ -2,26 +2,10 @@ use lykiadb_lang::ast::expr::Operation; use rustc_hash::FxHashMap; use serde::ser::{SerializeMap, SerializeSeq}; use serde::{Deserialize, Serialize}; -use std::fmt::Debug; use std::ops; use std::sync::{Arc, RwLock}; - -use crate::util::{alloc_shared, Shared}; - -use super::callable::Callable; - -#[derive(Debug, Clone)] -pub enum RV { - Str(Arc), - Num(f64), - Bool(bool), - Object(Shared>), - Array(Shared>), - Callable(Callable), - Undefined, - NaN, - Null, -} +use crate::util::alloc_shared; +use super::RV; impl Serialize for RV { fn serialize(&self, serializer: S) -> Result diff --git a/lykiadb-server/tests/runtime/blocks.rs b/lykiadb-server/tests/runtime/blocks.rs index faae0d4d..bd546ac0 100644 --- a/lykiadb-server/tests/runtime/blocks.rs +++ b/lykiadb-server/tests/runtime/blocks.rs @@ -6,7 +6,7 @@ use lykiadb_server::{ InterpretError, }, }, - value::types::RV, + value::RV, }; use std::sync::Arc; diff --git a/lykiadb-server/tests/runtime/functions.rs b/lykiadb-server/tests/runtime/functions.rs index 773299d7..7fb59d28 100644 --- a/lykiadb-server/tests/runtime/functions.rs +++ b/lykiadb-server/tests/runtime/functions.rs @@ -1,6 +1,6 @@ use lykiadb_server::{ engine::interpreter::test_helpers::{exec_assert, get_runtime}, - value::types::RV, + value::RV, }; use std::sync::Arc; diff --git a/lykiadb-server/tests/runtime/ifs.rs b/lykiadb-server/tests/runtime/ifs.rs index 76e0c510..f3fbe6f3 100644 --- a/lykiadb-server/tests/runtime/ifs.rs +++ b/lykiadb-server/tests/runtime/ifs.rs @@ -1,4 +1,4 @@ -use lykiadb_server::{engine::interpreter::test_helpers::exec_assert, value::types::RV}; +use lykiadb_server::{engine::interpreter::test_helpers::exec_assert, value::RV}; use std::sync::Arc; #[test] diff --git a/lykiadb-server/tests/runtime/loops.rs b/lykiadb-server/tests/runtime/loops.rs index 961c927e..a06cc646 100644 --- a/lykiadb-server/tests/runtime/loops.rs +++ b/lykiadb-server/tests/runtime/loops.rs @@ -1,4 +1,4 @@ -use lykiadb_server::{engine::interpreter::test_helpers::exec_assert, value::types::RV}; +use lykiadb_server::{engine::interpreter::test_helpers::exec_assert, value::RV}; use std::sync::Arc; From 2a27ef2848ea1a8564a0e20e4759beb3889b61e8 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Sun, 29 Sep 2024 14:24:11 +0300 Subject: [PATCH 3/7] fix: Value reorg cntd --- lykiadb-server/src/engine/interpreter.rs | 2 +- .../src/value/{types.rs => eval.rs} | 139 +---------------- lykiadb-server/src/value/mod.rs | 146 +++++++++++++++++- 3 files changed, 144 insertions(+), 143 deletions(-) rename lykiadb-server/src/value/{types.rs => eval.rs} (89%) diff --git a/lykiadb-server/src/engine/interpreter.rs b/lykiadb-server/src/engine/interpreter.rs index 7869d8fe..65dc94a2 100644 --- a/lykiadb-server/src/engine/interpreter.rs +++ b/lykiadb-server/src/engine/interpreter.rs @@ -17,7 +17,7 @@ use crate::plan::planner::Planner; use crate::util::{alloc_shared, Shared}; use crate::value::callable::{Callable, CallableKind, Function, Stateful}; use crate::value::environment::{EnvId, Environment}; -use crate::value::{RV, types::eval_binary}; +use crate::value::{RV, eval::eval_binary}; use std::sync::Arc; use std::vec; diff --git a/lykiadb-server/src/value/types.rs b/lykiadb-server/src/value/eval.rs similarity index 89% rename from lykiadb-server/src/value/types.rs rename to lykiadb-server/src/value/eval.rs index 524bc4c1..50d62212 100644 --- a/lykiadb-server/src/value/types.rs +++ b/lykiadb-server/src/value/eval.rs @@ -1,143 +1,8 @@ use lykiadb_lang::ast::expr::Operation; -use rustc_hash::FxHashMap; -use serde::ser::{SerializeMap, SerializeSeq}; -use serde::{Deserialize, Serialize}; use std::ops; -use std::sync::{Arc, RwLock}; -use crate::util::alloc_shared; +use std::sync::Arc; use super::RV; -impl Serialize for RV { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - RV::Str(s) => serializer.serialize_str(s), - RV::Num(n) => serializer.serialize_f64(*n), - RV::Bool(b) => serializer.serialize_bool(*b), - RV::Undefined => serializer.serialize_none(), - RV::NaN => serializer.serialize_none(), - RV::Null => serializer.serialize_none(), - RV::Array(arr) => { - let mut seq = serializer.serialize_seq(None).unwrap(); - let arr = (arr as &RwLock>).read().unwrap(); - for item in arr.iter() { - seq.serialize_element(&item)?; - } - seq.end() - } - RV::Object(obj) => { - let mut map = serializer.serialize_map(None).unwrap(); - let arr = (obj as &RwLock>) - .read() - .unwrap(); - for (key, value) in arr.iter() { - map.serialize_entry(key, value)?; - } - map.end() - }, - _ => serializer.serialize_none(), - } - } -} - -impl<'de> Deserialize<'de> for RV { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let value = serde_json::Value::deserialize(deserializer)?; - match value { - serde_json::Value::String(s) => Ok(RV::Str(Arc::new(s))), - serde_json::Value::Number(n) => Ok(RV::Num(n.as_f64().unwrap())), - serde_json::Value::Bool(b) => Ok(RV::Bool(b)), - serde_json::Value::Array(arr) => { - let mut vec = Vec::new(); - for item in arr { - vec.push(serde_json::from_value(item).unwrap()); - } - Ok(RV::Array(alloc_shared(vec))) - } - serde_json::Value::Object(obj) => { - let mut map = FxHashMap::default(); - for (key, value) in obj { - map.insert(key, serde_json::from_value(value).unwrap()); - } - Ok(RV::Object(alloc_shared(map))) - } - serde_json::Value::Null => Ok(RV::Null), - } - } -} - -impl RV { - pub fn as_bool(&self) -> bool { - match &self { - RV::Num(value) => !value.is_nan() && value.abs() > 0.0, - RV::Str(value) => !value.is_empty(), - RV::Bool(value) => *value, - RV::Null | RV::Undefined | RV::NaN => false, - _ => true, - } - } - - pub fn as_number(&self) -> Option { - match self { - RV::Num(value) => Some(*value), - RV::Bool(true) => Some(1.0), - RV::Bool(false) => Some(0.0), - RV::Str(s) => { - if let Ok(num) = s.parse::() { - Some(num) - } else { - None - } - } - _ => None, - } - } - - pub fn eq_any_bool(&self, b: bool) -> bool { - self.as_bool() == b - } - - pub fn eq_str_num(&self, n: f64) -> bool { - if let RV::Str(s) = self { - if let Ok(num) = s.parse::() { - return num == n; - } - } - false - } - - pub fn partial_cmp_str_bool(&self, other: bool) -> Option { - if let Some(num) = self.as_number() { - return num.partial_cmp(&if other { 1.0 } else { 0.0 }); - } - self.as_bool().partial_cmp(&other) - } - - pub fn is_in(&self, other: &RV) -> RV { - match (self, other) { - (RV::Str(lhs), RV::Str(rhs)) => { - RV::Bool(rhs.contains(lhs.as_str())) - } - (lhs, RV::Array(rhs)) => { - RV::Bool(rhs.read().unwrap().contains(&lhs)) - } - (RV::Str(key), RV::Object(map)) => { - RV::Bool(map.read().unwrap().contains_key(key.as_str())) - }, - _ => RV::Bool(false), - } - } - - pub fn not(&self) -> RV { - RV::Bool(!self.as_bool()) - } -} - impl PartialEq for RV { fn eq(&self, other: &Self) -> bool { match (self, other) { @@ -334,7 +199,7 @@ mod test { use crate::{ util::alloc_shared, - value::types::{eval_binary, RV}, + value::eval::{eval_binary, RV}, }; #[test] diff --git a/lykiadb-server/src/value/mod.rs b/lykiadb-server/src/value/mod.rs index eb7d8a89..7db8aae5 100644 --- a/lykiadb-server/src/value/mod.rs +++ b/lykiadb-server/src/value/mod.rs @@ -1,13 +1,16 @@ -use std::sync::Arc; - -use callable::Callable; +use std::sync::{Arc, RwLock}; +use serde::ser::{SerializeMap, SerializeSeq}; +use serde::{Deserialize, Serialize}; use rustc_hash::FxHashMap; +use crate::util::alloc_shared; use crate::util::Shared; +use callable::Callable; pub mod environment; -pub mod types; +pub mod eval; pub mod callable; + #[derive(Debug, Clone)] pub enum RV { Str(Arc), @@ -19,4 +22,137 @@ pub enum RV { Undefined, NaN, Null, -} \ No newline at end of file +} + +impl RV { + pub fn as_bool(&self) -> bool { + match &self { + RV::Num(value) => !value.is_nan() && value.abs() > 0.0, + RV::Str(value) => !value.is_empty(), + RV::Bool(value) => *value, + RV::Null | RV::Undefined | RV::NaN => false, + _ => true, + } + } + + pub fn as_number(&self) -> Option { + match self { + RV::Num(value) => Some(*value), + RV::Bool(true) => Some(1.0), + RV::Bool(false) => Some(0.0), + RV::Str(s) => { + if let Ok(num) = s.parse::() { + Some(num) + } else { + None + } + } + _ => None, + } + } + + pub fn eq_any_bool(&self, b: bool) -> bool { + self.as_bool() == b + } + + pub fn eq_str_num(&self, n: f64) -> bool { + if let RV::Str(s) = self { + if let Ok(num) = s.parse::() { + return num == n; + } + } + false + } + + pub fn partial_cmp_str_bool(&self, other: bool) -> Option { + if let Some(num) = self.as_number() { + return num.partial_cmp(&if other { 1.0 } else { 0.0 }); + } + self.as_bool().partial_cmp(&other) + } + + pub fn is_in(&self, other: &RV) -> RV { + match (self, other) { + (RV::Str(lhs), RV::Str(rhs)) => { + RV::Bool(rhs.contains(lhs.as_str())) + } + (lhs, RV::Array(rhs)) => { + RV::Bool(rhs.read().unwrap().contains(&lhs)) + } + (RV::Str(key), RV::Object(map)) => { + RV::Bool(map.read().unwrap().contains_key(key.as_str())) + }, + _ => RV::Bool(false), + } + } + + pub fn not(&self) -> RV { + RV::Bool(!self.as_bool()) + } +} + + +impl Serialize for RV { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + RV::Str(s) => serializer.serialize_str(s), + RV::Num(n) => serializer.serialize_f64(*n), + RV::Bool(b) => serializer.serialize_bool(*b), + RV::Undefined => serializer.serialize_none(), + RV::NaN => serializer.serialize_none(), + RV::Null => serializer.serialize_none(), + RV::Array(arr) => { + let mut seq = serializer.serialize_seq(None).unwrap(); + let arr = (arr as &RwLock>).read().unwrap(); + for item in arr.iter() { + seq.serialize_element(&item)?; + } + seq.end() + } + RV::Object(obj) => { + let mut map = serializer.serialize_map(None).unwrap(); + let arr = (obj as &RwLock>) + .read() + .unwrap(); + for (key, value) in arr.iter() { + map.serialize_entry(key, value)?; + } + map.end() + }, + _ => serializer.serialize_none(), + } + } +} + +impl<'de> Deserialize<'de> for RV { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let value = serde_json::Value::deserialize(deserializer)?; + match value { + serde_json::Value::String(s) => Ok(RV::Str(Arc::new(s))), + serde_json::Value::Number(n) => Ok(RV::Num(n.as_f64().unwrap())), + serde_json::Value::Bool(b) => Ok(RV::Bool(b)), + serde_json::Value::Array(arr) => { + let mut vec = Vec::new(); + for item in arr { + vec.push(serde_json::from_value(item).unwrap()); + } + Ok(RV::Array(alloc_shared(vec))) + } + serde_json::Value::Object(obj) => { + let mut map = FxHashMap::default(); + for (key, value) in obj { + map.insert(key, serde_json::from_value(value).unwrap()); + } + Ok(RV::Object(alloc_shared(map))) + } + serde_json::Value::Null => Ok(RV::Null), + } + } +} + From e32053cab2773b221ac826dd336d641a303c8dd2 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Thu, 24 Oct 2024 13:42:38 +0300 Subject: [PATCH 4/7] fix: New test structure for planner --- lykiadb-server/Cargo.toml | 1 + lykiadb-server/tests/planner/join.rs | 30 -------------------------- lykiadb-server/tests/planner/join/join | 26 ++++++++++++++++++++++ lykiadb-server/tests/planner/mod.rs | 1 - lykiadb-server/tests/tests.rs | 6 +++++- lykiadb-server/tests/util.rs | 28 ++++++++++++++++++++++++ 6 files changed, 60 insertions(+), 32 deletions(-) delete mode 100644 lykiadb-server/tests/planner/join.rs create mode 100644 lykiadb-server/tests/planner/join/join delete mode 100644 lykiadb-server/tests/planner/mod.rs create mode 100644 lykiadb-server/tests/util.rs diff --git a/lykiadb-server/Cargo.toml b/lykiadb-server/Cargo.toml index fd0c5838..2db3eaeb 100644 --- a/lykiadb-server/Cargo.toml +++ b/lykiadb-server/Cargo.toml @@ -30,6 +30,7 @@ tracing-subscriber = "0.3" [dev-dependencies] criterion = { version = "0.4", features = ["html_reports"] } +test_each_file = "0.3.4" [[bench]] name = "interpreter" diff --git a/lykiadb-server/tests/planner/join.rs b/lykiadb-server/tests/planner/join.rs deleted file mode 100644 index c9f8fb6f..00000000 --- a/lykiadb-server/tests/planner/join.rs +++ /dev/null @@ -1,30 +0,0 @@ -use lykiadb_server::{assert_plan, plan::planner::test_helpers::expect_plan}; - - -assert_plan! { - two_way_simple: { - "SELECT * FROM books b - INNER JOIN categories c ON b.category_id = c.id - WHERE c.name = 'Science';" => - -"- filter (c.name IsEqual Str(\"Science\")): - - join [Inner, (b.category_id IsEqual c.id)]: - - scan [books as b] - - scan [categories as c] -" -}, - three_way_simple: { - "SELECT * FROM books b - INNER JOIN categories c ON b.category_id = c.id - INNER JOIN publishers AS p ON b.publisher_id = p.id - WHERE p.name = 'Springer';" => - -"- filter (p.name IsEqual Str(\"Springer\")): - - join [Inner, (b.publisher_id IsEqual p.id)]: - - join [Inner, (b.category_id IsEqual c.id)]: - - scan [books as b] - - scan [categories as c] - - scan [publishers as p] -" - } -} diff --git a/lykiadb-server/tests/planner/join/join b/lykiadb-server/tests/planner/join/join new file mode 100644 index 00000000..12e4c0f4 --- /dev/null +++ b/lykiadb-server/tests/planner/join/join @@ -0,0 +1,26 @@ +#[name=two_way_simple, run=plan]> +SELECT * FROM books b + INNER JOIN categories c ON b.category_id = c.id + WHERE c.name = 'Science'; +--- +- filter (c.name IsEqual Str("Science")): + - join [Inner, (b.category_id IsEqual c.id)]: + - scan [books as b] + - scan [categories as c] + + +#[name=three_way_simple, run=plan]> + +SELECT * FROM books b + INNER JOIN categories c ON b.category_id = c.id + INNER JOIN publishers AS p ON b.publisher_id = p.id + WHERE p.name = 'Springer'; + +--- + +- filter (p.name IsEqual Str("Springer")): + - join [Inner, (b.publisher_id IsEqual p.id)]: + - join [Inner, (b.category_id IsEqual c.id)]: + - scan [books as b] + - scan [categories as c] + - scan [publishers as p] \ No newline at end of file diff --git a/lykiadb-server/tests/planner/mod.rs b/lykiadb-server/tests/planner/mod.rs deleted file mode 100644 index 76e7a061..00000000 --- a/lykiadb-server/tests/planner/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod join; \ No newline at end of file diff --git a/lykiadb-server/tests/tests.rs b/lykiadb-server/tests/tests.rs index 7f033b57..9f99d34e 100644 --- a/lykiadb-server/tests/tests.rs +++ b/lykiadb-server/tests/tests.rs @@ -1,4 +1,8 @@ #![recursion_limit = "192"] +use util::run_test; +use test_each_file::test_each_file; mod runtime; -mod planner; \ No newline at end of file +mod util; + +test_each_file! { in "lykiadb-server/tests/planner" => run_test } diff --git a/lykiadb-server/tests/util.rs b/lykiadb-server/tests/util.rs new file mode 100644 index 00000000..206f33d3 --- /dev/null +++ b/lykiadb-server/tests/util.rs @@ -0,0 +1,28 @@ +use lykiadb_lang::{ast::stmt::Stmt, parser::program::Program}; +use lykiadb_server::plan::planner::Planner; + +fn expect_plan(query: &str, expected_plan: &str) { + let mut planner = Planner::new(); + let program = query.parse::().unwrap(); + match *program.get_root() { + Stmt::Program { body, .. } if matches!(body.get(0), Some(Stmt::Expression { .. })) => { + if let Some(Stmt::Expression { expr, .. }) = body.get(0) { + let generated_plan = planner.build(&expr).unwrap(); + assert_eq!(expected_plan, generated_plan.to_string().trim()); + } + } + _ => panic!("Expected expression statement."), + } +} + +pub fn run_test(input: &str) { + let parts: Vec<&str> = input.split("#[").collect(); + + for part in parts[1..].iter() { + let directives_and_input = part.trim(); + let directives_end = directives_and_input.find('>').unwrap_or(directives_and_input.len()); + let rest = directives_and_input[directives_end+1..].trim().to_string(); + let io_parts: Vec<&str> = rest.split("---").collect(); + expect_plan(&io_parts[0].trim(),&io_parts[1].trim()); + } +} \ No newline at end of file From ae5dcb5729423a54c30bd470c113331dae81bcbc Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Thu, 24 Oct 2024 14:19:38 +0300 Subject: [PATCH 5/7] fix: New test case --- lykiadb-server/tests/planner/{join => }/join | 22 +++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) rename lykiadb-server/tests/planner/{join => }/join (59%) diff --git a/lykiadb-server/tests/planner/join/join b/lykiadb-server/tests/planner/join similarity index 59% rename from lykiadb-server/tests/planner/join/join rename to lykiadb-server/tests/planner/join index 12e4c0f4..3fb2538b 100644 --- a/lykiadb-server/tests/planner/join/join +++ b/lykiadb-server/tests/planner/join @@ -1,8 +1,11 @@ #[name=two_way_simple, run=plan]> + SELECT * FROM books b INNER JOIN categories c ON b.category_id = c.id WHERE c.name = 'Science'; + --- + - filter (c.name IsEqual Str("Science")): - join [Inner, (b.category_id IsEqual c.id)]: - scan [books as b] @@ -23,4 +26,21 @@ SELECT * FROM books b - join [Inner, (b.category_id IsEqual c.id)]: - scan [books as b] - scan [categories as c] - - scan [publishers as p] \ No newline at end of file + - scan [publishers as p] + + +#[name=three_way_reordered, run=plan]> + +SELECT * FROM books b + INNER JOIN + (categories c ON b.category_id = c.id INNER JOIN publishers AS p ON b.publisher_id = p.id) + WHERE p.name = 'Springer'; + +--- + +- filter (p.name IsEqual Str("Springer")): + - join [Inner, (b.publisher_id IsEqual p.id)]: + - join [Inner, (b.category_id IsEqual c.id)]: + - scan [categories as c] + - scan [publishers as p] + - scan [books as b] \ No newline at end of file From e7ef64e4a10d85d25634c5c1c0861012268a549c Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Thu, 24 Oct 2024 20:47:31 +0300 Subject: [PATCH 6/7] fix: Test case, pretty print --- lykiadb-server/Cargo.toml | 1 + lykiadb-server/tests/planner/join | 14 ++++++++++---- lykiadb-server/tests/util.rs | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lykiadb-server/Cargo.toml b/lykiadb-server/Cargo.toml index 2db3eaeb..e40f3279 100644 --- a/lykiadb-server/Cargo.toml +++ b/lykiadb-server/Cargo.toml @@ -27,6 +27,7 @@ tokio = { version = "~1.35.1", features = [ tokio-stream = { version = "~0.1.6", features = ["net"] } tracing = "0.1" tracing-subscriber = "0.3" +pretty_assertions = "1.4.1" [dev-dependencies] criterion = { version = "0.4", features = ["html_reports"] } diff --git a/lykiadb-server/tests/planner/join b/lykiadb-server/tests/planner/join index 3fb2538b..110a40df 100644 --- a/lykiadb-server/tests/planner/join +++ b/lykiadb-server/tests/planner/join @@ -32,15 +32,21 @@ SELECT * FROM books b #[name=three_way_reordered, run=plan]> SELECT * FROM books b - INNER JOIN - (categories c ON b.category_id = c.id INNER JOIN publishers AS p ON b.publisher_id = p.id) + INNER JOIN + ( + categories c + INNER JOIN + publishers AS p + ON b.category_id = c.id + ) + ON b.publisher_id = p.id WHERE p.name = 'Springer'; --- - filter (p.name IsEqual Str("Springer")): - join [Inner, (b.publisher_id IsEqual p.id)]: + - scan [books as b] - join [Inner, (b.category_id IsEqual c.id)]: - scan [categories as c] - - scan [publishers as p] - - scan [books as b] \ No newline at end of file + - scan [publishers as p] \ No newline at end of file diff --git a/lykiadb-server/tests/util.rs b/lykiadb-server/tests/util.rs index 206f33d3..09be7917 100644 --- a/lykiadb-server/tests/util.rs +++ b/lykiadb-server/tests/util.rs @@ -1,5 +1,6 @@ use lykiadb_lang::{ast::stmt::Stmt, parser::program::Program}; use lykiadb_server::plan::planner::Planner; +use pretty_assertions::assert_eq; fn expect_plan(query: &str, expected_plan: &str) { let mut planner = Planner::new(); From 12c326d9ff5e64cdb9649ba95a5fcfbe1b7c00f7 Mon Sep 17 00:00:00 2001 From: Vedat Can Keklik Date: Fri, 25 Oct 2024 21:38:47 +0300 Subject: [PATCH 7/7] fix: Test namespacing --- lykiadb-server/tests/tests.rs | 8 +++++--- lykiadb-server/tests/util.rs | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lykiadb-server/tests/tests.rs b/lykiadb-server/tests/tests.rs index 9f99d34e..0c02f139 100644 --- a/lykiadb-server/tests/tests.rs +++ b/lykiadb-server/tests/tests.rs @@ -1,8 +1,10 @@ #![recursion_limit = "192"] -use util::run_test; -use test_each_file::test_each_file; mod runtime; mod util; +mod planner { + use test_each_file::test_each_file; + use crate::util::run_test; -test_each_file! { in "lykiadb-server/tests/planner" => run_test } + test_each_file! { in "lykiadb-server/tests/planner" => run_test } +} diff --git a/lykiadb-server/tests/util.rs b/lykiadb-server/tests/util.rs index 09be7917..15a2db19 100644 --- a/lykiadb-server/tests/util.rs +++ b/lykiadb-server/tests/util.rs @@ -1,5 +1,5 @@ use lykiadb_lang::{ast::stmt::Stmt, parser::program::Program}; -use lykiadb_server::plan::planner::Planner; +use lykiadb_server::{assert_plan, plan::planner::Planner}; use pretty_assertions::assert_eq; fn expect_plan(query: &str, expected_plan: &str) { @@ -24,6 +24,6 @@ pub fn run_test(input: &str) { let directives_end = directives_and_input.find('>').unwrap_or(directives_and_input.len()); let rest = directives_and_input[directives_end+1..].trim().to_string(); let io_parts: Vec<&str> = rest.split("---").collect(); - expect_plan(&io_parts[0].trim(),&io_parts[1].trim()); + expect_plan(&io_parts[0].trim(),&io_parts[1].trim()); } } \ No newline at end of file