Added numerous operations like concat(...), coalesce(...), abs(...), etc (#20)

This commit is contained in:
Dr. Patrick Urbanke (劉自成)
2025-06-22 18:05:48 +02:00
committed by GitHub
parent a6bad187fe
commit 30ba548f1e
45 changed files with 2928 additions and 593 deletions

View File

@@ -30,6 +30,7 @@
#include "sqlgen/insert.hpp"
#include "sqlgen/is_connection.hpp"
#include "sqlgen/limit.hpp"
#include "sqlgen/operations.hpp"
#include "sqlgen/order_by.hpp"
#include "sqlgen/patterns.hpp"
#include "sqlgen/read.hpp"

View File

@@ -5,48 +5,61 @@
#include <type_traits>
#include "col.hpp"
#include "transpilation/aggregations.hpp"
#include "transpilation/Aggregation.hpp"
#include "transpilation/AggregationOp.hpp"
#include "transpilation/to_transpilation_type.hpp"
namespace sqlgen {
template <rfl::internal::StringLiteral _name>
auto avg(const Col<_name>&) {
return transpilation::aggregations::Avg<transpilation::Col<_name>>{
.val = transpilation::Col<_name>{}};
template <class T>
auto avg(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Aggregation<transpilation::AggregationOp::avg, Type>{
.val = transpilation::to_transpilation_type(_t)};
}
inline auto count() {
return transpilation::aggregations::Count<transpilation::aggregations::All>{};
return transpilation::Aggregation<transpilation::AggregationOp::count,
transpilation::All>{};
}
template <rfl::internal::StringLiteral _name>
auto count(const Col<_name>&) {
return transpilation::aggregations::Count<transpilation::Col<_name>>{
return transpilation::Aggregation<transpilation::AggregationOp::count,
transpilation::Col<_name>>{
.val = transpilation::Col<_name>{}};
}
template <rfl::internal::StringLiteral _name>
auto count_distinct(const Col<_name>&) {
return transpilation::aggregations::Count<transpilation::Col<_name>>{
return transpilation::Aggregation<transpilation::AggregationOp::count,
transpilation::Col<_name>>{
.val = transpilation::Col<_name>{}, .distinct = true};
}
template <rfl::internal::StringLiteral _name>
auto max(const Col<_name>&) {
return transpilation::aggregations::Max<transpilation::Col<_name>>{
.val = transpilation::Col<_name>{}};
template <class T>
auto max(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Aggregation<transpilation::AggregationOp::max, Type>{
.val = transpilation::to_transpilation_type(_t)};
}
template <rfl::internal::StringLiteral _name>
auto min(const Col<_name>&) {
return transpilation::aggregations::Min<transpilation::Col<_name>>{
.val = transpilation::Col<_name>{}};
template <class T>
auto min(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Aggregation<transpilation::AggregationOp::min, Type>{
.val = transpilation::to_transpilation_type(_t)};
}
template <rfl::internal::StringLiteral _name>
auto sum(const Col<_name>&) {
return transpilation::aggregations::Sum<transpilation::Col<_name>>{
.val = transpilation::Col<_name>{}};
template <class T>
auto sum(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Aggregation<transpilation::AggregationOp::sum, Type>{
.val = transpilation::to_transpilation_type(_t)};
}
} // namespace sqlgen

View File

@@ -8,9 +8,12 @@
#include "transpilation/Col.hpp"
#include "transpilation/Condition.hpp"
#include "transpilation/Desc.hpp"
#include "transpilation/Operation.hpp"
#include "transpilation/Operator.hpp"
#include "transpilation/Set.hpp"
#include "transpilation/Value.hpp"
#include "transpilation/conditions.hpp"
#include "transpilation/to_transpilation_type.hpp"
namespace sqlgen {
@@ -77,6 +80,103 @@ struct Col {
return transpilation::Set<transpilation::Col<_name>, std::string>{.to =
_to};
}
template <class T>
friend auto operator==(const Col&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::equal(
transpilation::Col<_name>{}, transpilation::to_transpilation_type(_t)));
}
template <class T>
friend auto operator!=(const Col&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::not_equal(
transpilation::Col<_name>{}, transpilation::to_transpilation_type(_t)));
}
template <class T>
friend auto operator<(const Col&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::lesser_than(
transpilation::Col<_name>{}, transpilation::to_transpilation_type(_t)));
}
template <class T>
friend auto operator<=(const Col&, const T& _t) {
return transpilation::make_condition(
transpilation::conditions::lesser_equal(
transpilation::Col<_name>{},
transpilation::to_transpilation_type(_t)));
}
template <class T>
friend auto operator>(const Col&, const T& _t) {
return transpilation::make_condition(
transpilation::conditions::greater_than(
transpilation::Col<_name>{},
transpilation::to_transpilation_type(_t)));
}
template <class T>
friend auto operator>=(const Col&, const T& _t) {
return transpilation::make_condition(
transpilation::conditions::greater_equal(
transpilation::Col<_name>{},
transpilation::to_transpilation_type(_t)));
}
template <class T>
friend auto operator/(const Col&, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::divides,
transpilation::Col<_name>, OtherType>{
.operand1 = transpilation::Col<_name>{},
.operand2 = transpilation::to_transpilation_type(_op2)};
}
template <class T>
friend auto operator-(const Col&, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::minus,
transpilation::Col<_name>, OtherType>{
.operand1 = transpilation::Col<_name>{},
.operand2 = transpilation::to_transpilation_type(_op2)};
}
template <class T>
friend auto operator%(const Col&, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::mod,
transpilation::Col<_name>, OtherType>{
.operand1 = transpilation::Col<_name>{},
.operand2 = transpilation::to_transpilation_type(_op2)};
}
template <class T>
friend auto operator*(const Col&, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::multiplies,
transpilation::Col<_name>, OtherType>{
.operand1 = transpilation::Col<_name>{},
.operand2 = transpilation::to_transpilation_type(_op2)};
}
template <class T>
friend auto operator+(const Col&, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::plus,
transpilation::Col<_name>, OtherType>{
.operand1 = transpilation::Col<_name>{},
.operand2 = transpilation::to_transpilation_type(_op2)};
}
};
template <rfl::internal::StringLiteral _name>
@@ -87,83 +187,18 @@ auto operator"" _c() {
return 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(
transpilation::Col<_name1>{}, transpilation::Col<_name2>{}));
}
namespace transpilation {
template <rfl::internal::StringLiteral _name1, class T>
auto operator==(const Col<_name1>&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::equal(
transpilation::Col<_name1>{}, transpilation::make_value(_t)));
}
template <rfl::internal::StringLiteral _name>
struct ToTranspilationType<sqlgen::Col<_name>> {
using Type = transpilation::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::not_equal(
transpilation::Col<_name1>{}, transpilation::Col<_name2>{}));
}
Type operator()(const auto&) const noexcept {
return transpilation::Col<_name>{};
}
};
template <rfl::internal::StringLiteral _name1, class T>
auto operator!=(const Col<_name1>&, const T& _t) {
return transpilation::make_condition(transpilation::conditions::not_equal(
transpilation::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(
transpilation::Col<_name1>{}, transpilation::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(
transpilation::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(
transpilation::Col<_name1>{}, transpilation::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(
transpilation::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(
transpilation::Col<_name1>{}, transpilation::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(
transpilation::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(
transpilation::Col<_name1>{}, transpilation::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(
transpilation::Col<_name1>{}, transpilation::make_value(_t)));
}
} // namespace transpilation
} // namespace sqlgen

View File

@@ -1,44 +1,11 @@
#ifndef SQLGEN_DYNAMIC_AGGREGATION_HPP_
#define SQLGEN_DYNAMIC_AGGREGATION_HPP_
#include <optional>
#include <rfl.hpp>
#include <string>
#include <vector>
#include "Column.hpp"
#include "ColumnOrValue.hpp"
#include "Operation.hpp"
namespace sqlgen::dynamic {
struct Aggregation {
struct Avg {
ColumnOrValue val;
};
struct Count {
std::optional<Column> val;
bool distinct = false;
};
struct Max {
ColumnOrValue val;
};
struct Min {
ColumnOrValue val;
};
struct Sum {
ColumnOrValue val;
};
using ReflectionType = rfl::TaggedUnion<"what", Avg, Count, Max, Min, Sum>;
const ReflectionType& reflection() const { return val; }
ReflectionType val;
};
using Aggregation = Operation::Aggregation;
} // namespace sqlgen::dynamic

View File

@@ -6,6 +6,7 @@
#include "../Ref.hpp"
#include "Column.hpp"
#include "ColumnOrValue.hpp"
#include "Operation.hpp"
namespace sqlgen::dynamic {
@@ -16,50 +17,54 @@ struct Condition {
};
struct Equal {
Column op1;
ColumnOrValue op2;
Operation op1;
Operation op2;
};
struct GreaterEqual {
Column op1;
ColumnOrValue op2;
Operation op1;
Operation op2;
};
struct GreaterThan {
Column op1;
ColumnOrValue op2;
Operation op1;
Operation op2;
};
struct IsNotNull {
Column op;
Operation op;
};
struct IsNull {
Column op;
Operation op;
};
struct LesserEqual {
Column op1;
ColumnOrValue op2;
Operation op1;
Operation op2;
};
struct LesserThan {
Column op1;
ColumnOrValue op2;
Operation op1;
Operation op2;
};
struct Like {
Column op;
Operation op;
dynamic::Value pattern;
};
struct Not {
Ref<Condition> cond;
};
struct NotEqual {
Column op1;
ColumnOrValue op2;
Operation op1;
Operation op2;
};
struct NotLike {
Column op;
Operation op;
dynamic::Value pattern;
};
@@ -70,7 +75,7 @@ struct Condition {
using ReflectionType =
rfl::TaggedUnion<"what", And, Equal, GreaterEqual, GreaterThan, IsNull,
IsNotNull, LesserEqual, LesserThan, Like, NotEqual,
IsNotNull, LesserEqual, LesserThan, Like, Not, NotEqual,
NotLike, Or>;
const ReflectionType& reflection() const { return val; }

View File

@@ -0,0 +1,175 @@
#ifndef SQLGEN_DYNAMIC_OPERATION_HPP_
#define SQLGEN_DYNAMIC_OPERATION_HPP_
#include <optional>
#include <rfl.hpp>
#include <string>
#include <vector>
#include "../Ref.hpp"
#include "Column.hpp"
#include "Type.hpp"
#include "Value.hpp"
namespace sqlgen::dynamic {
struct Operation {
struct Abs {
Ref<Operation> op1;
};
struct Aggregation {
struct Avg {
Ref<Operation> val;
};
struct Count {
std::optional<Column> val;
bool distinct = false;
};
struct Max {
Ref<Operation> val;
};
struct Min {
Ref<Operation> val;
};
struct Sum {
Ref<Operation> val;
};
using ReflectionType = rfl::TaggedUnion<"what", Avg, Count, Max, Min, Sum>;
const ReflectionType& reflection() const { return val; }
ReflectionType val;
};
struct Cast {
Ref<Operation> op1;
Type target_type;
};
struct Ceil {
Ref<Operation> op1;
};
struct Coalesce {
std::vector<Ref<Operation>> ops;
};
struct Concat {
std::vector<Ref<Operation>> ops;
};
struct Cos {
Ref<Operation> op1;
};
struct Divides {
Ref<Operation> op1;
Ref<Operation> op2;
};
struct Exp {
Ref<Operation> op1;
};
struct Floor {
Ref<Operation> op1;
};
struct Length {
Ref<Operation> op1;
};
struct Ln {
Ref<Operation> op1;
};
struct Lower {
Ref<Operation> op1;
};
struct LTrim {
Ref<Operation> op1;
Ref<Operation> op2;
};
struct Log2 {
Ref<Operation> op1;
};
struct Minus {
Ref<Operation> op1;
Ref<Operation> op2;
};
struct Mod {
Ref<Operation> op1;
Ref<Operation> op2;
};
struct Multiplies {
Ref<Operation> op1;
Ref<Operation> op2;
};
struct Plus {
Ref<Operation> op1;
Ref<Operation> op2;
};
struct Replace {
Ref<Operation> op1;
Ref<Operation> op2;
Ref<Operation> op3;
};
struct Round {
Ref<Operation> op1;
Ref<Operation> op2;
};
struct RTrim {
Ref<Operation> op1;
Ref<Operation> op2;
};
struct Sin {
Ref<Operation> op1;
};
struct Sqrt {
Ref<Operation> op1;
};
struct Tan {
Ref<Operation> op1;
};
struct Trim {
Ref<Operation> op1;
Ref<Operation> op2;
};
struct Upper {
Ref<Operation> op1;
};
using ReflectionType =
rfl::TaggedUnion<"what", Abs, Aggregation, Cast, Ceil, Column, Coalesce,
Concat, Cos, Divides, Exp, Floor, Length, Ln, Log2,
Lower, LTrim, Minus, Mod, Multiplies, Plus, Replace,
Round, RTrim, Sin, Sqrt, Tan, Trim, Upper, Value>;
const ReflectionType& reflection() const { return val; }
ReflectionType val;
};
} // namespace sqlgen::dynamic
#endif

View File

@@ -6,20 +6,18 @@
#include <string>
#include <vector>
#include "Aggregation.hpp"
#include "Column.hpp"
#include "Condition.hpp"
#include "GroupBy.hpp"
#include "Limit.hpp"
#include "Operation.hpp"
#include "OrderBy.hpp"
#include "Table.hpp"
#include "Value.hpp"
namespace sqlgen::dynamic {
struct SelectFrom {
struct Field {
rfl::TaggedUnion<"type", Aggregation, Column, Value> val;
Operation val;
std::optional<std::string> as;
};

View File

@@ -18,7 +18,11 @@ struct String {
std::string val;
};
using Value = rfl::TaggedUnion<"type", Float, Integer, String>;
struct Value {
using ReflectionType = rfl::TaggedUnion<"type", Float, Integer, String>;
const auto& reflection() const { return val; }
ReflectionType val;
};
} // namespace sqlgen::dynamic

View File

@@ -0,0 +1,229 @@
#ifndef SQLGEN_OPERATIONS_HPP_
#define SQLGEN_OPERATIONS_HPP_
#include <rfl.hpp>
#include <type_traits>
#include "col.hpp"
#include "transpilation/Operation.hpp"
#include "transpilation/Operator.hpp"
#include "transpilation/to_transpilation_type.hpp"
namespace sqlgen {
template <class T>
auto abs(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::abs, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class TargetType, class T>
auto cast(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<
transpilation::Operator::cast, Type,
transpilation::TypeHolder<std::remove_cvref_t<TargetType>>>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T>
auto ceil(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::ceil, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class... Ts>
auto coalesce(const Ts&... _ts) {
static_assert(sizeof...(_ts) > 1,
"coalesce(...) must have at least two inputs.");
using Type = rfl::Tuple<typename transpilation::ToTranspilationType<
std::remove_cvref_t<Ts>>::Type...>;
return transpilation::Operation<transpilation::Operator::coalesce, Type>{
.operand1 = Type(transpilation::to_transpilation_type(_ts)...)};
}
template <class... Ts>
auto concat(const Ts&... _ts) {
static_assert(sizeof...(_ts) > 0,
"concat(...) must have at least one input.");
using Type = rfl::Tuple<typename transpilation::ToTranspilationType<
std::remove_cvref_t<Ts>>::Type...>;
return transpilation::Operation<transpilation::Operator::concat, Type>{
.operand1 = Type(transpilation::to_transpilation_type(_ts)...)};
}
template <class T>
auto cos(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::cos, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T>
auto exp(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::exp, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T>
auto floor(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::floor, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T>
auto length(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::length, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T>
auto ln(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::ln, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T>
auto log2(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::log2, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T>
auto lower(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::lower, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T, class U>
auto ltrim(const T& _t, const U& _u) {
using Type1 =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
using Type2 =
typename transpilation::ToTranspilationType<std::remove_cvref_t<U>>::Type;
return transpilation::Operation<transpilation::Operator::ltrim, Type1, Type2>{
.operand1 = transpilation::to_transpilation_type(_t),
.operand2 = transpilation::to_transpilation_type(_u)};
}
template <class T>
auto ltrim(const T& _t) {
return ltrim(_t, std::string(" "));
}
template <class StringType, class FromType, class ToType>
auto replace(const StringType& _str, const FromType& _from, const ToType& _to) {
using Type1 = typename transpilation::ToTranspilationType<
std::remove_cvref_t<StringType>>::Type;
using Type2 = typename transpilation::ToTranspilationType<
std::remove_cvref_t<FromType>>::Type;
using Type3 = typename transpilation::ToTranspilationType<
std::remove_cvref_t<ToType>>::Type;
return transpilation::Operation<transpilation::Operator::replace, Type1,
Type2, Type3>{
.operand1 = transpilation::to_transpilation_type(_str),
.operand2 = transpilation::to_transpilation_type(_from),
.operand3 = transpilation::to_transpilation_type(_to)};
}
template <class T, class U>
auto round(const T& _t, const U& _u) {
using Type1 =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
using Type2 =
typename transpilation::ToTranspilationType<std::remove_cvref_t<U>>::Type;
return transpilation::Operation<transpilation::Operator::round, Type1, Type2>{
.operand1 = transpilation::to_transpilation_type(_t),
.operand2 = transpilation::to_transpilation_type(_u)};
}
template <class T>
auto round(const T& _t) {
return round(_t, 0);
}
template <class T, class U>
auto rtrim(const T& _t, const U& _u) {
using Type1 =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
using Type2 =
typename transpilation::ToTranspilationType<std::remove_cvref_t<U>>::Type;
return transpilation::Operation<transpilation::Operator::rtrim, Type1, Type2>{
.operand1 = transpilation::to_transpilation_type(_t),
.operand2 = transpilation::to_transpilation_type(_u)};
}
template <class T>
auto rtrim(const T& _t) {
return rtrim(_t, std::string(" "));
}
template <class T>
auto sin(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::sin, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T>
auto sqrt(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::sqrt, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T>
auto tan(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::tan, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
template <class T, class U>
auto trim(const T& _t, const U& _u) {
using Type1 =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
using Type2 =
typename transpilation::ToTranspilationType<std::remove_cvref_t<U>>::Type;
return transpilation::Operation<transpilation::Operator::trim, Type1, Type2>{
.operand1 = transpilation::to_transpilation_type(_t),
.operand2 = transpilation::to_transpilation_type(_u)};
}
template <class T>
auto trim(const T& _t) {
return trim(_t, std::string(" "));
}
template <class T>
auto upper(const T& _t) {
using Type =
typename transpilation::ToTranspilationType<std::remove_cvref_t<T>>::Type;
return transpilation::Operation<transpilation::Operator::upper, Type>{
.operand1 = transpilation::to_transpilation_type(_t)};
}
} // namespace sqlgen
#endif

View File

@@ -0,0 +1,86 @@
#ifndef SQLGEN_TRANSPILATION_AGGREGATION_HPP_
#define SQLGEN_TRANSPILATION_AGGREGATION_HPP_
#include <string>
#include "AggregationOp.hpp"
#include "As.hpp"
#include "Operation.hpp"
#include "Operator.hpp"
#include "to_transpilation_type.hpp"
namespace sqlgen::transpilation {
/// To be used when we want to count everything.
struct All {};
template <AggregationOp _agg, class _ValueType>
struct Aggregation {
static constexpr auto agg = _agg;
using ValueType = _ValueType;
template <rfl::internal::StringLiteral _new_name>
auto as() const noexcept {
using T = std::remove_cvref_t<decltype(*this)>;
return transpilation::As<T, _new_name>{.val = *this};
}
ValueType val;
bool distinct = false;
template <class T>
friend auto operator/(const Aggregation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::divides, Aggregation, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
template <class T>
friend auto operator-(const Aggregation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::minus, Aggregation, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
template <class T>
friend auto operator%(const Aggregation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::mod, Aggregation, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
template <class T>
friend auto operator*(const Aggregation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::multiplies, Aggregation, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
template <class T>
friend auto operator+(const Aggregation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::plus, Aggregation, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
};
template <AggregationOp _agg, class _ValueType>
struct ToTranspilationType<Aggregation<_agg, _ValueType>> {
using Type = Aggregation<_agg, _ValueType>;
Type operator()(const Type& _val) const noexcept { return _val; }
};
} // namespace sqlgen::transpilation
#endif

View File

@@ -0,0 +1,10 @@
#ifndef SQLGEN_TRANSPILATION_AGGREGATIONOP_HPP_
#define SQLGEN_TRANSPILATION_AGGREGATIONOP_HPP_
namespace sqlgen::transpilation {
enum class AggregationOp { avg, count, max, min, sum };
} // namespace sqlgen::transpilation
#endif

View File

@@ -11,6 +11,22 @@ template <class _ConditionType>
struct Condition {
using ConditionType = _ConditionType;
ConditionType condition;
auto operator!() {
return make_condition(conditions::Not<_ConditionType>{.cond = condition});
}
template <class C2>
friend auto operator&&(const Condition& _cond1, const Condition<C2>& _cond2) {
return make_condition(conditions::And<_ConditionType, C2>{
.cond1 = _cond1.condition, .cond2 = _cond2.condition});
}
template <class C2>
friend auto operator||(const Condition& _cond1, const Condition<C2>& _cond2) {
return make_condition(conditions::Or<_ConditionType, C2>{
.cond1 = _cond1.condition, .cond2 = _cond2.condition});
}
};
template <class T>
@@ -18,18 +34,6 @@ 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 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 make_condition(conditions::Or<C1, C2>{.cond1 = _cond1.condition,
.cond2 = _cond2.condition});
}
} // namespace sqlgen::transpilation
#endif

View File

@@ -0,0 +1,153 @@
#ifndef SQLGEN_TRANSPILATION_OPERATION_HPP_
#define SQLGEN_TRANSPILATION_OPERATION_HPP_
#include <string>
#include <type_traits>
#include "../Result.hpp"
#include "As.hpp"
#include "Condition.hpp"
#include "Operator.hpp"
#include "conditions.hpp"
#include "to_transpilation_type.hpp"
namespace sqlgen::transpilation {
/// Simple abstraction to be used for the cast operation.
template <class T>
struct TypeHolder {};
template <Operator _op, class _Operand1Type, class _Operand2Type = Nothing,
class _Operand3Type = Nothing>
struct Operation {
static constexpr Operator op = _op;
using Operand1Type = _Operand1Type;
using Operand2Type = _Operand2Type;
using Operand3Type = _Operand3Type;
Operand1Type operand1;
Operand2Type operand2;
Operand3Type operand3;
template <rfl::internal::StringLiteral _new_name>
auto as() const noexcept {
using T = std::remove_cvref_t<decltype(*this)>;
return transpilation::As<T, _new_name>{.val = *this};
}
/// Returns an IS NULL condition.
auto is_null() const noexcept {
return make_condition(conditions::is_null(*this));
}
/// Returns a IS NOT NULL condition.
auto is_not_null() const noexcept {
return make_condition(conditions::is_not_null(*this));
}
/// Returns a LIKE condition.
auto like(const std::string& _pattern) const noexcept {
return make_condition(conditions::like(*this, _pattern));
}
/// Returns a NOT LIKE condition.
auto not_like(const std::string& _pattern) const noexcept {
return make_condition(conditions::not_like(*this, _pattern));
}
template <class T>
friend auto operator==(const Operation& _o, const T& _t) {
return make_condition(conditions::equal(_o, to_transpilation_type(_t)));
}
template <class T>
friend auto operator!=(const Operation& _o, const T& _t) {
return make_condition(conditions::not_equal(_o, to_transpilation_type(_t)));
}
template <class T>
friend auto operator<(const Operation& _o, const T& _t) {
return make_condition(
conditions::lesser_than(_o, to_transpilation_type(_t)));
}
template <class T>
friend auto operator<=(const Operation& _o, const T& _t) {
return make_condition(
conditions::lesser_equal(_o, to_transpilation_type(_t)));
}
template <class T>
friend auto operator>(const Operation& _o, const T& _t) {
return make_condition(
conditions::greater_than(_o, to_transpilation_type(_t)));
}
template <class T>
friend auto operator>=(const Operation& _o, const T& _t) {
return make_condition(
conditions::greater_equal(_o, to_transpilation_type(_t)));
}
template <class T>
friend auto operator/(const Operation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::divides,
Operation<_op, _Operand1Type, _Operand2Type>, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
template <class T>
friend auto operator-(const Operation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::minus,
Operation<_op, _Operand1Type, _Operand2Type>, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
template <class T>
friend auto operator%(const Operation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::mod,
Operation<_op, _Operand1Type, _Operand2Type>, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
template <class T>
friend auto operator*(const Operation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::multiplies,
Operation<_op, _Operand1Type, _Operand2Type>, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
template <class T>
friend auto operator+(const Operation& _op1, const T& _op2) noexcept {
using OtherType = typename transpilation::ToTranspilationType<
std::remove_cvref_t<T>>::Type;
return Operation<Operator::plus,
Operation<_op, _Operand1Type, _Operand2Type>, OtherType>{
.operand1 = _op1, .operand2 = to_transpilation_type(_op2)};
}
};
template <Operator _op, class _Operand1Type, class _Operand2Type>
struct ToTranspilationType<Operation<_op, _Operand1Type, _Operand2Type>> {
using Type = Operation<_op, _Operand1Type, _Operand2Type>;
Type operator()(const Type& _val) const noexcept { return _val; }
};
} // namespace sqlgen::transpilation
#endif

View File

@@ -0,0 +1,37 @@
#ifndef SQLGEN_TRANSPILATION_OPERATOR_HPP_
#define SQLGEN_TRANSPILATION_OPERATOR_HPP_
namespace sqlgen::transpilation {
enum class Operator {
abs,
cast,
ceil,
coalesce,
concat,
cos,
divides,
exp,
floor,
length,
ln,
log2,
lower,
ltrim,
minus,
mod,
multiplies,
plus,
replace,
round,
rtrim,
sin,
sqrt,
tan,
trim,
upper
};
} // namespace sqlgen::transpilation
#endif

View File

@@ -0,0 +1,10 @@
#ifndef SQLGEN_TRANSPILATION_OPERATORCATEGORY_HPP_
#define SQLGEN_TRANSPILATION_OPERATORCATEGORY_HPP_
namespace sqlgen::transpilation {
enum class OperatorCategory { numerical, string, other };
} // namespace sqlgen::transpilation
#endif

View File

@@ -1,81 +0,0 @@
#ifndef SQLGEN_TRANSPILATION_AGGREGATIONS_HPP_
#define SQLGEN_TRANSPILATION_AGGREGATIONS_HPP_
#include <string>
#include "As.hpp"
namespace sqlgen::transpilation::aggregations {
/// To be used when we want to count everything.
struct All {};
template <class _ValueType>
struct Avg {
using ValueType = _ValueType;
template <rfl::internal::StringLiteral _new_name>
auto as() const noexcept {
using T = std::remove_cvref_t<decltype(*this)>;
return transpilation::As<T, _new_name>{.val = *this};
}
ValueType val;
};
template <class _ValueType>
struct Count {
using ValueType = _ValueType;
template <rfl::internal::StringLiteral _new_name>
auto as() const noexcept {
using T = std::remove_cvref_t<decltype(*this)>;
return transpilation::As<T, _new_name>{.val = *this};
}
ValueType val;
bool distinct = false;
};
template <class _ValueType>
struct Max {
using ValueType = _ValueType;
template <rfl::internal::StringLiteral _new_name>
auto as() const noexcept {
using T = std::remove_cvref_t<decltype(*this)>;
return transpilation::As<T, _new_name>{.val = *this};
}
ValueType val;
};
template <class _ValueType>
struct Min {
using ValueType = _ValueType;
template <rfl::internal::StringLiteral _new_name>
auto as() const noexcept {
using T = std::remove_cvref_t<decltype(*this)>;
return transpilation::As<T, _new_name>{.val = *this};
}
ValueType val;
};
template <class _ValueType>
struct Sum {
using ValueType = _ValueType;
template <rfl::internal::StringLiteral _new_name>
auto as() const noexcept {
using T = std::remove_cvref_t<decltype(*this)>;
return transpilation::As<T, _new_name>{.val = *this};
}
ValueType val;
};
} // namespace sqlgen::transpilation::aggregations
#endif

View File

@@ -49,7 +49,8 @@ struct CheckAggregation<StructType, rfl::Tuple<FieldTypes...>,
static constexpr bool value =
(true && ... &&
(MakeField<StructType, FieldTypes>::is_aggregation ||
!MakeField<StructType, FieldTypes>::is_column ||
(!MakeField<StructType, FieldTypes>::is_column &&
!MakeField<StructType, FieldTypes>::is_operation) ||
included_in_group_by<FieldTypes>));
static_assert(value,

View File

@@ -126,6 +126,13 @@ struct NotEqual {
OpType2 op2;
};
template <class CondType>
struct Not {
using ResultType = bool;
CondType cond;
};
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>>{

View File

@@ -0,0 +1,42 @@
#ifndef SQLGEN_TRANSPILATION_DYNAMICAGGREGATIONT_HPP_
#define SQLGEN_TRANSPILATION_DYNAMICAGGREGATIONT_HPP_
#include "../dynamic/Aggregation.hpp"
#include "AggregationOp.hpp"
namespace sqlgen::transpilation {
template <AggregationOp agg>
struct DynamicAggregation;
template <>
struct DynamicAggregation<AggregationOp::avg> {
using Type = dynamic::Aggregation::Avg;
};
template <>
struct DynamicAggregation<AggregationOp::count> {
using Type = dynamic::Aggregation::Count;
};
template <>
struct DynamicAggregation<AggregationOp::max> {
using Type = dynamic::Aggregation::Max;
};
template <>
struct DynamicAggregation<AggregationOp::min> {
using Type = dynamic::Aggregation::Min;
};
template <>
struct DynamicAggregation<AggregationOp::sum> {
using Type = dynamic::Aggregation::Sum;
};
template <AggregationOp agg>
using dynamic_aggregation_t = typename DynamicAggregation<agg>::Type;
} // namespace sqlgen::transpilation
#endif

View File

@@ -0,0 +1,208 @@
#ifndef SQLGEN_TRANSPILATION_DYNAMICOPERATORT_HPP_
#define SQLGEN_TRANSPILATION_DYNAMICOPERATORT_HPP_
#include <limits>
#include "../dynamic/Operation.hpp"
#include "Operator.hpp"
#include "OperatorCategory.hpp"
namespace sqlgen::transpilation {
template <Operator op>
struct DynamicOperator;
template <>
struct DynamicOperator<Operator::abs> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Abs;
};
template <>
struct DynamicOperator<Operator::cast> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::other;
using Type = dynamic::Operation::Cast;
};
template <>
struct DynamicOperator<Operator::ceil> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Ceil;
};
template <>
struct DynamicOperator<Operator::coalesce> {
static constexpr size_t num_operands = std::numeric_limits<size_t>::max();
static constexpr auto category = OperatorCategory::other;
using Type = dynamic::Operation::Coalesce;
};
template <>
struct DynamicOperator<Operator::concat> {
static constexpr size_t num_operands = std::numeric_limits<size_t>::max();
static constexpr auto category = OperatorCategory::string;
using Type = dynamic::Operation::Concat;
};
template <>
struct DynamicOperator<Operator::cos> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Cos;
};
template <>
struct DynamicOperator<Operator::divides> {
static constexpr size_t num_operands = 2;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Divides;
};
template <>
struct DynamicOperator<Operator::exp> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Exp;
};
template <>
struct DynamicOperator<Operator::floor> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Floor;
};
template <>
struct DynamicOperator<Operator::length> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::string;
using Type = dynamic::Operation::Length;
};
template <>
struct DynamicOperator<Operator::ln> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Ln;
};
template <>
struct DynamicOperator<Operator::log2> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Log2;
};
template <>
struct DynamicOperator<Operator::lower> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::string;
using Type = dynamic::Operation::Lower;
};
template <>
struct DynamicOperator<Operator::ltrim> {
static constexpr size_t num_operands = 2;
static constexpr auto category = OperatorCategory::string;
using Type = dynamic::Operation::LTrim;
};
template <>
struct DynamicOperator<Operator::minus> {
static constexpr size_t num_operands = 2;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Minus;
};
template <>
struct DynamicOperator<Operator::mod> {
static constexpr size_t num_operands = 2;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Mod;
};
template <>
struct DynamicOperator<Operator::multiplies> {
static constexpr size_t num_operands = 2;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Multiplies;
};
template <>
struct DynamicOperator<Operator::plus> {
static constexpr size_t num_operands = 2;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Plus;
};
template <>
struct DynamicOperator<Operator::replace> {
static constexpr size_t num_operands = 3;
static constexpr auto category = OperatorCategory::other;
using Type = dynamic::Operation::Replace;
};
template <>
struct DynamicOperator<Operator::round> {
static constexpr size_t num_operands = 2;
static constexpr auto category = OperatorCategory::other;
using Type = dynamic::Operation::Round;
};
template <>
struct DynamicOperator<Operator::rtrim> {
static constexpr size_t num_operands = 2;
static constexpr auto category = OperatorCategory::string;
using Type = dynamic::Operation::RTrim;
};
template <>
struct DynamicOperator<Operator::sin> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Sin;
};
template <>
struct DynamicOperator<Operator::sqrt> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Sqrt;
};
template <>
struct DynamicOperator<Operator::tan> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::numerical;
using Type = dynamic::Operation::Tan;
};
template <>
struct DynamicOperator<Operator::trim> {
static constexpr size_t num_operands = 2;
static constexpr auto category = OperatorCategory::string;
using Type = dynamic::Operation::Trim;
};
template <>
struct DynamicOperator<Operator::upper> {
static constexpr size_t num_operands = 1;
static constexpr auto category = OperatorCategory::string;
using Type = dynamic::Operation::Upper;
};
template <Operator op>
using dynamic_operator_t = typename DynamicOperator<op>::Type;
template <Operator op>
inline constexpr size_t num_operands_v = DynamicOperator<op>::num_operands;
template <Operator op>
inline constexpr auto operator_category_v = DynamicOperator<op>::category;
} // namespace sqlgen::transpilation
#endif

View File

@@ -0,0 +1,64 @@
#ifndef SQLGEN_TRANSPILATION_FLATTEN_FIELDS_T_HPP_
#define SQLGEN_TRANSPILATION_FLATTEN_FIELDS_T_HPP_
#include <rfl.hpp>
#include <type_traits>
#include "As.hpp"
#include "make_field.hpp"
#include "remove_as_t.hpp"
namespace sqlgen::transpilation {
template <class TupleType>
struct TupleWrapper;
template <class... FieldTypes>
struct TupleWrapper<rfl::Tuple<FieldTypes...>> {
using Type = rfl::Tuple<FieldTypes...>;
template <class... OtherFieldTypes>
friend consteval auto operator+(
const TupleWrapper&,
const TupleWrapper<rfl::Tuple<OtherFieldTypes...>>&) {
return TupleWrapper<rfl::Tuple<FieldTypes..., OtherFieldTypes...>>{};
}
};
template <class StructType, class FieldsType>
struct FlattenFields;
template <class StructType, class FieldType>
struct ExtractFields;
template <class StructType, class FieldType>
requires(!MakeField<StructType, remove_as_t<FieldType>>::is_operation)
struct ExtractFields<StructType, FieldType> {
using Type = rfl::Tuple<remove_as_t<FieldType>>;
};
template <class StructType, class FieldType>
requires(MakeField<StructType, remove_as_t<FieldType>>::is_operation)
struct ExtractFields<StructType, FieldType> {
using Type = typename FlattenFields<
StructType,
typename MakeField<StructType, remove_as_t<FieldType>>::Operands>::Type;
};
template <class StructType, class... FieldTypes>
struct FlattenFields<StructType, rfl::Tuple<FieldTypes...>> {
static constexpr auto wrapper =
(TupleWrapper<rfl::Tuple<>>{} + ... +
TupleWrapper<typename ExtractFields<StructType, FieldTypes>::Type>{});
using Type = typename decltype(wrapper)::Type;
};
template <class StructType, class FieldsType>
using flatten_fields_t =
typename FlattenFields<std::remove_cvref_t<StructType>,
std::remove_cvref_t<FieldsType>>::Type;
} // namespace sqlgen::transpilation
#endif

View File

@@ -7,11 +7,18 @@
#include "../Literal.hpp"
#include "../Result.hpp"
#include "../dynamic/SelectFrom.hpp"
#include "../parsing/Parser.hpp"
#include "Aggregation.hpp"
#include "AggregationOp.hpp"
#include "As.hpp"
#include "Col.hpp"
#include "Operation.hpp"
#include "Operator.hpp"
#include "OperatorCategory.hpp"
#include "Value.hpp"
#include "aggregations.hpp"
#include "all_columns_exist.hpp"
#include "dynamic_aggregation_t.hpp"
#include "dynamic_operator_t.hpp"
#include "remove_nullable_t.hpp"
#include "to_value.hpp"
#include "underlying_t.hpp"
@@ -21,16 +28,18 @@ namespace sqlgen::transpilation {
template <class StructType, class FieldType>
struct MakeField;
template <class StructType, class ValueType>
template <class StructType, class T>
struct MakeField {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = false;
using Name = Nothing;
using Type = ValueType;
using Type = std::remove_cvref_t<T>;
dynamic::SelectFrom::Field operator()(const auto& _val) const {
return dynamic::SelectFrom::Field{.val = to_value(_val)};
return dynamic::SelectFrom::Field{
dynamic::Operation{.val = to_value(_val)}};
}
};
@@ -41,13 +50,29 @@ struct MakeField<StructType, Col<_name>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = true;
static constexpr bool is_operation = false;
using Name = Literal<_name>;
using Type = rfl::field_type_t<_name, StructType>;
dynamic::SelectFrom::Field operator()(const auto&) const {
return dynamic::SelectFrom::Field{.val =
dynamic::Column{.name = _name.str()}};
return dynamic::SelectFrom::Field{
dynamic::Operation{.val = dynamic::Column{.name = _name.str()}}};
}
};
template <class StructType, class T>
struct MakeField<StructType, Value<T>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = false;
using Name = Nothing;
using Type = std::remove_cvref_t<T>;
dynamic::SelectFrom::Field operator()(const auto& _val) const {
return dynamic::SelectFrom::Field{
dynamic::Operation{.val = to_value(_val.val)}};
}
};
@@ -57,6 +82,8 @@ struct MakeField<StructType, As<ValueType, _new_name>> {
static constexpr bool is_aggregation =
MakeField<StructType, ValueType>::is_aggregation;
static constexpr bool is_column = MakeField<StructType, ValueType>::is_column;
static constexpr bool is_operation =
MakeField<StructType, ValueType>::is_operation;
using Name = Literal<_new_name>;
using Type =
@@ -64,132 +91,286 @@ struct MakeField<StructType, As<ValueType, _new_name>> {
dynamic::SelectFrom::Field operator()(const auto& _as) const {
return dynamic::SelectFrom::Field{
.val = MakeField<StructType, std::remove_cvref_t<ValueType>>{}(_as.val)
.val,
.val =
dynamic::Operation{
.val = MakeField<StructType, std::remove_cvref_t<ValueType>>{}(
_as.val)
.val.val},
.as = _new_name.str()};
}
};
template <class StructType, rfl::internal::StringLiteral _name>
struct MakeField<StructType, aggregations::Avg<Col<_name>>> {
static_assert(all_columns_exist<StructType, Col<_name>>(),
"A column required in the AVG aggregation does not exist.");
static_assert(
std::is_integral_v<
remove_nullable_t<underlying_t<StructType, Col<_name>>>> ||
std::is_floating_point_v<
remove_nullable_t<underlying_t<StructType, Col<_name>>>>,
"Values inside the AVG aggregation must be numerical.");
template <class StructType, AggregationOp _agg, class ValueType>
struct MakeField<StructType, Aggregation<_agg, ValueType>> {
static_assert(std::is_integral_v<
remove_nullable_t<underlying_t<StructType, ValueType>>> ||
std::is_floating_point_v<
remove_nullable_t<underlying_t<StructType, ValueType>>>,
"Values inside the aggregation must be numerical.");
static constexpr bool is_aggregation = true;
static constexpr bool is_column = true;
static constexpr bool is_operation = false;
using Name = Literal<_name>;
using Type = rfl::field_type_t<_name, StructType>;
using Name = Nothing;
using Type =
typename MakeField<StructType, std::remove_cvref_t<ValueType>>::Type;
dynamic::SelectFrom::Field operator()(const auto&) const {
return dynamic::SelectFrom::Field{
.val = dynamic::Aggregation{dynamic::Aggregation::Avg{
.val = dynamic::Column{.name = _name.str()}}}};
dynamic::SelectFrom::Field operator()(const auto& _val) const {
using DynamicAggregationType = dynamic_aggregation_t<_agg>;
return dynamic::SelectFrom::Field{dynamic::Operation{
.val = dynamic::Aggregation{DynamicAggregationType{
.val = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<ValueType>>{}(
_val.val)
.val)}}}};
}
};
template <class StructType, rfl::internal::StringLiteral _name>
struct MakeField<StructType, aggregations::Count<Col<_name>>> {
struct MakeField<StructType, Aggregation<AggregationOp::count, Col<_name>>> {
static_assert(all_columns_exist<StructType, Col<_name>>(),
"A column required in the COUNT or COUNT_DISTINCT aggregation "
"does not exist.");
static constexpr bool is_aggregation = true;
static constexpr bool is_column = true;
static constexpr bool is_operation = false;
using Name = Literal<_name>;
using Type = size_t;
dynamic::SelectFrom::Field operator()(const auto& _agg) const {
return dynamic::SelectFrom::Field{
return dynamic::SelectFrom::Field{dynamic::Operation{
.val = dynamic::Aggregation{dynamic::Aggregation::Count{
.val = dynamic::Column{.name = _name.str()},
.distinct = _agg.distinct}},
};
.distinct = _agg.distinct}}}};
}
};
template <class StructType>
struct MakeField<StructType, aggregations::Count<aggregations::All>> {
struct MakeField<StructType, Aggregation<AggregationOp::count, All>> {
static constexpr bool is_aggregation = true;
static constexpr bool is_column = true;
static constexpr bool is_operation = false;
using Name = Nothing;
using Type = size_t;
dynamic::SelectFrom::Field operator()(const auto&) const {
return dynamic::SelectFrom::Field{
return dynamic::SelectFrom::Field{dynamic::Operation{
.val = dynamic::Aggregation{
dynamic::Aggregation::Count{.val = std::nullopt, .distinct = false},
}};
}}};
}
};
template <class StructType, rfl::internal::StringLiteral _name>
struct MakeField<StructType, aggregations::Max<Col<_name>>> {
static_assert(all_columns_exist<StructType, Col<_name>>(),
"A column required in the MAX aggregation does not exist.");
template <class StructType, class Operand1Type, class TargetType>
struct MakeField<StructType, Operation<Operator::cast, Operand1Type,
TypeHolder<TargetType>>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = true;
static constexpr bool is_aggregation = true;
static constexpr bool is_column = true;
using Name = Nothing;
using Type = std::remove_cvref_t<TargetType>;
using Operands = rfl::Tuple<Operand1Type>;
using Name = Literal<_name>;
using Type = rfl::field_type_t<_name, StructType>;
dynamic::SelectFrom::Field operator()(const auto&) const {
dynamic::SelectFrom::Field operator()(const auto& _o) const {
return dynamic::SelectFrom::Field{
.val = dynamic::Aggregation{dynamic::Aggregation::Max{
.val = dynamic::Column{.name = _name.str()}}}};
dynamic::Operation{dynamic::Operation::Cast{
.op1 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand1Type>>{}(
_o.operand1)
.val),
.target_type =
parsing::Parser<std::remove_cvref_t<TargetType>>::to_type()}}};
}
};
template <class StructType, rfl::internal::StringLiteral _name>
struct MakeField<StructType, aggregations::Min<Col<_name>>> {
static_assert(all_columns_exist<StructType, Col<_name>>(),
"A column required in MIN aggregation does not exist.");
template <class StructType, Operator _op, class... OperandTypes>
requires((_op == Operator::coalesce) || (_op == Operator::concat))
struct MakeField<StructType, Operation<_op, rfl::Tuple<OperandTypes...>>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = true;
static constexpr bool is_aggregation = true;
static constexpr bool is_column = true;
using Name = Nothing;
using Type =
underlying_t<StructType, Operation<_op, rfl::Tuple<OperandTypes...>>>;
using Operands = rfl::Tuple<OperandTypes...>;
using Name = Literal<_name>;
using Type = rfl::field_type_t<_name, StructType>;
dynamic::SelectFrom::Field operator()(const auto&) const {
return dynamic::SelectFrom::Field{
.val = dynamic::Aggregation{dynamic::Aggregation::Min{
.val = dynamic::Column{.name = _name.str()}}}};
dynamic::SelectFrom::Field operator()(const auto& _o) const {
using DynamicOperatorType = dynamic_operator_t<_op>;
return dynamic::SelectFrom::Field{dynamic::Operation{DynamicOperatorType{
.ops = rfl::apply(
[](const auto&... _ops) {
return std::vector<Ref<dynamic::Operation>>(
{Ref<dynamic::Operation>::make(
MakeField<StructType,
std::remove_cvref_t<OperandTypes>>{}(_ops)
.val)...});
},
_o.operand1)}}};
}
};
template <class StructType, rfl::internal::StringLiteral _name>
struct MakeField<StructType, aggregations::Sum<Col<_name>>> {
static_assert(all_columns_exist<StructType, Col<_name>>(),
"A column required in SUM aggregation does not exist.");
template <class StructType, class Operand1Type, class Operand2Type,
class Operand3Type>
struct MakeField<StructType, Operation<Operator::replace, Operand1Type,
Operand2Type, Operand3Type>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = true;
static_assert(
std::is_integral_v<
remove_nullable_t<underlying_t<StructType, Col<_name>>>> ||
std::is_floating_point_v<
remove_nullable_t<underlying_t<StructType, Col<_name>>>>,
"Values inside the SUM aggregation must be numerical.");
using Name = Nothing;
using Type =
underlying_t<StructType, Operation<Operator::replace, Operand1Type,
Operand2Type, Operand3Type>>;
using Operands = rfl::Tuple<Operand1Type, Operand2Type, Operand3Type>;
static constexpr bool is_aggregation = true;
static constexpr bool is_column = true;
using Name = Literal<_name>;
using Type = rfl::field_type_t<_name, StructType>;
dynamic::SelectFrom::Field operator()(const auto&) const {
dynamic::SelectFrom::Field operator()(const auto& _o) const {
return dynamic::SelectFrom::Field{
.val = dynamic::Aggregation{dynamic::Aggregation::Sum{
.val = dynamic::Column{.name = _name.str()}}}};
dynamic::Operation{dynamic::Operation::Replace{
.op1 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand1Type>>{}(
_o.operand1)
.val),
.op2 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand2Type>>{}(
_o.operand2)
.val),
.op3 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand3Type>>{}(
_o.operand3)
.val)}}};
}
};
template <class StructType, class Operand1Type, class Operand2Type>
struct MakeField<StructType,
Operation<Operator::round, Operand1Type, Operand2Type>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = true;
using Name = Nothing;
using Type =
underlying_t<StructType,
Operation<Operator::round, Operand1Type, Operand2Type>>;
using Operands = rfl::Tuple<Operand1Type, Operand2Type>;
dynamic::SelectFrom::Field operator()(const auto& _o) const {
return dynamic::SelectFrom::Field{
dynamic::Operation{dynamic::Operation::Round{
.op1 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand1Type>>{}(
_o.operand1)
.val),
.op2 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand2Type>>{}(
_o.operand2)
.val)}}};
}
};
template <class StructType, Operator _op, class Operand1Type>
requires((num_operands_v<_op>) == 1 &&
(operator_category_v<_op>) == OperatorCategory::string)
struct MakeField<StructType, Operation<_op, Operand1Type>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = true;
using Name = Nothing;
using Type = underlying_t<StructType, Operation<_op, Operand1Type>>;
using Operands = rfl::Tuple<Operand1Type>;
dynamic::SelectFrom::Field operator()(const auto& _o) const {
using DynamicOperatorType = dynamic_operator_t<_op>;
return dynamic::SelectFrom::Field{dynamic::Operation{DynamicOperatorType{
.op1 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand1Type>>{}(
_o.operand1)
.val)}}};
}
};
template <class StructType, Operator _op, class Operand1Type,
class Operand2Type>
requires((num_operands_v<_op>) == 2 &&
(operator_category_v<_op>) == OperatorCategory::string)
struct MakeField<StructType, Operation<_op, Operand1Type, Operand2Type>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = true;
using Name = Nothing;
using Type =
underlying_t<StructType, Operation<_op, Operand1Type, Operand2Type>>;
using Operands = rfl::Tuple<Operand1Type, Operand2Type>;
dynamic::SelectFrom::Field operator()(const auto& _o) const {
using DynamicOperatorType = dynamic_operator_t<_op>;
return dynamic::SelectFrom::Field{dynamic::Operation{DynamicOperatorType{
.op1 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand1Type>>{}(
_o.operand1)
.val),
.op2 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand2Type>>{}(
_o.operand2)
.val)}}};
}
};
template <class StructType, Operator _op, class Operand1Type>
requires((num_operands_v<_op>) == 1 &&
(operator_category_v<_op>) == OperatorCategory::numerical)
struct MakeField<StructType, Operation<_op, Operand1Type>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = true;
using Name = Nothing;
using Type = underlying_t<StructType, Operation<_op, Operand1Type>>;
using Operands = rfl::Tuple<Operand1Type>;
dynamic::SelectFrom::Field operator()(const auto& _o) const {
using DynamicOperatorType = dynamic_operator_t<_op>;
return dynamic::SelectFrom::Field{dynamic::Operation{DynamicOperatorType{
.op1 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand1Type>>{}(
_o.operand1)
.val)}}};
}
};
template <class StructType, Operator _op, class Operand1Type,
class Operand2Type>
requires((num_operands_v<_op>) == 2 &&
(operator_category_v<_op>) == OperatorCategory::numerical)
struct MakeField<StructType, Operation<_op, Operand1Type, Operand2Type>> {
static constexpr bool is_aggregation = false;
static constexpr bool is_column = false;
static constexpr bool is_operation = true;
using Name = Nothing;
using Type =
underlying_t<StructType, Operation<_op, Operand1Type, Operand2Type>>;
using Operands = rfl::Tuple<Operand1Type, Operand2Type>;
dynamic::SelectFrom::Field operator()(const auto& _o) const {
using DynamicOperatorType = dynamic_operator_t<_op>;
return dynamic::SelectFrom::Field{dynamic::Operation{DynamicOperatorType{
.op1 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand1Type>>{}(
_o.operand1)
.val),
.op2 = Ref<dynamic::Operation>::make(
MakeField<StructType, std::remove_cvref_t<Operand2Type>>{}(
_o.operand2)
.val)}}};
}
};

View File

@@ -12,7 +12,8 @@
#include "Condition.hpp"
#include "all_columns_exist.hpp"
#include "conditions.hpp"
#include "to_value.hpp"
#include "make_field.hpp"
#include "to_transpilation_type.hpp"
#include "underlying_t.hpp"
namespace sqlgen::transpilation {
@@ -40,245 +41,135 @@ 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>>> {
static_assert(all_columns_exist<T, Col<_name1>, Col<_name2>>(),
"All columns must exist.");
static_assert(std::equality_comparable_with<underlying_t<T, Col<_name1>>,
underlying_t<T, Col<_name2>>>,
template <class T, class Op1Type, class Op2Type>
struct ToCondition<T, conditions::Equal<Op1Type, Op2Type>> {
static_assert(std::equality_comparable_with<underlying_t<T, Op1Type>,
underlying_t<T, Op2Type>>,
"Must be equality comparable.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::Equal{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
return dynamic::Condition{
.val = dynamic::Condition::Equal{.op1 = make_field<T>(_cond.op1).val,
.op2 = make_field<T>(_cond.op2).val}};
}
};
template <class T, rfl::internal::StringLiteral _name, class V>
struct ToCondition<T, conditions::Equal<Col<_name>, Value<V>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
static_assert(std::equality_comparable_with<underlying_t<T, Col<_name>>,
underlying_t<T, Value<V>>>,
"Must be equality comparable.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::Equal{
.op1 = dynamic::Column{.name = _name.str()},
.op2 = to_value(_cond.op2.val),
}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::GreaterEqual<Col<_name1>, Col<_name2>>> {
static_assert(all_columns_exist<T, Col<_name1>, Col<_name2>>(),
"All columns must exist.");
static_assert(std::totally_ordered_with<underlying_t<T, Col<_name1>>,
underlying_t<T, Col<_name2>>>,
template <class T, class Op1Type, class Op2Type>
struct ToCondition<T, conditions::GreaterEqual<Op1Type, Op2Type>> {
static_assert(std::totally_ordered_with<underlying_t<T, Op1Type>,
underlying_t<T, Op2Type>>,
"Must be totally ordered.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::GreaterEqual{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
.op1 = make_field<T>(_cond.op1).val,
.op2 = make_field<T>(_cond.op2).val}};
}
};
template <class T, rfl::internal::StringLiteral _name, class V>
struct ToCondition<T, conditions::GreaterEqual<Col<_name>, Value<V>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
static_assert(std::totally_ordered_with<underlying_t<T, Col<_name>>,
underlying_t<T, Value<V>>>,
"Must be totally ordered.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::GreaterEqual{
.op1 = dynamic::Column{.name = _name.str()},
.op2 = to_value(_cond.op2.val),
}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::GreaterThan<Col<_name1>, Col<_name2>>> {
static_assert(all_columns_exist<T, Col<_name1>, Col<_name2>>(),
"All columns must exist.");
static_assert(std::totally_ordered_with<underlying_t<T, Col<_name1>>,
underlying_t<T, Col<_name2>>>,
template <class T, class Op1Type, class Op2Type>
struct ToCondition<T, conditions::GreaterThan<Op1Type, Op2Type>> {
static_assert(std::totally_ordered_with<underlying_t<T, Op1Type>,
underlying_t<T, Op2Type>>,
"Must be totally ordered.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::GreaterThan{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
.op1 = make_field<T>(_cond.op1).val,
.op2 = make_field<T>(_cond.op2).val}};
}
};
template <class T, rfl::internal::StringLiteral _name, class V>
struct ToCondition<T, conditions::GreaterThan<Col<_name>, Value<V>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
static_assert(std::totally_ordered_with<underlying_t<T, Col<_name>>,
underlying_t<T, Value<V>>>,
"Must be totally ordered.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::GreaterThan{
.op1 = dynamic::Column{.name = _name.str()},
.op2 = to_value(_cond.op2.val),
}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::LesserEqual<Col<_name1>, Col<_name2>>> {
static_assert(all_columns_exist<T, Col<_name1>, Col<_name2>>(),
"All columns must exist.");
static_assert(std::totally_ordered_with<underlying_t<T, Col<_name1>>,
underlying_t<T, Col<_name2>>>,
template <class T, class Op1Type, class Op2Type>
struct ToCondition<T, conditions::LesserEqual<Op1Type, Op2Type>> {
static_assert(std::totally_ordered_with<underlying_t<T, Op1Type>,
underlying_t<T, Op2Type>>,
"Must be totally ordered.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::LesserEqual{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
.op1 = make_field<T>(_cond.op1).val,
.op2 = make_field<T>(_cond.op2).val}};
}
};
template <class T, rfl::internal::StringLiteral _name, class V>
struct ToCondition<T, conditions::LesserEqual<Col<_name>, Value<V>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
static_assert(std::totally_ordered_with<underlying_t<T, Col<_name>>,
underlying_t<T, Value<V>>>,
"Must be totally ordered.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::LesserEqual{
.op1 = dynamic::Column{.name = _name.str()},
.op2 = to_value(_cond.op2.val),
}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::LesserThan<Col<_name1>, Col<_name2>>> {
static_assert(all_columns_exist<T, Col<_name1>, Col<_name2>>(),
"All columns must exist.");
static_assert(std::totally_ordered_with<underlying_t<T, Col<_name1>>,
underlying_t<T, Col<_name2>>>,
template <class T, class Op1Type, class Op2Type>
struct ToCondition<T, conditions::LesserThan<Op1Type, Op2Type>> {
static_assert(std::totally_ordered_with<underlying_t<T, Op1Type>,
underlying_t<T, Op2Type>>,
"Must be totally ordered.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::LesserThan{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
.op1 = make_field<T>(_cond.op1).val,
.op2 = make_field<T>(_cond.op2).val}};
}
};
template <class T, rfl::internal::StringLiteral _name, class V>
struct ToCondition<T, conditions::LesserThan<Col<_name>, Value<V>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
static_assert(std::totally_ordered_with<underlying_t<T, Col<_name>>,
underlying_t<T, Value<V>>>,
"Must be totally ordered.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::LesserThan{
.op1 = dynamic::Column{.name = _name.str()},
.op2 = to_value(_cond.op2.val),
}};
}
};
template <class T, rfl::internal::StringLiteral _name>
struct ToCondition<T, conditions::Like<Col<_name>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
template <class T, class OpType>
struct ToCondition<T, conditions::Like<OpType>> {
static_assert(
std::equality_comparable_with<underlying_t<T, Col<_name>>,
std::equality_comparable_with<underlying_t<T, OpType>,
underlying_t<T, Value<std::string>>>,
"Must be equality comparable with a string.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::Like{
.op = dynamic::Column{.name = _name.str()},
.pattern = to_value(_cond.pattern)}};
return dynamic::Condition{
.val = dynamic::Condition::Like{.op = make_field<T>(_cond.op).val,
.pattern = to_value(_cond.pattern)}};
}
};
template <class T, rfl::internal::StringLiteral _name>
struct ToCondition<T, conditions::IsNotNull<Col<_name>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
dynamic::Condition operator()(const auto&) const {
template <class T, class OpType>
struct ToCondition<T, conditions::IsNotNull<OpType>> {
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::IsNotNull{
.op = dynamic::Column{.name = _name.str()}}};
.op = make_field<T>(_cond.op).val}};
}
};
template <class T, rfl::internal::StringLiteral _name>
struct ToCondition<T, conditions::IsNull<Col<_name>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
dynamic::Condition operator()(const auto&) const {
return dynamic::Condition{.val = dynamic::Condition::IsNull{
.op = dynamic::Column{.name = _name.str()}}};
template <class T, class OpType>
struct ToCondition<T, conditions::IsNull<OpType>> {
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{
.val = dynamic::Condition::IsNull{.op = make_field<T>(_cond.op).val}};
}
};
template <class T, rfl::internal::StringLiteral _name1,
rfl::internal::StringLiteral _name2>
struct ToCondition<T, conditions::NotEqual<Col<_name1>, Col<_name2>>> {
static_assert(all_columns_exist<T, Col<_name1>, Col<_name2>>(),
"All columns must exist.");
static_assert(std::equality_comparable_with<underlying_t<T, Col<_name1>>,
underlying_t<T, Col<_name2>>>,
template <class T, class CondType>
struct ToCondition<T, conditions::Not<CondType>> {
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{
.val = dynamic::Condition::Not{
.cond = Ref<dynamic::Condition>::make(
ToCondition<T, std::remove_cvref_t<CondType>>{}(_cond.cond))}};
}
};
template <class T, class Op1Type, class Op2Type>
struct ToCondition<T, conditions::NotEqual<Op1Type, Op2Type>> {
static_assert(std::equality_comparable_with<underlying_t<T, Op1Type>,
underlying_t<T, Op2Type>>,
"Must be equality comparable.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::NotEqual{
.op1 = dynamic::Column{.name = _name1.str()},
.op2 = dynamic::Column{.name = _name2.str()},
}};
.op1 = make_field<T>(_cond.op1).val,
.op2 = make_field<T>(_cond.op2).val}};
}
};
template <class T, rfl::internal::StringLiteral _name, class V>
struct ToCondition<T, conditions::NotEqual<Col<_name>, Value<V>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
static_assert(std::equality_comparable_with<underlying_t<T, Col<_name>>,
underlying_t<T, Value<V>>>,
"Must be equality comparable.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::NotEqual{
.op1 = dynamic::Column{.name = _name.str()},
.op2 = to_value(_cond.op2.val),
}};
}
};
template <class T, rfl::internal::StringLiteral _name>
struct ToCondition<T, conditions::NotLike<Col<_name>>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
template <class T, class OpType>
struct ToCondition<T, conditions::NotLike<OpType>> {
static_assert(
std::equality_comparable_with<underlying_t<T, Col<_name>>,
std::equality_comparable_with<underlying_t<T, OpType>,
underlying_t<T, Value<std::string>>>,
"Must be equality comparable with a string.");
dynamic::Condition operator()(const auto& _cond) const {
return dynamic::Condition{.val = dynamic::Condition::NotLike{
.op = dynamic::Column{.name = _name.str()},
.pattern = to_value(_cond.pattern)}};
return dynamic::Condition{
.val = dynamic::Condition::NotLike{.op = make_field<T>(_cond.op).val,
.pattern = to_value(_cond.pattern)}};
}
};

