0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 12:51:13 +08:00

More tests

This commit is contained in:
Roland Bock 2024-08-03 12:48:22 +02:00
parent e3f95a8e69
commit 8e688f3c34
21 changed files with 458 additions and 1162 deletions

View File

@ -74,8 +74,9 @@ namespace sqlpp
template <typename Context, typename Select> template <typename Context, typename Select>
Context& serialize(Context& context, const any_t<Select>& t) Context& serialize(Context& context, const any_t<Select>& t)
{ {
context << "ANY"; context << "ANY (";
serialize_operand(context, t._select); serialize(context, t._select);
context << ")";
return context; return context;
} }

View File

@ -35,6 +35,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace sqlpp namespace sqlpp
{ {
struct plus
{
static constexpr auto symbol = " + ";
};
struct minus
{
static constexpr auto symbol = " - ";
};
struct multiplies
{
static constexpr auto symbol = " * ";
};
struct divides
{
static constexpr auto symbol = " / ";
};
struct negate
{
static constexpr auto symbol = "-";
};
struct modulus
{
static constexpr auto symbol = " % ";
};
struct concatenation
{
static constexpr auto symbol = " || ";
};
#warning: mysql does not offer operator||, we need to fail compilation, but maybe offer the concat function in addition #warning: mysql does not offer operator||, we need to fail compilation, but maybe offer the concat function in addition
template <typename L, typename Operator, typename R> template <typename L, typename Operator, typename R>
struct arithmetic_expression : public enable_as<arithmetic_expression<L, Operator, R>>, struct arithmetic_expression : public enable_as<arithmetic_expression<L, Operator, R>>,
@ -59,20 +94,54 @@ namespace sqlpp
using check_arithmetic_args = ::sqlpp::enable_if_t<is_numeric<L>::value and is_numeric<R>::value>; using check_arithmetic_args = ::sqlpp::enable_if_t<is_numeric<L>::value and is_numeric<R>::value>;
#warning: need to document that this is on purpose (not integral, or unsigned integral, or floating_point) because it is difficult to know for the library to know what the actual result type will be (it is difficult to guess in C++ already, and it is probably different from DB vendor to vendor). #warning: need to document that this is on purpose (not integral, or unsigned integral, or floating_point) because it is difficult to know for the library to know what the actual result type will be (it is difficult to guess in C++ already, and it is probably different from DB vendor to vendor).
namespace detail
{
template <typename L, typename Operator, typename R>
struct result_type
{
using type = numeric;
};
template <typename L, typename Operator, typename R>
struct result_type<sqlpp::optional<L>, Operator, R> : public result_type<L, Operator, R>{};
template <typename L, typename Operator, typename R>
struct result_type<L, Operator, sqlpp::optional<R>> : public result_type<L, Operator, R>{};
template <typename L, typename Operator, typename R>
struct result_type<sqlpp::optional<L>, Operator, sqlpp::optional<R>> : public result_type<L, Operator, R>{};
template <typename ValueType>
struct result_type<ValueType, plus, ValueType>
{
using type = ValueType;
};
template <typename ValueType>
struct result_type<ValueType, multiplies, ValueType>
{
using type = ValueType;
};
template <typename L, typename R>
struct result_type<L, divides, R>
{
using type = floating_point;
};
}
template <typename L, typename Operator, typename R> template <typename L, typename Operator, typename R>
struct value_type_of<arithmetic_expression<L, Operator, R>> struct value_type_of<arithmetic_expression<L, Operator, R>>
: public detail::result_type<value_type_of_t<L>, Operator, value_type_of_t<R>>
/*
: public std::conditional<sqlpp::is_optional<value_type_of_t<L>>::value or : public std::conditional<sqlpp::is_optional<value_type_of_t<L>>::value or
sqlpp::is_optional<value_type_of_t<R>>::value, sqlpp::is_optional<value_type_of_t<R>>::value,
::sqlpp::optional<numeric>, ::sqlpp::optional<numeric>,
numeric> numeric>
*/
{ {
}; };
struct concatenation
{
static constexpr auto symbol = " || ";
};
template <typename L, typename R> template <typename L, typename R>
struct value_type_of<arithmetic_expression<L, concatenation, R>> struct value_type_of<arithmetic_expression<L, concatenation, R>>
: public std::conditional<sqlpp::is_optional<value_type_of_t<L>>::value or : public std::conditional<sqlpp::is_optional<value_type_of_t<L>>::value or
@ -100,11 +169,6 @@ namespace sqlpp
return context; return context;
} }
struct plus
{
static constexpr auto symbol = " + ";
};
template <typename L, typename R, typename = check_arithmetic_args<L, R>> template <typename L, typename R, typename = check_arithmetic_args<L, R>>
constexpr auto operator+(L l, R r) -> arithmetic_expression<L, plus, R> constexpr auto operator+(L l, R r) -> arithmetic_expression<L, plus, R>
{ {
@ -120,55 +184,30 @@ namespace sqlpp
return {std::move(l), std::move(r)}; return {std::move(l), std::move(r)};
} }
struct minus
{
static constexpr auto symbol = " - ";
};
template <typename L, typename R, typename = check_arithmetic_args<L, R>> template <typename L, typename R, typename = check_arithmetic_args<L, R>>
constexpr auto operator-(L l, R r) -> arithmetic_expression<L, minus, R> constexpr auto operator-(L l, R r) -> arithmetic_expression<L, minus, R>
{ {
return {std::move(l), std::move(r)}; return {std::move(l), std::move(r)};
} }
struct multiplies
{
static constexpr auto symbol = " * ";
};
template <typename L, typename R, typename = check_arithmetic_args<L, R>> template <typename L, typename R, typename = check_arithmetic_args<L, R>>
constexpr auto operator*(L l, R r) -> arithmetic_expression<L, multiplies, R> constexpr auto operator*(L l, R r) -> arithmetic_expression<L, multiplies, R>
{ {
return {std::move(l), std::move(r)}; return {std::move(l), std::move(r)};
} }
struct divides
{
static constexpr auto symbol = " / ";
};
template <typename L, typename R, typename = check_arithmetic_args<L, R>> template <typename L, typename R, typename = check_arithmetic_args<L, R>>
constexpr auto operator/(L l, R r) -> arithmetic_expression<L, divides, R> constexpr auto operator/(L l, R r) -> arithmetic_expression<L, divides, R>
{ {
return {std::move(l), std::move(r)}; return {std::move(l), std::move(r)};
} }
struct negate
{
static constexpr auto symbol = "-";
};
template <typename R, typename = check_arithmetic_args<R, R>> template <typename R, typename = check_arithmetic_args<R, R>>
constexpr auto operator-(R r) -> arithmetic_expression<noop, divides, R> constexpr auto operator-(R r) -> arithmetic_expression<noop, negate, R>
{ {
return {{}, std::move(r)}; return {{}, std::move(r)};
} }
struct modulus
{
static constexpr auto symbol = " % ";
};
template <typename L, typename R> template <typename L, typename R>
using check_modulus_args = ::sqlpp::enable_if_t<(is_integral<L>::value or is_unsigned_integral<L>::value) and (is_integral<R>::value or is_unsigned_integral<R>::value)>; using check_modulus_args = ::sqlpp::enable_if_t<(is_integral<L>::value or is_unsigned_integral<L>::value) and (is_integral<R>::value or is_unsigned_integral<R>::value)>;

View File

@ -70,13 +70,6 @@ namespace sqlpp
template <typename L, typename R1, typename R2> template <typename L, typename R1, typename R2>
struct requires_parentheses<between_expression<L, R1, R2>> : public std::true_type{}; struct requires_parentheses<between_expression<L, R1, R2>> : public std::true_type{};
#warning: Need tests for between expressions
template <typename L, typename R1, typename R2, typename = check_between_args<L, R1, R2>>
constexpr auto between(L l, R1 r1, R2 r2) -> between_expression<L, R1, R2>
{
return {std::move(l), std::move(r1), std::move(r2)};
}
template <typename Context, typename L, typename R1, typename R2> template <typename Context, typename L, typename R1, typename R2>
auto serialize(Context& context, const between_expression<L, R1, R2>& t) -> Context& auto serialize(Context& context, const between_expression<L, R1, R2>& t) -> Context&
{ {
@ -88,4 +81,10 @@ namespace sqlpp
return context; return context;
} }
template <typename L, typename R1, typename R2, typename = check_between_args<L, R1, R2>>
constexpr auto between(L l, R1 r1, R2 r2) -> between_expression<L, R1, R2>
{
return {std::move(l), std::move(r1), std::move(r2)};
}
} // namespace sqlpp } // namespace sqlpp

View File

