From 159b4c715205807dcf6f22873c08b0253fe22b50 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 28 Jul 2014 21:14:20 +0200 Subject: [PATCH 01/17] Fixed error in determining can_be_null for joins --- include/sqlpp11/statement.h | 2 +- tests/SelectTest.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/sqlpp11/statement.h b/include/sqlpp11/statement.h index 64d17e82..615a50cb 100644 --- a/include/sqlpp11/statement.h +++ b/include/sqlpp11/statement.h @@ -112,7 +112,7 @@ namespace sqlpp ::sqlpp::detail::make_intersect_set_t< required_tables_of<_result_type_provider>, provided_outer_tables_of - >::size::value>; + >::size::value != 0>; }; }; } diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 7bdf43a5..5ccc94e4 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -64,6 +64,11 @@ int main() std::cout << a << ", " << b << ", " << g << std::endl; } + for (const auto& row : db(select(all_of(t), all_of(f)).from(t.join(f).on(t.alpha > f.omega)).where(true))) + { + std::cout << row.alpha << std::endl; + } + auto stat = sqlpp::select().columns(all_of(t)).flags(sqlpp::all).from(t).extra_tables(f,t).where(t.alpha > 0).group_by(t.alpha).order_by(t.gamma.asc()).having(t.gamma).limit(7).offset(19); auto s = dynamic_select(db).dynamic_columns(all_of(t)).dynamic_flags().dynamic_from(t).extra_tables(f,t).dynamic_where().dynamic_group_by(t.alpha).dynamic_order_by().dynamic_having(t.gamma).dynamic_limit().dynamic_offset(); From 4be53d9933030d79c6a1931be358dd531cca2d9b Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 28 Jul 2014 21:36:53 +0200 Subject: [PATCH 02/17] Fixed a error in type set intersect calculation and in tracking outer tables --- include/sqlpp11/detail/type_set.h | 2 +- include/sqlpp11/join.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/detail/type_set.h b/include/sqlpp11/detail/type_set.h index 1e95cc6a..0f85d875 100644 --- a/include/sqlpp11/detail/type_set.h +++ b/include/sqlpp11/detail/type_set.h @@ -221,7 +221,7 @@ namespace sqlpp struct make_intersect_set, type_set> { template - using is_in_both = is_element_of>; + using is_in_both = all_t>::value, is_element_of>::value>; using type = typename make_type_set_if::type; }; diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index d5ae7b4c..6e90ca37 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -50,14 +50,14 @@ namespace sqlpp struct left_outer_join_t { template - using _provided_outer_tables = detail::make_joined_set_t, provided_tables_of>; + using _provided_outer_tables = detail::make_joined_set_t, provided_outer_tables_of>; static constexpr const char* _name = " LEFT OUTER "; }; struct right_outer_join_t { template - using _provided_outer_tables = detail::make_joined_set_t, provided_outer_tables_of>; + using _provided_outer_tables = detail::make_joined_set_t, provided_tables_of>; static constexpr const char* _name = " RIGHT OUTER "; }; From b1f1de8a08ca81a4cd51fc4204d2302b0d155c7b Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 29 Jul 2014 08:57:55 +0200 Subject: [PATCH 03/17] Allowing result fields to be used as arguments for queries --- include/sqlpp11/assignment.h | 6 +-- include/sqlpp11/boolean.h | 10 +++++ include/sqlpp11/expression.h | 8 +++- include/sqlpp11/floating_point.h | 10 +++++ include/sqlpp11/integral.h | 10 +++++ include/sqlpp11/rhs_is_null.h | 20 +++++---- include/sqlpp11/rhs_is_trivial.h | 77 ++++++++++++++++++++++++++++++++ include/sqlpp11/text.h | 10 +++++ include/sqlpp11/tvin.h | 5 +++ include/sqlpp11/type_traits.h | 1 + tests/ResultTest.cpp | 14 ++++++ tests/SelectTest.cpp | 2 +- 12 files changed, 158 insertions(+), 15 deletions(-) create mode 100644 include/sqlpp11/rhs_is_trivial.h diff --git a/include/sqlpp11/assignment.h b/include/sqlpp11/assignment.h index 36938311..4594f663 100644 --- a/include/sqlpp11/assignment.h +++ b/include/sqlpp11/assignment.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -70,9 +71,8 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - if (((trivial_value_is_null_t::value or is_tvin_t::value) - and is_trivial(t._rhs)) - or (std::is_same::value)) + if ((trivial_value_is_null_t::value and rhs_is_trivial(t)) + or rhs_is_null(t)) { serialize(simple_column(t._lhs), context); context << "=NULL"; diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 0ed43af3..be7b195d 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -123,6 +123,8 @@ namespace sqlpp using _field_methods_t = field_methods_t<_result_field_t>; using _traits = make_traits>; struct _recursive_traits @@ -160,6 +162,14 @@ namespace sqlpp return _is_null; } + bool is_trivial() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + + return value() == false; + } + _cpp_value_type value() const { if (not _is_valid) diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index c856b56f..cb221ccd 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -70,7 +72,8 @@ namespace sqlpp { context << "("; serialize(t._lhs, context); - if (rhs_is_null(t)) + if ((trivial_value_is_null_t::value and rhs_is_trivial(t)) + or rhs_is_null(t)) { context << " IS NULL"; } @@ -117,7 +120,8 @@ namespace sqlpp { context << "("; serialize(t._lhs, context); - if (rhs_is_null(t)) + if ((trivial_value_is_null_t::value and rhs_is_trivial(t)) + or rhs_is_null(t)) { context << " IS NOT NULL"; } diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index da5f3943..37c69207 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -122,6 +122,8 @@ namespace sqlpp using _field_methods_t = field_methods_t<_result_field_t>; using _traits = make_traits>; struct _recursive_traits @@ -159,6 +161,14 @@ namespace sqlpp return _is_null; } + bool is_trivial() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + + return value() == 0; + } + _cpp_value_type value() const { if (not _is_valid) diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index 8dad0912..c1441fd3 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -123,6 +123,8 @@ namespace sqlpp using _field_methods_t = field_methods_t<_result_field_t>; using _traits = make_traits>; struct _recursive_traits @@ -160,6 +162,14 @@ namespace sqlpp return _is_null; } + bool is_trivial() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + + return value() == 0; + } + _cpp_value_type value() const { if (not _is_valid) diff --git a/include/sqlpp11/rhs_is_null.h b/include/sqlpp11/rhs_is_null.h index 1eda20d9..aa6d8ed0 100644 --- a/include/sqlpp11/rhs_is_null.h +++ b/include/sqlpp11/rhs_is_null.h @@ -32,7 +32,7 @@ namespace sqlpp { template - struct is_trivial_t + struct rhs_is_null_t { static constexpr bool _(const T&) { @@ -41,27 +41,29 @@ namespace sqlpp }; template - struct is_trivial_t::value, void>::type> + struct rhs_is_null_t::value, void>::type> { static bool _(const T& t) { - return t._is_trivial(); + return t._is_null(); } }; template - bool is_trivial(const T& t) + struct rhs_is_null_t::value, void>::type> { - return is_trivial_t::_(t); - } + static bool _(const T& t) + { + return t.is_null(); + } + }; template constexpr bool rhs_is_null(const Expression& e) { - return (((trivial_value_is_null_t::value or is_tvin_t::value) - and is_trivial(e._rhs)) - or (std::is_same::value)); + return rhs_is_null_t::type::_rhs_t>::_(e._rhs); } + } #endif diff --git a/include/sqlpp11/rhs_is_trivial.h b/include/sqlpp11/rhs_is_trivial.h new file mode 100644 index 00000000..14de2675 --- /dev/null +++ b/include/sqlpp11/rhs_is_trivial.h @@ -0,0 +1,77 @@ +/* + * 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_RHS_IS_TRIVIAL_H +#define SQLPP_RHS_IS_TRIVIAL_H + +#include + +namespace sqlpp +{ + template + struct rhs_is_trivial_t + { + static constexpr bool _(const T&) + { + return false; + } + }; + + template + struct rhs_is_trivial_t::value, void>::type> + { + static bool _(const T& t) + { + return t._is_trivial(); + } + }; + + template + struct rhs_is_trivial_t::value, void>::type> + { + static bool _(const T& t) + { + return t._is_trivial(); + } + }; + + template + struct rhs_is_trivial_t::value, void>::type> + { + static bool _(const T& t) + { + return t.is_trivial(); + } + }; + + template + constexpr bool rhs_is_trivial(const Expression& e) + { + return rhs_is_trivial_t::type::_rhs_t>::_(e._rhs); + } +} + +#endif diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index e90d5e6c..d45544f3 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -122,6 +122,8 @@ namespace sqlpp using _field_methods_t = field_methods_t<_result_field_t>; using _traits = make_traits>; struct _recursive_traits @@ -162,6 +164,14 @@ namespace sqlpp return _value_ptr == nullptr; } + bool is_trivial() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + + return value() == ""; + } + _cpp_value_type value() const { if (not _is_valid) diff --git a/include/sqlpp11/tvin.h b/include/sqlpp11/tvin.h index 0b80cc44..7f3cce23 100644 --- a/include/sqlpp11/tvin.h +++ b/include/sqlpp11/tvin.h @@ -108,6 +108,11 @@ namespace sqlpp return _value._is_trivial(); } + bool _is_null() const + { + return _value._is_trivial(); + } + _operand_t _value; }; diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 659d7bab..79e3f22a 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -85,6 +85,7 @@ namespace sqlpp SQLPP_VALUE_TRAIT_GENERATOR(is_multi_expression); SQLPP_VALUE_TRAIT_GENERATOR(is_alias); SQLPP_VALUE_TRAIT_GENERATOR(is_select_flag); + SQLPP_VALUE_TRAIT_GENERATOR(is_result_field); SQLPP_VALUE_TRAIT_GENERATOR(must_not_insert); SQLPP_VALUE_TRAIT_GENERATOR(must_not_update); diff --git a/tests/ResultTest.cpp b/tests/ResultTest.cpp index 1353c791..c54d7686 100644 --- a/tests/ResultTest.cpp +++ b/tests/ResultTest.cpp @@ -47,6 +47,20 @@ int main() { static_assert(sqlpp::can_be_null_t::value, "row.alpha can be null"); static_assert(sqlpp::null_is_trivial_value_t::value, "row.alpha interprets null_is_trivial"); + static_assert(std::is_member_function_pointer::value, "Yikes"); + using T = sqlpp::wrap_operand_t; + static_assert(sqlpp::can_be_null_t::value, "row.alpha can be null"); + static_assert(sqlpp::is_result_field_t::value, "row.alpha can be null"); + + bool x = sqlpp::rhs_is_null(t.alpha == row.alpha); + bool y = sqlpp::rhs_is_trivial(t.alpha == row.alpha); + std::cerr << x << std::endl; + std::cerr << y << std::endl; + + for (const auto& sub : db(select(all_of(t)).from(t).where(t.alpha == row.alpha))) + { + std::cerr << sub.alpha << std::endl; + } } sqlpp::select((t.alpha + 1).as(t.alpha)).flags(sqlpp::all).from(t); diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 5ccc94e4..1e97562c 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -64,7 +64,7 @@ int main() std::cout << a << ", " << b << ", " << g << std::endl; } - for (const auto& row : db(select(all_of(t), all_of(f)).from(t.join(f).on(t.alpha > f.omega)).where(true))) + for (const auto& row : db(select(all_of(t), all_of(f)).from(t.join(f).on(t.alpha > f.omega and not t.gamma)).where(true))) { std::cout << row.alpha << std::endl; } From c818e110b636a5c8e8656ec0b0dd111f0ea3f0e2 Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 29 Jul 2014 09:14:51 +0200 Subject: [PATCH 04/17] A few minor fixes and cleanup --- include/sqlpp11/boolean.h | 2 +- include/sqlpp11/floating_point.h | 2 +- include/sqlpp11/integral.h | 2 +- include/sqlpp11/rhs_is_trivial.h | 16 +++++++++++++++- include/sqlpp11/text.h | 2 +- include/sqlpp11/tvin.h | 3 +-- include/sqlpp11/wrap_operand.h | 2 +- 7 files changed, 21 insertions(+), 8 deletions(-) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index be7b195d..1ae482ac 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -162,7 +162,7 @@ namespace sqlpp return _is_null; } - bool is_trivial() const + bool _is_trivial() const { if (not _is_valid) throw exception("accessing is_null in non-existing row"); diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 37c69207..0feb7f7e 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -161,7 +161,7 @@ namespace sqlpp return _is_null; } - bool is_trivial() const + bool _is_trivial() const { if (not _is_valid) throw exception("accessing is_null in non-existing row"); diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index c1441fd3..f100e81b 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -162,7 +162,7 @@ namespace sqlpp return _is_null; } - bool is_trivial() const + bool _is_trivial() const { if (not _is_valid) throw exception("accessing is_null in non-existing row"); diff --git a/include/sqlpp11/rhs_is_trivial.h b/include/sqlpp11/rhs_is_trivial.h index 14de2675..5a38db17 100644 --- a/include/sqlpp11/rhs_is_trivial.h +++ b/include/sqlpp11/rhs_is_trivial.h @@ -63,7 +63,21 @@ namespace sqlpp { static bool _(const T& t) { - return t.is_trivial(); + if (null_is_trivial_value_t::value) + { + return t._is_trivial(); + } + else + { + if (t.is_null()) + { + return false; + } + else + { + return t._is_trivial(); + } + } } }; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index d45544f3..d1ba51e2 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -164,7 +164,7 @@ namespace sqlpp return _value_ptr == nullptr; } - bool is_trivial() const + bool _is_trivial() const { if (not _is_valid) throw exception("accessing is_null in non-existing row"); diff --git a/include/sqlpp11/tvin.h b/include/sqlpp11/tvin.h index 7f3cce23..0c541972 100644 --- a/include/sqlpp11/tvin.h +++ b/include/sqlpp11/tvin.h @@ -155,8 +155,7 @@ namespace sqlpp auto tvin(Operand operand) -> tvin_arg_t::type> { using _operand_t = typename wrap_operand::type; - static_assert(std::is_same<_operand_t, text_operand>::value - or not std::is_same<_operand_t, Operand>::value, "tvin() used with invalid type (only string and primitive types allowed)"); + static_assert(not std::is_same<_operand_t, Operand>::value or is_result_field_t::value, "tvin() used with invalid type (only string and primitive types allowed)"); return {{operand}}; } diff --git a/include/sqlpp11/wrap_operand.h b/include/sqlpp11/wrap_operand.h index 0b0f8d23..b6926055 100644 --- a/include/sqlpp11/wrap_operand.h +++ b/include/sqlpp11/wrap_operand.h @@ -219,7 +219,7 @@ namespace sqlpp }; template - struct wrap_operand::value>::type> + struct wrap_operand::value and not is_result_field_t::value>::type> { using type = text_operand; }; From a62c660ad54f7521a8f111c9035d95d09edd1129 Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 29 Jul 2014 18:18:57 +0200 Subject: [PATCH 05/17] Added some tvin-tests --- tests/FunctionTest.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/FunctionTest.cpp b/tests/FunctionTest.cpp index e668a668..18eddde1 100644 --- a/tests/FunctionTest.cpp +++ b/tests/FunctionTest.cpp @@ -389,5 +389,20 @@ int main() static_assert(sqlpp::is_alias_t::value, "type requirement"); } + // test tvin + { + static_assert(std::is_same>::value, "integral values are accepted and wrapped") ; + static_assert(std::is_same>::value, "bool values are accepted and wrapped") ; + static_assert(std::is_same>::value, "float values are accepted and wrapped") ; + static_assert(std::is_same>::value, "text values are accepted and wrapped") ; + + for (const auto& row : db(select(all_of(t)).from(t).where(true))) + { + static_assert(std::is_same>::value, "result fields are accepted and not wrapped") ; + static_assert(std::is_same>::value, "result fields are accepted and not wrapped") ; + static_assert(std::is_same>::value, "result fields are accepted and not wrapped") ; + } + } + return 0; } From 828106acbdacbbadcee1f2f58b03ea095fc0fc9c Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 30 Jul 2014 17:56:33 +0200 Subject: [PATCH 06/17] Moved shared result field code into separate file --- include/sqlpp11/boolean.h | 41 +---------- include/sqlpp11/floating_point.h | 41 +---------- include/sqlpp11/integral.h | 41 +---------- include/sqlpp11/result_field_methods.h | 97 ++++++++++++++++++++++++++ include/sqlpp11/text.h | 41 +---------- include/sqlpp11/type_traits.h | 3 + 6 files changed, 108 insertions(+), 156 deletions(-) create mode 100644 include/sqlpp11/result_field_methods.h diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 1ae482ac..d37b7546 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace sqlpp { @@ -97,46 +98,8 @@ namespace sqlpp }; template - struct _result_field_t; - - // I am SO waiting for concepts lite! - template - struct field_methods_t + struct _result_field_t: public result_field_methods_t<_result_field_t> { - static constexpr bool _null_is_trivial = true; - operator _cpp_value_type() const { return static_cast(*this).value(); } - }; - - template - struct field_methods_t< - _result_field_t, - typename std::enable_if::value - and column_spec_can_be_null_t::value - and not null_is_trivial_value_t::value>::type> - { - static constexpr bool _null_is_trivial = false; - }; - - template - struct _result_field_t: public field_methods_t<_result_field_t> - { - using _field_methods_t = field_methods_t<_result_field_t>; - - using _traits = make_traits>; - - struct _recursive_traits - { - using _parameters = std::tuple<>; - using _provided_tables = detail::type_set<>; - using _provided_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set<>; - using _extra_tables = detail::type_set<>; - using _can_be_null = column_spec_can_be_null_t; - }; - _result_field_t(): _is_valid(false), _is_null(true), diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 0feb7f7e..a9decec7 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace sqlpp { @@ -96,46 +97,8 @@ namespace sqlpp }; template - struct _result_field_t; - - // I am SO waiting for concepts lite! - template - struct field_methods_t + struct _result_field_t: public result_field_methods_t<_result_field_t> { - static constexpr bool _null_is_trivial = true; - operator _cpp_value_type() const { return static_cast(*this).value(); } - }; - - template - struct field_methods_t< - _result_field_t, - typename std::enable_if::value - and column_spec_can_be_null_t::value - and not null_is_trivial_value_t::value>::type> - { - static constexpr bool _null_is_trivial = false; - }; - - template - struct _result_field_t: public field_methods_t<_result_field_t> - { - using _field_methods_t = field_methods_t<_result_field_t>; - - using _traits = make_traits>; - - struct _recursive_traits - { - using _parameters = std::tuple<>; - using _provided_tables = detail::type_set<>; - using _provided_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set<>; - using _extra_tables = detail::type_set<>; - using _can_be_null = column_spec_can_be_null_t; - }; - _result_field_t(): _is_valid(false), _is_null(true), diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index f100e81b..f99d772c 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -33,6 +33,7 @@ #include #include #include +#include namespace sqlpp { @@ -97,46 +98,8 @@ namespace sqlpp }; template - struct _result_field_t; - - // I am SO waiting for concepts lite! - template - struct field_methods_t + struct _result_field_t: public result_field_methods_t<_result_field_t> { - static constexpr bool _null_is_trivial = true; - operator _cpp_value_type() const { return static_cast(*this).value(); } - }; - - template - struct field_methods_t< - _result_field_t, - typename std::enable_if::value - and column_spec_can_be_null_t::value - and not null_is_trivial_value_t::value>::type> - { - static constexpr bool _null_is_trivial = false; - }; - - template - struct _result_field_t: public field_methods_t<_result_field_t> - { - using _field_methods_t = field_methods_t<_result_field_t>; - - using _traits = make_traits>; - - struct _recursive_traits - { - using _parameters = std::tuple<>; - using _provided_tables = detail::type_set<>; - using _provided_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set<>; - using _extra_tables = detail::type_set<>; - using _can_be_null = column_spec_can_be_null_t; - }; - _result_field_t(): _is_valid(false), _is_null(true), diff --git a/include/sqlpp11/result_field_methods.h b/include/sqlpp11/result_field_methods.h new file mode 100644 index 00000000..c561a0d2 --- /dev/null +++ b/include/sqlpp11/result_field_methods.h @@ -0,0 +1,97 @@ +/* + * 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_RESULT_FIELD_METHODS_H +#define SQLPP_RESULT_FIELD_METHODS_H + +#include + +namespace sqlpp +{ + namespace detail + { + template + struct get_field_spec_impl + { + static_assert(wrong_t::value, "Invalid argument for get_field_spec"); + }; + + template class Field, typename Db, typename FieldSpec> + struct get_field_spec_impl> + { + using type = FieldSpec; + }; + + template + using get_field_spec_t = typename get_field_spec_impl::type; + } + + template + struct result_field_methods_base_t + { + using _field_spec_t = detail::get_field_spec_t; + static constexpr bool _null_is_trivial = true; + operator cpp_value_type_of<_field_spec_t>() const { return static_cast(*this).value(); } + }; + + template class Field, typename Db, typename FieldSpec> + struct result_field_methods_base_t< + Field, + typename std::enable_if::value + and column_spec_can_be_null_t::value + and not null_is_trivial_value_t::value>::type> + { + using _field_spec_t = FieldSpec; + static constexpr bool _null_is_trivial = false; + }; + + template + struct result_field_methods_t: public result_field_methods_base_t + { + using _base_t = result_field_methods_base_t; + using _field_spec_t = typename _base_t::_field_spec_t; + + using _traits = make_traits, + tag::is_result_field, + tag::is_expression, + tag_if>; + + struct _recursive_traits + { + using _parameters = std::tuple<>; + using _provided_tables = detail::type_set<>; + using _provided_outer_tables = detail::type_set<>; + using _required_tables = detail::type_set<>; + using _extra_tables = detail::type_set<>; + using _can_be_null = column_spec_can_be_null_t<_field_spec_t>; + }; + + using _name_t = typename _field_spec_t::_name_t; + + }; + +} +#endif diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index d1ba51e2..1a264676 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace sqlpp { @@ -96,46 +97,8 @@ namespace sqlpp }; template - struct _result_field_t; - - // I am SO waiting for concepts lite! - template - struct field_methods_t + struct _result_field_t: public result_field_methods_t<_result_field_t> { - static constexpr bool _null_is_trivial = true; - operator _cpp_value_type() const { return static_cast(*this).value(); } - }; - - template - struct field_methods_t< - _result_field_t, - typename std::enable_if::value - and column_spec_can_be_null_t::value - and not null_is_trivial_value_t::value>::type> - { - static constexpr bool _null_is_trivial = false; - }; - - template - struct _result_field_t: public field_methods_t<_result_field_t> - { - using _field_methods_t = field_methods_t<_result_field_t>; - - using _traits = make_traits>; - - struct _recursive_traits - { - using _parameters = std::tuple<>; - using _provided_tables = detail::type_set<>; - using _provided_outer_tables = detail::type_set<>; - using _required_tables = detail::type_set<>; - using _extra_tables = detail::type_set<>; - using _can_be_null = column_spec_can_be_null_t; - }; - _result_field_t(): _is_valid(false), _value_ptr(nullptr), diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 79e3f22a..f12f1785 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -192,6 +192,9 @@ namespace sqlpp template using value_type_of = typename detail::value_type_of_impl::type; + template + using cpp_value_type_of = typename value_type_of::_cpp_value_type; + template using required_tables_of = typename detail::required_table_of_impl::type; From 7c45e8b83f80696e4e0422b93a19adcde114a40b Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 30 Jul 2014 22:03:11 +0200 Subject: [PATCH 07/17] Removed _name_t from and added alias operators to result field. A result field really is just a value, if you insist on using it as a select column, give it a name via an alias. --- include/sqlpp11/result_field_methods.h | 6 +++--- tests/ResultTest.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/sqlpp11/result_field_methods.h b/include/sqlpp11/result_field_methods.h index c561a0d2..280a5357 100644 --- a/include/sqlpp11/result_field_methods.h +++ b/include/sqlpp11/result_field_methods.h @@ -28,6 +28,7 @@ #define SQLPP_RESULT_FIELD_METHODS_H #include +#include namespace sqlpp { @@ -69,7 +70,8 @@ namespace sqlpp }; template - struct result_field_methods_t: public result_field_methods_base_t + struct result_field_methods_t: public result_field_methods_base_t, + public alias_operators { using _base_t = result_field_methods_base_t; using _field_spec_t = typename _base_t::_field_spec_t; @@ -89,8 +91,6 @@ namespace sqlpp using _can_be_null = column_spec_can_be_null_t<_field_spec_t>; }; - using _name_t = typename _field_spec_t::_name_t; - }; } diff --git a/tests/ResultTest.cpp b/tests/ResultTest.cpp index c54d7686..bc01bd1b 100644 --- a/tests/ResultTest.cpp +++ b/tests/ResultTest.cpp @@ -50,13 +50,13 @@ int main() static_assert(std::is_member_function_pointer::value, "Yikes"); using T = sqlpp::wrap_operand_t; static_assert(sqlpp::can_be_null_t::value, "row.alpha can be null"); - static_assert(sqlpp::is_result_field_t::value, "row.alpha can be null"); + static_assert(sqlpp::is_result_field_t::value, "result_fields are not wrapped"); bool x = sqlpp::rhs_is_null(t.alpha == row.alpha); bool y = sqlpp::rhs_is_trivial(t.alpha == row.alpha); std::cerr << x << std::endl; std::cerr << y << std::endl; - + for (const auto& sub : db(select(all_of(t)).from(t).where(t.alpha == row.alpha))) { std::cerr << sub.alpha << std::endl; From f60f1504b86d7eac79cae38c844daacb6111b597 Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 30 Jul 2014 22:37:07 +0200 Subject: [PATCH 08/17] Extracted result_field_t from value types. This is a preparation for adding serializer specializations for them --- include/sqlpp11/boolean.h | 151 ++++++++++++------------ include/sqlpp11/floating_point.h | 151 ++++++++++++------------ include/sqlpp11/integral.h | 150 ++++++++++++------------ include/sqlpp11/result_field_methods.h | 8 +- include/sqlpp11/result_row.h | 6 +- include/sqlpp11/text.h | 155 +++++++++++++------------ 6 files changed, 320 insertions(+), 301 deletions(-) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index d37b7546..626323cd 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include namespace sqlpp { @@ -97,73 +97,6 @@ namespace sqlpp bool _is_null; }; - template - struct _result_field_t: public result_field_methods_t<_result_field_t> - { - _result_field_t(): - _is_valid(false), - _is_null(true), - _value(false) - {} - - void _validate() - { - _is_valid = true; - } - - void _invalidate() - { - _is_valid = false; - _is_null = true; - _value = 0; - } - - bool is_null() const - { - if (not _is_valid) - throw exception("accessing is_null in non-existing row"); - return _is_null; - } - - bool _is_trivial() const - { - if (not _is_valid) - throw exception("accessing is_null in non-existing row"); - - return value() == false; - } - - _cpp_value_type value() const - { - if (not _is_valid) - throw exception("accessing value in non-existing row"); - - if (_is_null) - { - if (enforce_null_result_treatment_t::value and not null_is_trivial_value_t::value) - { - throw exception("accessing value of NULL field"); - } - else - { - return false; - } - } - return _value; - } - - template - void _bind(Target& target, size_t i) - { - target._bind_boolean_result(i, &_value, &_is_null); - } - - private: - bool _is_valid; - bool _is_null; - signed char _value; - }; - template struct _is_valid_operand { @@ -206,13 +139,85 @@ namespace sqlpp }; }; - template - inline std::ostream& operator<<(std::ostream& os, const boolean::_result_field_t& e) - { - return os << e.value(); - } } + template + struct result_field_t: public result_field_methods_t> + { + static_assert(std::is_same, detail::boolean>::value, "field type mismatch"); + using _cpp_value_type = typename detail::boolean::_cpp_value_type; + + result_field_t(): + _is_valid(false), + _is_null(true), + _value(false) + {} + + void _validate() + { + _is_valid = true; + } + + void _invalidate() + { + _is_valid = false; + _is_null = true; + _value = 0; + } + + bool is_null() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + return _is_null; + } + + bool _is_trivial() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + + return value() == false; + } + + _cpp_value_type value() const + { + if (not _is_valid) + throw exception("accessing value in non-existing row"); + + if (_is_null) + { + if (enforce_null_result_treatment_t::value and not null_is_trivial_value_t::value) + { + throw exception("accessing value of NULL field"); + } + else + { + return false; + } + } + return _value; + } + + template + void _bind(Target& target, size_t i) + { + target._bind_boolean_result(i, &_value, &_is_null); + } + + private: + bool _is_valid; + bool _is_null; + signed char _value; + }; + + template + inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) + { + return os << e.value(); + } + + using boolean = detail::boolean; } diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index a9decec7..964b5cc1 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -31,7 +31,7 @@ #include #include #include -#include +#include namespace sqlpp { @@ -96,73 +96,6 @@ namespace sqlpp bool _is_null; }; - template - struct _result_field_t: public result_field_methods_t<_result_field_t> - { - _result_field_t(): - _is_valid(false), - _is_null(true), - _value(0) - {} - - void _validate() - { - _is_valid = true; - } - - void _invalidate() - { - _is_valid = false; - _is_null = true; - _value = 0; - } - - bool is_null() const - { - if (not _is_valid) - throw exception("accessing is_null in non-existing row"); - return _is_null; - } - - bool _is_trivial() const - { - if (not _is_valid) - throw exception("accessing is_null in non-existing row"); - - return value() == 0; - } - - _cpp_value_type value() const - { - if (not _is_valid) - throw exception("accessing value in non-existing row"); - - if (_is_null) - { - if (enforce_null_result_treatment_t::value and not null_is_trivial_value_t::value) - { - throw exception("accessing value of NULL field"); - } - else - { - return 0; - } - } - return _value; - } - - template - void _bind(Target& target, size_t i) - { - target._bind_floating_point_result(i, &_value, &_is_null); - } - - private: - bool _is_valid; - bool _is_null; - _cpp_value_type _value; - }; - template struct _is_valid_operand { @@ -261,13 +194,85 @@ namespace sqlpp }; }; - template - inline std::ostream& operator<<(std::ostream& os, const floating_point::_result_field_t& e) - { - return os << e.value(); - } } + template + struct result_field_t: public result_field_methods_t> + { + static_assert(std::is_same, detail::floating_point>::value, "field type mismatch"); + using _cpp_value_type = typename detail::floating_point::_cpp_value_type; + + result_field_t(): + _is_valid(false), + _is_null(true), + _value(0) + {} + + void _validate() + { + _is_valid = true; + } + + void _invalidate() + { + _is_valid = false; + _is_null = true; + _value = 0; + } + + bool is_null() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + return _is_null; + } + + bool _is_trivial() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + + return value() == 0; + } + + _cpp_value_type value() const + { + if (not _is_valid) + throw exception("accessing value in non-existing row"); + + if (_is_null) + { + if (enforce_null_result_treatment_t::value and not null_is_trivial_value_t::value) + { + throw exception("accessing value of NULL field"); + } + else + { + return 0; + } + } + return _value; + } + + template + void _bind(Target& target, size_t i) + { + target._bind_floating_point_result(i, &_value, &_is_null); + } + + private: + bool _is_valid; + bool _is_null; + _cpp_value_type _value; + }; + + template + inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) + { + return os << e.value(); + } + + using floating_point = detail::floating_point; } diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index f99d772c..16695215 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -33,7 +33,7 @@ #include #include #include -#include +#include namespace sqlpp { @@ -97,73 +97,6 @@ namespace sqlpp bool _is_null; }; - template - struct _result_field_t: public result_field_methods_t<_result_field_t> - { - _result_field_t(): - _is_valid(false), - _is_null(true), - _value(0) - {} - - void _invalidate() - { - _is_valid = false; - _is_null = true; - _value = 0; - } - - void _validate() - { - _is_valid = true; - } - - bool is_null() const - { - if (not _is_valid) - throw exception("accessing is_null in non-existing row"); - return _is_null; - } - - bool _is_trivial() const - { - if (not _is_valid) - throw exception("accessing is_null in non-existing row"); - - return value() == 0; - } - - _cpp_value_type value() const - { - if (not _is_valid) - throw exception("accessing value in non-existing row"); - - if (_is_null) - { - if (enforce_null_result_treatment_t::value and not null_is_trivial_value_t::value) - { - throw exception("accessing value of NULL field"); - } - else - { - return 0; - } - } - return _value; - } - - template - void _bind(Target& target, size_t i) - { - target._bind_integral_result(i, &_value, &_is_null); - } - - private: - bool _is_valid; - bool _is_null; - _cpp_value_type _value; - }; - template struct _is_valid_operand { @@ -273,13 +206,84 @@ namespace sqlpp }; }; - template - inline std::ostream& operator<<(std::ostream& os, const integral::_result_field_t& e) - { - return os << e.value(); - } } + template + struct result_field_t: public result_field_methods_t> + { + static_assert(std::is_same, detail::integral>::value, "field type mismatch"); + using _cpp_value_type = typename detail::integral::_cpp_value_type; + + result_field_t(): + _is_valid(false), + _is_null(true), + _value(0) + {} + + void _invalidate() + { + _is_valid = false; + _is_null = true; + _value = 0; + } + + void _validate() + { + _is_valid = true; + } + + bool is_null() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + return _is_null; + } + + bool _is_trivial() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + + return value() == 0; + } + + _cpp_value_type value() const + { + if (not _is_valid) + throw exception("accessing value in non-existing row"); + + if (_is_null) + { + if (enforce_null_result_treatment_t::value and not null_is_trivial_value_t::value) + { + throw exception("accessing value of NULL field"); + } + else + { + return 0; + } + } + return _value; + } + + template + void _bind(Target& target, size_t i) + { + target._bind_integral_result(i, &_value, &_is_null); + } + + private: + bool _is_valid; + bool _is_null; + _cpp_value_type _value; + }; + + template + inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) + { + return os << e.value(); + } + using tinyint = detail::integral; using smallint = detail::integral; using integer = detail::integral; diff --git a/include/sqlpp11/result_field_methods.h b/include/sqlpp11/result_field_methods.h index 280a5357..ad37b1ef 100644 --- a/include/sqlpp11/result_field_methods.h +++ b/include/sqlpp11/result_field_methods.h @@ -40,8 +40,8 @@ namespace sqlpp static_assert(wrong_t::value, "Invalid argument for get_field_spec"); }; - template class Field, typename Db, typename FieldSpec> - struct get_field_spec_impl> + template class Field, typename ValueType, typename Db, typename FieldSpec> + struct get_field_spec_impl> { using type = FieldSpec; }; @@ -58,9 +58,9 @@ namespace sqlpp operator cpp_value_type_of<_field_spec_t>() const { return static_cast(*this).value(); } }; - template class Field, typename Db, typename FieldSpec> + template class Field, typename ValueType, typename Db, typename FieldSpec> struct result_field_methods_base_t< - Field, + Field, typename std::enable_if::value and column_spec_can_be_null_t::value and not null_is_trivial_value_t::value>::type> diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index fe2a6c63..3ab024a0 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -41,9 +41,9 @@ namespace sqlpp template struct result_field: - public FieldSpec::_name_t::template _member_t::template _result_field_t> + public FieldSpec::_name_t::template _member_t, Db, FieldSpec>> { - using _field = typename FieldSpec::_name_t::template _member_t::template _result_field_t>; + using _field = typename FieldSpec::_name_t::template _member_t, Db, FieldSpec>>; result_field() = default; @@ -189,7 +189,7 @@ namespace sqlpp struct _name_t {}; }; - using _field_type = detail::text::_result_field_t; + using _field_type = result_field_t; static constexpr size_t _last_static_index = _impl::_last_index; bool _is_valid; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 1a264676..99e95e73 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include namespace sqlpp { @@ -96,75 +96,6 @@ namespace sqlpp bool _is_null; }; - template - struct _result_field_t: public result_field_methods_t<_result_field_t> - { - _result_field_t(): - _is_valid(false), - _value_ptr(nullptr), - _len(0) - {} - - void _validate() - { - _is_valid = true; - } - - void _invalidate() - { - _is_valid = false; - _value_ptr = nullptr; - _len = 0; - } - - bool operator==(const _cpp_value_type& rhs) const { return value() == rhs; } - bool operator!=(const _cpp_value_type& rhs) const { return not operator==(rhs); } - - bool is_null() const - { - if (not _is_valid) - throw exception("accessing is_null in non-existing row"); - return _value_ptr == nullptr; - } - - bool _is_trivial() const - { - if (not _is_valid) - throw exception("accessing is_null in non-existing row"); - - return value() == ""; - } - - _cpp_value_type value() const - { - if (not _is_valid) - throw exception("accessing value in non-existing row"); - - if (not _value_ptr) - { - if (enforce_null_result_treatment_t::value and not null_is_trivial_value_t::value) - { - throw exception("accessing value of NULL field"); - } - else - { - return ""; - } - } - return std::string(_value_ptr, _value_ptr + _len); - } - - template - void _bind(Target& target, size_t i) - { - target._bind_text_result(i, &_value_ptr, &_len); - } - - private: - bool _is_valid; - const char* _value_ptr; - size_t _len; - }; template struct _is_valid_operand @@ -211,13 +142,87 @@ namespace sqlpp }; }; - template - inline std::ostream& operator<<(std::ostream& os, const text::_result_field_t& e) - { - return os << e.value(); - } } + template + struct result_field_t: public result_field_methods_t> + { + static_assert(std::is_same, detail::text>::value, "field type mismatch"); + using _cpp_value_type = typename detail::text::_cpp_value_type; + + result_field_t(): + _is_valid(false), + _value_ptr(nullptr), + _len(0) + {} + + void _validate() + { + _is_valid = true; + } + + void _invalidate() + { + _is_valid = false; + _value_ptr = nullptr; + _len = 0; + } + + bool operator==(const _cpp_value_type& rhs) const { return value() == rhs; } + bool operator!=(const _cpp_value_type& rhs) const { return not operator==(rhs); } + + bool is_null() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + return _value_ptr == nullptr; + } + + bool _is_trivial() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); + + return value() == ""; + } + + _cpp_value_type value() const + { + if (not _is_valid) + throw exception("accessing value in non-existing row"); + + if (not _value_ptr) + { + if (enforce_null_result_treatment_t::value and not null_is_trivial_value_t::value) + { + throw exception("accessing value of NULL field"); + } + else + { + return ""; + } + } + return std::string(_value_ptr, _value_ptr + _len); + } + + template + void _bind(Target& target, size_t i) + { + target._bind_text_result(i, &_value_ptr, &_len); + } + + private: + bool _is_valid; + const char* _value_ptr; + size_t _len; + }; + + template + inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) + { + return os << e.value(); + } + using text = detail::text; using blob = detail::text; using varchar = detail::text; From ff9a6ff8f08d8f267144dea83ae476f9ee98f94f Mon Sep 17 00:00:00 2001 From: rbock Date: Wed, 30 Jul 2014 23:10:45 +0200 Subject: [PATCH 09/17] Added missing result_field.h --- include/sqlpp11/boolean.h | 3 +- include/sqlpp11/floating_point.h | 2 +- include/sqlpp11/integral.h | 2 +- include/sqlpp11/result_field.h | 63 ++++++++++++++++++++++++++++++++ include/sqlpp11/text.h | 31 +++++++++++++++- tests/InterpretTest.cpp | 8 ++++ 6 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 include/sqlpp11/result_field.h diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 626323cd..669b49bb 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -214,10 +214,9 @@ namespace sqlpp template inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) { - return os << e.value(); + return serialize(e, os); } - using boolean = detail::boolean; } diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 964b5cc1..683ae1f9 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -269,7 +269,7 @@ namespace sqlpp template inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) { - return os << e.value(); + return serialize(e, os); } diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index 16695215..24b9ebe1 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -281,7 +281,7 @@ namespace sqlpp template inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) { - return os << e.value(); + return serialize(e, os); } using tinyint = detail::integral; diff --git a/include/sqlpp11/result_field.h b/include/sqlpp11/result_field.h new file mode 100644 index 00000000..9fa41de9 --- /dev/null +++ b/include/sqlpp11/result_field.h @@ -0,0 +1,63 @@ +/* + * 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_RESULT_FIELD_H +#define SQLPP_RESULT_FIELD_H + +#include +#include + +namespace sqlpp +{ + template + struct result_field_t + { +#warning: Need to rewrite all uses of wrong like this to prevent them from being initialized at the wrong place... + static_assert(wrong_t>::value, "Missing specialization for result_field_t"); + }; + + template + struct serializer_t> + { + using T = result_field_t; + + static Context& _(const T& t, Context& context) + { + if (t.is_null() and not null_is_trivial_value_t::value) + { + context << "NULL"; + } + else + { + context << t.value(); + } + return context; + } + }; + + +} +#endif diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 99e95e73..85201f33 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -47,7 +47,7 @@ namespace sqlpp struct _parameter_t { - using _value_type = integral; + using _value_type = text; _parameter_t(): _value(""), @@ -217,10 +217,37 @@ namespace sqlpp size_t _len; }; + template + struct serializer_t> + { + using T = result_field_t; + + static Context& _(const T& t, Context& context) + { + if (t.is_null() and not null_is_trivial_value_t::value) + { + context << "NULL"; + } + else + { + context << '\'' << context.escape(t.value()) << '\''; + } + return context; + } + }; + template inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) { - return os << e.value(); + if (e.is_null() and not null_is_trivial_value_t::value) + { + os << "NULL"; + } + else + { + os << e.value(); + } + return serialize(e, os); } using text = detail::text; diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 02f00dd5..ea62ace4 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -156,6 +156,7 @@ int main() serialize(s, printer).str(); } + // distinct aggregate serialize(count(sqlpp::distinct, t.alpha % 7), printer).str(); serialize(avg(sqlpp::distinct, t.alpha - 7), printer).str(); @@ -164,5 +165,12 @@ int main() serialize(select(all_of(t)).from(t).where(true), printer).str(); serialize(select(all_of(t)).from(t).where(false), printer).str(); + for (const auto& row : db(select(all_of(t)).from(t).where(true))) + { + serialize(row.alpha, printer); + serialize(row.beta, printer); + serialize(row.gamma, printer); + } + return 0; } From c88a1097c2a7870af360fabf8067b3377c0c24da Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 31 Jul 2014 08:19:00 +0200 Subject: [PATCH 10/17] Added some hints --- include/sqlpp11/functions.h | 2 ++ tests/MockDb.h | 1 + 2 files changed, 3 insertions(+) diff --git a/include/sqlpp11/functions.h b/include/sqlpp11/functions.h index 6c13fd7e..ff561e2a 100644 --- a/include/sqlpp11/functions.h +++ b/include/sqlpp11/functions.h @@ -45,6 +45,8 @@ 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 { diff --git a/tests/MockDb.h b/tests/MockDb.h index 8642208e..3356c214 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -30,6 +30,7 @@ #include #include +#warning add serialization to run methods to increase the number of tests template struct MockDbT: public sqlpp::connection { From 88d28d68305039332c98ba64371da7d452b9449f Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 31 Jul 2014 08:40:13 +0200 Subject: [PATCH 11/17] Moved value types out of detail namespace --- include/sqlpp11/boolean.h | 183 ++++++++--------- include/sqlpp11/count.h | 4 +- include/sqlpp11/expression.h | 6 +- include/sqlpp11/expression_fwd.h | 31 ++- include/sqlpp11/floating_point.h | 336 +++++++++++++++---------------- include/sqlpp11/integral.h | 320 +++++++++++++++-------------- include/sqlpp11/result_row.h | 4 +- include/sqlpp11/text.h | 201 +++++++++--------- include/sqlpp11/wrap_operand.h | 19 +- tests/InterpretTest.cpp | 2 +- 10 files changed, 538 insertions(+), 568 deletions(-) diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 669b49bb..653b0d01 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -36,116 +36,111 @@ namespace sqlpp { - // boolean operators - namespace detail + // boolean value type + struct boolean { - // boolean value type - struct boolean + using _traits = make_traits; + using _tag = ::sqlpp::tag::is_boolean; + using _cpp_value_type = bool; + + struct _parameter_t { - using _traits = make_traits; - using _tag = ::sqlpp::tag::is_boolean; - using _cpp_value_type = bool; + using _value_type = boolean; // FIXME - struct _parameter_t + _parameter_t(): + _value(false), + _is_null(true) + {} + + _parameter_t(const _cpp_value_type& value): + _value(value), + _is_null(false) + {} + + _parameter_t& operator=(const _cpp_value_type& value) { - using _value_type = boolean; // FIXME + _value = value; + _is_null = (false); + return *this; + } - _parameter_t(): - _value(false), - _is_null(true) - {} - - _parameter_t(const _cpp_value_type& value): - _value(value), - _is_null(false) - {} - - _parameter_t& operator=(const _cpp_value_type& value) - { - _value = value; - _is_null = (false); - return *this; - } - - _parameter_t& operator=(const std::nullptr_t&) - { - _value = false; - _is_null = true; - return *this; - } - - bool is_null() const - { - return _is_null; - } - - _cpp_value_type value() const - { - return _value; - } - - operator _cpp_value_type() const { return value(); } - - template - void _bind(Target& target, size_t index) const - { - target._bind_boolean_parameter(index, &_value, _is_null); - } - - private: - signed char _value; - bool _is_null; - }; - - template - struct _is_valid_operand - { - static constexpr bool value = - is_expression_t::value // expressions are OK - and is_boolean_t::value // the correct value type is required, of course - ; - }; - - template - struct expression_operators: public basic_expression_operators + _parameter_t& operator=(const std::nullptr_t&) { - template - logical_and_t> operator and(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); + _value = false; + _is_null = true; + return *this; + } - return { *static_cast(this), rhs{t} }; - } + bool is_null() const + { + return _is_null; + } - template - logical_or_t> operator or(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); + _cpp_value_type value() const + { + return _value; + } - return { *static_cast(this), rhs{t} }; - } + operator _cpp_value_type() const { return value(); } - logical_not_t operator not() const + template + void _bind(Target& target, size_t index) const { - return { *static_cast(this) }; + target._bind_boolean_parameter(index, &_value, _is_null); } - }; - template - struct column_operators - { - }; + private: + signed char _value; + bool _is_null; }; - } + template + struct _is_valid_operand + { + static constexpr bool value = + is_expression_t::value // expressions are OK + and is_boolean_t::value // the correct value type is required, of course + ; + }; + + template + struct expression_operators: public basic_expression_operators + { + template + logical_and_t> operator and(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), rhs{t} }; + } + + template + logical_or_t> operator or(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), rhs{t} }; + } + + logical_not_t operator not() const + { + return { *static_cast(this) }; + } + }; + + template + struct column_operators + { + }; + }; template - struct result_field_t: public result_field_methods_t> + struct result_field_t: public result_field_methods_t> { - static_assert(std::is_same, detail::boolean>::value, "field type mismatch"); - using _cpp_value_type = typename detail::boolean::_cpp_value_type; + static_assert(std::is_same, boolean>::value, "field type mismatch"); + using _cpp_value_type = typename boolean::_cpp_value_type; result_field_t(): _is_valid(false), @@ -212,12 +207,10 @@ namespace sqlpp }; template - inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) + inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) { return serialize(e, os); } - using boolean = detail::boolean; - } #endif diff --git a/include/sqlpp11/count.h b/include/sqlpp11/count.h index a2970de1..814dcf22 100644 --- a/include/sqlpp11/count.h +++ b/include/sqlpp11/count.h @@ -33,10 +33,10 @@ namespace sqlpp { template - struct count_t: public sqlpp::detail::integral::template expression_operators>, + struct count_t: public sqlpp::integral::template expression_operators>, public alias_operators> { - using _traits = make_traits<::sqlpp::detail::integral, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_named_expression>; + using _traits = make_traits<::sqlpp::integral, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_named_expression>; using _recursive_traits = make_recursive_traits; static_assert(is_noop::value or std::is_same::value, "count() used with flag other than 'distinct'"); diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index cb221ccd..22c6c92b 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -40,7 +40,7 @@ namespace sqlpp { template - struct binary_expression_t: public ::sqlpp::detail::boolean::template expression_operators>, + struct binary_expression_t: public ::sqlpp::boolean::template expression_operators>, public alias_operators> { using _traits = make_traits; @@ -88,7 +88,7 @@ namespace sqlpp }; template - struct binary_expression_t: public ::sqlpp::detail::boolean::template expression_operators>, + struct binary_expression_t: public ::sqlpp::boolean::template expression_operators>, public alias_operators> { using _traits = make_traits; @@ -136,7 +136,7 @@ namespace sqlpp }; template - struct unary_expression_t: public ::sqlpp::detail::boolean::template expression_operators>, + struct unary_expression_t: public ::sqlpp::boolean::template expression_operators>, public alias_operators> { using _traits = make_traits; diff --git a/include/sqlpp11/expression_fwd.h b/include/sqlpp11/expression_fwd.h index 2a389e5b..71958635 100644 --- a/include/sqlpp11/expression_fwd.h +++ b/include/sqlpp11/expression_fwd.h @@ -29,64 +29,61 @@ namespace sqlpp { - namespace detail - { - struct boolean; - struct integral; - struct floating_point; - } + struct boolean; + struct integral; + struct floating_point; namespace op { struct less { - using _traits = make_traits<::sqlpp::detail::boolean>; + using _traits = make_traits<::sqlpp::boolean>; static constexpr const char* _name = "<"; }; struct less_equal { - using _traits = make_traits<::sqlpp::detail::boolean>; + using _traits = make_traits<::sqlpp::boolean>; static constexpr const char* _name = "<="; }; struct equal_to { - using _traits = make_traits<::sqlpp::detail::boolean>; + using _traits = make_traits<::sqlpp::boolean>; }; struct not_equal_to { - using _traits = make_traits<::sqlpp::detail::boolean>; + using _traits = make_traits<::sqlpp::boolean>; }; struct greater_equal { - using _traits = make_traits<::sqlpp::detail::boolean>; + using _traits = make_traits<::sqlpp::boolean>; static constexpr const char* _name = ">="; }; struct greater { - using _traits = make_traits<::sqlpp::detail::boolean>; + using _traits = make_traits<::sqlpp::boolean>; static constexpr const char* _name = ">"; }; struct logical_or { - using _traits = make_traits<::sqlpp::detail::boolean>; + using _traits = make_traits<::sqlpp::boolean>; static constexpr const char* _name = " OR "; }; struct logical_and { - using _traits = make_traits<::sqlpp::detail::boolean>; + using _traits = make_traits<::sqlpp::boolean>; static constexpr const char* _name = " AND "; }; struct logical_not { - using _traits = make_traits<::sqlpp::detail::boolean>; + using _traits = make_traits<::sqlpp::boolean>; }; template @@ -112,13 +109,13 @@ namespace sqlpp struct divides { - using _traits = make_traits<::sqlpp::detail::floating_point>; + using _traits = make_traits<::sqlpp::floating_point>; static constexpr const char* _name = "/"; }; struct modulus { - using _traits = make_traits<::sqlpp::detail::integral>; + using _traits = make_traits<::sqlpp::integral>; static constexpr const char* _name = "%"; }; diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 683ae1f9..12bb9979 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -35,195 +35,190 @@ namespace sqlpp { - namespace detail + // floating_point value type + struct floating_point { + using _traits = make_traits; + using _tag = ::sqlpp::tag::is_floating_point; + using _cpp_value_type = double; - // floating_point value type - struct floating_point + struct _parameter_t { - using _traits = make_traits; - using _tag = ::sqlpp::tag::is_floating_point; - using _cpp_value_type = double; + using _value_type = floating_point; - struct _parameter_t + _parameter_t(): + _value(0), + _is_null(true) + {} + + _parameter_t(const _cpp_value_type& value): + _value(value), + _is_null(false) + {} + + _parameter_t& operator=(const _cpp_value_type& value) { - using _value_type = floating_point; + _value = value; + _is_null = false; + return *this; + } - _parameter_t(): - _value(0), - _is_null(true) - {} - - _parameter_t(const _cpp_value_type& value): - _value(value), - _is_null(false) - {} - - _parameter_t& operator=(const _cpp_value_type& value) - { - _value = value; - _is_null = false; - return *this; - } - - _parameter_t& operator=(const std::nullptr_t&) - { - _value = 0; - _is_null = true; - return *this; - } - - bool is_null() const - { - return _is_null; - } - - const _cpp_value_type& value() const - { - return _value; - } - - operator _cpp_value_type() const { return _value; } - - template - void _bind(Target& target, size_t index) const - { - target._bind_floating_point_parameter(index, &_value, _is_null); - } - - private: - _cpp_value_type _value; - bool _is_null; - }; - - template - struct _is_valid_operand - { - static constexpr bool value = - is_expression_t::value // expressions are OK - and is_numeric_t::value // the correct value type is required, of course - ; - }; - - template - struct expression_operators: public basic_expression_operators + _parameter_t& operator=(const std::nullptr_t&) { - template - plus_t> operator +(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); + _value = 0; + _is_null = true; + return *this; + } - return { *static_cast(this), rhs{t} }; - } + bool is_null() const + { + return _is_null; + } - template - minus_t> operator -(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); + const _cpp_value_type& value() const + { + return _value; + } - return { *static_cast(this), rhs{t} }; - } + operator _cpp_value_type() const { return _value; } - template - multiplies_t> operator *(T t) const - { - using rhs = wrap_operand_t; - - return { *static_cast(this), rhs{t} }; - } - - template - divides_t> operator /(T t) const - { - using rhs = wrap_operand_t; - - return { *static_cast(this), rhs{t} }; - } - - unary_plus_t operator +() const + template + void _bind(Target& target, size_t index) const { - return { *static_cast(this) }; + target._bind_floating_point_parameter(index, &_value, _is_null); } - unary_minus_t operator -() const - { - return { *static_cast(this) }; - } - }; - - template - struct column_operators - { - template - auto operator +=(T t) const -> assignment_t>> - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - - return { *static_cast(this), { *static_cast(this), rhs{t} } }; - } - - template - auto operator -=(T t) const -> assignment_t>> - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - - return { *static_cast(this), { *static_cast(this), rhs{t} } }; - } - - template - auto operator /=(T t) const -> assignment_t>> - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - - return { *static_cast(this), { *static_cast(this), rhs{t} } }; - } - - template - auto operator *=(T t) const -> assignment_t>> - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - - return { *static_cast(this), { *static_cast(this), rhs{t} } }; - } - }; + private: + _cpp_value_type _value; + bool _is_null; }; - } + template + struct _is_valid_operand + { + static constexpr bool value = + is_expression_t::value // expressions are OK + and is_numeric_t::value // the correct value type is required, of course + ; + }; + + template + struct expression_operators: public basic_expression_operators + { + template + plus_t> operator +(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), rhs{t} }; + } + + template + minus_t> operator -(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), rhs{t} }; + } + + template + multiplies_t> operator *(T t) const + { + using rhs = wrap_operand_t; + + return { *static_cast(this), rhs{t} }; + } + + template + divides_t> operator /(T t) const + { + using rhs = wrap_operand_t; + + return { *static_cast(this), rhs{t} }; + } + + unary_plus_t operator +() const + { + return { *static_cast(this) }; + } + + unary_minus_t operator -() const + { + return { *static_cast(this) }; + } + }; + + template + struct column_operators + { + template + auto operator +=(T t) const -> assignment_t>> + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } + + template + auto operator -=(T t) const -> assignment_t>> + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } + + template + auto operator /=(T t) const -> assignment_t>> + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } + + template + auto operator *=(T t) const -> assignment_t>> + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } + }; + }; template - struct result_field_t: public result_field_methods_t> - { - static_assert(std::is_same, detail::floating_point>::value, "field type mismatch"); - using _cpp_value_type = typename detail::floating_point::_cpp_value_type; - - result_field_t(): - _is_valid(false), - _is_null(true), - _value(0) - {} - - void _validate() + struct result_field_t: public result_field_methods_t> { - _is_valid = true; - } + static_assert(std::is_same, floating_point>::value, "field type mismatch"); + using _cpp_value_type = typename floating_point::_cpp_value_type; - void _invalidate() - { - _is_valid = false; - _is_null = true; - _value = 0; - } + result_field_t(): + _is_valid(false), + _is_null(true), + _value(0) + {} - bool is_null() const - { - if (not _is_valid) - throw exception("accessing is_null in non-existing row"); + void _validate() + { + _is_valid = true; + } + + void _invalidate() + { + _is_valid = false; + _is_null = true; + _value = 0; + } + + bool is_null() const + { + if (not _is_valid) + throw exception("accessing is_null in non-existing row"); return _is_null; } @@ -267,13 +262,10 @@ namespace sqlpp }; template - inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) + inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) { return serialize(e, os); } - - using floating_point = detail::floating_point; - } #endif diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index 24b9ebe1..8c6ae5ec 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -37,182 +37,178 @@ namespace sqlpp { - namespace detail + // integral value type + struct integral { + using _traits = make_traits; + using _tag = ::sqlpp::tag::is_integral; + using _cpp_value_type = int64_t; - // integral value type - struct integral + struct _parameter_t { - using _traits = make_traits; - using _tag = ::sqlpp::tag::is_integral; - using _cpp_value_type = int64_t; + using _value_type = integral; - struct _parameter_t + _parameter_t(): + _value(0), + _is_null(true) + {} + + explicit _parameter_t(const _cpp_value_type& value): + _value(value), + _is_null(false) + {} + + _parameter_t& operator=(const _cpp_value_type& value) { - using _value_type = integral; + _value = value; + _is_null = false; + return *this; + } - _parameter_t(): - _value(0), - _is_null(true) - {} - - explicit _parameter_t(const _cpp_value_type& value): - _value(value), - _is_null(false) - {} - - _parameter_t& operator=(const _cpp_value_type& value) - { - _value = value; - _is_null = false; - return *this; - } - - void set_null() - { - _value = 0; - _is_null = true; - } - - bool is_null() const - { - return _is_null; - } - - const _cpp_value_type& value() const - { - return _value; - } - - operator _cpp_value_type() const { return _value; } - - template - void _bind(Target& target, size_t index) const - { - target._bind_integral_parameter(index, &_value, _is_null); - } - - private: - _cpp_value_type _value; - bool _is_null; - }; - - template - struct _is_valid_operand - { - static constexpr bool value = - is_expression_t::value // expressions are OK - and is_numeric_t::value // the correct value type is required, of course - ; - }; - - template - struct expression_operators: public basic_expression_operators + void set_null() { - template - plus_t, wrap_operand_t> operator +(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); + _value = 0; + _is_null = true; + } - return { *static_cast(this), {t} }; - } + bool is_null() const + { + return _is_null; + } - template - minus_t, wrap_operand_t> operator -(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); + const _cpp_value_type& value() const + { + return _value; + } - return { *static_cast(this), {t} }; - } + operator _cpp_value_type() const { return _value; } - template - multiplies_t, wrap_operand_t> operator *(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); - - return { *static_cast(this), {t} }; - } - - template - divides_t> operator /(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); - - return { *static_cast(this), {t} }; - } - - template - modulus_t> operator %(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); - - return { *static_cast(this), {t} }; - } - - unary_plus_t operator +() const + template + void _bind(Target& target, size_t index) const { - return { *static_cast(this) }; + target._bind_integral_parameter(index, &_value, _is_null); } - unary_minus_t operator -() const - { - return { *static_cast(this) }; - } - }; - - template - struct column_operators - { - template - auto operator +=(T t) const -> assignment_t, wrap_operand_t>> - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - - return { *static_cast(this), { *static_cast(this), rhs{t} } }; - } - - template - auto operator -=(T t) const -> assignment_t, wrap_operand_t>> - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - - return { *static_cast(this), { *static_cast(this), rhs{t} } }; - } - - template - auto operator /=(T t) const -> assignment_t>> - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - - return { *static_cast(this), { *static_cast(this), rhs{t} } }; - } - - template - auto operator *=(T t) const -> assignment_t, wrap_operand_t>> - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); - - return { *static_cast(this), { *static_cast(this), rhs{t} } }; - } - }; + private: + _cpp_value_type _value; + bool _is_null; }; - } + template + struct _is_valid_operand + { + static constexpr bool value = + is_expression_t::value // expressions are OK + and is_numeric_t::value // the correct value type is required, of course + ; + }; + + template + struct expression_operators: public basic_expression_operators + { + template + plus_t, wrap_operand_t> operator +(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), {t} }; + } + + template + minus_t, wrap_operand_t> operator -(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), {t} }; + } + + template + multiplies_t, wrap_operand_t> operator *(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), {t} }; + } + + template + divides_t> operator /(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), {t} }; + } + + template + modulus_t> operator %(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), {t} }; + } + + unary_plus_t operator +() const + { + return { *static_cast(this) }; + } + + unary_minus_t operator -() const + { + return { *static_cast(this) }; + } + }; + + template + struct column_operators + { + template + auto operator +=(T t) const -> assignment_t, wrap_operand_t>> + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } + + template + auto operator -=(T t) const -> assignment_t, wrap_operand_t>> + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } + + template + auto operator /=(T t) const -> assignment_t>> + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } + + template + auto operator *=(T t) const -> assignment_t, wrap_operand_t>> + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } + }; + }; + template - struct result_field_t: public result_field_methods_t> + struct result_field_t: public result_field_methods_t> { - static_assert(std::is_same, detail::integral>::value, "field type mismatch"); - using _cpp_value_type = typename detail::integral::_cpp_value_type; + static_assert(std::is_same, integral>::value, "field type mismatch"); + using _cpp_value_type = typename integral::_cpp_value_type; result_field_t(): _is_valid(false), @@ -279,15 +275,15 @@ namespace sqlpp }; template - inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) + inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) { return serialize(e, os); } - using tinyint = detail::integral; - using smallint = detail::integral; - using integer = detail::integral; - using bigint = detail::integral; + using tinyint = integral; + using smallint = integral; + using integer = integral; + using bigint = integral; } #endif diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 3ab024a0..676a8eef 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -184,12 +184,12 @@ namespace sqlpp using _impl = detail::result_row_impl, FieldSpecs...>; struct _field_spec_t { - using _traits = make_traits; + using _traits = make_traits; using _recursive_traits = make_recursive_traits<>; struct _name_t {}; }; - using _field_type = result_field_t; + using _field_type = result_field_t; static constexpr size_t _last_static_index = _impl::_last_index; bool _is_valid; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 85201f33..6c87e845 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -36,119 +36,115 @@ namespace sqlpp { - namespace detail + // text value type + struct text { - // text value type - struct text + using _traits = make_traits; + using _tag = ::sqlpp::tag::is_text; + using _cpp_value_type = std::string; + + struct _parameter_t { - using _traits = make_traits; - using _tag = ::sqlpp::tag::is_text; - using _cpp_value_type = std::string; + using _value_type = text; - struct _parameter_t + _parameter_t(): + _value(""), + _is_null(true) + {} + + _parameter_t(const _cpp_value_type& value): + _value(value), + _is_null(false) + {} + + _parameter_t& operator=(const _cpp_value_type& value) { - using _value_type = text; + _value = value; + _is_null = false; + return *this; + } - _parameter_t(): - _value(""), - _is_null(true) - {} - - _parameter_t(const _cpp_value_type& value): - _value(value), - _is_null(false) - {} - - _parameter_t& operator=(const _cpp_value_type& value) - { - _value = value; - _is_null = false; - return *this; - } - - _parameter_t& operator=(const std::nullptr_t&) - { - _value = ""; - _is_null = true; - return *this; - } - - bool is_null() const - { - return _is_null; - } - - _cpp_value_type value() const - { - return _value; - } - - operator _cpp_value_type() const { return value(); } - - template - void _bind(Target& target, size_t index) const - { - target._bind_text_parameter(index, &_value, _is_null); - } - - private: - _cpp_value_type _value; - bool _is_null; - }; - - - template - struct _is_valid_operand - { - static constexpr bool value = - is_expression_t::value // expressions are OK - and is_text_t::value // the correct value type is required, of course - ; - }; - - template - struct expression_operators: public basic_expression_operators + _parameter_t& operator=(const std::nullptr_t&) { - template - concat_t> operator+(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs operand"); + _value = ""; + _is_null = true; + return *this; + } - return { *static_cast(this), {t} }; - } + bool is_null() const + { + return _is_null; + } - template - like_t> like(T t) const - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid argument for like()"); + _cpp_value_type value() const + { + return _value; + } - return { *static_cast(this), {t} }; - } - }; + operator _cpp_value_type() const { return value(); } - template - struct column_operators + template + void _bind(Target& target, size_t index) const { - template - auto operator +=(T t) const -> assignment_t>> - { - using rhs = wrap_operand_t; - static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + target._bind_text_parameter(index, &_value, _is_null); + } - return { *static_cast(this), { *static_cast(this), rhs{t} } }; - } - }; + private: + _cpp_value_type _value; + bool _is_null; }; - } + + template + struct _is_valid_operand + { + static constexpr bool value = + is_expression_t::value // expressions are OK + and is_text_t::value // the correct value type is required, of course + ; + }; + + template + struct expression_operators: public basic_expression_operators + { + template + concat_t> operator+(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs operand"); + + return { *static_cast(this), {t} }; + } + + template + like_t> like(T t) const + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid argument for like()"); + + return { *static_cast(this), {t} }; + } + }; + + template + struct column_operators + { + template + auto operator +=(T t) const -> assignment_t>> + { + using rhs = wrap_operand_t; + static_assert(_is_valid_operand::value, "invalid rhs assignment operand"); + + return { *static_cast(this), { *static_cast(this), rhs{t} } }; + } + }; + }; template - struct result_field_t: public result_field_methods_t> + struct result_field_t: public result_field_methods_t> { - static_assert(std::is_same, detail::text>::value, "field type mismatch"); - using _cpp_value_type = typename detail::text::_cpp_value_type; + static_assert(std::is_same, text>::value, "field type mismatch"); + using _cpp_value_type = typename text::_cpp_value_type; result_field_t(): _is_valid(false), @@ -218,9 +214,9 @@ namespace sqlpp }; template - struct serializer_t> + struct serializer_t> { - using T = result_field_t; + using T = result_field_t; static Context& _(const T& t, Context& context) { @@ -237,7 +233,7 @@ namespace sqlpp }; template - inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) + inline std::ostream& operator<<(std::ostream& os, const result_field_t& e) { if (e.is_null() and not null_is_trivial_value_t::value) { @@ -250,10 +246,9 @@ namespace sqlpp return serialize(e, os); } - using text = detail::text; - using blob = detail::text; - using varchar = detail::text; - using char_ = detail::text; + using blob = text; + using varchar = text; + using char_ = text; } #endif diff --git a/include/sqlpp11/wrap_operand.h b/include/sqlpp11/wrap_operand.h index b6926055..ffab6e94 100644 --- a/include/sqlpp11/wrap_operand.h +++ b/include/sqlpp11/wrap_operand.h @@ -33,17 +33,14 @@ namespace sqlpp { - namespace detail - { - struct boolean; - struct integral; - struct floating_point; - struct text; - } + struct boolean; + struct integral; + struct floating_point; + struct text; struct boolean_operand { - using _traits = make_traits<::sqlpp::detail::boolean, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; + using _traits = make_traits<::sqlpp::boolean, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; using _recursive_traits = make_recursive_traits<>; using _value_t = bool; @@ -81,7 +78,7 @@ namespace sqlpp struct integral_operand { - using _traits = make_traits<::sqlpp::detail::integral, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; + using _traits = make_traits<::sqlpp::integral, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; using _recursive_traits = make_recursive_traits<>; using _value_t = int64_t; @@ -120,7 +117,7 @@ namespace sqlpp struct floating_point_operand { - using _traits = make_traits<::sqlpp::detail::floating_point, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; + using _traits = make_traits<::sqlpp::floating_point, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; using _recursive_traits = make_recursive_traits<>; using _value_t = double; @@ -158,7 +155,7 @@ namespace sqlpp struct text_operand { - using _traits = make_traits<::sqlpp::detail::text, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; + using _traits = make_traits<::sqlpp::text, ::sqlpp::tag::is_expression, ::sqlpp::tag::is_wrapped_value>; using _recursive_traits = make_recursive_traits<>; using _value_t = std::string; diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index ea62ace4..b927e239 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -101,7 +101,7 @@ int main() // functions serialize(sqlpp::value(7), printer).str(); - serialize(sqlpp::verbatim("irgendwas integrales"), printer).str(); + serialize(sqlpp::verbatim("irgendwas integrales"), printer).str(); serialize(sqlpp::value_list(std::vector({1,2,3,4,5,6,8})), printer).str(); serialize(exists(select(t.alpha).from(t)), printer).str(); serialize(any(select(t.alpha).from(t)), printer).str(); From 64c4ba029f6c5478679e7bbf5e90076780c84102 Mon Sep 17 00:00:00 2001 From: rbock Date: Thu, 31 Jul 2014 09:08:00 +0200 Subject: [PATCH 12/17] Adjusted usage of wrong_t. I think there was a risk of wrong_t based static_asserts firing, if the template parameters are used. Anyway, this is shorter. --- include/sqlpp11/all_of.h | 2 +- include/sqlpp11/detail/copy_tuple_args.h | 2 +- include/sqlpp11/detail/type_set.h | 16 ++++++++-------- include/sqlpp11/interpreter.h | 2 +- include/sqlpp11/into.h | 8 ++++---- include/sqlpp11/multi_column.h | 2 +- include/sqlpp11/parameter_list.h | 2 +- include/sqlpp11/result_field.h | 3 +-- include/sqlpp11/result_field_methods.h | 2 +- include/sqlpp11/serializer.h | 2 +- include/sqlpp11/tvin.h | 2 +- include/sqlpp11/where.h | 2 +- 12 files changed, 22 insertions(+), 23 deletions(-) diff --git a/include/sqlpp11/all_of.h b/include/sqlpp11/all_of.h index b4d90fae..0af691a4 100644 --- a/include/sqlpp11/all_of.h +++ b/include/sqlpp11/all_of.h @@ -58,7 +58,7 @@ namespace sqlpp static Context& _(const T& t, const Context&) { - static_assert(wrong_t::value, "all_of(table) does not seem to be used in select"); + static_assert(wrong_t::value, "all_of(table) does not seem to be used in select"); } }; diff --git a/include/sqlpp11/detail/copy_tuple_args.h b/include/sqlpp11/detail/copy_tuple_args.h index 3496a2be..32631e01 100644 --- a/include/sqlpp11/detail/copy_tuple_args.h +++ b/include/sqlpp11/detail/copy_tuple_args.h @@ -57,7 +57,7 @@ namespace sqlpp template class Target, typename First, typename T> struct copy_tuple_args_impl { - static_assert(wrong_t::value, "copy_tuple_args must be called with a tuple"); + static_assert(wrong_t::value, "copy_tuple_args must be called with a tuple"); }; template class Target, typename First, typename... Args> diff --git a/include/sqlpp11/detail/type_set.h b/include/sqlpp11/detail/type_set.h index 0f85d875..4f6f1ef4 100644 --- a/include/sqlpp11/detail/type_set.h +++ b/include/sqlpp11/detail/type_set.h @@ -73,7 +73,7 @@ namespace sqlpp template struct is_element_of { - static_assert(::sqlpp::wrong_t::value, "SET has to be a type set"); + static_assert(::sqlpp::wrong_t::value, "SET has to be a type set"); }; template @@ -85,7 +85,7 @@ namespace sqlpp template struct joined_set { - static_assert(::sqlpp::wrong_t::value, "L and R have to be type sets"); + static_assert(::sqlpp::wrong_t::value, "L and R have to be type sets"); }; template @@ -100,7 +100,7 @@ namespace sqlpp template struct is_superset_of { - static_assert(::sqlpp::wrong_t::value, "L and R have to be type sets"); + static_assert(::sqlpp::wrong_t::value, "L and R have to be type sets"); }; template @@ -118,7 +118,7 @@ namespace sqlpp template struct is_disjunct_from { - static_assert(::sqlpp::wrong_t::value, "invalid argument for is_disjunct_from"); + static_assert(::sqlpp::wrong_t::value, "invalid argument for is_disjunct_from"); }; template @@ -174,7 +174,7 @@ namespace sqlpp template struct make_joined_set { - static_assert(::sqlpp::wrong_t::value, "invalid argument for joined set"); + static_assert(::sqlpp::wrong_t::value, "invalid argument for joined set"); }; template<> @@ -197,7 +197,7 @@ namespace sqlpp template struct make_difference_set { - static_assert(::sqlpp::wrong_t::value, "invalid argument for difference set"); + static_assert(::sqlpp::wrong_t::value, "invalid argument for difference set"); }; template @@ -214,7 +214,7 @@ namespace sqlpp template struct make_intersect_set { - static_assert(::sqlpp::wrong_t::value, "invalid argument for intersect set"); + static_assert(::sqlpp::wrong_t::value, "invalid argument for intersect set"); }; template @@ -232,7 +232,7 @@ namespace sqlpp template class Transformation, typename T> struct transform_set { - static_assert(::sqlpp::wrong_t::value, "invalid argument for transform_set"); + static_assert(::sqlpp::wrong_t::value, "invalid argument for transform_set"); }; template class Transformation, typename... E> diff --git a/include/sqlpp11/interpreter.h b/include/sqlpp11/interpreter.h index cd7c9690..17ea9ffa 100644 --- a/include/sqlpp11/interpreter.h +++ b/include/sqlpp11/interpreter.h @@ -36,7 +36,7 @@ namespace sqlpp { static void _(const T& t, Context& context) { - static_assert(wrong_t::value, "missing interpreter specialization"); + static_assert(wrong_t::value, "missing interpreter specialization"); } }; diff --git a/include/sqlpp11/into.h b/include/sqlpp11/into.h index 3d2b2f90..6cf97ff4 100644 --- a/include/sqlpp11/into.h +++ b/include/sqlpp11/into.h @@ -140,10 +140,10 @@ namespace sqlpp template using _new_statement_t = typename Policies::template _new_statement_t; - static void _check_consistency() - { - static_assert(wrong_t::value, "into() required"); - } + static void _check_consistency() + { + static_assert(wrong_t<_methods_t>::value, "into() required"); + } template auto into(Args... args) diff --git a/include/sqlpp11/multi_column.h b/include/sqlpp11/multi_column.h index 892a8c4d..5b7763a9 100644 --- a/include/sqlpp11/multi_column.h +++ b/include/sqlpp11/multi_column.h @@ -117,7 +117,7 @@ namespace sqlpp static void _(const T& t, Context& context) { - static_assert(wrong_t::value, "multi_column must be used with an alias"); + static_assert(wrong_t::value, "multi_column must be used with an alias"); } }; diff --git a/include/sqlpp11/parameter_list.h b/include/sqlpp11/parameter_list.h index c023e3f7..89d75d33 100644 --- a/include/sqlpp11/parameter_list.h +++ b/include/sqlpp11/parameter_list.h @@ -37,7 +37,7 @@ namespace sqlpp template struct parameter_list_t { - static_assert(wrong_t::value, "Template parameter for parameter_list_t has to be a tuple"); + static_assert(wrong_t::value, "Template parameter for parameter_list_t has to be a tuple"); }; template diff --git a/include/sqlpp11/result_field.h b/include/sqlpp11/result_field.h index 9fa41de9..e78b3938 100644 --- a/include/sqlpp11/result_field.h +++ b/include/sqlpp11/result_field.h @@ -35,8 +35,7 @@ namespace sqlpp template struct result_field_t { -#warning: Need to rewrite all uses of wrong like this to prevent them from being initialized at the wrong place... - static_assert(wrong_t>::value, "Missing specialization for result_field_t"); + static_assert(wrong_t::value, "Missing specialization for result_field_t"); }; template diff --git a/include/sqlpp11/result_field_methods.h b/include/sqlpp11/result_field_methods.h index ad37b1ef..54492a38 100644 --- a/include/sqlpp11/result_field_methods.h +++ b/include/sqlpp11/result_field_methods.h @@ -37,7 +37,7 @@ namespace sqlpp template struct get_field_spec_impl { - static_assert(wrong_t::value, "Invalid argument for get_field_spec"); + static_assert(wrong_t::value, "Invalid argument for get_field_spec"); }; template class Field, typename ValueType, typename Db, typename FieldSpec> diff --git a/include/sqlpp11/serializer.h b/include/sqlpp11/serializer.h index 682c9602..04629bda 100644 --- a/include/sqlpp11/serializer.h +++ b/include/sqlpp11/serializer.h @@ -36,7 +36,7 @@ namespace sqlpp { static void _(const T& t, Context& context) { - static_assert(wrong_t::value, "missing serializer specialization"); + static_assert(wrong_t::value, "missing serializer specialization"); } }; diff --git a/include/sqlpp11/tvin.h b/include/sqlpp11/tvin.h index 0c541972..ad65ed38 100644 --- a/include/sqlpp11/tvin.h +++ b/include/sqlpp11/tvin.h @@ -63,7 +63,7 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - static_assert(wrong_t::value, "tvin may only be used with operators =, == and !="); + static_assert(wrong_t::value, "tvin may only be used with operators =, == and !="); } }; diff --git a/include/sqlpp11/where.h b/include/sqlpp11/where.h index 20933fee..cd2b924b 100644 --- a/include/sqlpp11/where.h +++ b/include/sqlpp11/where.h @@ -224,7 +224,7 @@ namespace sqlpp static void _check_consistency() { - static_assert(Required ? wrong_t::value : true, "where expression required, e.g. where(true)"); + static_assert(Required ? wrong_t<_methods_t>::value : true, "where expression required, e.g. where(true)"); } template From 18dc6b1a03f52d852699fc3232778c52f1d3681b Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 1 Aug 2014 18:21:23 +0200 Subject: [PATCH 13/17] Added value_or_null method/type --- include/sqlpp11/boolean.h | 2 +- include/sqlpp11/floating_point.h | 2 +- include/sqlpp11/functions.h | 14 +++++- include/sqlpp11/integral.h | 2 +- include/sqlpp11/null.h | 2 +- include/sqlpp11/parameter.h | 2 +- include/sqlpp11/text.h | 2 +- include/sqlpp11/type_traits.h | 2 + include/sqlpp11/value_or_null.h | 86 ++++++++++++++++++++++++++++++++ tests/FunctionTest.cpp | 36 +++++++++++++ 10 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 include/sqlpp11/value_or_null.h 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")); From 8b5fc67af6d532aa0bccd26b3144170a86b7b576 Mon Sep 17 00:00:00 2001 From: rbock Date: Sat, 2 Aug 2014 09:18:01 +0200 Subject: [PATCH 14/17] Added generic boolean_expression --- include/sqlpp11/boolean_expression.h | 83 ++++++++++++++++++++++++++++ include/sqlpp11/functions.h | 1 - include/sqlpp11/sqlpp11.h | 1 + tests/BooleanExpressionTest.cpp | 42 ++++++++++++++ tests/CMakeLists.txt | 1 + 5 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 include/sqlpp11/boolean_expression.h create mode 100644 tests/BooleanExpressionTest.cpp diff --git a/include/sqlpp11/boolean_expression.h b/include/sqlpp11/boolean_expression.h new file mode 100644 index 00000000..b2c66acc --- /dev/null +++ b/include/sqlpp11/boolean_expression.h @@ -0,0 +1,83 @@ +/* + * 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_BOOLEAN_EXPRESSION_H +#define SQLPP_BOOLEAN_EXPRESSION_H + +#include +#include + +namespace sqlpp +{ + template + struct boolean_expression_t + { + using _traits = make_traits; + using _recursive_traits = make_recursive_traits<>; + + template + boolean_expression_t(Expression expression): + _expression(expression) + { + static_assert(is_expression_t::value, "boolean_expression requires a boolean expression argument"); + static_assert(is_boolean_t::value, "boolean_expression requires a boolean expression argument"); + } + + boolean_expression_t(const boolean_expression_t&) = default; + boolean_expression_t(boolean_expression_t&&) = default; + boolean_expression_t& operator=(const boolean_expression_t&) = default; + boolean_expression_t& operator=(boolean_expression_t&&) = default; + ~boolean_expression_t() = default; + + interpretable_t _expression; + }; + + template + boolean_expression_t boolean_expression(const Database&, T t) + { + return {t}; + } + + template + boolean_expression_t boolean_expression(T t) + { + return {t}; + } + + template + struct serializer_t> + { + using T = boolean_expression_t; + + static Context& _(const T& t, Context& context) + { + return serialize(t._expression); + } + }; + +} + +#endif diff --git a/include/sqlpp11/functions.h b/include/sqlpp11/functions.h index 34c79994..af8ebdb2 100644 --- a/include/sqlpp11/functions.h +++ b/include/sqlpp11/functions.h @@ -46,7 +46,6 @@ namespace sqlpp { -#warning add a template bool_expression which takes any bool expression as constructor argument template auto value(T t) -> wrap_operand_t { diff --git a/include/sqlpp11/sqlpp11.h b/include/sqlpp11/sqlpp11.h index e0ccca48..d4278a2f 100644 --- a/include/sqlpp11/sqlpp11.h +++ b/include/sqlpp11/sqlpp11.h @@ -35,6 +35,7 @@ #include #include #include +#include #endif diff --git a/tests/BooleanExpressionTest.cpp b/tests/BooleanExpressionTest.cpp new file mode 100644 index 00000000..3eaf8544 --- /dev/null +++ b/tests/BooleanExpressionTest.cpp @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#include +#include "Sample.h" +#include "MockDb.h" +#include + +MockDb db = {}; + +int main() +{ + test::TabBar t; + + auto x = boolean_expression(db, t.alpha == 7); + x = boolean_expression(db, t.gamma); + x = sqlpp::boolean_expression(t.beta.like("%cheesecake")); + + return 0; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ed2c041d..6582425b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,6 +6,7 @@ macro (build_and_run arg) add_test(${arg} ${arg}) endmacro () +build_and_run(BooleanExpressionTest) build_and_run(InterpretTest) build_and_run(InsertTest) build_and_run(RemoveTest) From cc512d095581d433d4b5028c6c62ccb907308f03 Mon Sep 17 00:00:00 2001 From: rbock Date: Sun, 3 Aug 2014 09:27:20 +0200 Subject: [PATCH 15/17] Fixed text field stream operator --- include/sqlpp11/text.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 7e7d9ad7..58affcfc 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -237,13 +237,12 @@ namespace sqlpp { if (e.is_null() and not null_is_trivial_value_t::value) { - os << "NULL"; + return os << "NULL"; } else { - os << e.value(); + return os << e.value(); } - return serialize(e, os); } using blob = text; From c9372eff8959c4f6fb5981d801099a2b5009dfa4 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 4 Aug 2014 18:24:51 +0200 Subject: [PATCH 16/17] Added serialization to MockDb run methods Implicitly increased number of serialization tests. Fixed serialization for logical_not --- include/sqlpp11/expression.h | 4 +++- tests/MockDb.h | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/sqlpp11/expression.h b/include/sqlpp11/expression.h index 22c6c92b..73b6c3a8 100644 --- a/include/sqlpp11/expression.h +++ b/include/sqlpp11/expression.h @@ -165,7 +165,7 @@ namespace sqlpp context << "("; if (trivial_value_is_null_t::value) { - serialize(t._lhs, context); + serialize(t._rhs, context); context << " IS NULL "; } else @@ -174,6 +174,8 @@ namespace sqlpp serialize(t._rhs, context); } context << ")"; + + return context; } }; diff --git a/tests/MockDb.h b/tests/MockDb.h index 3356c214..64cbb883 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -30,7 +30,6 @@ #include #include -#warning add serialization to run methods to increase the number of tests template struct MockDbT: public sqlpp::connection { @@ -105,24 +104,32 @@ struct MockDbT: public sqlpp::connection template size_t insert(const Insert& x) { + _serializer_context_t context; + ::sqlpp::serialize(x, context); return 0; } template size_t update(const Update& x) { + _serializer_context_t context; + ::sqlpp::serialize(x, context); return 0; } template size_t remove(const Remove& x) { + _serializer_context_t context; + ::sqlpp::serialize(x, context); return 0; } template - result_t select(const Select& s) + result_t select(const Select& x) { + _serializer_context_t context; + ::sqlpp::serialize(x, context); return {}; } @@ -139,24 +146,32 @@ struct MockDbT: public sqlpp::connection template _prepared_statement_t prepare_insert(Insert& x) { + _serializer_context_t context; + ::sqlpp::serialize(x, context); return nullptr; } template size_t run_prepared_insert(const PreparedInsert& x) { + _serializer_context_t context; + ::sqlpp::serialize(x, context); return 0; } template _prepared_statement_t prepare_select(Select& x) { + _serializer_context_t context; + ::sqlpp::serialize(x, context); return nullptr; } template result_t run_prepared_select(PreparedSelect& x) { + _serializer_context_t context; + ::sqlpp::serialize(x, context); return {}; } From 5c4dc0caf01bb29e1bc8dbe01c50616ed6b5c3d6 Mon Sep 17 00:00:00 2001 From: rbock Date: Fri, 8 Aug 2014 07:57:08 +0200 Subject: [PATCH 17/17] Added a first experimental fail test --- CMakeLists.txt | 1 + test_constraints/CMakeLists.txt | 17 +++++++ ...onversion_operator_if_null_not_trivial.cpp | 48 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 test_constraints/CMakeLists.txt create mode 100644 test_constraints/no_conversion_operator_if_null_not_trivial.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dd3e7ea..32fd43cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ set(include_dir "${PROJECT_SOURCE_DIR}/include") file(GLOB_RECURSE sqlpp_headers ${include_dir}/*.h) include_directories(${include_dir}) add_subdirectory(tests) +add_subdirectory(test_constraints) install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/sqlpp11" DESTINATION include) diff --git a/test_constraints/CMakeLists.txt b/test_constraints/CMakeLists.txt new file mode 100644 index 00000000..678412dc --- /dev/null +++ b/test_constraints/CMakeLists.txt @@ -0,0 +1,17 @@ +include_directories(${CMAKE_BINARY_DIR}/tests) + +add_executable( + no_conversion_operator_if_null_not_trivial + EXCLUDE_FROM_ALL + no_conversion_operator_if_null_not_trivial.cpp + ) + +add_custom_command(OUTPUT no_conversion_operator_if_null_not_trivial.out + COMMAND ${CMAKE_MAKE_PROGRAM} no_conversion_operator_if_null_not_trivial > ${CMAKE_CURRENT_BINARY_DIR}/no_conversion_operator_if_null_not_trivial.out 2>&1 || true + COMMAND grep "int i = row.alpha" ${CMAKE_CURRENT_BINARY_DIR}/no_conversion_operator_if_null_not_trivial.out > /dev/null + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/no_conversion_operator_if_null_not_trivial.cpp + COMMENT "no_conversion_operator_if_null_not_trivial" + ) + +add_custom_target(test_constraints DEPENDS no_conversion_operator_if_null_not_trivial.out COMMAND true) + diff --git a/test_constraints/no_conversion_operator_if_null_not_trivial.cpp b/test_constraints/no_conversion_operator_if_null_not_trivial.cpp new file mode 100644 index 00000000..7b995626 --- /dev/null +++ b/test_constraints/no_conversion_operator_if_null_not_trivial.cpp @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#include "Sample.h" +#include "MockDb.h" +#include + +EnforceDb edb {}; + +int main() +{ + test::TabBar t; + + static_assert(sqlpp::can_be_null_t::value, "t.alpha can be null"); + static_assert(not sqlpp::null_is_trivial_value_t::value, "t.alpha does not say null_is_trivial"); + + for (const auto& row : edb(select(all_of(t)).from(t).where(true))) + { + static_assert(sqlpp::can_be_null_t::value, "row.alpha can be null"); + static_assert(not sqlpp::null_is_trivial_value_t::value, "row.alpha does not interpret null_is_trivial"); + + int i = row.alpha; + } + + return 0; +}