View File

@@ -14,6 +14,7 @@
#include "../dynamic/Table.hpp"
#include "../internal/collect/vector.hpp"
#include "check_aggregations.hpp"
#include "flatten_fields_t.hpp"
#include "get_schema.hpp"
#include "get_tablename.hpp"
#include "make_fields.hpp"
@@ -31,9 +32,11 @@ template <class StructType, class FieldsType, class WhereType,
dynamic::SelectFrom to_select_from(const FieldsType& _fields,
const WhereType& _where,
const LimitType& _limit) {
static_assert(check_aggregations<StructType, FieldsType, GroupByType>(),
"The aggregations were not set up correctly. Please check the "
"trace for a more detailed error message.");
static_assert(
check_aggregations<StructType, flatten_fields_t<StructType, FieldsType>,
GroupByType>(),
"The aggregations were not set up correctly. Please check the "
"trace for a more detailed error message.");
const auto fields = make_fields<StructType, FieldsType>(
_fields,

View File

@@ -77,9 +77,9 @@ struct ToSQL<Read<ContainerType, WhereType, OrderByType, LimitType>> {
};
template <class StructType, class FieldsType, class WhereType,
class GroupByType, class OrderByType, class LimitType>
class GroupByType, class OrderByType, class LimitType, class ToType>
struct ToSQL<SelectFrom<StructType, FieldsType, WhereType, GroupByType,
OrderByType, LimitType>> {
OrderByType, LimitType, ToType>> {
dynamic::Statement operator()(const auto& _select_from) const {
return to_select_from<StructType, FieldsType, WhereType, GroupByType,
OrderByType, LimitType>(

View File

@@ -0,0 +1,46 @@
#ifndef SQLGEN_TRANSPILATION_TO_TRANSPILATION_TYPE_HPP_
#define SQLGEN_TRANSPILATION_TO_TRANSPILATION_TYPE_HPP_
#include <string>
#include <type_traits>
#include "Value.hpp"
namespace sqlgen::transpilation {
template <class T>
struct ToTranspilationType;
template <class T>
struct ToTranspilationType {
using Type = Value<T>;
Type operator()(const T& _val) const noexcept { return make_value(_val); }
};
template <>
struct ToTranspilationType<const char*> {
using Type = Value<std::string>;
Type operator()(const char* _val) const noexcept { return make_value(_val); }
};
template <int _length>
struct ToTranspilationType<char[_length]> {
using Type = Value<std::string>;
Type operator()(const char* _val) const noexcept { return make_value(_val); }
};
template <class T>
auto to_transpilation_type(const T& _t) {
return ToTranspilationType<std::remove_cvref_t<T>>{}(_t);
}
inline auto to_transpilation_type(const char* _t) {
return ToTranspilationType<const char*>{}(_t);
}
} // namespace sqlgen::transpilation
#endif

View File

@@ -14,13 +14,13 @@ template <class T>
dynamic::Value to_value(const T& _t) {
using Type = std::remove_cvref_t<T>;
if constexpr (std::is_floating_point_v<Type>) {
return dynamic::Float{.val = static_cast<double>(_t)};
return dynamic::Value{dynamic::Float{.val = static_cast<double>(_t)}};
} else if constexpr (std::is_integral_v<Type>) {
return dynamic::Integer{.val = static_cast<int64_t>(_t)};
return dynamic::Value{dynamic::Integer{.val = static_cast<int64_t>(_t)}};
} else if constexpr (std::is_convertible_v<Type, std::string>) {
return dynamic::String{.val = std::string(_t)};
return dynamic::Value{dynamic::String{.val = std::string(_t)}};
} else if constexpr (has_reflection_method<Type>) {
return to_value(_t.reflection());

View File

@@ -2,11 +2,19 @@
#define SQLGEN_TRANSPILATION_UNDERLYINGT_HPP_
#include <rfl.hpp>
#include <string>
#include <type_traits>
#include "Aggregation.hpp"
#include "AggregationOp.hpp"
#include "Col.hpp"
#include "Desc.hpp"
#include "Operation.hpp"
#include "Value.hpp"
#include "all_columns_exist.hpp"
#include "dynamic_operator_t.hpp"
#include "is_nullable.hpp"
#include "remove_nullable_t.hpp"
#include "remove_reflection_t.hpp"
namespace sqlgen::transpilation {
@@ -14,8 +22,14 @@ namespace sqlgen::transpilation {
template <class T, class _Type>
struct Underlying;
template <class T, AggregationOp _op, class ValueType>
struct Underlying<T, Aggregation<_op, ValueType>> {
using Type = typename Underlying<T, std::remove_cvref_t<ValueType>>::Type;
};
template <class T, rfl::internal::StringLiteral _name>
struct Underlying<T, Col<_name>> {
static_assert(all_columns_exist<T, Col<_name>>(), "All columns must exist.");
using Type = remove_reflection_t<rfl::field_type_t<_name, T>>;
};
@@ -24,6 +38,162 @@ struct Underlying<T, Desc<Col<_name>>> {
using Type = remove_reflection_t<rfl::field_type_t<_name, T>>;
};
template <class T, class Operand1Type, class TargetType>
struct Underlying<
T, Operation<Operator::cast, Operand1Type, TypeHolder<TargetType>>> {
using Type =
std::conditional_t<is_nullable_v<typename Underlying<
T, std::remove_cvref_t<Operand1Type>>::Type>,
std::optional<std::remove_cvref_t<TargetType>>,
std::remove_cvref_t<TargetType>>;
};
template <class T, class Head, class... Tail>
struct Underlying<T, Operation<Operator::coalesce, rfl::Tuple<Head, Tail...>>> {
using Operand1Type = typename Underlying<T, std::remove_cvref_t<Head>>::Type;
static_assert((true && ... &&
std::is_same_v<remove_nullable_t<Operand1Type>,
remove_nullable_t<typename Underlying<
T, std::remove_cvref_t<Tail>>::Type>>),
"All inputs into coalesce(...) must have the same type.");
using Type = std::conditional_t<
(is_nullable_v<Operand1Type> && ... &&
is_nullable_v<typename Underlying<T, std::remove_cvref_t<Tail>>::Type>),
std::optional<remove_nullable_t<Operand1Type>>,
remove_nullable_t<Operand1Type>>;
};
template <class T, class... OperandTypes>
struct Underlying<T, Operation<Operator::concat, rfl::Tuple<OperandTypes...>>> {
static_assert(
(true && ... &&
std::is_same_v<remove_nullable_t<typename Underlying<
T, std::remove_cvref_t<OperandTypes>>::Type>,
std::string>),
"Must be a string");
using Type =
std::conditional_t<(false || ... ||
is_nullable_v<typename Underlying<
T, std::remove_cvref_t<OperandTypes>>::Type>),
std::optional<std::string>, std::string>;
};
template <class T, class Operand1Type, class Operand2Type, class Operand3Type>
struct Underlying<
T, Operation<Operator::replace, Operand1Type, Operand2Type, Operand3Type>> {
using Underlying1 =
typename Underlying<T, std::remove_cvref_t<Operand1Type>>::Type;
using Underlying2 =
typename Underlying<T, std::remove_cvref_t<Operand2Type>>::Type;
using Underlying3 =
typename Underlying<T, std::remove_cvref_t<Operand3Type>>::Type;
static_assert(std::is_same_v<remove_nullable_t<Underlying1>, std::string>,
"Must be a string");
static_assert(std::is_same_v<remove_nullable_t<Underlying2>, std::string>,
"Must be a string");
static_assert(std::is_same_v<remove_nullable_t<Underlying3>, std::string>,
"Must be a string");
using Type = std::conditional_t<is_nullable_v<Underlying1> ||
is_nullable_v<Underlying2> ||
is_nullable_v<Underlying3>,
std::optional<std::string>, std::string>;
};
template <class T, class Operand1Type, class Operand2Type>
struct Underlying<T, Operation<Operator::round, Operand1Type, Operand2Type>> {
using Underlying1 =
typename Underlying<T, std::remove_cvref_t<Operand1Type>>::Type;
using Underlying2 =
typename Underlying<T, std::remove_cvref_t<Operand2Type>>::Type;
static_assert(std::is_integral_v<remove_nullable_t<Underlying1>> ||
std::is_floating_point_v<remove_nullable_t<Underlying1>>,
"Must be a numerical type");
static_assert(std::is_integral_v<Underlying2>, "Must be an integral type");
using Type = Underlying1;
};
template <class T, Operator _op, class Operand1Type>
requires((num_operands_v<_op>) == 1 &&
(operator_category_v<_op>) == OperatorCategory::string)
struct Underlying<T, Operation<_op, Operand1Type>> {
using Underlying1 =
typename Underlying<T, std::remove_cvref_t<Operand1Type>>::Type;
static_assert(std::is_same_v<remove_nullable_t<Underlying1>, std::string>,
"Must be a string");
using StringType =
std::conditional_t<is_nullable_v<Underlying1>, std::optional<std::string>,
std::string>;
using SizeType = std::conditional_t<is_nullable_v<Underlying1>,
std::optional<size_t>, size_t>;
using Type =
std::conditional_t<_op == Operator::length, SizeType, StringType>;
};
template <class T, Operator _op, class Operand1Type, class Operand2Type>
requires((num_operands_v<_op>) == 2 &&
(operator_category_v<_op>) == OperatorCategory::string)
struct Underlying<T, Operation<_op, Operand1Type, Operand2Type>> {
using Underlying1 =
typename Underlying<T, std::remove_cvref_t<Operand1Type>>::Type;
using Underlying2 =
typename Underlying<T, std::remove_cvref_t<Operand2Type>>::Type;
static_assert(std::is_same_v<remove_nullable_t<Underlying1>, std::string>,
"Must be a string");
static_assert(std::is_same_v<remove_nullable_t<Underlying2>, std::string>,
"Must be a string");
using Type = std::conditional_t<is_nullable_v<Underlying1> ||
is_nullable_v<Underlying2>,
std::optional<std::string>, std::string>;
};
template <class T, Operator _op, class Operand1Type>
requires((num_operands_v<_op>) == 1 &&
(operator_category_v<_op>) == OperatorCategory::numerical)
struct Underlying<T, Operation<_op, Operand1Type>> {
using Underlying1 =
typename Underlying<T, std::remove_cvref_t<Operand1Type>>::Type;
static_assert(std::is_integral_v<remove_nullable_t<Underlying1>> ||
std::is_floating_point_v<remove_nullable_t<Underlying1>>,
"Must be a numerical type");
using Type = Underlying1;
};
template <class T, Operator _op, class Operand1Type, class Operand2Type>
requires((num_operands_v<_op>) == 2 &&
(operator_category_v<_op>) == OperatorCategory::numerical)
struct Underlying<T, Operation<_op, Operand1Type, Operand2Type>> {
using Underlying1 =
typename Underlying<T, std::remove_cvref_t<Operand1Type>>::Type;
using Underlying2 =
typename Underlying<T, std::remove_cvref_t<Operand2Type>>::Type;
static_assert(
requires(remove_nullable_t<Underlying1> op1,
remove_nullable_t<Underlying2> op2) { op1 + op2; },
"Binary operations are not possible on these types.");
using ResultType = std::invoke_result_t<
decltype([](const auto& op1, const auto& op2) { return op1 + op2; }),
remove_nullable_t<Underlying1>, remove_nullable_t<Underlying2>>;
using Type = std::conditional_t<is_nullable_v<Underlying1> ||
is_nullable_v<Underlying2>,
std::optional<ResultType>, ResultType>;
};
template <class T, class _Type>
struct Underlying<T, Value<_Type>> {
using Type = _Type;