mirror of
https://github.com/getml/sqlgen.git
synced 2026-01-05 00:49:58 -06:00
Added numerous operations like concat(...), coalesce(...), abs(...), etc (#20)
This commit is contained in:
committed by
GitHub
parent
a6bad187fe
commit
30ba548f1e
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
175
include/sqlgen/dynamic/Operation.hpp
Normal file
175
include/sqlgen/dynamic/Operation.hpp
Normal 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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
229
include/sqlgen/operations.hpp
Normal file
229
include/sqlgen/operations.hpp
Normal 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
|
||||
86
include/sqlgen/transpilation/Aggregation.hpp
Normal file
86
include/sqlgen/transpilation/Aggregation.hpp
Normal 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
|
||||
10
include/sqlgen/transpilation/AggregationOp.hpp
Normal file
10
include/sqlgen/transpilation/AggregationOp.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
153
include/sqlgen/transpilation/Operation.hpp
Normal file
153
include/sqlgen/transpilation/Operation.hpp
Normal 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
|
||||
37
include/sqlgen/transpilation/Operator.hpp
Normal file
37
include/sqlgen/transpilation/Operator.hpp
Normal 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
|
||||
10
include/sqlgen/transpilation/OperatorCategory.hpp
Normal file
10
include/sqlgen/transpilation/OperatorCategory.hpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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>>{
|
||||
|
||||
42
include/sqlgen/transpilation/dynamic_aggregation_t.hpp
Normal file
42
include/sqlgen/transpilation/dynamic_aggregation_t.hpp
Normal 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
|
||||
208
include/sqlgen/transpilation/dynamic_operator_t.hpp
Normal file
208
include/sqlgen/transpilation/dynamic_operator_t.hpp
Normal 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
|
||||
64
include/sqlgen/transpilation/flatten_fields_t.hpp
Normal file
64
include/sqlgen/transpilation/flatten_fields_t.hpp
Normal 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
|
||||
@@ -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)}}};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)}};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>(
|
||||
|
||||
46
include/sqlgen/transpilation/to_transpilation_type.hpp
Normal file
46
include/sqlgen/transpilation/to_transpilation_type.hpp
Normal 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
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user