From 813549690e15065fcced8202014b3dfc9e0e526f Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Thu, 7 Nov 2013 15:06:13 +0100 Subject: [PATCH] More function tests and a few corrections for names and return types --- database_api/api.h | 2 + include/sqlpp11/any.h | 2 +- include/sqlpp11/detail/basic_operators.h | 12 +- include/sqlpp11/expression.h | 33 ------ include/sqlpp11/in.h | 2 +- include/sqlpp11/is_null.h | 88 +++++++++++++++ include/sqlpp11/some.h | 2 +- include/sqlpp11/type_traits.h | 1 + tests/FunctionTest.cpp | 137 ++++++++++++++++++++++- 9 files changed, 231 insertions(+), 48 deletions(-) create mode 100644 include/sqlpp11/is_null.h diff --git a/database_api/api.h b/database_api/api.h index 0e8901d9..e3519075 100644 --- a/database_api/api.h +++ b/database_api/api.h @@ -69,6 +69,8 @@ namespace sqlpp static constexpr bool _supports_exists = true; static constexpr bool _supports_like = true; static constexpr bool _supports_in = true; + static constexpr bool _supports_is_null = true; + static constexpr bool _supports_is_not_null = true; static constexpr bool _supports_max = true; static constexpr bool _supports_min = true; static constexpr bool _supports_not_in = true; diff --git a/include/sqlpp11/any.h b/include/sqlpp11/any.h index 8b042297..ec01a4e0 100644 --- a/include/sqlpp11/any.h +++ b/include/sqlpp11/any.h @@ -42,7 +42,7 @@ namespace sqlpp struct _value_type: public Select::_value_type::_base_value_type { - using _is_named_expression = std::true_type; + using _is_nameless_expression = std::true_type; // must not be named }; struct _name_t diff --git a/include/sqlpp11/detail/basic_operators.h b/include/sqlpp11/detail/basic_operators.h index 41425f96..d0a5a5b1 100644 --- a/include/sqlpp11/detail/basic_operators.h +++ b/include/sqlpp11/detail/basic_operators.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace sqlpp { @@ -64,12 +65,6 @@ namespace sqlpp static constexpr const char* _name = ">"; }; - struct is_null_ - { - using _value_type = boolean; - static constexpr const char* _name = "IS NULL"; - }; - struct is_not_null_ { using _value_type = boolean; @@ -116,12 +111,12 @@ namespace sqlpp return { *static_cast(this), std::forward(t) }; } - null_expression_t is_null() const + is_null_t is_null() const { return { *static_cast(this) }; } - null_expression_t is_not_null() const + is_null_t is_not_null() const { return { *static_cast(this) }; } @@ -152,6 +147,7 @@ namespace sqlpp template expression_alias_t::type> as(alias_provider&&) { + static_assert(not is_nameless_expression_t::value, "expression cannot have a name, e.g. like any()"); return { *static_cast(this) }; } diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index b5a27f4b..9a5b2288 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -175,39 +175,6 @@ namespace sqlpp Lhs _lhs; }; - template - struct null_expression_t: public O::_value_type::template operators> - { - using _value_type = typename O::_value_type; - - null_expression_t(Lhs&& l): - _lhs(std::move(l)) - {} - - null_expression_t(const Lhs& l): - _lhs(l) - {} - - null_expression_t(const null_expression_t&) = default; - null_expression_t(null_expression_t&&) = default; - null_expression_t& operator=(const null_expression_t&) = default; - null_expression_t& operator=(null_expression_t&&) = default; - ~null_expression_t() = default; - - template - void serialize(std::ostream& os, Db& db) const - { - os << "("; - _lhs.serialize(os, db); - os << " "; - os << O::_name; - os << ")"; - } - - private: - Lhs _lhs; - }; - template struct binary_expression_t: public O::_value_type::template operators> { diff --git a/include/sqlpp11/in.h b/include/sqlpp11/in.h index 660787df..5653a3dc 100644 --- a/include/sqlpp11/in.h +++ b/include/sqlpp11/in.h @@ -77,7 +77,7 @@ namespace sqlpp void serialize(std::ostream& os, Db& db) const { static_assert(NotInverted and Db::_supports_in - or _inverted and Db::_supports_not_in, "in() not supported by current database"); + or _inverted and Db::_supports_not_in, "in() and/or not_in() not supported by current database"); _operand.serialize(os, db); os << (_inverted ? " NOT IN(" : " IN("); detail::serialize_tuple(os, db, _args, ','); diff --git a/include/sqlpp11/is_null.h b/include/sqlpp11/is_null.h new file mode 100644 index 00000000..a9dc2d93 --- /dev/null +++ b/include/sqlpp11/is_null.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_IS_NULL_H +#define SQLPP_IS_NULL_H + +#include +#include +#include + +namespace sqlpp +{ + namespace detail + { + // The ValueType should be boolean, this is a hack because boolean is not fully defined when the compiler first gets here... + template + struct is_null_t: public ValueType::_base_value_type::template operators> + { + static constexpr bool _inverted = not NotInverted; + + struct _value_type: public ValueType::_base_value_type // we requite fully defined boolean here + { + using _is_named_expression = std::true_type; + }; + + struct _name_t + { + static constexpr const char* _get_name() { return _inverted ? "IS NOT NULL" : "IS NULL"; } + template + struct _member_t + { + T in; + }; + }; + + is_null_t(const Operand& operand): + _operand(operand) + {} + + is_null_t(Operand&& operand): + _operand(std::move(operand)) + {} + + is_null_t(const is_null_t&) = default; + is_null_t(is_null_t&&) = default; + is_null_t& operator=(const is_null_t&) = default; + is_null_t& operator=(is_null_t&&) = default; + ~is_null_t() = default; + + template + void serialize(std::ostream& os, Db& db) const + { + static_assert(NotInverted and Db::_supports_is_null + or _inverted and Db::_supports_is_not_null, "is_null() and/or is_not_null() not supported by current database"); + _operand.serialize(os, db); + os << (_inverted ? " IS NOT NULL" : " IS NULL"); + } + + private: + Operand _operand; + }; + } +} + +#endif diff --git a/include/sqlpp11/some.h b/include/sqlpp11/some.h index 54a1f910..976a8285 100644 --- a/include/sqlpp11/some.h +++ b/include/sqlpp11/some.h @@ -42,7 +42,7 @@ namespace sqlpp struct _value_type: public Select::_value_type::_base_value_type { - using _is_named_expression = std::true_type; + using _is_nameless_expression = std::true_type; // must not be named }; struct _name_t diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index cb61a3e2..c4917c58 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -84,6 +84,7 @@ namespace sqlpp SQLPP_IS_VALUE_TRAIT_GENERATOR(value); SQLPP_IS_VALUE_TRAIT_GENERATOR(expression); SQLPP_IS_VALUE_TRAIT_GENERATOR(named_expression); + SQLPP_IS_VALUE_TRAIT_GENERATOR(nameless_expression); SQLPP_IS_VALUE_TRAIT_GENERATOR(alias); // FIXME: Is this really part of the value? SQLPP_IS_VALUE_TRAIT_GENERATOR(select_flag); diff --git a/tests/FunctionTest.cpp b/tests/FunctionTest.cpp index 7d94f21b..bb58d246 100644 --- a/tests/FunctionTest.cpp +++ b/tests/FunctionTest.cpp @@ -46,12 +46,15 @@ int main() using TI = decltype(t.alpha.in(1, 2, 3)); using TF = decltype(f.omega.in(1.0, 2.0, 3.0)); using TT = decltype(t.beta.in("a", "b", "c")); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); @@ -62,12 +65,15 @@ int main() using TI = decltype(t.alpha.not_in(1, 2, 3)); using TF = decltype(f.omega.not_in(1.0, 2.0, 3.0)); using TT = decltype(t.beta.not_in("a", "b", "c")); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); @@ -76,6 +82,45 @@ int main() // Test like { using TT = decltype(t.beta.like("%c%")); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + } + + // Test is_null + { + using TI = decltype(t.alpha.is_null()); + using TF = decltype(f.omega.is_null()); + using TT = decltype(t.beta.is_null()); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + } + + // Test is_not_null + { + using TI = decltype(t.alpha.is_not_null()); + using TF = decltype(f.omega.is_not_null()); + using TT = decltype(t.beta.is_not_null()); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); @@ -88,9 +133,11 @@ int main() { using TI = decltype(exists(select(t.alpha).from(t))); using TT = decltype(exists(select(t.beta).from(t))); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_boolean_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); @@ -101,12 +148,18 @@ int main() using TI = decltype(any(select(t.alpha).from(t))); using TT = decltype(any(select(t.beta).from(t))); using TF = decltype(any(select(f.omega).from(t))); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_nameless_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_nameless_expression_t::value, "type requirement"); + static_assert(sqlpp::is_numeric_t::value, "tFpe requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_nameless_expression_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); @@ -118,13 +171,19 @@ int main() using TI = decltype(some(select(t.alpha).from(t))); using TT = decltype(some(select(t.beta).from(t))); using TF = decltype(some(select(f.omega).from(t))); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_nameless_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_nameless_expression_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); static_assert(not sqlpp::is_text_t::value, "type requirement"); static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_nameless_expression_t::value, "type requirement"); static_assert(not sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); static_assert(sqlpp::is_text_t::value, "type requirement"); @@ -137,9 +196,11 @@ int main() { using TI = decltype(avg(t.alpha)); using TF = decltype(avg(f.omega)); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_integral_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_integral_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); @@ -150,52 +211,120 @@ int main() using TI = decltype(count(t.alpha)); using TT = decltype(count(t.beta)); using TF = decltype(count(f.omega)); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_integral_t::value, "type requirement"); - static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); } // Test max { using TI = decltype(max(t.alpha)); using TF = decltype(max(f.omega)); + using TT = decltype(max(t.beta)); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_integral_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_text_t::value, "type requirement"); } // Test min { using TI = decltype(min(t.alpha)); using TF = decltype(min(f.omega)); + using TT = decltype(min(t.beta)); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_integral_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_text_t::value, "type requirement"); } // Test sum { using TI = decltype(sum(t.alpha)); using TF = decltype(sum(f.omega)); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(sqlpp::is_integral_t::value, "type requirement"); static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); static_assert(not sqlpp::is_integral_t::value, "type requirement"); static_assert(sqlpp::is_floating_point_t::value, "type requirement"); } + // MISC FUNCTIONS + // -------------- + + // test value + { + using TB = decltype(sqlpp::value(true)); + using TI = decltype(sqlpp::value(7)); + using TF = decltype(sqlpp::value(1.5)); + using TT = decltype(sqlpp::value("cheesecake")); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_text_t::value, "type requirement"); + } + + // test flatten + { + using TB = decltype(flatten(t.gamma, db)); + using TI = decltype(flatten(t.alpha, db)); + using TF = decltype(flatten(f.omega, db)); + using TT = decltype(flatten(t.beta, db)); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_text_t::value, "type requirement"); + } + + // test verbatim + { + using TB = decltype(sqlpp::verbatim("1")); + using TI = decltype(sqlpp::verbatim("42")); + using TF = decltype(sqlpp::verbatim("1.5")); + using TT = decltype(sqlpp::verbatim("cheesecake")); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(sqlpp::is_text_t::value, "type requirement"); + } + return 0; }