diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 653b0d01..2c65f798 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -39,7 +39,7 @@ namespace sqlpp // boolean value type struct boolean { - using _traits = make_traits; + using _traits = make_traits; using _tag = ::sqlpp::tag::is_boolean; using _cpp_value_type = bool; diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 12bb9979..424ac555 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -38,7 +38,7 @@ namespace sqlpp // floating_point value type struct floating_point { - using _traits = make_traits; + using _traits = make_traits; using _tag = ::sqlpp::tag::is_floating_point; using _cpp_value_type = double; diff --git a/include/sqlpp11/functions.h b/include/sqlpp11/functions.h index ff561e2a..34c79994 100644 --- a/include/sqlpp11/functions.h +++ b/include/sqlpp11/functions.h @@ -42,10 +42,10 @@ #include #include #include // Csaba Csoma suggests: unsafe_sql instead of verbatim +#include namespace sqlpp { -#warning add a value_or_null method that yields a type that can be NULL or have a value (very similar to an optional) #warning add a template bool_expression which takes any bool expression as constructor argument template auto value(T t) -> wrap_operand_t @@ -101,6 +101,18 @@ namespace sqlpp return { context.str() }; } + template + auto is_null(Expression e) -> decltype(e.is_null()) + { + return e.is_null(); + } + + template + auto is_not_null(Expression e) -> decltype(e.is_not_null()) + { + return e.is_not_null(); + } + template struct value_list_t // to be used in .in() method { diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index 8c6ae5ec..003690ce 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -40,7 +40,7 @@ namespace sqlpp // integral value type struct integral { - using _traits = make_traits; + using _traits = make_traits; using _tag = ::sqlpp::tag::is_integral; using _cpp_value_type = int64_t; diff --git a/include/sqlpp11/null.h b/include/sqlpp11/null.h index 63586c7f..93e0706b 100644 --- a/include/sqlpp11/null.h +++ b/include/sqlpp11/null.h @@ -33,7 +33,7 @@ namespace sqlpp { struct null_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits<>; }; diff --git a/include/sqlpp11/parameter.h b/include/sqlpp11/parameter.h index 025ed94e..665523f9 100644 --- a/include/sqlpp11/parameter.h +++ b/include/sqlpp11/parameter.h @@ -83,7 +83,7 @@ namespace sqlpp auto parameter(const ValueType&, const AliasProvider&) -> parameter_t, AliasProvider> { - static_assert(is_expression_t::value, "first argument is not a value type"); + static_assert(is_value_type_t::value, "first argument is not a value type"); static_assert(is_alias_provider_t::value, "second argument is not an alias provider"); return {}; } diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 6c87e845..7e7d9ad7 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -39,7 +39,7 @@ namespace sqlpp // text value type struct text { - using _traits = make_traits; + using _traits = make_traits; using _tag = ::sqlpp::tag::is_text; using _cpp_value_type = std::string; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index f12f1785..9b30d438 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -71,6 +71,8 @@ namespace sqlpp template\ using name##_t = typename detail::name##_impl::type; + SQLPP_VALUE_TRAIT_GENERATOR(is_value_type); + SQLPP_VALUE_TRAIT_GENERATOR(is_sql_null); SQLPP_VALUE_TRAIT_GENERATOR(is_boolean); SQLPP_VALUE_TRAIT_GENERATOR(is_integral); SQLPP_VALUE_TRAIT_GENERATOR(is_floating_point); diff --git a/include/sqlpp11/value_or_null.h b/include/sqlpp11/value_or_null.h new file mode 100644 index 00000000..68ce8c83 --- /dev/null +++ b/include/sqlpp11/value_or_null.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013-2014, 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_VALUE_OR_NULL_H +#define SQLPP_VALUE_OR_NULL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Csaba Csoma suggests: unsafe_sql instead of verbatim +#include + +namespace sqlpp +{ + template + struct value_or_null_t + { + using _cpp_value_type = typename ValueType::_cpp_value_type; + + using _traits = make_traits; + using _recursive_traits = make_recursive_traits<>; + + value_or_null_t(_cpp_value_type value): + _value(value), + _is_null(false) + {} + + value_or_null_t(const null_t&): + _value(), + _is_null(true) + {} + + typename ValueType::_cpp_value_type _value; + bool _is_null; + }; + + template + auto value_or_null(T t) -> value_or_null_t>> + { + static_assert(is_wrapped_value_t>::value, "value_or_null() is to be called with non-sql-type like int, or string or null"); + return { t }; + } + + template + auto value_or_null(null_t t) -> value_or_null_t + { + static_assert(is_value_type_t::value, "value_or_null() is to be called with non-sql-type like int, or string"); + return { t }; + } + +} + +#endif diff --git a/tests/FunctionTest.cpp b/tests/FunctionTest.cpp index 18eddde1..374a7c20 100644 --- a/tests/FunctionTest.cpp +++ b/tests/FunctionTest.cpp @@ -135,6 +135,12 @@ int main() using TI = decltype(t.alpha.is_null()); using TF = decltype(f.omega.is_null()); using TT = decltype(t.beta.is_null()); + using TTI = decltype(is_null(t.alpha)); + using TTF = decltype(is_null(f.omega)); + using TTT = decltype(is_null(t.beta)); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::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"); @@ -154,6 +160,12 @@ int main() using TI = decltype(t.alpha.is_not_null()); using TF = decltype(f.omega.is_not_null()); using TT = decltype(t.beta.is_not_null()); + using TTI = decltype(is_not_null(t.alpha)); + using TTF = decltype(is_not_null(f.omega)); + using TTT = decltype(is_not_null(t.beta)); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::value, "type requirement"); + static_assert(std::is_same::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"); @@ -356,6 +368,30 @@ int main() static_assert(sqlpp::is_text_t::value, "type requirement"); } + // test value_or_null + { + using TB = decltype(sqlpp::value_or_null(true)); + using TI = decltype(sqlpp::value_or_null(7)); + using TF = decltype(sqlpp::value_or_null(5.6)); + using TT = decltype(sqlpp::value_or_null("hallo")); + using TBN = decltype(sqlpp::value_or_null(sqlpp::null)); + using TIN = decltype(sqlpp::value_or_null(sqlpp::null)); + using TFN = decltype(sqlpp::value_or_null(sqlpp::null)); + using TTN = decltype(sqlpp::value_or_null(sqlpp::null)); + static_assert(std::is_same::value, "type_requirement"); + static_assert(std::is_same::value, "type_requirement"); + static_assert(std::is_same::value, "type_requirement"); + static_assert(std::is_same::value, "type_requirement"); + 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"));