mirror of
https://github.com/getml/sqlgen.git
synced 2025-12-31 06:30:18 -06:00
Continued working on .where(...)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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}; };
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
40
include/sqlgen/where.hpp
Normal 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
|
||||
Reference in New Issue
Block a user