WHERE works on SQLite

This commit is contained in:
Dr. Patrick Urbanke
2025-05-05 06:08:24 +02:00
parent 5496464de7
commit 4fc2eb7766
4 changed files with 100 additions and 3 deletions

View File

@@ -2,6 +2,7 @@
#define SQLGEN_COL_HPP_
#include <rfl.hpp>
#include <string>
#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<Col<_name>>{}; }
/// Returns the column name.
std::string name() const noexcept { return Name().str(); }
};
template <rfl::internal::StringLiteral _name>

View File

@@ -5,6 +5,7 @@
#include <memory>
#include <rfl.hpp>
#include <sstream>
#include <stdexcept>
#include <string>
@@ -46,10 +47,23 @@ class Connection : public sqlgen::Connection {
const std::vector<std::vector<std::optional<std::string>>>& _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 <class ConditionType>
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 <class ConditionType>
std::string Connection::condition_to_sql_impl(
const ConditionType& _condition) const noexcept {
using C = std::remove_cvref_t<ConditionType>;
std::stringstream stream;
if constexpr (std::is_same_v<C, dynamic::Condition::And>) {
stream << "(" << condition_to_sql(*_condition.cond1) << ") AND ("
<< condition_to_sql(*_condition.cond2) << ")";
} else if constexpr (std::is_same_v<C, dynamic::Condition::Equal>) {
stream << column_or_value_to_sql(_condition.op1) << " = "
<< column_or_value_to_sql(_condition.op2);
} else if constexpr (std::is_same_v<C, dynamic::Condition::GreaterEqual>) {
stream << column_or_value_to_sql(_condition.op1)
<< " >= " << column_or_value_to_sql(_condition.op2);
} else if constexpr (std::is_same_v<C, dynamic::Condition::GreaterThan>) {
stream << column_or_value_to_sql(_condition.op1) << " > "
<< column_or_value_to_sql(_condition.op2);
} else if constexpr (std::is_same_v<C, dynamic::Condition::NotEqual>) {
stream << column_or_value_to_sql(_condition.op1)
<< " != " << column_or_value_to_sql(_condition.op2);
} else if constexpr (std::is_same_v<C, dynamic::Condition::LesserEqual>) {
stream << column_or_value_to_sql(_condition.op1)
<< " <= " << column_or_value_to_sql(_condition.op2);
} else if constexpr (std::is_same_v<C, dynamic::Condition::LesserThan>) {
stream << column_or_value_to_sql(_condition.op1) << " < "
<< column_or_value_to_sql(_condition.op2);
} else if constexpr (std::is_same_v<C, dynamic::Condition::Or>) {
stream << "(" << condition_to_sql(*_condition.cond1) << ") OR ("
<< condition_to_sql(*_condition.cond2) << ")";
} else {
static_assert(rfl::always_false_v<C>, "Not all cases where covered.");
}
return stream.str();
}
} // namespace sqlgen::sqlite
#endif

View File

@@ -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<decltype(_v)>;
if constexpr (std::is_same_v<Type, dynamic::String>) {
return "'" + _v.val + "'";
} else {
return std::to_string(_v.val);
}
};
return _col.visit([&](const auto& _c) -> std::string {
using Type = std::remove_cvref_t<decltype(_c)>;
if constexpr (std::is_same_v<Type, dynamic::Column>) {
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<Ref<IteratorBase>> 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(

View File

@@ -32,9 +32,10 @@ TEST(sqlite, test_where) {
using namespace sqlgen;
const auto query = sqlgen::read<std::vector<Person>> |
where(col<"first_name"> != col<"last_name">) |
order_by(col<"age">, col<"first_name">.desc());
const auto query =
sqlgen::read<std::vector<Person>> |
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();