Continued working on .where(...)

This commit is contained in:
Dr. Patrick Urbanke
2025-05-05 05:00:09 +02:00
parent 360e31bdda
commit e736abfbb1
12 changed files with 285 additions and 27 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -3,7 +3,10 @@
#include <rfl.hpp>
#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 <rfl::internal::StringLiteral _name>
const auto col = Col<_name>{};
template <rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
auto operator==(const Col<_name1>&, const Col<_name2>&) {
return transpilation::make_condition(
transpilation::conditions::equal(Col<_name1>{}, Col<_name2>{}));
}
template <rfl::internal::StringLiteral _name1, class T>
auto operator==(const Col<_name1>&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::equal(
Col<_name1>{}, transpilation::make_value(_t)));
}
template <rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
auto operator!=(const Col<_name1>&, const Col<_name2>&) {
return transpilation::make_condition(
transpilation::conditions::not_equal(Col<_name1>{}, Col<_name2>{}));
}
template <rfl::internal::StringLiteral _name1, class T>
auto operator!=(const Col<_name1>&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::not_equal(
Col<_name1>{}, transpilation::make_value(_t)));
}
template <rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
auto operator<(const Col<_name1>&, const Col<_name2>&) {
return transpilation::make_condition(
transpilation::conditions::lesser_than(Col<_name1>{}, Col<_name2>{}));
}
template <rfl::internal::StringLiteral _name1, class T>
auto operator<(const Col<_name1>&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::lesser_than(
Col<_name1>{}, transpilation::make_value(_t)));
}
template <rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
auto operator<=(const Col<_name1>&, const Col<_name2>&) {
return transpilation::make_condition(
transpilation::conditions::lesser_equal(Col<_name1>{}, Col<_name2>{}));
}
template <rfl::internal::StringLiteral _name1, class T>
auto operator<=(const Col<_name1>&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::lesser_equal(
Col<_name1>{}, transpilation::make_value(_t)));
}
template <rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
auto operator>(const Col<_name1>&, const Col<_name2>&) {
return transpilation::make_condition(
transpilation::conditions::greater_than(Col<_name1>{}, Col<_name2>{}));
}
template <rfl::internal::StringLiteral _name1, class T>
auto operator>(const Col<_name1>&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::greater_than(
Col<_name1>{}, transpilation::make_value(_t)));
}
template <rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
auto operator>=(const Col<_name1>&, const Col<_name2>&) {
return transpilation::make_condition(
transpilation::conditions::greater_equal(Col<_name1>{}, Col<_name2>{}));
}
template <rfl::internal::StringLiteral _name1, class T>
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

View File

@@ -15,7 +15,7 @@ struct Condition {
Ref<Condition> 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; }

View File

