diff --git a/include/sqlgen.hpp b/include/sqlgen.hpp index ee491b4..b656928 100644 --- a/include/sqlgen.hpp +++ b/include/sqlgen.hpp @@ -14,6 +14,7 @@ #include "sqlgen/limit.hpp" #include "sqlgen/order_by.hpp" #include "sqlgen/read.hpp" +#include "sqlgen/where.hpp" #include "sqlgen/write.hpp" #endif diff --git a/include/sqlgen/IteratorBase.hpp b/include/sqlgen/IteratorBase.hpp index aabac61..7bd3598 100644 --- a/include/sqlgen/IteratorBase.hpp +++ b/include/sqlgen/IteratorBase.hpp @@ -11,6 +11,8 @@ namespace sqlgen { /// Abstract base class for an iterator to be returned by Connection::read(...). struct IteratorBase { + virtual ~IteratorBase() = default; + /// Whether the end of the available data has been reached. virtual bool end() const = 0; diff --git a/include/sqlgen/col.hpp b/include/sqlgen/col.hpp index c3c707a..1dd369b 100644 --- a/include/sqlgen/col.hpp +++ b/include/sqlgen/col.hpp @@ -3,7 +3,10 @@ #include +#include "transpilation/Condition.hpp" #include "transpilation/Desc.hpp" +#include "transpilation/Value.hpp" +#include "transpilation/conditions.hpp" namespace sqlgen { @@ -18,6 +21,84 @@ struct Col { template const auto col = Col<_name>{}; +template +auto operator==(const Col<_name1>&, const Col<_name2>&) { + return transpilation::make_condition( + transpilation::conditions::equal(Col<_name1>{}, Col<_name2>{})); +} + +template +auto operator==(const Col<_name1>&, const T& _t) { + return transpilation::make_condition(transpilation::conditions::equal( + Col<_name1>{}, transpilation::make_value(_t))); +} + +template +auto operator!=(const Col<_name1>&, const Col<_name2>&) { + return transpilation::make_condition( + transpilation::conditions::not_equal(Col<_name1>{}, Col<_name2>{})); +} + +template +auto operator!=(const Col<_name1>&, const T& _t) { + return transpilation::make_condition(transpilation::conditions::not_equal( + Col<_name1>{}, transpilation::make_value(_t))); +} + +template +auto operator<(const Col<_name1>&, const Col<_name2>&) { + return transpilation::make_condition( + transpilation::conditions::lesser_than(Col<_name1>{}, Col<_name2>{})); +} + +template +auto operator<(const Col<_name1>&, const T& _t) { + return transpilation::make_condition(transpilation::conditions::lesser_than( + Col<_name1>{}, transpilation::make_value(_t))); +} + +template +auto operator<=(const Col<_name1>&, const Col<_name2>&) { + return transpilation::make_condition( + transpilation::conditions::lesser_equal(Col<_name1>{}, Col<_name2>{})); +} + +template +auto operator<=(const Col<_name1>&, const T& _t) { + return transpilation::make_condition(transpilation::conditions::lesser_equal( + Col<_name1>{}, transpilation::make_value(_t))); +} + +template +auto operator>(const Col<_name1>&, const Col<_name2>&) { + return transpilation::make_condition( + transpilation::conditions::greater_than(Col<_name1>{}, Col<_name2>{})); +} + +template +auto operator>(const Col<_name1>&, const T& _t) { + return transpilation::make_condition(transpilation::conditions::greater_than( + Col<_name1>{}, transpilation::make_value(_t))); +} + +template +auto operator>=(const Col<_name1>&, const Col<_name2>&) { + return transpilation::make_condition( + transpilation::conditions::greater_equal(Col<_name1>{}, Col<_name2>{})); +} + +template +auto operator>=(const Col<_name1>&, const T& _t) { + return transpilation::make_condition(transpilation::conditions::greater_equal( + Col<_name1>{}, transpilation::make_value(_t))); +} + } // namespace sqlgen #endif diff --git a/include/sqlgen/dynamic/Condition.hpp b/include/sqlgen/dynamic/Condition.hpp index eb8fa7b..9ceb1ec 100644 --- a/include/sqlgen/dynamic/Condition.hpp +++ b/include/sqlgen/dynamic/Condition.hpp @@ -15,7 +15,7 @@ struct Condition { Ref cond2; }; - struct Equals { + struct Equal { Column op1; ColumnOrValue op2; }; @@ -30,7 +30,7 @@ struct Condition { ColumnOrValue op2; }; - struct NotEquals { + struct NotEqual { Column op1; ColumnOrValue op2; }; @@ -51,8 +51,8 @@ struct Condition { }; using ReflectionType = - rfl::TaggedUnion<"what", And, Equals, GreaterEqual, GreaterThan, - NotEquals, LesserEqual, LesserThan, Or>; + rfl::TaggedUnion<"what", And, Equal, GreaterEqual, GreaterThan, NotEqual, + LesserEqual, LesserThan, Or>; const ReflectionType& reflection() const { return val; } diff --git a/include/sqlgen/limit.hpp b/include/sqlgen/limit.hpp index a2cf811..6e29a7f 100644 --- a/include/sqlgen/limit.hpp +++ b/include/sqlgen/limit.hpp @@ -12,14 +12,15 @@ namespace sqlgen { using Limit = transpilation::Limit; -template -auto operator|(const Read& _r, +template +auto operator|(const Read& _r, const Limit& _limit) { static_assert(std::is_same_v, "You cannot call limit twice (but you can order by more " "than one column)."); - return Read{.order_by_ = _r.order_by_, - .limit_ = _limit}; + return Read{ + .where_ = _r.where_, .order_by_ = _r.order_by_, .limit_ = _limit}; } inline auto limit(const size_t _val) { return Limit{_val}; }; diff --git a/include/sqlgen/order_by.hpp b/include/sqlgen/order_by.hpp index 426f33d..6f24792 100644 --- a/include/sqlgen/order_by.hpp +++ b/include/sqlgen/order_by.hpp @@ -13,17 +13,21 @@ namespace sqlgen { template struct OrderBy {}; -template -auto operator|(const Read&, +template +auto operator|(const Read& _r, const OrderBy&) { static_assert(std::is_same_v, "You cannot call order_by twice (but you can order by more " "than one column)."); + static_assert(std::is_same_v, + "Limit must be called after order_by."); static_assert(sizeof...(ColTypes) != 0, "You must assign at least one column to order by."); - return Read, - std::remove_cvref_t...>>{}; + std::remove_cvref_t...>, + LimitType>{.where_ = _r.where_}; } template diff --git a/include/sqlgen/read.hpp b/include/sqlgen/read.hpp index f628506..c8c9af7 100644 --- a/include/sqlgen/read.hpp +++ b/include/sqlgen/read.hpp @@ -13,8 +13,10 @@ namespace sqlgen { -template +template Result read_impl(const Ref& _conn, + const WhereType& _where, const LimitType& _limit) { using ValueType = transpilation::value_t; if constexpr (internal::is_range_v) { @@ -36,30 +38,37 @@ Result read_impl(const Ref& _conn, return container; }; - return read_impl, OrderByType>(_conn, _limit) + return read_impl, WhereType, OrderByType, LimitType>( + _conn, _where, _limit) .and_then(to_container); } } -template +template Result read_impl(const Result>& _res, + const WhereType& _where, const LimitType& _limit) { return _res.and_then([&](const auto& _conn) { - return read_impl(_conn, _limit); + return read_impl( + _conn, _where, _limit); }); } -template +template struct Read { Result operator()(const auto& _conn) const noexcept { try { - return read_impl(_conn, limit_); + return read_impl( + _conn, where_, limit_); } catch (std::exception& e) { return error(e.what()); } } + WhereType where_; + OrderByType order_by_; LimitType limit_; diff --git a/include/sqlgen/transpilation/Condition.hpp b/include/sqlgen/transpilation/Condition.hpp index 2984115..1b86417 100644 --- a/include/sqlgen/transpilation/Condition.hpp +++ b/include/sqlgen/transpilation/Condition.hpp @@ -1,6 +1,8 @@ #ifndef SQLGEN_TRANSPILATION_CONDITION_HPP_ #define SQLGEN_TRANSPILATION_CONDITION_HPP_ +#include + #include "conditions.hpp" namespace sqlgen::transpilation { @@ -11,18 +13,21 @@ struct Condition { ConditionType condition; }; +template +auto make_condition(T&& _t) { + return Condition>{.condition = _t}; +} + template auto operator&&(const Condition& _cond1, const Condition& _cond2) { - return Condition>{ - .condition = conditions::And{.cond1 = _cond1.condition, - .cond2 = _cond2.condition}}; + return make_condition(conditions::And{.cond1 = _cond1.condition, + .cond2 = _cond2.condition}); } template auto operator||(const Condition& _cond1, const Condition& _cond2) { - return Condition>{ - .condition = conditions::Or{.cond1 = _cond1.condition, - .cond2 = _cond2.condition}}; + return make_condition(conditions::Or{.cond1 = _cond1.condition, + .cond2 = _cond2.condition}); } } // namespace sqlgen::transpilation diff --git a/include/sqlgen/transpilation/Value.hpp b/include/sqlgen/transpilation/Value.hpp index de49d0d..15552c1 100644 --- a/include/sqlgen/transpilation/Value.hpp +++ b/include/sqlgen/transpilation/Value.hpp @@ -1,6 +1,8 @@ #ifndef SQLGEN_TRANSPILATION_VALUE_HPP_ #define SQLGEN_TRANSPILATION_VALUE_HPP_ +#include + namespace sqlgen::transpilation { template @@ -8,6 +10,11 @@ struct Value { T val; }; +template +auto make_value(T&& _t) { + return Value>{.val_ = _t}; +} + } // namespace sqlgen::transpilation #endif diff --git a/include/sqlgen/transpilation/conditions.hpp b/include/sqlgen/transpilation/conditions.hpp index c6c202e..502b48a 100644 --- a/include/sqlgen/transpilation/conditions.hpp +++ b/include/sqlgen/transpilation/conditions.hpp @@ -10,17 +10,29 @@ struct And { }; template -struct Equals { +struct Equal { OpType1 op1; OpType2 op2; }; +template +auto equal(const OpType1& _op1, const OpType2& _op2) { + return Equal, std::remove_cvref_t>{ + .op1 = _op1, .op2 = _op2}; +} + template struct GreaterEqual { OpType1 op1; OpType2 op2; }; +template +auto greater_equal(const OpType1& _op1, const OpType2& _op2) { + return GreaterEqual, + std::remove_cvref_t>{.op1 = _op1, .op2 = _op2}; +} + template struct GreaterThan { OpType1 op1; @@ -28,23 +40,47 @@ struct GreaterThan { }; template -struct NotEquals { +auto greater_than(const OpType1& _op1, const OpType2& _op2) { + return GreaterThan, + std::remove_cvref_t>{.op1 = _op1, .op2 = _op2}; +} + +template +struct NotEqual { OpType1 op1; OpType2 op2; }; +template +auto not_equal(const OpType1& _op1, const OpType2& _op2) { + return NotEqual, std::remove_cvref_t>{ + .op1 = _op1, .op2 = _op2}; +} + template struct LesserEqual { OpType1 op1; OpType2 op2; }; +template +auto lesser_equal(const OpType1& _op1, const OpType2& _op2) { + return LesserEqual, + std::remove_cvref_t>{.op1 = _op1, .op2 = _op2}; +} + template struct LesserThan { OpType1 op1; OpType2 op2; }; +template +auto lesser_than(const OpType1& _op1, const OpType2& _op2) { + return LesserThan, std::remove_cvref_t>{ + .op1 = _op1, .op2 = _op2}; +} + template struct Or { CondType1 cond1; diff --git a/include/sqlgen/transpilation/to_condition.hpp b/include/sqlgen/transpilation/to_condition.hpp index 06bad2a..ffb9d57 100644 --- a/include/sqlgen/transpilation/to_condition.hpp +++ b/include/sqlgen/transpilation/to_condition.hpp @@ -36,6 +36,78 @@ struct ToCondition> { } }; +template +struct ToCondition, Col<_name2>>> { + dynamic::Condition operator()( + const conditions::Equal, Col<_name2>>& _cond) const { + return dynamic::Condition{.val = dynamic::Condition::Equal{ + .op1 = dynamic::Column{.name = _name1.str()}, + .op2 = dynamic::Column{.name = _name2.str()}, + }}; + } +}; + +template +struct ToCondition, Col<_name2>>> { + dynamic::Condition operator()( + const conditions::GreaterEqual, Col<_name2>>& _cond) const { + return dynamic::Condition{.val = dynamic::Condition::GreaterEqual{ + .op1 = dynamic::Column{.name = _name1.str()}, + .op2 = dynamic::Column{.name = _name2.str()}, + }}; + } +}; + +template +struct ToCondition, Col<_name2>>> { + dynamic::Condition operator()( + const conditions::GreaterThan, Col<_name2>>& _cond) const { + return dynamic::Condition{.val = dynamic::Condition::GreaterThan{ + .op1 = dynamic::Column{.name = _name1.str()}, + .op2 = dynamic::Column{.name = _name2.str()}, + }}; + } +}; + +template +struct ToCondition, Col<_name2>>> { + dynamic::Condition operator()( + const conditions::LesserEqual, Col<_name2>>& _cond) const { + return dynamic::Condition{.val = dynamic::Condition::LesserEqual{ + .op1 = dynamic::Column{.name = _name1.str()}, + .op2 = dynamic::Column{.name = _name2.str()}, + }}; + } +}; + +template +struct ToCondition, Col<_name2>>> { + dynamic::Condition operator()( + const conditions::LesserThan, Col<_name2>>& _cond) const { + return dynamic::Condition{.val = dynamic::Condition::LesserThan{ + .op1 = dynamic::Column{.name = _name1.str()}, + .op2 = dynamic::Column{.name = _name2.str()}, + }}; + } +}; + +template +struct ToCondition, Col<_name2>>> { + dynamic::Condition operator()( + const conditions::NotEqual, Col<_name2>>& _cond) const { + return dynamic::Condition{.val = dynamic::Condition::NotEqual{ + .op1 = dynamic::Column{.name = _name1.str()}, + .op2 = dynamic::Column{.name = _name2.str()}, + }}; + } +}; + template struct ToCondition> { dynamic::Condition operator()( diff --git a/include/sqlgen/where.hpp b/include/sqlgen/where.hpp new file mode 100644 index 0000000..7774100 --- /dev/null +++ b/include/sqlgen/where.hpp @@ -0,0 +1,40 @@ +#ifndef SQLGEN_WHERE_HPP_ +#define SQLGEN_WHERE_HPP_ + +#include + +#include "Result.hpp" +#include "read.hpp" +#include "transpilation/Limit.hpp" +#include "transpilation/value_t.hpp" + +namespace sqlgen { + +template +struct Where { + ConditionType condition; +}; + +template +auto operator|(const Read& _r, + const Where& _where) { + static_assert(std::is_same_v, + "You cannot call where(...) twice (but you can apply more " + "than one condition by combining them with && or ||)."); + static_assert(std::is_same_v, + "You must call order_by(...) after where(...)."); + static_assert(std::is_same_v, + "You must call limit(...) after where(...)."); + return Read{ + .where_ = _where.condition}; +} + +template +inline auto where(const ConditionType& _cond) { + return Where>{.condition = _cond}; +}; + +} // namespace sqlgen + +#endif