From 5b6ed601333b912ee6e2f7e250d49063ad970c65 Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Tue, 27 May 2025 15:13:27 -0300 Subject: [PATCH] simpler select tests + fixes to printing --- .../sqlite3-parser/src/to_sql_string/expr.rs | 2 +- .../src/to_sql_string/stmt/mod.rs | 52 ++++++++++++++ .../src/to_sql_string/stmt/select.rs | 70 +++++++++++++++++-- 3 files changed, 119 insertions(+), 5 deletions(-) diff --git a/vendored/sqlite3-parser/src/to_sql_string/expr.rs b/vendored/sqlite3-parser/src/to_sql_string/expr.rs index 84e63104b..7fbb875e0 100644 --- a/vendored/sqlite3-parser/src/to_sql_string/expr.rs +++ b/vendored/sqlite3-parser/src/to_sql_string/expr.rs @@ -285,7 +285,7 @@ impl ToSqlString for ast::Operator { Self::BitwiseOr => "|", Self::Concat => "||", Self::Divide => "/", - Self::Equals => "==", + Self::Equals => "=", Self::Greater => ">", Self::GreaterEquals => ">=", Self::Is => "IS", diff --git a/vendored/sqlite3-parser/src/to_sql_string/stmt/mod.rs b/vendored/sqlite3-parser/src/to_sql_string/stmt/mod.rs index 4476670a4..8353b9c46 100644 --- a/vendored/sqlite3-parser/src/to_sql_string/stmt/mod.rs +++ b/vendored/sqlite3-parser/src/to_sql_string/stmt/mod.rs @@ -1 +1,53 @@ +use crate::ast; + +use super::ToSqlString; + mod select; + +impl ToSqlString for ast::Stmt { + fn to_sql_string(&self, context: &C) -> String { + match self { + Self::Select(select) => select.to_sql_string(context), + _ => todo!(), + } + } +} + +#[cfg(test)] +mod tests { + use crate::to_sql_string::ToSqlContext; + + #[macro_export] + /// Create a test that first parses then input, the converts the parsed ast back to a string and compares with original input + macro_rules! to_sql_string_test { + ($test_name:ident, $input:literal) => { + #[test] + fn $test_name() { + let context = crate::to_sql_string::stmt::tests::TestContext; + let input: &str = $input; + let mut parser = crate::lexer::sql::Parser::new(input.as_bytes()); + let cmd = fallible_iterator::FallibleIterator::next(&mut parser) + .unwrap() + .unwrap(); + assert_eq!( + input, + crate::to_sql_string::ToSqlString::to_sql_string(cmd.stmt(), &context) + ); + } + }; + } + + pub(crate) struct TestContext; + + // Placeholders for compilation + // Context only necessary parsing inside limbo_core or in the simulator + impl ToSqlContext for TestContext { + fn get_column_name(&self, _table_id: crate::ast::TableInternalId, _col_idx: usize) -> &str { + todo!() + } + + fn get_table_name(&self, _id: crate::ast::TableInternalId) -> &str { + todo!() + } + } +} diff --git a/vendored/sqlite3-parser/src/to_sql_string/stmt/select.rs b/vendored/sqlite3-parser/src/to_sql_string/stmt/select.rs index de1aa0c84..99d554e41 100644 --- a/vendored/sqlite3-parser/src/to_sql_string/stmt/select.rs +++ b/vendored/sqlite3-parser/src/to_sql_string/stmt/select.rs @@ -188,14 +188,18 @@ impl ToSqlString for ast::SelectTable { } } Self::Select(select, alias) => { + ret.push('('); ret.push_str(&select.to_sql_string(context)); + ret.push(')'); if let Some(alias) = alias { ret.push(' '); ret.push_str(&alias.to_sql_string(context)); } } Self::Sub(from_clause, alias) => { + ret.push('('); ret.push_str(&from_clause.to_sql_string(context)); + ret.push(')'); if let Some(alias) = alias { ret.push(' '); ret.push_str(&alias.to_sql_string(context)); @@ -338,10 +342,14 @@ impl ToSqlString for ast::JoinOperator { fn to_sql_string(&self, context: &C) -> String { match self { Self::Comma => ",".to_string(), - Self::TypedJoin(join) => format!( - "JOIN {}", - join.map_or(String::new(), |join| join.to_sql_string(context)) - ), + Self::TypedJoin(join) => { + let join_keyword = "JOIN"; + if let Some(join) = join { + format!("{} {}", join_keyword, join.to_sql_string(context)) + } else { + join_keyword.to_string() + } + } } } } @@ -497,3 +505,57 @@ impl ToSqlString for ast::FrameExclude { format!("EXCLUDE {}", clause) } } + +#[cfg(test)] +mod tests { + use crate::to_sql_string_test; + + to_sql_string_test!(test_select_basic, "SELECT 1"); + + to_sql_string_test!(test_select_table, "SELECT * FROM t"); + + to_sql_string_test!(test_select_table_2, "SELECT a FROM t"); + + to_sql_string_test!(test_select_multiple_columns, "SELECT a, b, c FROM t"); + + to_sql_string_test!(test_select_with_alias, "SELECT a AS col1 FROM t"); + + to_sql_string_test!(test_select_with_table_alias, "SELECT t1.a FROM t AS t1"); + + to_sql_string_test!(test_select_with_where, "SELECT a FROM t WHERE b = 1"); + + to_sql_string_test!( + test_select_with_multiple_conditions, + "SELECT a FROM t WHERE b = 1 AND c > 2" + ); + + to_sql_string_test!(test_select_with_order_by, "SELECT a FROM t ORDER BY a DESC"); + + to_sql_string_test!(test_select_with_limit, "SELECT a FROM t LIMIT 10"); + + to_sql_string_test!(test_select_with_offset, "SELECT a FROM t LIMIT 10 OFFSET 5"); + + to_sql_string_test!( + test_select_with_join, + "SELECT a FROM t JOIN t2 ON t.b = t2.b" + ); + + to_sql_string_test!( + test_select_with_group_by, + "SELECT a, COUNT(*) FROM t GROUP BY a" + ); + + to_sql_string_test!( + test_select_with_having, + "SELECT a, COUNT(*) FROM t GROUP BY a HAVING COUNT(*) > 1" + ); + + to_sql_string_test!(test_select_with_distinct, "SELECT DISTINCT a FROM t"); + + to_sql_string_test!(test_select_with_function, "SELECT COUNT(a) FROM t"); + + to_sql_string_test!( + test_select_with_subquery, + "SELECT a FROM (SELECT b FROM t) AS sub" + ); +}