diff --git a/include/sqlgen/col.hpp b/include/sqlgen/col.hpp index 1dd369b..cc8c438 100644 --- a/include/sqlgen/col.hpp +++ b/include/sqlgen/col.hpp @@ -2,6 +2,7 @@ #define SQLGEN_COL_HPP_ #include +#include #include "transpilation/Condition.hpp" #include "transpilation/Desc.hpp" @@ -16,6 +17,9 @@ struct Col { /// Signals to order_by that this column is to be sorted in descending order. auto desc() const noexcept { return transpilation::Desc>{}; } + + /// Returns the column name. + std::string name() const noexcept { return Name().str(); } }; template diff --git a/include/sqlgen/sqlite/Connection.hpp b/include/sqlgen/sqlite/Connection.hpp index 9a34717..9f15ef0 100644 --- a/include/sqlgen/sqlite/Connection.hpp +++ b/include/sqlgen/sqlite/Connection.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -46,10 +47,23 @@ class Connection : public sqlgen::Connection { const std::vector>>& _data) final; private: + /// Transforms a column or value to SQL. + std::string column_or_value_to_sql( + const dynamic::ColumnOrValue& _col) const noexcept; + /// Transforms a dynamic::Column to an SQL string that defines the column in /// a CREATE TABLE statement. std::string column_to_sql_definition(const dynamic::Column& _col) noexcept; + /// Transforms a condition to SQL. + std::string condition_to_sql( + const dynamic::Condition& _condition) const noexcept; + + /// Transforms a partilar condition to SQL. + template + std::string condition_to_sql_impl( + const ConditionType& _condition) const noexcept; + /// Transforms a CreateTable Statement to an SQL string. std::string create_table_to_sql(const dynamic::CreateTable& _stmt) noexcept; @@ -77,6 +91,51 @@ class Connection : public sqlgen::Connection { ConnPtr conn_; }; +template +std::string Connection::condition_to_sql_impl( + const ConditionType& _condition) const noexcept { + using C = std::remove_cvref_t; + std::stringstream stream; + + if constexpr (std::is_same_v) { + stream << "(" << condition_to_sql(*_condition.cond1) << ") AND (" + << condition_to_sql(*_condition.cond2) << ")"; + + } else if constexpr (std::is_same_v) { + stream << column_or_value_to_sql(_condition.op1) << " = " + << column_or_value_to_sql(_condition.op2); + + } else if constexpr (std::is_same_v) { + stream << column_or_value_to_sql(_condition.op1) + << " >= " << column_or_value_to_sql(_condition.op2); + + } else if constexpr (std::is_same_v) { + stream << column_or_value_to_sql(_condition.op1) << " > " + << column_or_value_to_sql(_condition.op2); + + } else if constexpr (std::is_same_v) { + stream << column_or_value_to_sql(_condition.op1) + << " != " << column_or_value_to_sql(_condition.op2); + + } else if constexpr (std::is_same_v) { + stream << column_or_value_to_sql(_condition.op1) + << " <= " << column_or_value_to_sql(_condition.op2); + + } else if constexpr (std::is_same_v) { + stream << column_or_value_to_sql(_condition.op1) << " < " + << column_or_value_to_sql(_condition.op2); + + } else if constexpr (std::is_same_v) { + stream << "(" << condition_to_sql(*_condition.cond1) << ") OR (" + << condition_to_sql(*_condition.cond2) << ")"; + + } else { + static_assert(rfl::always_false_v, "Not all cases where covered."); + } + + return stream.str(); +} + } // namespace sqlgen::sqlite #endif diff --git a/src/sqlgen/sqlite/Connection.cpp b/src/sqlgen/sqlite/Connection.cpp index f414312..0f1661e 100644 --- a/src/sqlgen/sqlite/Connection.cpp +++ b/src/sqlgen/sqlite/Connection.cpp @@ -10,6 +10,27 @@ namespace sqlgen::sqlite { +std::string Connection::column_or_value_to_sql( + const dynamic::ColumnOrValue& _col) const noexcept { + const auto handle_value = [](const auto& _v) -> std::string { + using Type = std::remove_cvref_t; + if constexpr (std::is_same_v) { + return "'" + _v.val + "'"; + } else { + return std::to_string(_v.val); + } + }; + + return _col.visit([&](const auto& _c) -> std::string { + using Type = std::remove_cvref_t; + if constexpr (std::is_same_v) { + return "\"" + _c.name + "\""; + } else { + return _c.visit(handle_value); + } + }); +} + std::string Connection::column_to_sql_definition( const dynamic::Column& _col) noexcept { return "\"" + _col.name + "\"" + " " + type_to_sql(_col.type) + @@ -17,6 +38,12 @@ std::string Connection::column_to_sql_definition( _col.type.visit([](const auto& _t) { return _t.properties; })); } +std::string Connection::condition_to_sql( + const dynamic::Condition& _cond) const noexcept { + return _cond.val.visit( + [&](const auto& _c) { return condition_to_sql_impl(_c); }); +} + std::string Connection::create_table_to_sql( const dynamic::CreateTable& _stmt) noexcept { using namespace std::ranges::views; @@ -116,6 +143,8 @@ std::string Connection::properties_to_sql( Result> Connection::read(const dynamic::SelectFrom& _query) { const auto sql = to_sql(_query); + std::cout << sql << std::endl; + sqlite3_stmt* p_stmt = nullptr; sqlite3_prepare(conn_.get(), /* Database handle */ @@ -158,6 +187,10 @@ std::string Connection::select_from_to_sql( } stream << "\"" << _stmt.table.name << "\""; + if (_stmt.where) { + stream << " WHERE " << condition_to_sql(*_stmt.where); + } + if (_stmt.order_by) { stream << " ORDER BY " << internal::strings::join( diff --git a/tests/sqlite/test_where.cpp b/tests/sqlite/test_where.cpp index d5b15d3..dba2d02 100644 --- a/tests/sqlite/test_where.cpp +++ b/tests/sqlite/test_where.cpp @@ -32,9 +32,10 @@ TEST(sqlite, test_where) { using namespace sqlgen; - const auto query = sqlgen::read> | - where(col<"first_name"> != col<"last_name">) | - order_by(col<"age">, col<"first_name">.desc()); + const auto query = + sqlgen::read> | + where(col<"first_name"> != col<"last_name"> or col<"id"> != col<"age">) | + order_by(col<"age">, col<"first_name">.desc()); const auto people2 = query(conn).value();