@ -124,7 +124,7 @@ namespace sqlpp
template <typename R, typename = check_bit_expression_args<R, R>> template <typename R, typename = check_bit_expression_args<R, R>>
constexpr auto operator~(R r) -> bit_expression<noop, bit_not, R> constexpr auto operator~(R r) -> bit_expression<noop, bit_not, R>
{ {
return {std::move(r)}; return {{}, std::move(r)};
} }
struct bit_shift_left struct bit_shift_left

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
/* /*
* Copyright (c) 2015-2015, Roland Bock * Copyright (c) 2015, Roland Bock
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
@ -160,11 +160,11 @@ namespace sqlpp
Context& serialize(Context& context, const case_t<When, Then, Else>& t) Context& serialize(Context& context, const case_t<When, Then, Else>& t)
{ {
context << "CASE WHEN "; context << "CASE WHEN ";
serialize(context, t._when); serialize_operand(context, t._when);
context << " THEN "; context << " THEN ";
serialize(context, t._then); serialize_operand(context, t._then);
context << " ELSE "; context << " ELSE ";
serialize(context, t._else); serialize_operand(context, t._else);
context << " END"; context << " END";
return context; return context;
} }

View File

@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <sqlpp11/core/operator/comparison_expression.h> #include <sqlpp11/core/operator/comparison_expression.h>
#include <sqlpp11/core/operator/between_expression.h>
#include <sqlpp11/core/operator/in_expression.h> #include <sqlpp11/core/operator/in_expression.h>
#include <sqlpp11/core/operator/sort_order_expression.h> #include <sqlpp11/core/operator/sort_order_expression.h>
#include <sqlpp11/core/type_traits.h> #include <sqlpp11/core/type_traits.h>
@ -102,6 +103,12 @@ namespace sqlpp
return ::sqlpp::is_not_distinct_from(this->derived(), std::move(r)); return ::sqlpp::is_not_distinct_from(this->derived(), std::move(r));
} }
template <typename R1, typename R2>
constexpr auto between(R1 r1, R2 r2) const -> between_expression<Expr, R1, R2>
{
return ::sqlpp::between(this->derived(), std::move(r1), std::move(r2));
}
constexpr auto asc() const -> sort_order_expression<Expr> constexpr auto asc() const -> sort_order_expression<Expr>
{ {
return ::sqlpp::asc(this->derived()); return ::sqlpp::asc(this->derived());

View File

@ -36,6 +36,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace sqlpp namespace sqlpp
{ {
struct operator_in
{
static constexpr auto symbol = " IN";
};
struct operator_not_in
{
static constexpr auto symbol = " NOT IN";
};
template<typename L, typename Operator, typename Container> template<typename L, typename Operator, typename Container>
struct in_expression : public enable_as<in_expression<L, Operator, Container>> struct in_expression : public enable_as<in_expression<L, Operator, Container>>
{ {
@ -111,7 +121,7 @@ namespace sqlpp
auto serialize(Context& context, const in_expression<L, Operator, std::tuple<Args...>>& t) -> Context& auto serialize(Context& context, const in_expression<L, Operator, std::tuple<Args...>>& t) -> Context&
{ {
serialize_operand(context, t._l); serialize_operand(context, t._l);
context << Operator::symbol << "("; context << Operator::symbol << " (";
if (sizeof...(Args) == 1) if (sizeof...(Args) == 1)
{ {
serialize(context, std::get<0>(t._r)); serialize(context, std::get<0>(t._r));
@ -119,7 +129,7 @@ namespace sqlpp
else else
{ {
#warning: interpret_tuple arguments should take Context first, too #warning: interpret_tuple arguments should take Context first, too
interpret_tuple(t._r, ',', context); interpret_tuple(t._r, ", ", context);
} }
context << ')'; context << ')';
return context; return context;
@ -133,11 +143,13 @@ namespace sqlpp
{ {
if (t._r.empty()) if (t._r.empty())
{ {
return serialize(context, false); // SQL would normally treat this as a bug in the query.
// IN requires one parameter at least.
// But the statement "L NOT IN empty_set" is true, so let's treat this as a bool result.
return serialize(context, std::is_same<Operator, operator_not_in>::value);
} }
serialize(context, t._l); serialize(context, t._l);
context << Operator::symbol context << Operator::symbol << " (";
<< "(";
bool first = true; bool first = true;
for (const auto& entry : t._r) for (const auto& entry : t._r)
{ {
@ -147,20 +159,22 @@ namespace sqlpp
} }
else else
{ {
context << ','; context << ", ";
} }
if (t._r.size() == 1) {
// A single entry does not need extra parentheses.
serialize(context, entry); serialize(context, entry);
} }
else
{
serialize_operand(context, entry);
}
}
context << ')'; context << ')';
return context; return context;
} }
struct operator_in
{
static constexpr auto symbol = " IN";
};
#warning: something.in(select(...)); should be suppported as is, need to test #warning: something.in(select(...)); should be suppported as is, need to test
template <typename L, typename... Args, typename = check_in_args<L, Args...>> template <typename L, typename... Args, typename = check_in_args<L, Args...>>
constexpr auto in(L l, std::tuple<Args...> args) -> in_expression<L, operator_in, std::tuple<Args...>> constexpr auto in(L l, std::tuple<Args...> args) -> in_expression<L, operator_in, std::tuple<Args...>>
@ -182,11 +196,6 @@ namespace sqlpp
return {std::move(l), std::move(args)}; return {std::move(l), std::move(args)};
} }
struct operator_not_in
{
static constexpr auto symbol = " NOT IN";
};
template <typename L, typename... Args, typename = check_in_args<L, Args...>> template <typename L, typename... Args, typename = check_in_args<L, Args...>>
constexpr auto not_in(L l, std::tuple<Args...> args) -> in_expression<L, operator_not_in, std::tuple<Args...>> constexpr auto not_in(L l, std::tuple<Args...> args) -> in_expression<L, operator_not_in, std::tuple<Args...>>
{ {

View File

@ -35,6 +35,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace sqlpp namespace sqlpp
{ {
struct logical_and
{
static constexpr auto symbol = " AND ";
};
struct logical_or
{
static constexpr auto symbol = " OR ";
};
template <typename L, typename Operator, typename R> template <typename L, typename Operator, typename R>
struct logical_expression : public enable_as<logical_expression<L, Operator, R>> struct logical_expression : public enable_as<logical_expression<L, Operator, R>>
{ {
@ -87,6 +97,16 @@ namespace sqlpp
return serialize_impl(context, t); return serialize_impl(context, t);
} }
template <typename Context, typename L, typename Operator, typename R1, typename R2>
auto serialize(Context& context,
const logical_expression<logical_expression<L, Operator, R1>, Operator, R2>& t) -> Context&
{
serialize(context, t._l);
context << Operator::symbol;
serialize_operand(context, t._r);
return context;
}
template <typename Context, typename L, typename Operator, typename R> template <typename Context, typename L, typename Operator, typename R>
auto serialize(Context& context, const logical_expression<L, Operator, dynamic_t<R>>& t) -> Context& auto serialize(Context& context, const logical_expression<L, Operator, dynamic_t<R>>& t) -> Context&
{ {
@ -99,11 +119,6 @@ namespace sqlpp
return serialize(context, t._l); return serialize(context, t._l);
} }
struct logical_and
{
static constexpr auto symbol = " AND ";
};
#warning: need tests with dynamic AND/OR #warning: need tests with dynamic AND/OR
template <typename L, typename R, typename = check_logical_args<L, remove_dynamic_t<R>>> template <typename L, typename R, typename = check_logical_args<L, remove_dynamic_t<R>>>
constexpr auto operator and(L l, R r) -> logical_expression<L, logical_and, R> constexpr auto operator and(L l, R r) -> logical_expression<L, logical_and, R>
@ -111,11 +126,6 @@ namespace sqlpp
return {std::move(l), std::move(r)}; return {std::move(l), std::move(r)};
} }
struct logical_or
{
static constexpr auto symbol = " OR ";
};
template <typename L, typename R, typename = check_logical_args<L, remove_dynamic_t<R>>> template <typename L, typename R, typename = check_logical_args<L, remove_dynamic_t<R>>>
constexpr auto operator||(L l, R r) -> logical_expression<L, logical_or, R> constexpr auto operator||(L l, R r) -> logical_expression<L, logical_or, R>
{ {

View File

@ -88,6 +88,20 @@ namespace sqlpp
return context; return context;
} }
template <typename Context, typename Select>
Context& serialize_operand(Context& context, const dynamic_t<Select>& t)
{
if (t._condition)
{
serialize_operand(context, t._expr);
}
else
{
serialize(context, ::sqlpp::nullopt);
}
return context;
}
template <typename Expr> template <typename Expr>
using check_dynamic_args = ::sqlpp::enable_if_t<has_value_type<Expr>::value>; using check_dynamic_args = ::sqlpp::enable_if_t<has_value_type<Expr>::value>;
@ -97,6 +111,12 @@ namespace sqlpp
return {condition, std::move(t)}; return {condition, std::move(t)};
} }
template <typename L, typename Operator, typename R, typename = check_dynamic_args<L>>
auto dynamic(bool condition, assign_expression<L, Operator, R> t) -> dynamic_t<assign_expression<L, Operator, R>>
{
return {condition, std::move(t)};
}
template <typename Expr, typename = check_dynamic_args<Expr>> template <typename Expr, typename = check_dynamic_args<Expr>>
auto dynamic(bool condition, sort_order_expression<Expr> t) -> dynamic_t<sort_order_expression<Expr>> auto dynamic(bool condition, sort_order_expression<Expr> t) -> dynamic_t<sort_order_expression<Expr>>
{ {

View File

@ -32,8 +32,8 @@ int main(int, char* [])
{ {
const auto val = sqlpp::value(17); const auto val = sqlpp::value(17);
SQLPP_COMPARE(any(select(val.as(v))), "ANY(SELECT 17 AS v)"); SQLPP_COMPARE(any(select(val.as(v))), "ANY (SELECT 17 AS v)");
SQLPP_COMPARE(val == any(select(val.as(v))), "17 = ANY(SELECT 17 AS v)"); SQLPP_COMPARE(val == any(select(val.as(v))), "17 = ANY (SELECT 17 AS v)");
return 0; return 0;
} }

View File

@ -23,173 +23,51 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "MockDb.h" #include "../compare.h"
#include "Sample.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#include "../../include/test_helpers.h" int main(int, char* [])
namespace
{ {
template<typename A, typename B> const auto val = sqlpp::value(1);
constexpr bool is_same_type() const auto expr = sqlpp::value(17) + 4;
{
return std::is_same<A, B>::value; // Operands are enclosed in parenheses where required.
} SQLPP_COMPARE(val + val, "1 + 1");
} SQLPP_COMPARE(val - val, "1 - 1");
SQLPP_COMPARE(val * val, "1 * 1");
#warning: implement serialize instead of type tests here! SQLPP_COMPARE(val / val, "1 / 1");
SQLPP_ALIAS_PROVIDER(r_not_null); SQLPP_COMPARE(val % val, "1 % 1");
SQLPP_ALIAS_PROVIDER(r_maybe_null);
SQLPP_ALIAS_PROVIDER(r_opt_not_null); SQLPP_COMPARE(val + expr, "1 + (17 + 4)");
SQLPP_ALIAS_PROVIDER(r_opt_maybe_null); SQLPP_COMPARE(val - expr, "1 - (17 + 4)");
SQLPP_COMPARE(val * expr, "1 * (17 + 4)");
template<typename Value> SQLPP_COMPARE(val / expr, "1 / (17 + 4)");
void test_arithmetic_expressions(Value v) SQLPP_COMPARE(val % expr, "1 % (17 + 4)");
{
using ValueType = sqlpp::numeric; SQLPP_COMPARE(expr + val, "(17 + 4) + 1");
using OptValueType = ::sqlpp::optional<sqlpp::numeric>; SQLPP_COMPARE(expr - val, "(17 + 4) - 1");
SQLPP_COMPARE(expr * val, "(17 + 4) * 1");
auto value = sqlpp::value(v); SQLPP_COMPARE(expr / val, "(17 + 4) / 1");
auto opt_value = sqlpp::value(::sqlpp::make_optional(v)); SQLPP_COMPARE(expr % val, "(17 + 4) % 1");
// Arithmetically combining non-optional values SQLPP_COMPARE(expr + expr, "(17 + 4) + (17 + 4)");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value + value)>, ValueType>(), ""); SQLPP_COMPARE(expr - expr, "(17 + 4) - (17 + 4)");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value - value)>, ValueType>(), ""); SQLPP_COMPARE(expr * expr, "(17 + 4) * (17 + 4)");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value * value)>, ValueType>(), ""); SQLPP_COMPARE(expr / expr, "(17 + 4) / (17 + 4)");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value / value)>, ValueType>(), ""); SQLPP_COMPARE(expr % expr, "(17 + 4) % (17 + 4)");
// Arithmetically combining non-optional with optional values // Same for unary expressions.
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value + opt_value)>, OptValueType>(), ""); SQLPP_COMPARE(-val, "-1");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value - opt_value)>, OptValueType>(), ""); SQLPP_COMPARE(-expr, "-(17 + 4)");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value * opt_value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value / opt_value)>, OptValueType>(), ""); const auto text = sqlpp::value("a");
const auto text_expr = sqlpp::value("b") + "c";
// Arithmetically combining optional with non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value + value)>, OptValueType>(), ""); // Same for concatenation.
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value - value)>, OptValueType>(), ""); SQLPP_COMPARE(text + text, "'a' || 'a'");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value * value)>, OptValueType>(), ""); SQLPP_COMPARE(text + text_expr, "'a' || ('b' || 'c')");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value / value)>, OptValueType>(), ""); SQLPP_COMPARE(text_expr + text, "('b' || 'c') || 'a'");
SQLPP_COMPARE(text_expr + text_expr, "('b' || 'c') || ('b' || 'c')");
// Arithmetically combining optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value + opt_value)>, OptValueType>(), ""); return 0;
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value - opt_value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value * opt_value)>, OptValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value / opt_value)>, OptValueType>(), "");
// Same with negate.
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(-value)>, ValueType>(), "");
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(-opt_value)>, OptValueType>(), "");
// Arithmetic expressions enable the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(value + opt_value)>::value, "");
static_assert(sqlpp::has_enabled_as<decltype(-opt_value)>::value, "");
// Arithmetic expressions enable comparison member functions.
static_assert(sqlpp::has_enabled_comparison<decltype(-opt_value)>::value, "");
// Arithmetic expressions have their arguments as nodes
using L = typename std::decay<decltype(value)>::type;
using R = typename std::decay<decltype(opt_value)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(value + opt_value)>, sqlpp::detail::type_vector<L, R>>::value, "");
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(-opt_value)>, sqlpp::detail::type_vector<sqlpp::noop, R>>::value, "");
}
template<typename Value>
void test_modulus_expressions(Value v)
{
using ValueType = sqlpp::numeric;
using OptValueType = ::sqlpp::optional<sqlpp::numeric>;
auto value = sqlpp::value(v);
auto opt_value = sqlpp::value(::sqlpp::make_optional(v));
// Modulus combining non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value % value)>, ValueType>(), "");
// Modulus combining non-optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value % opt_value)>, OptValueType>(), "");
// Modulus combining optional with non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value % value)>, OptValueType>(), "");
// Modulus combining optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value % opt_value)>, OptValueType>(), "");
// Modulus expressions enable the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(value % opt_value)>::value, "");
// Modulus expressions enable comparison member functions.
static_assert(sqlpp::has_enabled_comparison<decltype(value % opt_value)>::value, "");
// Modulus expressions have their arguments as nodes
using L = typename std::decay<decltype(value)>::type;
using R = typename std::decay<decltype(opt_value)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(value % opt_value)>, sqlpp::detail::type_vector<L, R>>::value, "");
}
template<typename Value>
void test_concatenation_expressions(Value v)
{
using ValueType = sqlpp::text;
using OptValueType = ::sqlpp::optional<sqlpp::text>;
auto value = sqlpp::value(v);
auto opt_value = sqlpp::value(::sqlpp::make_optional(v));
// Concatenating non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value + value)>, ValueType>(), "");
// Concatenating non-optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(value + opt_value)>, OptValueType>(), "");
// Concatenating optional with non-optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value + value)>, OptValueType>(), "");
// Concatenating optional with optional values
static_assert(is_same_type<sqlpp::value_type_of_t<decltype(opt_value + opt_value)>, OptValueType>(), "");
// Modulus expressions enable the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(value + opt_value)>::value, "");
// Modulus expressions enable comparison member functions.
static_assert(sqlpp::has_enabled_comparison<decltype(value + opt_value)>::value, "");
// Modulus expressions have their arguments as nodes
using L = typename std::decay<decltype(value)>::type;
using R = typename std::decay<decltype(opt_value)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(value + opt_value)>, sqlpp::detail::type_vector<L, R>>::value, "");
}
int main()
{
// integral
test_arithmetic_expressions(int8_t{7});
test_arithmetic_expressions(int16_t{7});
test_arithmetic_expressions(int32_t{7});
test_arithmetic_expressions(int64_t{7});
test_modulus_expressions(int8_t{7});
test_modulus_expressions(int16_t{7});
test_modulus_expressions(int32_t{7});
test_modulus_expressions(int64_t{7});
// unsigned integral
test_arithmetic_expressions(uint8_t{7});
test_arithmetic_expressions(uint16_t{7});
test_arithmetic_expressions(uint32_t{7});
test_arithmetic_expressions(uint64_t{7});
test_modulus_expressions(uint8_t{7});
test_modulus_expressions(uint16_t{7});
test_modulus_expressions(uint32_t{7});
test_modulus_expressions(uint64_t{7});
// floating point
test_arithmetic_expressions(float{7.7});
test_arithmetic_expressions(double{7.7});
// text
test_concatenation_expressions('7');
test_concatenation_expressions("seven");
test_concatenation_expressions(std::string("seven"));
test_concatenation_expressions(::sqlpp::string_view("seven"));
} }

View File

@ -23,96 +23,24 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "../compare.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#warning: implement serialize instead of type tests here! SQLPP_ALIAS_PROVIDER(v);
SQLPP_ALIAS_PROVIDER(cheese);
template <typename T, typename ValueType> int main(int, char* [])
using is_select_column_value_type = std::is_same<sqlpp::select_column_value_type_of_t<T>, ValueType>;
template<typename Value>
void test_as_expression(Value v)
{ {
using ValueType = sqlpp::value_type_of_t<Value>; const auto val = sqlpp::value(17);
using OptValueType = ::sqlpp::optional<ValueType>; const auto expr = sqlpp::value(17) + 4;
auto v_not_null= sqlpp::value(v); SQLPP_COMPARE(val.as(v), "17 AS v");
auto v_maybe_null= sqlpp::value(::sqlpp::make_optional(v)); SQLPP_COMPARE(expr.as(v), "(17 + 4) AS v");
auto v_dynamic_not_null = dynamic(true, sqlpp::value(v));
auto v_dynamic_maybe_null = dynamic(true, sqlpp::value(::sqlpp::make_optional(v)));
static_assert(not sqlpp::has_value_type<decltype(v_not_null.as(cheese))>::value, ""); SQLPP_COMPARE(dynamic(true, val).as(v), "17 AS v");
static_assert(not sqlpp::has_value_type<decltype(v_maybe_null.as(cheese))>::value, ""); SQLPP_COMPARE(dynamic(true, expr).as(v), "(17 + 4) AS v");
static_assert(not sqlpp::has_value_type<decltype(v_dynamic_not_null.as(cheese))>::value, "");
static_assert(not sqlpp::has_value_type<decltype(v_dynamic_maybe_null.as(cheese))>::value, "");
static_assert(not sqlpp::has_name<decltype(v_not_null.as(cheese))>::value, ""); SQLPP_COMPARE(dynamic(false, val).as(v), "NULL AS v");
static_assert(not sqlpp::has_name<decltype(v_maybe_null.as(cheese))>::value, ""); SQLPP_COMPARE(dynamic(false, expr).as(v), "NULL AS v");
static_assert(not sqlpp::has_name<decltype(v_dynamic_not_null.as(cheese))>::value, "");
static_assert(not sqlpp::has_name<decltype(v_dynamic_maybe_null.as(cheese))>::value, "");
static_assert(is_select_column_value_type<decltype(v_not_null.as(cheese)), ValueType>::value, ""); return 0;
static_assert(is_select_column_value_type<decltype(v_maybe_null.as(cheese)), OptValueType>::value, "");
static_assert(is_select_column_value_type<decltype(v_dynamic_not_null.as(cheese)), OptValueType>::value, "");
static_assert(is_select_column_value_type<decltype(v_dynamic_maybe_null.as(cheese)), OptValueType>::value, "");
static_assert(sqlpp::select_column_has_name<decltype(v_not_null.as(cheese))>::value, "");
static_assert(sqlpp::select_column_has_name<decltype(v_maybe_null.as(cheese))>::value, "");
static_assert(sqlpp::select_column_has_name<decltype(v_dynamic_not_null.as(cheese))>::value, "");
static_assert(sqlpp::select_column_has_name<decltype(v_dynamic_maybe_null.as(cheese))>::value, "");
// AS expressions have do not enable the `as` member function.
static_assert(not sqlpp::has_enabled_as<decltype(v_not_null.as(cheese))>::value, "");
// AS expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(v_not_null.as(cheese))>::value, "");
// AS expressions have their arguments as nodes.
using L = typename std::decay<decltype(v_not_null)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(v_not_null.as(cheese))>, sqlpp::detail::type_vector<L>>::value, "");
} }
int main()
{
// boolean
test_as_expression(bool{true});
// integral
test_as_expression(int8_t{7});
test_as_expression(int16_t{7});
test_as_expression(int32_t{7});
test_as_expression(int64_t{7});
// unsigned integral
test_as_expression(uint8_t{7});
test_as_expression(uint16_t{7});
test_as_expression(uint32_t{7});
test_as_expression(uint64_t{7});
// floating point
test_as_expression(float{7.7});
test_as_expression(double{7.7});
// text
test_as_expression('7');
test_as_expression("seven");
test_as_expression(std::string("seven"));
test_as_expression(::sqlpp::string_view("seven"));
// blob
test_as_expression(std::vector<uint8_t>{});
// date
test_as_expression(::sqlpp::chrono::day_point{});
// timestamp
test_as_expression(::sqlpp::chrono::microsecond_point{});
using minute_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
test_as_expression(minute_point{});
// time_of_day
test_as_expression(std::chrono::microseconds{});
}

View File

@ -23,110 +23,26 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "MockDb.h" #include "../compare.h"
#include "Sample.h" #include "Sample.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#warning: implement serialize instead of type tests here! int main(int, char* [])
namespace
{ {
auto db = MockDb{}; constexpr auto t = test::TabFoo{};
const auto val = sqlpp::value(17);
template <typename T> // Operands in assignments are enclosed in parentheses as required.
using is_bool = std::is_same<sqlpp::value_type_of_t<T>, sqlpp::boolean>; SQLPP_COMPARE(t.id = val, "id = 17");
SQLPP_COMPARE(t.id = val + 4, "id = (17 + 4)");
template <typename T> // Active dynamic assignments are just as above.
using is_maybe_bool = std::is_same<sqlpp::value_type_of_t<T>, ::sqlpp::optional<sqlpp::boolean>>; SQLPP_COMPARE(dynamic(true, t.id = val), "id = 17");
SQLPP_COMPARE(dynamic(true, t.id = val + 4), "id = (17 + 4)");
// This should be skipped by insert and update and should therefore never be called.
SQLPP_COMPARE(dynamic(false, t.id = val), "NULL");
SQLPP_COMPARE(dynamic(false, t.id = val + 4), "NULL");
return 0;
} }
template <typename Column, typename Value>
void test_assign_expression(const Column& col, const Value& v)
{
auto v_not_null = sqlpp::value(v);
auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v));
using ValueType = decltype(v_not_null);
using OptValueType = decltype(v_maybe_null);
// Assignments have no value
static_assert(not sqlpp::has_value_type<decltype(col = sqlpp::default_value)>::value, "");
static_assert(not sqlpp::has_value_type<decltype(col = v_not_null)>::value, "");
static_assert(not sqlpp::has_value_type<decltype(col = v_maybe_null)>::value, "");
// Assignments have no name
static_assert(not sqlpp::has_name<decltype(col = sqlpp::default_value)>::value, "");
static_assert(not sqlpp::has_name<decltype(col = v_not_null)>::value, "");
static_assert(not sqlpp::has_name<decltype(col = v_maybe_null)>::value, "");
// Assignment nodes
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(col = sqlpp::default_value)>,
sqlpp::detail::type_vector<Column, sqlpp::default_value_t>>::value,
"");
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(col = v_not_null)>,
sqlpp::detail::type_vector<Column, ValueType>>::value,
"");
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(col = v_maybe_null)>,
sqlpp::detail::type_vector<Column, OptValueType>>::value,
"");
// Assign expressions do not have the `as` member function.
static_assert(not sqlpp::has_enabled_as<decltype(col = v_not_null)>::value, "");
// Assign expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(col = v_not_null)>::value, "");
// Assign expressions have their arguments as nodes.
using L = typename std::decay<decltype(col)>::type;
using R = typename std::decay<decltype(v_not_null)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(col = v_not_null)>, sqlpp::detail::type_vector<L, R>>::value, "");
}
#warning: test that non-nullable columns cannot be assigned optional values
#warning: test that non-default columns cannot be assigned to default_value
int main()
{
const auto bar = test::TabBar{};
const auto foo = test::TabFoo{};
const auto date_time = test::TabDateTime{};
// boolean
test_assign_expression(foo.boolN, bool{true});
// integral
test_assign_expression(foo.intN, int8_t{7});
test_assign_expression(foo.intN, int16_t{7});
test_assign_expression(foo.intN, int32_t{7});
test_assign_expression(foo.intN, int64_t{7});
// unsigned integral
test_assign_expression(foo.uIntN, uint8_t{7});
test_assign_expression(foo.uIntN, uint16_t{7});
test_assign_expression(foo.uIntN, uint32_t{7});
test_assign_expression(foo.uIntN, uint64_t{7});
// floating point
test_assign_expression(foo.doubleN, float{7.7});
test_assign_expression(foo.doubleN, double{7.7});
// text
test_assign_expression(bar.textN, '7');
test_assign_expression(bar.textN, "seven");
test_assign_expression(bar.textN, std::string("seven"));
test_assign_expression(bar.textN, ::sqlpp::string_view("seven"));
// blob
test_assign_expression(foo.blobN, std::vector<uint8_t>{});
// date
test_assign_expression(date_time.dayPointN, ::sqlpp::chrono::day_point{});
// timestamp
test_assign_expression(date_time.timePointN, ::sqlpp::chrono::microsecond_point{});
using minute_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
test_assign_expression(date_time.timePointN, minute_point{});
// time_of_day
test_assign_expression(date_time.timeOfDayN, std::chrono::microseconds{});
}

View File

@ -23,91 +23,24 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "MockDb.h" #include "../compare.h"
#include "Sample.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#warning: implement serialize instead of type tests here! int main(int, char* [])
namespace
{ {
auto db = MockDb{}; const auto val = sqlpp::value(1);
const auto expr = sqlpp::value(17) + 4;
template <typename T> // Operands are enclosed in parenheses where required
using is_bool = std::is_same<sqlpp::value_type_of_t<T>, sqlpp::boolean>; SQLPP_COMPARE(val.between(val, val), "1 BETWEEN 1 AND 1");
SQLPP_COMPARE(val.between(val, expr), "1 BETWEEN 1 AND (17 + 4)");
SQLPP_COMPARE(val.between(expr, val), "1 BETWEEN (17 + 4) AND 1");
SQLPP_COMPARE(val.between(expr, expr), "1 BETWEEN (17 + 4) AND (17 + 4)");
SQLPP_COMPARE(expr.between(val, val), "(17 + 4) BETWEEN 1 AND 1");
SQLPP_COMPARE(expr.between(val, expr), "(17 + 4) BETWEEN 1 AND (17 + 4)");
SQLPP_COMPARE(expr.between(expr, val), "(17 + 4) BETWEEN (17 + 4) AND 1");
SQLPP_COMPARE(expr.between(expr, expr), "(17 + 4) BETWEEN (17 + 4) AND (17 + 4)");
template <typename T> SQLPP_COMPARE(val.between(val, val) and true, "(1 BETWEEN 1 AND 1) AND 1");
using is_maybe_bool = std::is_same<sqlpp::value_type_of_t<T>, ::sqlpp::optional<sqlpp::boolean>>; return 0;
} }
template <typename Value>
void test_between_expression(Value v)
{
auto v_not_null = sqlpp::value(v);
auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v));
// Variations of nullable and non-nullable values
static_assert(is_bool<decltype(between(v_not_null, v_not_null, v_not_null))>::value, "");
static_assert(is_maybe_bool<decltype(between(v_not_null, v_not_null, v_maybe_null))>::value, "");
static_assert(is_maybe_bool<decltype(between(v_not_null, v_maybe_null, v_not_null))>::value, "");
static_assert(is_maybe_bool<decltype(between(v_not_null, v_maybe_null, v_maybe_null))>::value, "");
static_assert(is_maybe_bool<decltype(between(v_maybe_null, v_not_null, v_not_null))>::value, "");
static_assert(is_maybe_bool<decltype(between(v_maybe_null, v_not_null, v_maybe_null))>::value, "");
static_assert(is_maybe_bool<decltype(between(v_maybe_null, v_maybe_null, v_not_null))>::value, "");
static_assert(is_maybe_bool<decltype(between(v_maybe_null, v_maybe_null, v_maybe_null))>::value, "");
// Between expressions have the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(between(v_not_null, v_not_null, v_not_null))>::value, "");
// Between expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(between(v_not_null, v_not_null, v_not_null))>::value, "");
// Between expressions have their arguments as nodes.
using L = typename std::decay<decltype(v_not_null)>::type;
using M = Value;
using R = typename std::decay<decltype(v_maybe_null)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(between(v_not_null, v, v_maybe_null))>, sqlpp::detail::type_vector<L, M, R>>::value, "");
}
int main()
{
// boolean
test_between_expression(bool{true});
// integral
test_between_expression(int8_t{7});
test_between_expression(int16_t{7});
test_between_expression(int32_t{7});
test_between_expression(int64_t{7});
// unsigned integral
test_between_expression(uint8_t{7});
test_between_expression(uint16_t{7});
test_between_expression(uint32_t{7});
test_between_expression(uint64_t{7});
// floating point
test_between_expression(float{7.7});
test_between_expression(double{7.7});
// text
test_between_expression('7');
test_between_expression("seven");
test_between_expression(std::string("seven"));
test_between_expression(::sqlpp::string_view("seven"));
// blob
test_between_expression(std::vector<uint8_t>{});
// date
test_between_expression(::sqlpp::chrono::day_point{});
// timestamp
test_between_expression(::sqlpp::chrono::microsecond_point{});
using minute_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
test_between_expression(minute_point{});
// time_of_day
test_between_expression(std::chrono::microseconds{});
}

View File

@ -23,123 +23,42 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "MockDb.h" #include "../compare.h"
#include "Sample.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#warning: implement serialize instead of type tests here! int main(int, char* [])
namespace
{ {
auto db = MockDb{}; const auto val = sqlpp::value(1);
const auto expr = sqlpp::value(17) + 4;
template <typename T> // Operands are enclosed in parentheses where required.
using is_integral = std::is_same<sqlpp::value_type_of_t<T>, sqlpp::integral>; SQLPP_COMPARE(val & val, "1 & 1");
SQLPP_COMPARE(val | val, "1 | 1");
SQLPP_COMPARE(val ^ val, "1 ^ 1");
SQLPP_COMPARE(val << val, "1 << 1");
SQLPP_COMPARE(val >> val, "1 >> 1");
template <typename T> SQLPP_COMPARE(val & expr, "1 & (17 + 4)");
using is_maybe_integral = std::is_same<sqlpp::value_type_of_t<T>, ::sqlpp::optional<sqlpp::integral>>; SQLPP_COMPARE(val | expr, "1 | (17 + 4)");
SQLPP_COMPARE(val ^ expr, "1 ^ (17 + 4)");
SQLPP_COMPARE(val << expr, "1 << (17 + 4)");
SQLPP_COMPARE(val >> expr, "1 >> (17 + 4)");
SQLPP_COMPARE(expr & val, "(17 + 4) & 1");
SQLPP_COMPARE(expr | val, "(17 + 4) | 1");
SQLPP_COMPARE(expr ^ val, "(17 + 4) ^ 1");
SQLPP_COMPARE(expr << val, "(17 + 4) << 1");
SQLPP_COMPARE(expr >> val, "(17 + 4) >> 1");
SQLPP_COMPARE(expr & expr, "(17 + 4) & (17 + 4)");
SQLPP_COMPARE(expr | expr, "(17 + 4) | (17 + 4)");
SQLPP_COMPARE(expr ^ expr, "(17 + 4) ^ (17 + 4)");
SQLPP_COMPARE(expr << expr, "(17 + 4) << (17 + 4)");
SQLPP_COMPARE(expr >> expr, "(17 + 4) >> (17 + 4)");
// Same for unary operators
SQLPP_COMPARE(~val, "~1");
SQLPP_COMPARE(~expr, "~(17 + 4)");
return 0;
} }
template <typename Value>
void test_bit_expression(Value v)
{
auto v_not_null = sqlpp::value(v);
auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v));
// Compare non-nullable with non-nullable.
static_assert(is_integral<decltype(v_not_null << v_not_null)>::value, "");
static_assert(is_integral<decltype(v_not_null >> v_not_null)>::value, "");
static_assert(is_integral<decltype(v_not_null | v_not_null)>::value, "");
static_assert(is_integral<decltype(v_not_null & v_not_null)>::value, "");
static_assert(is_integral<decltype(v_not_null ^ v_not_null)>::value, "");
// Compare non-nullable with nullable.
static_assert(is_maybe_integral<decltype(v_not_null << v_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_not_null >> v_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_not_null | v_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_not_null & v_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_not_null ^ v_maybe_null)>::value, "");
// Compare nullable with non-nullable.
static_assert(is_maybe_integral<decltype(v_maybe_null << v_not_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_maybe_null >> v_not_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_maybe_null | v_not_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_maybe_null & v_not_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_maybe_null ^ v_not_null)>::value, "");
// Compare nullable with nullable.
static_assert(is_maybe_integral<decltype(v_maybe_null << v_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_maybe_null >> v_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_maybe_null | v_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_maybe_null & v_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(v_maybe_null ^ v_maybe_null)>::value, "");
// Compare with null.
static_assert(is_integral<decltype(~v_not_null)>::value, "");
static_assert(is_maybe_integral<decltype(~v_maybe_null)>::value, "");
// Comparison expressions have the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(v_not_null << v_maybe_null)>::value, "");
static_assert(sqlpp::has_enabled_as<decltype(~v_not_null)>::value, "");
// Comparison expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(v_not_null << v_maybe_null)>::value, "");
// Comparison expressions have their arguments as nodes.
using L = typename std::decay<decltype(v_not_null)>::type;
using R = typename std::decay<decltype(v_maybe_null)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(v_not_null << v_maybe_null)>, sqlpp::detail::type_vector<L, R>>::value, "");
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(~v_not_null)>, sqlpp::detail::type_vector<sqlpp::noop, L>>::value, "");
}
template <typename Left, typename Right>
void test_bit_shift_expression(Left l, Right r)
{
auto l_not_null = sqlpp::value(l);
auto l_maybe_null = sqlpp::value(::sqlpp::make_optional(l));
auto r_not_null = sqlpp::value(r);
auto r_maybe_null = sqlpp::value(::sqlpp::make_optional(r));
// Compare non-nullable with non-nullable.
static_assert(is_integral<decltype(l_not_null << r_not_null)>::value, "");
static_assert(is_integral<decltype(l_not_null >> r_not_null)>::value, "");
// Compare non-nullable with nullable.
static_assert(is_maybe_integral<decltype(l_not_null << r_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(l_not_null >> r_maybe_null)>::value, "");
// Compare nullable with non-nullable.
static_assert(is_maybe_integral<decltype(l_maybe_null << r_not_null)>::value, "");
static_assert(is_maybe_integral<decltype(l_maybe_null >> r_not_null)>::value, "");
// Compare nullable with nullable.
static_assert(is_maybe_integral<decltype(l_maybe_null << r_maybe_null)>::value, "");
static_assert(is_maybe_integral<decltype(l_maybe_null >> r_maybe_null)>::value, "");
// Comparison expressions have the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(l_not_null << r_maybe_null)>::value, "");
// Comparison expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(l_not_null << r_maybe_null)>::value, "");
// Comparison expressions have their arguments as nodes.
using L = typename std::decay<decltype(l_not_null)>::type;
using R = typename std::decay<decltype(r_maybe_null)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(l_not_null << r_maybe_null)>, sqlpp::detail::type_vector<L, R>>::value, "");
}
int main()
{
// bit expression require integral operands
test_bit_expression(int8_t{7});
test_bit_expression(int16_t{7});
test_bit_expression(int32_t{7});
test_bit_expression(int64_t{7});
// bit shift operations can have unsigned rhs operands
test_bit_shift_expression(int8_t{7}, uint8_t{7});
test_bit_shift_expression(int8_t{7}, uint16_t{7});
test_bit_shift_expression(int8_t{7}, uint32_t{7});
test_bit_shift_expression(int8_t{7}, uint64_t{7});
}

View File

@ -23,90 +23,26 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "../compare.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
template<typename T, typename Value> SQLPP_ALIAS_PROVIDER(v);
using is_same_type = std::is_same<sqlpp::value_type_of_t<T>, sqlpp::value_type_of_t<Value>>;
#warning: implement serialize instead of type tests here! int main(int, char* [])
template <typename Value>
void test_case_expression(Value v)
{ {
auto c_not_null = sqlpp::value(true); const auto cond = sqlpp::value(true);
auto c_maybe_null = sqlpp::value(::sqlpp::make_optional(false)); const auto val = sqlpp::value(11);
const auto expr = sqlpp::value(17) + 4;
auto v_not_null = sqlpp::value(v); // Case operands use parentheses where required.
auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v)); SQLPP_COMPARE(case_when(cond).then(val).else_(val), "CASE WHEN 1 THEN 11 ELSE 11 END");
SQLPP_COMPARE(case_when(cond).then(val).else_(expr), "CASE WHEN 1 THEN 11 ELSE (17 + 4) END");
SQLPP_COMPARE(case_when(cond).then(expr).else_(val), "CASE WHEN 1 THEN (17 + 4) ELSE 11 END");
SQLPP_COMPARE(case_when(cond).then(expr).else_(expr), "CASE WHEN 1 THEN (17 + 4) ELSE (17 + 4) END");
SQLPP_COMPARE(case_when(false or cond).then(val).else_(val), "CASE WHEN (0 OR 1) THEN 11 ELSE 11 END");
SQLPP_COMPARE(case_when(false or cond).then(val).else_(expr), "CASE WHEN (0 OR 1) THEN 11 ELSE (17 + 4) END");
SQLPP_COMPARE(case_when(false or cond).then(expr).else_(val), "CASE WHEN (0 OR 1) THEN (17 + 4) ELSE 11 END");
SQLPP_COMPARE(case_when(false or cond).then(expr).else_(expr), "CASE WHEN (0 OR 1) THEN (17 + 4) ELSE (17 + 4) END");
using ValueType = sqlpp::value_type_of_t<decltype(v_not_null)>; return 0;
using OptValueType = sqlpp::value_type_of_t<decltype(v_maybe_null)>;
// Variations of nullable and non-nullable values
static_assert(is_same_type<decltype(case_when(c_not_null).then(v_not_null).else_(v_not_null)), ValueType>::value, "");
static_assert(is_same_type<decltype(case_when(c_not_null).then(v_not_null).else_(v_maybe_null)), OptValueType>::value, "");
static_assert(is_same_type<decltype(case_when(c_not_null).then(v_maybe_null).else_(v_not_null)), OptValueType>::value, "");
static_assert(is_same_type<decltype(case_when(c_not_null).then(v_maybe_null).else_(v_maybe_null)), OptValueType>::value, "");
static_assert(is_same_type<decltype(case_when(c_maybe_null).then(v_not_null).else_(v_not_null)), OptValueType>::value, "");
static_assert(is_same_type<decltype(case_when(c_maybe_null).then(v_not_null).else_(v_maybe_null)), OptValueType>::value, "");
static_assert(is_same_type<decltype(case_when(c_maybe_null).then(v_maybe_null).else_(v_not_null)), OptValueType>::value, "");
static_assert(is_same_type<decltype(case_when(c_maybe_null).then(v_maybe_null).else_(v_maybe_null)), OptValueType>::value, "");
// Incomplete case expressions have no value.
static_assert(not sqlpp::has_value_type<decltype(case_when(c_not_null))>::value, "");
static_assert(not sqlpp::has_value_type<decltype(case_when(c_not_null).then(v_not_null))>::value, "");
// Case expressions have the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(case_when(c_not_null).then(v_not_null).else_(v_not_null))>::value, "");
// Case expressions enable comparison member functions.
static_assert(sqlpp::has_enabled_comparison<decltype(case_when(c_not_null).then(v_not_null).else_(v_not_null))>::value, "");
// Between expressions have their arguments as nodes.
using L = typename std::decay<decltype(c_not_null)>::type;
using M = typename std::decay<decltype(v_not_null)>::type;
using R = typename std::decay<decltype(v_maybe_null)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(case_when(c_not_null).then(v_not_null).else_(v_maybe_null))>, sqlpp::detail::type_vector<L, M, R>>::value, "");
} }
int main()
{
// boolean
test_case_expression(bool{true});
// integral
test_case_expression(int8_t{7});
test_case_expression(int16_t{7});
test_case_expression(int32_t{7});
test_case_expression(int64_t{7});
// unsigned integral
test_case_expression(uint8_t{7});
test_case_expression(uint16_t{7});
test_case_expression(uint32_t{7});
test_case_expression(uint64_t{7});
// floating point
test_case_expression(float{7.7});
test_case_expression(double{7.7});
// text
test_case_expression('7');
test_case_expression("seven");
test_case_expression(std::string("seven"));
test_case_expression(::sqlpp::string_view("seven"));
// blob
test_case_expression(std::vector<uint8_t>{});
// date
test_case_expression(::sqlpp::chrono::day_point{});
// timestamp
test_case_expression(::sqlpp::chrono::microsecond_point{});
using minute_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
test_case_expression(minute_point{});
// time_of_day
test_case_expression(std::chrono::microseconds{});
}

View File

@ -23,159 +23,57 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "MockDb.h" #include "../compare.h"
#include "Sample.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#warning: implement serialize instead of type tests here! int main(int, char* [])
namespace
{ {
auto db = MockDb{}; const auto val = sqlpp::value(1);
const auto expr = sqlpp::value(17) + 4;
template <typename T> // Operands are enclosed in parentheses where required.
using is_bool = std::is_same<sqlpp::value_type_of_t<T>, sqlpp::boolean>; SQLPP_COMPARE(val < val, "1 < 1");
SQLPP_COMPARE(val <= val, "1 <= 1");
SQLPP_COMPARE(val == val, "1 = 1");
SQLPP_COMPARE(val != val, "1 <> 1");
SQLPP_COMPARE(val >= val, "1 >= 1");
SQLPP_COMPARE(val > val, "1 > 1");
SQLPP_COMPARE(val.is_distinct_from(val), "1 IS DISTINCT FROM 1");
SQLPP_COMPARE(val.is_not_distinct_from(val), "1 IS NOT DISTINCT FROM 1");
template <typename T> SQLPP_COMPARE(val < expr, "1 < (17 + 4)");
using is_maybe_bool = std::is_same<sqlpp::value_type_of_t<T>, ::sqlpp::optional<sqlpp::boolean>>; SQLPP_COMPARE(val <= expr, "1 <= (17 + 4)");
SQLPP_COMPARE(val == expr, "1 = (17 + 4)");
SQLPP_COMPARE(val != expr, "1 <> (17 + 4)");
SQLPP_COMPARE(val >= expr, "1 >= (17 + 4)");
SQLPP_COMPARE(val > expr, "1 > (17 + 4)");
SQLPP_COMPARE(val.is_distinct_from(expr), "1 IS DISTINCT FROM (17 + 4)");
SQLPP_COMPARE(val.is_not_distinct_from(expr), "1 IS NOT DISTINCT FROM (17 + 4)");
SQLPP_COMPARE(expr < val, "(17 + 4) < 1");
SQLPP_COMPARE(expr <= val, "(17 + 4) <= 1");
SQLPP_COMPARE(expr == val, "(17 + 4) = 1");
SQLPP_COMPARE(expr != val, "(17 + 4) <> 1");
SQLPP_COMPARE(expr >= val, "(17 + 4) >= 1");
SQLPP_COMPARE(expr > val, "(17 + 4) > 1");
SQLPP_COMPARE(expr.is_distinct_from(val), "(17 + 4) IS DISTINCT FROM 1");
SQLPP_COMPARE(expr.is_not_distinct_from(val), "(17 + 4) IS NOT DISTINCT FROM 1");
SQLPP_COMPARE(expr < expr, "(17 + 4) < (17 + 4)");
SQLPP_COMPARE(expr <= expr, "(17 + 4) <= (17 + 4)");
SQLPP_COMPARE(expr == expr, "(17 + 4) = (17 + 4)");
SQLPP_COMPARE(expr != expr, "(17 + 4) <> (17 + 4)");
SQLPP_COMPARE(expr >= expr, "(17 + 4) >= (17 + 4)");
SQLPP_COMPARE(expr > expr, "(17 + 4) > (17 + 4)");
SQLPP_COMPARE(expr.is_distinct_from(expr), "(17 + 4) IS DISTINCT FROM (17 + 4)");
SQLPP_COMPARE(expr.is_not_distinct_from(expr), "(17 + 4) IS NOT DISTINCT FROM (17 + 4)");
// Same for unary operators
SQLPP_COMPARE(val.is_null(), "1 IS NULL");
SQLPP_COMPARE(val.is_not_null(), "1 IS NOT NULL");
SQLPP_COMPARE(expr.is_null(), "(17 + 4) IS NULL");
SQLPP_COMPARE(expr.is_not_null(), "(17 + 4) IS NOT NULL");
return 0;
} }
template <typename Value>
void test_comparison_expression(Value v)
{
auto v_not_null = sqlpp::value(v);
auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v));
#warning : Should also implement between as member functions?
// Compare non-nullable with non-nullable.
static_assert(is_bool<decltype(v_not_null < v_not_null)>::value, "");
static_assert(is_bool<decltype(v_not_null <= v_not_null)>::value, "");
static_assert(is_bool<decltype(v_not_null == v_not_null)>::value, "");
static_assert(is_bool<decltype(v_not_null != v_not_null)>::value, "");
static_assert(is_bool<decltype(v_not_null == v_not_null)>::value, "");
static_assert(is_bool<decltype(v_not_null >= v_not_null)>::value, "");
static_assert(is_bool<decltype(v_not_null > v_not_null)>::value, "");
static_assert(is_bool<decltype(is_distinct_from(v_not_null, v_not_null))>::value, "");
static_assert(is_bool<decltype(is_not_distinct_from(v_not_null, v_not_null))>::value, "");
// Compare non-nullable with nullable.
static_assert(is_maybe_bool<decltype(v_not_null < v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_not_null <= v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_not_null == v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_not_null != v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_not_null == v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_not_null >= v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_not_null > v_maybe_null)>::value, "");
static_assert(is_bool<decltype(is_distinct_from(v_not_null, v_maybe_null))>::value, "");
static_assert(is_bool<decltype(is_not_distinct_from(v_not_null, v_maybe_null))>::value, "");
// Compare nullable with non-nullable.
static_assert(is_maybe_bool<decltype(v_maybe_null < v_not_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null <= v_not_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null == v_not_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null != v_not_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null == v_not_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null >= v_not_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null > v_not_null)>::value, "");
static_assert(is_bool<decltype(is_distinct_from(v_maybe_null, v_not_null))>::value, "");
static_assert(is_bool<decltype(is_not_distinct_from(v_maybe_null, v_not_null))>::value, "");
// Compare nullable with nullable.
static_assert(is_maybe_bool<decltype(v_maybe_null < v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null <= v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null == v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null != v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null == v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null >= v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null > v_maybe_null)>::value, "");
static_assert(is_bool<decltype(is_distinct_from(v_maybe_null, v_maybe_null))>::value, "");
static_assert(is_bool<decltype(is_not_distinct_from(v_maybe_null, v_maybe_null))>::value, "");
// Compare with null.
static_assert(is_bool<decltype(is_null(v_not_null))>::value, "");
static_assert(is_bool<decltype(is_null(v_maybe_null))>::value, "");
static_assert(is_bool<decltype(is_not_null(v_maybe_null))>::value, "");
static_assert(is_bool<decltype(is_not_null(v_not_null))>::value, "");
// Comparison expressions have the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(v_not_null == v_maybe_null)>::value, "");
static_assert(sqlpp::has_enabled_as<decltype(is_null(v_not_null))>::value, "");
// Comparison expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(v_not_null == v_maybe_null)>::value, "");
// Comparison expressions have their arguments as nodes.
using L = typename std::decay<decltype(v_not_null)>::type;
using R = typename std::decay<decltype(v_maybe_null)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(v_not_null == v_maybe_null)>, sqlpp::detail::type_vector<L, R>>::value, "");
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(is_null(v_not_null))>, sqlpp::detail::type_vector<L, ::sqlpp::nullopt_t>>::value, "");
}
template<typename Value>
void test_like(Value v)
{
auto v_not_null= sqlpp::value(v);
auto v_maybe_null= sqlpp::value(::sqlpp::make_optional(v));
// Compare non-nullable with non-nullable.
static_assert(is_bool<decltype(like(v_not_null, v_not_null))>::value, "");
// Compare non-nullable with nullable.
static_assert(is_maybe_bool<decltype(like(v_not_null, v_maybe_null))>::value, "");
// Compare nullable with non-nullable.
static_assert(is_maybe_bool<decltype(like(v_maybe_null, v_not_null))>::value, "");
// Compare nullable with nullable.
static_assert(is_maybe_bool<decltype(like(v_maybe_null, v_maybe_null))>::value, "");
}
int main()
{
// boolean
test_comparison_expression(bool{true});
// integral
test_comparison_expression(int8_t{7});
test_comparison_expression(int16_t{7});
test_comparison_expression(int32_t{7});
test_comparison_expression(int64_t{7});
// unsigned integral
test_comparison_expression(uint8_t{7});
test_comparison_expression(uint16_t{7});
test_comparison_expression(uint32_t{7});
test_comparison_expression(uint64_t{7});
// floating point
test_comparison_expression(float{7.7});
test_comparison_expression(double{7.7});
// text
test_comparison_expression('7');
test_comparison_expression("seven");
test_comparison_expression(std::string("seven"));
test_comparison_expression(::sqlpp::string_view("seven"));
// blob
test_comparison_expression(std::vector<uint8_t>{});
// date
test_comparison_expression(::sqlpp::chrono::day_point{});
// timestamp
test_comparison_expression(::sqlpp::chrono::microsecond_point{});
using minute_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
test_comparison_expression(minute_point{});
// time_of_day
test_comparison_expression(std::chrono::microseconds{});
// text
test_like('7');
test_like("seven");
test_like(std::string("seven"));
test_like(::sqlpp::string_view("seven"));
}

View File

@ -23,75 +23,16 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "../compare.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#warning: implement serialize instead of type tests here! SQLPP_ALIAS_PROVIDER(v);
SQLPP_ALIAS_PROVIDER(r_not_null);
SQLPP_ALIAS_PROVIDER(r_maybe_null);
template <typename Value> int main(int, char* [])
void test_exists(Value v)
{ {
// Selectable values. const auto val = sqlpp::value(17);
const auto v_not_null = sqlpp::value(v).as(r_not_null);
const auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v)).as(r_maybe_null);
// EXISTS expression can be used in basic comparison expressions, which use remove_exists_t to look inside. SQLPP_COMPARE(exists(select(val.as(v))), "EXISTS (SELECT 17 AS v)");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(exists(select(v_not_null)))>, sqlpp::boolean>::value, "");
static_assert(std::is_same<sqlpp::value_type_of_t<decltype(exists(select(v_maybe_null)))>, sqlpp::boolean>::value, "");
// EXISTS expressions enable `as` member function. return 0;
static_assert(sqlpp::has_enabled_as<decltype(exists(select(v_not_null)))>::value, "");
// EXISTS expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(exists(select(v_not_null)))>::value, "");
// EXISTS expressions have the SELECT as node.
using S = decltype(select(v_not_null));
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(exists(select(v_not_null)))>, sqlpp::detail::type_vector<S>>::value, "");
#warning: Note that a sub select may require tables from the enclosing select. This is currently not correctly implemented. We need to test that.
} }
int main()
{
// boolean
test_exists(bool{true});
// integral
test_exists(int8_t{7});
test_exists(int16_t{7});
test_exists(int32_t{7});
test_exists(int64_t{7});
// unsigned integral
test_exists(uint8_t{7});
test_exists(uint16_t{7});
test_exists(uint32_t{7});
test_exists(uint64_t{7});
// floating point
test_exists(float{7.7});
test_exists(double{7.7});
// text
test_exists('7');
test_exists("seven");
test_exists(std::string("seven"));
test_exists(::sqlpp::string_view("seven"));
// blob
test_exists(std::vector<uint8_t>{});
// date
test_exists(::sqlpp::chrono::day_point{});
// timestamp
test_exists(::sqlpp::chrono::microsecond_point{});
using minute_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
test_exists(minute_point{});
// time_of_day
test_exists(std::chrono::microseconds{});
}

View File

@ -23,101 +23,38 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "../compare.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#warning: implement serialize instead of type tests here! SQLPP_ALIAS_PROVIDER(v);
namespace
int main(int, char* [])
{ {
template <typename T> const auto val = sqlpp::value(17);
using is_bool = std::is_same<sqlpp::value_type_of_t<T>, sqlpp::boolean>; const auto expr = sqlpp::value(17) + 4;
using expr_t = typename std::decay<decltype(expr)>::type;
template <typename T> // IN expression with single select or other singe expression: No extra parentheses.
using is_maybe_bool = std::is_same<sqlpp::value_type_of_t<T>, ::sqlpp::optional<sqlpp::boolean>>; SQLPP_COMPARE(val.in(val), "17 IN (17)");
SQLPP_COMPARE(val.in(expr), "17 IN (17 + 4)");
SQLPP_COMPARE(val.in(select(val.as(v))), "17 IN (SELECT 17 AS v)");
SQLPP_COMPARE(val.not_in(val), "17 NOT IN (17)");
SQLPP_COMPARE(val.not_in(expr), "17 NOT IN (17 + 4)");
SQLPP_COMPARE(val.not_in(select(val.as(v))), "17 NOT IN (SELECT 17 AS v)");
// IN expressions with multiple arguments require inner parentheses.
SQLPP_COMPARE(val.in(1, select(val.as(v))), "17 IN (1, (SELECT 17 AS v))");
SQLPP_COMPARE(val.in(std::vector<int>{17, 18, 19}), "17 IN (17, 18, 19)");
SQLPP_COMPARE(val.in(std::vector<expr_t>{expr, expr, expr}), "17 IN ((17 + 4), (17 + 4), (17 + 4))");
SQLPP_COMPARE(val.not_in(1, select(val.as(v))), "17 NOT IN (1, (SELECT 17 AS v))");
SQLPP_COMPARE(val.not_in(std::vector<int>{17, 18, 19}), "17 NOT IN (17, 18, 19)");
SQLPP_COMPARE(val.not_in(std::vector<expr_t>{expr, expr, expr}), "17 NOT IN ((17 + 4), (17 + 4), (17 + 4))");
// IN expressions with no arguments would be an error in SQL, but the library interprets the intent gracefully.
SQLPP_COMPARE(val.in(std::vector<expr_t>{}), "0");
SQLPP_COMPARE(val.not_in(std::vector<expr_t>{}), "1");
return 0;
} }
template <typename Value>
void test_in_expression(Value v)
{
using OptValue = ::sqlpp::optional<Value>;
auto v_not_null = sqlpp::value(v);
auto v_maybe_null = sqlpp::value(::sqlpp::make_optional(v));
// Compare non-nullable with non-nullable.
static_assert(is_bool<decltype(in(v_not_null, std::make_tuple(v_not_null, v_not_null)))>::value, "");
static_assert(is_bool<decltype(in(v_not_null, std::vector<Value>{}))>::value, "");
static_assert(is_bool<decltype(in(v_not_null, select(v_not_null.as(sqlpp::alias::a))))>::value, "");
// Compare non-nullable with nullable.
static_assert(is_maybe_bool<decltype(in(v_not_null, std::make_tuple(v_not_null, v_maybe_null)))>::value, "");
static_assert(is_maybe_bool<decltype(in(v_not_null, std::vector<OptValue>{}))>::value, "");
static_assert(is_maybe_bool<decltype(in(v_not_null, select(v_maybe_null.as(sqlpp::alias::a))))>::value, "");
// Compare nullable with non-nullable.
static_assert(is_maybe_bool<decltype(in(v_maybe_null, std::make_tuple(v_not_null, v_not_null)))>::value, "");
static_assert(is_maybe_bool<decltype(in(v_maybe_null, std::vector<Value>{}))>::value, "");
static_assert(is_maybe_bool<decltype(in(v_maybe_null, select(v_not_null.as(sqlpp::alias::a))))>::value, "");
// Compare nullable with nullable.
static_assert(is_maybe_bool<decltype(in(v_maybe_null, std::make_tuple(v_not_null, v_maybe_null)))>::value, "");
static_assert(is_maybe_bool<decltype(in(v_maybe_null, std::vector<OptValue>{}))>::value, "");
static_assert(is_maybe_bool<decltype(in(v_maybe_null, select(v_maybe_null.as(sqlpp::alias::a))))>::value, "");
// IN expressions have the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(in(v_maybe_null, std::vector<OptValue>{}))>::value, "");
// IN expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(in(v_maybe_null, std::vector<OptValue>{}))>::value, "");
// IN expressions have their arguments as nodes.
using L = typename std::decay<decltype(v_maybe_null)>::type;
using R1= Value;
using R2= OptValue;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(in(v_maybe_null, std::vector<Value>{}))>, sqlpp::detail::type_vector<L, R1>>::value, "");
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(in(v_maybe_null, v, ::sqlpp::make_optional(v)))>, sqlpp::detail::type_vector<L, R1, R2>>::value, "");
}
int main()
{
// boolean
test_in_expression(bool{true});
#warning reactivate
#if 0
// integral
test_in_expression(int8_t{7});
test_in_expression(int16_t{7});
test_in_expression(int32_t{7});
test_in_expression(int64_t{7});
// unsigned integral
test_in_expression(uint8_t{7});
test_in_expression(uint16_t{7});
test_in_expression(uint32_t{7});
test_in_expression(uint64_t{7});
// floating point
test_in_expression(float{7.7});
test_in_expression(double{7.7});
// text
test_in_expression('7');
test_in_expression("seven");
test_in_expression(std::string("seven"));
test_in_expression(::sqlpp::string_view("seven"));
// blob
test_in_expression(std::vector<uint8_t>{});
// date
test_in_expression(::sqlpp::chrono::day_point{});
// timestamp
test_in_expression(::sqlpp::chrono::microsecond_point{});
using minute_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
test_in_expression(minute_point{});
// time_of_day
test_in_expression(std::chrono::microseconds{});
#endif
}

View File

@ -23,74 +23,66 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "../compare.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#warning: implement serialize instead of type tests here! int main(int, char* [])
namespace
{ {
template <typename T> const auto val = sqlpp::value(true);
using is_bool = std::is_same<sqlpp::value_type_of_t<T>, sqlpp::boolean>; const auto expr = sqlpp::value(17) > 15;
template <typename T> // Operands are enclosed in parenheses where required
using is_maybe_bool = std::is_same<sqlpp::value_type_of_t<T>, ::sqlpp::optional<sqlpp::boolean>>; SQLPP_COMPARE(val and val, "1 AND 1");
SQLPP_COMPARE(val and expr, "1 AND (17 > 15)");
SQLPP_COMPARE(expr and val, "(17 > 15) AND 1");
SQLPP_COMPARE(expr and expr, "(17 > 15) AND (17 > 15)");
SQLPP_COMPARE(val or val, "1 OR 1");
SQLPP_COMPARE(val or expr, "1 OR (17 > 15)");
SQLPP_COMPARE(expr or val, "(17 > 15) OR 1");
SQLPP_COMPARE(expr or expr, "(17 > 15) OR (17 > 15)");
SQLPP_COMPARE(not val, "NOT 1");
SQLPP_COMPARE(not expr, "NOT (17 > 15)");
// Chains are not nested in parentheses.
SQLPP_COMPARE(val and val and val and val and val, "1 AND 1 AND 1 AND 1 AND 1");
SQLPP_COMPARE(val or val or val or val or val, "1 OR 1 OR 1 OR 1 OR 1");
// Broken chains use parentheses for the respective blocks.
SQLPP_COMPARE((val and val and val) or (val and val), "(1 AND 1 AND 1) OR (1 AND 1)");
SQLPP_COMPARE((val or val or val) and (val or val), "(1 OR 1 OR 1) AND (1 OR 1)");
// NOT is not chained gracefully, but hey, don't do that anyways.
SQLPP_COMPARE(not not not val, "NOT (NOT (NOT 1))");
// Operands are enclosed in parenheses where required or completely dropped if inactive
SQLPP_COMPARE(val and dynamic(true, val), "1 AND 1");
SQLPP_COMPARE(val and dynamic(true, expr), "1 AND (17 > 15)");
SQLPP_COMPARE(expr and dynamic(true, val), "(17 > 15) AND 1");
SQLPP_COMPARE(expr and dynamic(true, expr), "(17 > 15) AND (17 > 15)");
SQLPP_COMPARE(val or dynamic(true, val), "1 OR 1");
SQLPP_COMPARE(val or dynamic(true, expr), "1 OR (17 > 15)");
SQLPP_COMPARE(expr or dynamic(true, val), "(17 > 15) OR 1");
SQLPP_COMPARE(expr or dynamic(true, expr), "(17 > 15) OR (17 > 15)");
SQLPP_COMPARE(val and dynamic(false, val), "1");
SQLPP_COMPARE(val and dynamic(false, expr), "1");
SQLPP_COMPARE(expr and dynamic(false, val), "17 > 15");
SQLPP_COMPARE(expr and dynamic(false, expr), "17 > 15");
SQLPP_COMPARE(val or dynamic(false, val), "1");
SQLPP_COMPARE(val or dynamic(false, expr), "1");
SQLPP_COMPARE(expr or dynamic(false, val), "17 > 15");
SQLPP_COMPARE(expr or dynamic(false, expr), "17 > 15");
// Chained partially dynamic expressions
SQLPP_COMPARE(val and dynamic(true, val) and expr, "1 AND 1 AND (17 > 15)");
SQLPP_COMPARE(val and dynamic(false, val) and expr, "1 AND (17 > 15)");
SQLPP_COMPARE(val or dynamic(true, val) or expr, "1 OR 1 OR (17 > 15)");
SQLPP_COMPARE(val or dynamic(false, val) or expr, "1 OR (17 > 15)");
return 0;
} }
template<typename Value>
void test_logical_expression(Value v)
{
auto v_not_null= sqlpp::value(v);
auto v_maybe_null= sqlpp::value(::sqlpp::make_optional(v));
// Combine non-nullable with non-nullable.
static_assert(is_bool<decltype(v_not_null and v_not_null)>::value, "");
static_assert(is_bool<decltype(v_not_null or v_not_null)>::value, "");
static_assert(is_bool<decltype(v_not_null and dynamic(true, v_not_null))>::value, "");
static_assert(is_bool<decltype(v_not_null or dynamic(true, v_not_null))>::value, "");
// Combine nullable with non-nullable.
static_assert(is_maybe_bool<decltype(v_maybe_null and v_not_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null or v_not_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null and dynamic(true, v_not_null))>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null or dynamic(true, v_not_null))>::value, "");
// Combine non-nullable with nullable.
static_assert(is_maybe_bool<decltype(v_not_null and v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_not_null or v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_not_null and dynamic(true, v_maybe_null))>::value, "");
static_assert(is_maybe_bool<decltype(v_not_null or dynamic(true, v_maybe_null))>::value, "");
// Combine nullable with nullable.
static_assert(is_maybe_bool<decltype(v_maybe_null and v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null or v_maybe_null)>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null and dynamic(true, v_maybe_null))>::value, "");
static_assert(is_maybe_bool<decltype(v_maybe_null or dynamic(true, v_maybe_null))>::value, "");
// not.
static_assert(is_bool<decltype(not(v_not_null))>::value, "");
static_assert(is_maybe_bool<decltype(not(v_maybe_null))>::value, "");
// Logical expressions have the `as` member function.
static_assert(sqlpp::has_enabled_as<decltype(v_not_null and v_maybe_null)>::value, "");
static_assert(sqlpp::has_enabled_as<decltype(v_maybe_null or dynamic(true, v_maybe_null))>::value, "");
// Logical expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(v_not_null == v_maybe_null)>::value, "");
static_assert(not sqlpp::has_enabled_comparison<decltype(v_maybe_null or dynamic(true, v_maybe_null))>::value, "");
// Logical expressions have their arguments as nodes.
using L = typename std::decay<decltype(v_not_null)>::type;
using R = typename std::decay<decltype(v_maybe_null)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(v_not_null and v_maybe_null)>, sqlpp::detail::type_vector<L, R>>::value, "");
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(v_not_null and dynamic(true, v_maybe_null))>, sqlpp::detail::type_vector<L, sqlpp::dynamic_t<R>>>::value, "");
}
int main()
{
// boolean
test_logical_expression(bool{true});
}

View File

@ -23,91 +23,24 @@
* OF THE POSSIBILITY OF SUCH DAMAGE. * OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "../compare.h"
#include <sqlpp11/sqlpp11.h> #include <sqlpp11/sqlpp11.h>
#warning: implement serialize instead of type tests here! int main(int, char* [])
template<typename Value>
void test_as_expression(Value v)
{ {
using ValueType = sqlpp::value_type_of_t<Value>; const auto val = sqlpp::value(1);
using OptValueType = ::sqlpp::optional<ValueType>; const auto expr = sqlpp::value(17) + 4;
auto v_not_null= sqlpp::value(v); // Operands are enclosed in parentheses where required.
auto v_maybe_null= sqlpp::value(::sqlpp::make_optional(v)); SQLPP_COMPARE(val.asc(), "1 ASC");
SQLPP_COMPARE(val.desc(), "1 DESC");
SQLPP_COMPARE(val.order(sqlpp::sort_type::asc), "1 ASC");
SQLPP_COMPARE(val.order(sqlpp::sort_type::desc), "1 DESC");
// Sort order expressions have no value. SQLPP_COMPARE(expr.asc(), "(17 + 4) ASC");
static_assert(not sqlpp::has_value_type<decltype(v_not_null.asc())>::value, ""); SQLPP_COMPARE(expr.desc(), "(17 + 4) DESC");
static_assert(not sqlpp::has_value_type<decltype(v_not_null.desc())>::value, ""); SQLPP_COMPARE(expr.order(sqlpp::sort_type::asc), "(17 + 4) ASC");
static_assert(not sqlpp::has_value_type<decltype(v_not_null.order(sqlpp::sort_type::asc))>::value, ""); SQLPP_COMPARE(expr.order(sqlpp::sort_type::desc), "(17 + 4) DESC");
static_assert(not sqlpp::has_value_type<decltype(v_maybe_null.asc())>::value, ""); return 0;
static_assert(not sqlpp::has_value_type<decltype(v_maybe_null.desc())>::value, "");
static_assert(not sqlpp::has_value_type<decltype(v_maybe_null.order(sqlpp::sort_type::asc))>::value, "");
static_assert(not sqlpp::has_value_type<decltype(dynamic(true, v_not_null.asc()))>::value, "");
static_assert(not sqlpp::has_value_type<decltype(dynamic(true, v_not_null.desc()))>::value, "");
static_assert(not sqlpp::has_value_type<decltype(dynamic(true, v_not_null.order(sqlpp::sort_type::asc)))>::value, "");
static_assert(not sqlpp::has_value_type<decltype(dynamic(true, v_maybe_null.asc()))>::value, "");
static_assert(not sqlpp::has_value_type<decltype(dynamic(true, v_maybe_null.desc()))>::value, "");
static_assert(not sqlpp::has_value_type<decltype(dynamic(true, v_maybe_null.order(sqlpp::sort_type::asc)))>::value, "");
// Sort order expressions have no name.
static_assert(not sqlpp::has_name<decltype(v_not_null.asc())>::value, "");
static_assert(not sqlpp::has_name<decltype(v_maybe_null.asc())>::value, "");
static_assert(not sqlpp::has_name<decltype(dynamic(true, v_not_null.asc()))>::value, "");
static_assert(not sqlpp::has_name<decltype(dynamic(true, v_maybe_null.asc()))>::value, "");
// Sort order expression do not enable the `as` member function.
static_assert(not sqlpp::has_enabled_as<decltype(v_not_null.asc())>::value, "");
// Sort order expressions do not enable comparison member functions.
static_assert(not sqlpp::has_enabled_comparison<decltype(v_not_null.asc())>::value, "");
// Sort order expressions have their arguments as nodes.
using L = typename std::decay<decltype(v_not_null)>::type;
static_assert(std::is_same<sqlpp::nodes_of_t<decltype(v_not_null.asc())>, sqlpp::detail::type_vector<L>>::value, "");
} }
int main()
{
// boolean
test_as_expression(bool{true});
// integral
test_as_expression(int8_t{7});
test_as_expression(int16_t{7});
test_as_expression(int32_t{7});
test_as_expression(int64_t{7});
// unsigned integral
test_as_expression(uint8_t{7});
test_as_expression(uint16_t{7});
test_as_expression(uint32_t{7});
test_as_expression(uint64_t{7});
// floating point
test_as_expression(float{7.7});
test_as_expression(double{7.7});
// text
test_as_expression('7');
test_as_expression("seven");
test_as_expression(std::string("seven"));
test_as_expression(::sqlpp::string_view("seven"));
// blob
test_as_expression(std::vector<uint8_t>{});
// date
test_as_expression(::sqlpp::chrono::day_point{});
// timestamp
test_as_expression(::sqlpp::chrono::microsecond_point{});
using minute_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
test_as_expression(minute_point{});
// time_of_day
test_as_expression(std::chrono::microseconds{});
}