@@ -12,14 +12,15 @@ namespace sqlgen {
using Limit = transpilation::Limit;
template <class ContainerType, class OrderByType, class LimitType>
auto operator|(const Read<ContainerType, OrderByType, LimitType>& _r,
template <class ContainerType, class WhereType, class OrderByType,
class LimitType>
auto operator|(const Read<ContainerType, WhereType, OrderByType, LimitType>& _r,
const Limit& _limit) {
static_assert(std::is_same_v<LimitType, Nothing>,
"You cannot call limit twice (but you can order by more "
"than one column).");
return Read<ContainerType, OrderByType, Limit>{.order_by_ = _r.order_by_,
.limit_ = _limit};
return Read<ContainerType, WhereType, OrderByType, Limit>{
.where_ = _r.where_, .order_by_ = _r.order_by_, .limit_ = _limit};
}
inline auto limit(const size_t _val) { return Limit{_val}; };

View File

@@ -13,17 +13,21 @@ namespace sqlgen {
template <class... ColTypes>
struct OrderBy {};
template <class ContainerType, class OrderByType, class... ColTypes>
auto operator|(const Read<ContainerType, OrderByType>&,
template <class ContainerType, class WhereType, class OrderByType,
class LimitType, class... ColTypes>
auto operator|(const Read<ContainerType, WhereType, OrderByType, LimitType>& _r,
const OrderBy<ColTypes...>&) {
static_assert(std::is_same_v<OrderByType, Nothing>,
"You cannot call order_by twice (but you can order by more "
"than one column).");
static_assert(std::is_same_v<LimitType, Nothing>,
"Limit must be called after order_by.");
static_assert(sizeof...(ColTypes) != 0,
"You must assign at least one column to order by.");
return Read<ContainerType,
return Read<ContainerType, WhereType,
transpilation::order_by_t<transpilation::value_t<ContainerType>,
std::remove_cvref_t<ColTypes>...>>{};
std::remove_cvref_t<ColTypes>...>,
LimitType>{.where_ = _r.where_};
}
template <class... ColTypes>

View File

@@ -13,8 +13,10 @@
namespace sqlgen {
template <class ContainerType, class OrderByType, class LimitType>
template <class ContainerType, class WhereType, class OrderByType,
class LimitType>
Result<ContainerType> read_impl(const Ref<Connection>& _conn,
const WhereType& _where,
const LimitType& _limit) {
using ValueType = transpilation::value_t<ContainerType>;
if constexpr (internal::is_range_v<ContainerType>) {
@@ -36,30 +38,37 @@ Result<ContainerType> read_impl(const Ref<Connection>& _conn,
return container;
};
return read_impl<Range<ValueType>, OrderByType>(_conn, _limit)
return read_impl<Range<ValueType>, WhereType, OrderByType, LimitType>(
_conn, _where, _limit)
.and_then(to_container);
}
}
template <class ContainerType, class OrderByType, class LimitType>
template <class ContainerType, class WhereType, class OrderByType,
class LimitType>
Result<ContainerType> read_impl(const Result<Ref<Connection>>& _res,
const WhereType& _where,
const LimitType& _limit) {
return _res.and_then([&](const auto& _conn) {
return read_impl<ContainerType, OrderByType>(_conn, _limit);
return read_impl<ContainerType, WhereType, OrderByType, LimitType>(
_conn, _where, _limit);
});
}
template <class ContainerType, class OrderByType = Nothing,
class LimitType = Nothing>
template <class ContainerType, class WhereType = Nothing,
class OrderByType = Nothing, class LimitType = Nothing>
struct Read {
Result<ContainerType> operator()(const auto& _conn) const noexcept {
try {
return read_impl<ContainerType, OrderByType>(_conn, limit_);
return read_impl<ContainerType, WhereType, OrderByType, LimitType>(
_conn, where_, limit_);
} catch (std::exception& e) {
return error(e.what());
}
}
WhereType where_;
OrderByType order_by_;
LimitType limit_;

View File

@@ -1,6 +1,8 @@
#ifndef SQLGEN_TRANSPILATION_CONDITION_HPP_
#define SQLGEN_TRANSPILATION_CONDITION_HPP_
#include <type_traits>
#include "conditions.hpp"
namespace sqlgen::transpilation {
@@ -11,18 +13,21 @@ struct Condition {
ConditionType condition;
};
template <class T>
auto make_condition(T&& _t) {
return Condition<std::remove_cvref_t<T>>{.condition = _t};
}
template <class C1, class C2>
auto operator&&(const Condition<C1>& _cond1, const Condition<C2>& _cond2) {
return Condition<conditions::And<C1, C2>>{
.condition = conditions::And<C1, C2>{.cond1 = _cond1.condition,
.cond2 = _cond2.condition}};
return make_condition(conditions::And<C1, C2>{.cond1 = _cond1.condition,
.cond2 = _cond2.condition});
}
template <class C1, class C2>
auto operator||(const Condition<C1>& _cond1, const Condition<C2>& _cond2) {
return Condition<conditions::Or<C1, C2>>{
.condition = conditions::Or<C1, C2>{.cond1 = _cond1.condition,
.cond2 = _cond2.condition}};
return make_condition(conditions::Or<C1, C2>{.cond1 = _cond1.condition,
.cond2 = _cond2.condition});
}
} // namespace sqlgen::transpilation

View File

@@ -1,6 +1,8 @@
#ifndef SQLGEN_TRANSPILATION_VALUE_HPP_
#define SQLGEN_TRANSPILATION_VALUE_HPP_
#include <type_traits>
namespace sqlgen::transpilation {
template <class T>
@@ -8,6 +10,11 @@ struct Value {
T val;
};
template <class T>
auto make_value(T&& _t) {
return Value<std::remove_cvref_t<T>>{.val_ = _t};
}
} // namespace sqlgen::transpilation
#endif

View File

@@ -10,17 +10,29 @@ struct And {
};
template <class OpType1, class OpType2>
struct Equals {
struct Equal {
OpType1 op1;
OpType2 op2;
};
template <class OpType1, class OpType2>
auto equal(const OpType1& _op1, const OpType2& _op2) {
return Equal<std::remove_cvref_t<OpType1>, std::remove_cvref_t<OpType2>>{
.op1 = _op1, .op2 = _op2};
}
template <class OpType1, class OpType2>
struct GreaterEqual {
OpType1 op1;
OpType2 op2;
};
template <class OpType1, class OpType2>
auto greater_equal(const OpType1& _op1, const OpType2& _op2) {
return GreaterEqual<std::remove_cvref_t<OpType1>,
std::remove_cvref_t<OpType2>>{.op1 = _op1, .op2 = _op2};
}
template <class OpType1, class OpType2>
struct GreaterThan {
OpType1 op1;
@@ -28,23 +40,47 @@ struct GreaterThan {
};
template <class OpType1, class OpType2>
struct NotEquals {
auto greater_than(const OpType1& _op1, const OpType2& _op2) {
return GreaterThan<std::remove_cvref_t<OpType1>,
std::remove_cvref_t<OpType2>>{.op1 = _op1, .op2 = _op2};
}
template <class OpType1, class OpType2>
struct NotEqual {
OpType1 op1;
OpType2 op2;
};
template <class OpType1, class OpType2>
auto not_equal(const OpType1& _op1, const OpType2& _op2) {
return NotEqual<std::remove_cvref_t<OpType1>, std::remove_cvref_t<OpType2>>{
.op1 = _op1, .op2 = _op2};
}
template <class OpType1, class OpType2>
struct LesserEqual {
OpType1 op1;
OpType2 op2;
};
template <class OpType1, class OpType2>
auto lesser_equal(const OpType1& _op1, const OpType2& _op2) {
return LesserEqual<std::remove_cvref_t<OpType1>,
std::remove_cvref_t<OpType2>>{.op1 = _op1, .op2 = _op2};
}
template <class OpType1, class OpType2>
struct LesserThan {
OpType1 op1;
OpType2 op2;
};
template <class OpType1, class OpType2>
auto lesser_than(const OpType1& _op1, const OpType2& _op2) {
return LesserThan<std::remove_cvref_t<OpType1>, std::remove_cvref_t<OpType2>>{
.op1 = _op1, .op2 = _op2};
}
template <class CondType1, class CondType2>
struct Or {
CondType1 cond1;

View File

@@ -36,6 +36,78 @@ struct ToCondition<T, conditions::And<CondType1, CondType2>> {
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::Equal<Col<_name1>, Col<_name2>>> {
dynamic::Condition operator()(
const conditions::Equal<Col<_name1>, Col<_name2>>& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::Equal{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::GreaterEqual<Col<_name1>, Col<_name2>>> {
dynamic::Condition operator()(
const conditions::GreaterEqual<Col<_name1>, Col<_name2>>& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::GreaterEqual{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::GreaterThan<Col<_name1>, Col<_name2>>> {
dynamic::Condition operator()(
const conditions::GreaterThan<Col<_name1>, Col<_name2>>& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::GreaterThan{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::LesserEqual<Col<_name1>, Col<_name2>>> {
dynamic::Condition operator()(
const conditions::LesserEqual<Col<_name1>, Col<_name2>>& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::LesserEqual{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::LesserThan<Col<_name1>, Col<_name2>>> {
dynamic::Condition operator()(
const conditions::LesserThan<Col<_name1>, Col<_name2>>& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::LesserThan{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::NotEqual<Col<_name1>, Col<_name2>>> {
dynamic::Condition operator()(
const conditions::NotEqual<Col<_name1>, Col<_name2>>& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::NotEqual{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
}
};
template <class T, class CondType1, class CondType2>
struct ToCondition<T, conditions::Or<CondType1, CondType2>> {
dynamic::Condition operator()(

40
include/sqlgen/where.hpp Normal file
View File

@@ -0,0 +1,40 @@
#ifndef SQLGEN_WHERE_HPP_
#define SQLGEN_WHERE_HPP_
#include <type_traits>
#include "Result.hpp"
#include "read.hpp"
#include "transpilation/Limit.hpp"
#include "transpilation/value_t.hpp"
namespace sqlgen {
template <class ConditionType>
struct Where {
ConditionType condition;
};
template <class ContainerType, class WhereType, class OrderByType,
class LimitType, class ConditionType>
auto operator|(const Read<ContainerType, WhereType, OrderByType, LimitType>& _r,
const Where<ConditionType>& _where) {
static_assert(std::is_same_v<WhereType, Nothing>,
"You cannot call where(...) twice (but you can apply more "
"than one condition by combining them with && or ||).");
static_assert(std::is_same_v<OrderByType, Nothing>,
"You must call order_by(...) after where(...).");
static_assert(std::is_same_v<LimitType, Nothing>,
"You must call limit(...) after where(...).");
return Read<ContainerType, ConditionType, OrderByType, Limit>{
.where_ = _where.condition};
}
template <class ConditionType>
inline auto where(const ConditionType& _cond) {
return Where<std::remove_cvref_t<ConditionType>>{.condition = _cond};
};
} // namespace sqlgen
#endif