diff --git a/include/sqlpp11/boolean.h b/include/sqlpp11/boolean.h index 113575d3..117d75b9 100644 --- a/include/sqlpp11/boolean.h +++ b/include/sqlpp11/boolean.h @@ -28,6 +28,7 @@ #define SQLPP_BOOLEAN_H #include +#include #include #include #include @@ -98,6 +99,7 @@ namespace sqlpp bool _is_null; }; + template struct _result_entry_t { _result_entry_t(): @@ -133,15 +135,28 @@ namespace sqlpp bool is_null() const { - if (not _is_valid) + if (connector_assert_result_validity_t::value) + assert(_is_valid); + else if (not _is_valid) throw exception("accessing is_null in non-existing row"); return _is_null; } _cpp_value_type value() const { - if (not _is_valid) - throw exception("accessing value in non-existing row"); + const bool null_value = _is_null and not NullIsTrivial and not connector_null_result_is_trivial_value_t::value; + if (connector_assert_result_validity_t::value) + { + assert(_is_valid); + assert(not null_value); + } + else + { + if (not _is_valid) + throw exception("accessing value in non-existing row"); + if (null_value) + throw exception("accessing value of NULL field"); + } return _value; } @@ -189,7 +204,8 @@ namespace sqlpp }; }; - inline std::ostream& operator<<(std::ostream& os, const boolean::_result_entry_t& e) + template + inline std::ostream& operator<<(std::ostream& os, const boolean::_result_entry_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/detail/logic.h b/include/sqlpp11/detail/logic.h index 72e3a318..152da35e 100644 --- a/include/sqlpp11/detail/logic.h +++ b/include/sqlpp11/detail/logic.h @@ -34,52 +34,52 @@ namespace sqlpp namespace detail { template - struct and_impl; + struct all_impl; template<> - struct and_impl<> + struct all_impl<> { static constexpr bool value = true; }; template - struct and_impl + struct all_impl { - static constexpr bool value = and_impl::value; + static constexpr bool value = all_impl::value; }; template - struct and_impl + struct all_impl { static constexpr bool value = false; }; template class Predicate, typename... T> - using and_t = and_impl::value...>; + using all_t = all_impl::value...>; template - struct or_impl; + struct any_impl; template<> - struct or_impl<> + struct any_impl<> { static constexpr bool value = false; }; template - struct or_impl + struct any_impl { - static constexpr bool value = or_impl::value; + static constexpr bool value = any_impl::value; }; template - struct or_impl + struct any_impl { static constexpr bool value = true; }; template class Predicate, typename... T> - using or_t = or_impl::value...>; + using any_t = any_impl::value...>; } } diff --git a/include/sqlpp11/detail/type_set.h b/include/sqlpp11/detail/type_set.h index 53450cbe..3388748a 100644 --- a/include/sqlpp11/detail/type_set.h +++ b/include/sqlpp11/detail/type_set.h @@ -38,7 +38,10 @@ namespace sqlpp { // some forward declarations and helpers template - struct make_set; + struct make_type_set; + + template + struct is_element_of; // A type set template @@ -47,118 +50,126 @@ namespace sqlpp using size = std::integral_constant; using _is_type_set = std::true_type; - static_assert(std::is_same::type>::value, "use make_set to construct a set"); - - template - struct count - { - template - using same = std::is_same; - static constexpr bool value = or_t::value; - }; - - template - struct is_superset_of - { - static_assert(::sqlpp::vendor::wrong_t::value, "invalid argument for is_superset_of"); - }; - - template - struct is_superset_of> - { - static constexpr bool value = and_t::value; - }; - - template - struct join - { - static_assert(::sqlpp::vendor::wrong_t::value, "invalid argument for type_set::join"); - }; - - template - struct join> - { - using type = typename make_set::type; - }; - - template - struct is_subset_of - { - static_assert(::sqlpp::vendor::wrong_t::value, "invalid argument for is_subset_of"); - }; - - template - struct is_subset_of> - { - static constexpr bool value = type_set::template is_superset_of::value; - }; - - template - struct is_disjunct_from - { - static_assert(::sqlpp::vendor::wrong_t::value, "invalid argument for is_disjunct_from"); - }; - - template - struct is_disjunct_from> - { - static constexpr bool value = not(or_t::value or or_t::template count, Elements...>::value); - }; + static_assert(std::is_same::type>::value, "use make_type_set to construct a set"); template struct insert { - using type = typename std::conditional::value, - type_set, - type_set>::type; + using type = typename std::conditional::value, + type_set, + type_set>::type; }; template class Predicate, typename T> struct insert_if { - using type = typename std::conditional::value, + using type = typename std::conditional::value and not is_element_of::value, type_set, type_set>::type; }; }; + + template + struct is_element_of + { + static_assert(::sqlpp::vendor::wrong_t::value, "SET has to be a type set"); + }; + + template + struct is_element_of> + { + template + using matchE = std::is_same; + static constexpr bool value = any_t::value; + }; + + template + struct is_superset_of + { + static_assert(::sqlpp::vendor::wrong_t::value, "L and R have to be type sets"); + }; + + template + struct is_superset_of, type_set> + { + template + using is_element_of_L = is_element_of>; + static constexpr bool value = all_t::value; + }; + + template + struct is_subset_of + { + static constexpr bool value = is_superset_of::value; + }; + + template + struct joined_set + { + static_assert(::sqlpp::vendor::wrong_t::value, "L and R have to be type sets"); + }; + + template + struct joined_set, type_set> + { + using type = typename make_type_set::type; + }; + + template + struct is_disjunct_from + { + static_assert(::sqlpp::vendor::wrong_t::value, "invalid argument for is_disjunct_from"); + }; + + template + struct is_disjunct_from, type_set> + { + template + using is_element_of_L = is_element_of>; + template + using is_element_of_R = is_element_of>; + static constexpr bool value = + not(any_t::value or any_t::value); + }; + template<> - struct make_set<> + struct make_type_set<> { using type = type_set<>; }; template - struct make_set + struct make_type_set { - using type = typename make_set::type::template insert::type; + using type = typename make_type_set::type::template insert::type; }; template class Predicate, typename... T> - struct make_set_if; + struct make_type_set_if; template class Predicate> - struct make_set_if + struct make_type_set_if { using type = type_set<>; }; template class Predicate, typename T, typename... Rest> - struct make_set_if + struct make_type_set_if { - using type = typename make_set_if::type::template insert_if::type; + using type = typename make_type_set_if::type::template insert_if::type; }; template class Predicate, typename... T> - struct make_set_if_not + struct make_type_set_if_not { template using InversePredicate = std::integral_constant::value>; - using type = typename make_set_if::type; + using type = typename make_type_set_if::type; }; template - using has_duplicates = std::integral_constant::type::size::value != sizeof...(T)>; + using has_duplicates = std::integral_constant::type::size::value != sizeof...(T)>; template struct make_joined_set @@ -172,20 +183,12 @@ namespace sqlpp using type = type_set<>; }; - /* - template - struct make_joined_set> - { - using type = type_set; - }; - */ - template struct make_joined_set, T...> { using _rest = typename make_joined_set::type; - using type = typename type_set::template join<_rest>::type; + using type = typename joined_set, _rest>::type; }; } diff --git a/include/sqlpp11/floating_point.h b/include/sqlpp11/floating_point.h index 36e98ce2..4f8a47e8 100644 --- a/include/sqlpp11/floating_point.h +++ b/include/sqlpp11/floating_point.h @@ -28,6 +28,7 @@ #define SQLPP_FLOATING_POINT_H #include +#include #include #include #include @@ -98,6 +99,7 @@ namespace sqlpp bool _is_null; }; + template struct _result_entry_t { using _value_type = integral; @@ -135,15 +137,28 @@ namespace sqlpp bool is_null() const { - if (not _is_valid) + if (connector_assert_result_validity_t::value) + assert(_is_valid); + else if (not _is_valid) throw exception("accessing is_null in non-existing row"); return _is_null; } _cpp_value_type value() const { - if (not _is_valid) - throw exception("accessing value in non-existing row"); + const bool null_value = _is_null and not NullIsTrivial and not connector_null_result_is_trivial_value_t::value; + if (connector_assert_result_validity_t::value) + { + assert(_is_valid); + assert(not null_value); + } + else + { + if (not _is_valid) + throw exception("accessing value in non-existing row"); + if (null_value) + throw exception("accessing value of NULL field"); + } return _value; } @@ -237,7 +252,8 @@ namespace sqlpp }; }; - inline std::ostream& operator<<(std::ostream& os, const floating_point::_result_entry_t& e) + template + inline std::ostream& operator<<(std::ostream& os, const floating_point::_result_entry_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/insert.h b/include/sqlpp11/insert.h index eb60554a..11bda07f 100644 --- a/include/sqlpp11/insert.h +++ b/include/sqlpp11/insert.h @@ -45,7 +45,7 @@ namespace sqlpp > struct insert_t { - static_assert(Table::_table_set::template is_superset_of::value, "columns do not match the table they are to be inserted into"); + static_assert(::sqlpp::detail::is_superset_of::value, "columns do not match the table they are to be inserted into"); using _database_t = Database; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; diff --git a/include/sqlpp11/integral.h b/include/sqlpp11/integral.h index dcddb299..a143e5de 100644 --- a/include/sqlpp11/integral.h +++ b/include/sqlpp11/integral.h @@ -28,6 +28,7 @@ #define SQLPP_INTEGRAL_H #include +#include #include #include #include @@ -98,6 +99,7 @@ namespace sqlpp bool _is_null; }; + template struct _result_entry_t { using _value_type = integral; @@ -135,15 +137,28 @@ namespace sqlpp bool is_null() const { - if (not _is_valid) + if (connector_assert_result_validity_t::value) + assert(_is_valid); + else if (not _is_valid) throw exception("accessing is_null in non-existing row"); return _is_null; } _cpp_value_type value() const { - if (not _is_valid) - throw exception("accessing value in non-existing row"); + const bool null_value = _is_null and not NullIsTrivial and not connector_null_result_is_trivial_value_t::value; + if (connector_assert_result_validity_t::value) + { + assert(_is_valid); + assert(not null_value); + } + else + { + if (not _is_valid) + throw exception("accessing value in non-existing row"); + if (null_value) + throw exception("accessing value of NULL field"); + } return _value; } @@ -244,7 +259,8 @@ namespace sqlpp }; }; - inline std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t& e) + template + inline std::ostream& operator<<(std::ostream& os, const integral::_result_entry_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/join.h b/include/sqlpp11/join.h index 23816184..4351bf58 100644 --- a/include/sqlpp11/join.h +++ b/include/sqlpp11/join.h @@ -82,11 +82,11 @@ namespace sqlpp static_assert(not is_join_t::value, "rhs argument for join must not be a join"); static_assert(vendor::is_noop::value or is_on_t::value, "invalid on expression in join().on()"); - static_assert(Lhs::_table_set::template is_disjunct_from::value, "joined tables must not be identical"); + static_assert(::sqlpp::detail::is_disjunct_from::value, "joined tables must not be identical"); using _is_table = std::true_type; using _is_join = std::true_type; - using _table_set = typename Lhs::_table_set::template join::type; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; template using set_on_t = join_t; diff --git a/include/sqlpp11/multi_column.h b/include/sqlpp11/multi_column.h index c6260b30..cfe7c212 100644 --- a/include/sqlpp11/multi_column.h +++ b/include/sqlpp11/multi_column.h @@ -40,7 +40,7 @@ namespace sqlpp template struct multi_column_t { - static_assert(detail::and_t::value, "multi_column parameters need to be named expressions"); + static_assert(detail::all_t::value, "multi_column parameters need to be named expressions"); multi_column_t(std::tuple columns): _columns(columns) @@ -72,7 +72,7 @@ namespace sqlpp template struct multi_column_alias_t { - static_assert(detail::and_t::value, "multi_column parameters need to be named expressions"); + static_assert(detail::all_t::value, "multi_column parameters need to be named expressions"); using _name_t = typename AliasProvider::_name_t; diff --git a/include/sqlpp11/null.h b/include/sqlpp11/null.h index af742da1..c3d864c9 100644 --- a/include/sqlpp11/null.h +++ b/include/sqlpp11/null.h @@ -36,8 +36,6 @@ namespace sqlpp static constexpr bool _is_expression = true; using _value_type = no_value_t; using _table_set = ::sqlpp::detail::type_set<>; - - static constexpr bool _is_trivial() { return false; } }; namespace vendor diff --git a/include/sqlpp11/on.h b/include/sqlpp11/on.h index 96ade430..9db74885 100644 --- a/include/sqlpp11/on.h +++ b/include/sqlpp11/on.h @@ -41,7 +41,7 @@ namespace sqlpp using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; static_assert(_is_dynamic::value or sizeof...(Expr), "at least one expression argument required in on()"); - static_assert(detail::and_t::value, "at least one argument is not an expression in on()"); + static_assert(detail::all_t::value, "at least one argument is not an expression in on()"); template void add(E expr) diff --git a/include/sqlpp11/prepared_select.h b/include/sqlpp11/prepared_select.h index 7c7947e9..68aecf1e 100644 --- a/include/sqlpp11/prepared_select.h +++ b/include/sqlpp11/prepared_select.h @@ -32,15 +32,15 @@ namespace sqlpp { - template + template struct prepared_select_t { - using _result_row_t = typename Select::_result_row_t; + using _result_row_t = typename Select::template _result_row_t; using _parameter_list_t = typename Select::_parameter_list_t; using _dynamic_names_t = typename Select::_dynamic_names_t; - using _prepared_statement_t = typename Db::_prepared_statement_t; + using _prepared_statement_t = typename Database::_prepared_statement_t; - auto _run(Db& db) const + auto _run(Database& db) const -> result_t { return {db.run_prepared_select(*this), _dynamic_names}; diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index 1a8df8c3..0249737a 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -41,13 +41,13 @@ namespace sqlpp template struct result_row_impl; - template - struct result_row_impl: - public NamedExpr::_name_t::template _member_t, - public result_row_impl + template + struct result_row_impl: + public NamedExpr::_name_t::template _member_t>, + public result_row_impl { - using _field = typename NamedExpr::_name_t::template _member_t; - using _rest = result_row_impl; + using _field = typename NamedExpr::_name_t::template _member_t>; + using _rest = result_row_impl; static constexpr size_t _last_index = _rest::_last_index; result_row_impl() = default; @@ -84,13 +84,13 @@ namespace sqlpp } }; - template - struct result_row_impl>, Rest...>: - public AliasProvider::_name_t::template _member_t>, // level prevents identical closures to be present twice in the inheritance tree - public result_row_impl + template + struct result_row_impl>, Rest...>: + public AliasProvider::_name_t::template _member_t>, // level prevents identical closures to be present twice in the inheritance tree + public result_row_impl { - using _multi_field = typename AliasProvider::_name_t::template _member_t>; - using _rest = result_row_impl; + using _multi_field = typename AliasProvider::_name_t::template _member_t>; + using _rest = result_row_impl; static constexpr size_t _last_index = _rest::_last_index; result_row_impl() = default; @@ -126,8 +126,8 @@ namespace sqlpp } }; - template - struct result_row_impl + template + struct result_row_impl { static constexpr size_t _last_index = index; result_row_impl() = default; @@ -155,10 +155,10 @@ namespace sqlpp }; } - template - struct result_row_t: public detail::result_row_impl<0, 0, NamedExpr...> + template + struct result_row_t: public detail::result_row_impl<0, 0, Db, NamedExpr...> { - using _impl = detail::result_row_impl<0, 0, NamedExpr...>; + using _impl = detail::result_row_impl<0, 0, Db, NamedExpr...>; bool _is_valid; static constexpr size_t _last_static_index = _impl::_last_index; @@ -221,11 +221,11 @@ namespace sqlpp } }; - template - struct dynamic_result_row_t: public detail::result_row_impl<0, 0, NamedExpr...> + template + struct dynamic_result_row_t: public detail::result_row_impl<0, 0, Db, NamedExpr...> { - using _impl = detail::result_row_impl<0, 0, NamedExpr...>; - using _field_type = detail::text::_result_entry_t; + using _impl = detail::result_row_impl<0, 0, Db, NamedExpr...>; + using _field_type = detail::text::_result_entry_t; static constexpr size_t _last_static_index = _impl::_last_index; bool _is_valid; diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 9ef444cf..44df0227 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -58,8 +58,8 @@ namespace sqlpp > struct select_helper_t { - static_assert(is_noop_t::value or sqlpp::is_select_column_list_t::value, "Yikes"); - static_assert(is_noop_t::value or sqlpp::is_from_t::value, "Yikes"); + static_assert(is_noop_t::value or sqlpp::is_select_column_list_t::value, "column list of select is neither naught nor a valid column list"); + static_assert(is_noop_t::value or sqlpp::is_from_t::value, "from() part of select is neither naught nor a valid from()"); using _value_type = typename std::conditional< sqlpp::is_from_t::value, typename ColumnList::_value_type, @@ -99,7 +99,8 @@ namespace sqlpp using _table_set = ::sqlpp::detail::type_set<>; using _column_list_t = ColumnList; - using _result_row_t = typename _column_list_t::_result_row_t; + template + using _result_row_t = typename _column_list_t::template _result_row_t; using _dynamic_names_t = typename _column_list_t::_dynamic_names_t; using _is_select = std::true_type; @@ -490,13 +491,19 @@ namespace sqlpp size_t get_no_of_result_columns() const { - return _result_row_t::static_size() + get_dynamic_names().size(); + return _column_list_t::static_size() + get_dynamic_names().size(); } template struct can_run_t { - //static_assert(is_where_t::value, "cannot select remove without having a where condition, use .where(true) to remove all rows"); + /* + static_assert(column_list::_table_set::template is_subset_t<_from_t::_table_set>::value + static_assert(detail::is_subset_of::value + subset_of_t sollte ein eigenes template sein, das macht so etwas wie obiges sicher einfacher lesbar + also: use any and all instead of and_t and or_t + */ + //static_assert(is_where_t::value, "cannot select select without having a where condition, use .where(true) to remove all rows"); //static_assert(not vendor::is_noop::value, "cannot run select without having selected anything"); //static_assert(is_from_t::value, "cannot run select without a from()"); //static_assert(is_where_t::value, "cannot run select without having a where condition, use .where(true) to select all rows"); @@ -509,7 +516,7 @@ namespace sqlpp // Execute template auto _run(Db& db) const - -> result_t + -> result_t> { static_assert(can_run_t::value, "Cannot execute select statement"); static_assert(_get_static_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead"); diff --git a/include/sqlpp11/serialize.h b/include/sqlpp11/serialize.h index 8ff650ef..34561439 100644 --- a/include/sqlpp11/serialize.h +++ b/include/sqlpp11/serialize.h @@ -38,6 +38,18 @@ namespace sqlpp return vendor::serializer_t::_(t, context); } + /* + namespace vendor // Required if you want to call serialize(sqlpp::value(7), printer), for instance + { + template + auto serialize(const T& t, Context& context) + -> decltype(vendor::serializer_t::_(t, context)) + { + return vendor::serializer_t::_(t, context); + } + } + */ + } #endif diff --git a/include/sqlpp11/serializer_context.h b/include/sqlpp11/serializer_context.h index 8e3ee35d..3a4ed724 100644 --- a/include/sqlpp11/serializer_context.h +++ b/include/sqlpp11/serializer_context.h @@ -42,15 +42,21 @@ namespace sqlpp return _os << t; } - void flush() + static std::string escape(std::string arg) { - _os << std::endl; - } - - std::string escape(std::string arg) - { -// FIXME: Need to do better escaping - return arg; + if (arg.find('\'')) + { + std::string retVal; + for (const auto c : arg) + { + if (c == '\'') + retVal.push_back(c); + retVal.push_back(c); + } + return retVal; + } + else + return arg; } std::ostream& _os; diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index 909074e4..ca694c0e 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -44,7 +44,7 @@ namespace sqlpp { using _table_set = detail::type_set; // Hint need a type_set here to be similar to a join (which always represents more than one table) static_assert(sizeof...(ColumnSpec), "at least one column required per table"); - using _required_insert_columns = typename detail::make_set_if...>::type; + using _required_insert_columns = typename detail::make_type_set_if...>::type; using _column_tuple_t = std::tuple...>; template using _alias_t = table_alias_t; diff --git a/include/sqlpp11/text.h b/include/sqlpp11/text.h index 33ad3f75..b16f4ea8 100644 --- a/include/sqlpp11/text.h +++ b/include/sqlpp11/text.h @@ -27,6 +27,7 @@ #ifndef SQLPP_TEXT_H #define SQLPP_TEXT_H +#include #include #include #include @@ -97,6 +98,7 @@ namespace sqlpp bool _is_null; }; + template struct _result_entry_t { _result_entry_t(): @@ -135,16 +137,29 @@ namespace sqlpp bool is_null() const { - if (not _is_valid) + if (connector_assert_result_validity_t::value) + assert(_is_valid); + else if (not _is_valid) throw exception("accessing is_null in non-existing row"); return _value_ptr == nullptr; } _cpp_value_type value() const { - if (not _is_valid) - throw exception("accessing value in non-existing row"); - if (_value_ptr) + const bool null_value = _value_ptr == nullptr and not NullIsTrivial and not connector_null_result_is_trivial_value_t::value; + if (connector_assert_result_validity_t::value) + { + assert(_is_valid); + assert(not null_value); + } + else + { + if (not _is_valid) + throw exception("accessing value in non-existing row"); + if (null_value) + throw exception("accessing value of NULL field"); + } + if (_value_ptr) return std::string(_value_ptr, _value_ptr + _len); else return ""; @@ -195,7 +210,8 @@ namespace sqlpp }; }; - inline std::ostream& operator<<(std::ostream& os, const text::_result_entry_t& e) + template + inline std::ostream& operator<<(std::ostream& os, const text::_result_entry_t& e) { return os << e.value(); } diff --git a/include/sqlpp11/tvin.h b/include/sqlpp11/tvin.h index cf6cbfa5..8cb96623 100644 --- a/include/sqlpp11/tvin.h +++ b/include/sqlpp11/tvin.h @@ -74,7 +74,7 @@ namespace sqlpp } template - struct tvin_wrap_t + struct maybe_tvin_t { using _table_set = typename T::_table_set; static constexpr bool _is_trivial() @@ -82,20 +82,20 @@ namespace sqlpp return false; } - tvin_wrap_t(T t): + maybe_tvin_t(T t): _value(t) {} - tvin_wrap_t(const tvin_wrap_t&) = default; - tvin_wrap_t(tvin_wrap_t&&) = default; - tvin_wrap_t& operator=(const tvin_wrap_t&) = default; - tvin_wrap_t& operator=(tvin_wrap_t&&) = default; - ~tvin_wrap_t() = default; + maybe_tvin_t(const maybe_tvin_t&) = default; + maybe_tvin_t(maybe_tvin_t&&) = default; + maybe_tvin_t& operator=(const maybe_tvin_t&) = default; + maybe_tvin_t& operator=(maybe_tvin_t&&) = default; + ~maybe_tvin_t() = default; T _value; }; template - struct tvin_wrap_t> + struct maybe_tvin_t> { using _table_set = typename T::_table_set; bool _is_trivial() const @@ -103,14 +103,14 @@ namespace sqlpp return _value._is_trivial(); }; - tvin_wrap_t(tvin_t t): + maybe_tvin_t(tvin_t t): _value(t._value) {} - tvin_wrap_t(const tvin_wrap_t&) = default; - tvin_wrap_t(tvin_wrap_t&&) = default; - tvin_wrap_t& operator=(const tvin_wrap_t&) = default; - tvin_wrap_t& operator=(tvin_wrap_t&&) = default; - ~tvin_wrap_t() = default; + maybe_tvin_t(const maybe_tvin_t&) = default; + maybe_tvin_t(maybe_tvin_t&&) = default; + maybe_tvin_t& operator=(const maybe_tvin_t&) = default; + maybe_tvin_t& operator=(maybe_tvin_t&&) = default; + ~maybe_tvin_t() = default; typename tvin_t::_operand_t _value; }; @@ -118,9 +118,9 @@ namespace sqlpp namespace vendor { template - struct serializer_t> + struct serializer_t> { - using T = tvin_wrap_t; + using T = maybe_tvin_t; static Context& _(const T& t, Context& context) { diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 52f7f90b..8ee87cfa 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -92,6 +92,7 @@ namespace sqlpp SQLPP_IS_COLUMN_TRAIT_GENERATOR(must_not_update); SQLPP_IS_COLUMN_TRAIT_GENERATOR(require_insert); SQLPP_IS_COLUMN_TRAIT_GENERATOR(can_be_null); + SQLPP_IS_COLUMN_TRAIT_GENERATOR(trivial_value_is_null); SQLPP_TYPE_TRAIT_GENERATOR(is_noop); SQLPP_TYPE_TRAIT_GENERATOR(is_table); @@ -123,7 +124,8 @@ namespace sqlpp SQLPP_TYPE_TRAIT_GENERATOR(requires_braces); SQLPP_TYPE_TRAIT_GENERATOR(is_parameter); - SQLPP_CONNECTOR_TRAIT_GENERATOR(has_empty_list_insert); + SQLPP_CONNECTOR_TRAIT_GENERATOR(null_result_is_trivial_value); + SQLPP_CONNECTOR_TRAIT_GENERATOR(assert_result_validity); template class IsTag> using copy_type_trait = typename std::conditional::value, std::true_type, std::false_type>::type; diff --git a/include/sqlpp11/update.h b/include/sqlpp11/update.h index 9173a969..5c8be581 100644 --- a/include/sqlpp11/update.h +++ b/include/sqlpp11/update.h @@ -57,8 +57,8 @@ namespace sqlpp typename Where = vendor::no_where_t> struct update_t { - static_assert(Table::_table_set::template is_superset_of::value, "updated columns do not match the table"); - static_assert(Table::_table_set::template is_superset_of::value, "where condition does not match updated table"); + static_assert(::sqlpp::detail::is_superset_of::value, "updated columns do not match the table"); + static_assert(::sqlpp::detail::is_superset_of::value, "where condition does not match updated table"); using _database_t = Database; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; diff --git a/include/sqlpp11/vendor/assignment.h b/include/sqlpp11/vendor/assignment.h index c0d288d9..c3e17156 100644 --- a/include/sqlpp11/vendor/assignment.h +++ b/include/sqlpp11/vendor/assignment.h @@ -38,6 +38,30 @@ namespace sqlpp { namespace vendor { + template + struct is_trivial_t + { + static constexpr bool _(const T&) + { + return false; + } + }; + + template + struct is_trivial_t::value, void>::type> + { + static bool _(const T& t) + { + return t._is_trivial(); + } + }; + + template + bool is_trivial(const T& t) + { + return is_trivial_t::_(t); + } + template struct assignment_t { @@ -45,9 +69,9 @@ namespace sqlpp using _column_t = Lhs; using value_type = Rhs; using _parameter_tuple_t = std::tuple<_column_t, Rhs>; - using _table_set = typename Lhs::_table_set::template join::type; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; - static_assert(not std::is_same::value or can_be_null_t<_column_t>::value, "column cannot be null"); + static_assert(can_be_null_t<_column_t>::value ? true : not std::is_same::value, "column must not be null"); assignment_t(_column_t lhs, value_type rhs): _lhs(lhs), @@ -71,9 +95,19 @@ namespace sqlpp static Context& _(const T& t, Context& context) { - serialize(simple_column(t._lhs), context); - context << "="; - serialize(t._rhs, context); + if ((trivial_value_is_null_t::value + and is_trivial_t::_(t._rhs)) + or (std::is_same::value)) + { + serialize(simple_column(t._lhs), context); + context << "=NULL"; + } + else + { + serialize(simple_column(t._lhs), context); + context << "="; + serialize(t._rhs, context); + } return context; } }; @@ -85,6 +119,7 @@ namespace sqlpp using _column_t = Lhs; using value_type = tvin_t; using _parameter_tuple_t = std::tuple<_column_t, Rhs>; + using _table_set = typename ::sqlpp::detail::make_joined_set::type; static_assert(can_be_null_t<_column_t>::value, "column cannot be null"); diff --git a/include/sqlpp11/vendor/concat.h b/include/sqlpp11/vendor/concat.h index 9d851da5..fb8e97b4 100644 --- a/include/sqlpp11/vendor/concat.h +++ b/include/sqlpp11/vendor/concat.h @@ -39,7 +39,7 @@ namespace sqlpp struct concat_t: public First::_value_type::template operators> { static_assert(sizeof...(Args) > 0, "concat requires two arguments at least"); - static_assert(sqlpp::detail::and_t::value, "at least one non-text argument detected in concat()"); + static_assert(sqlpp::detail::all_t::value, "at least one non-text argument detected in concat()"); using _table_set = typename ::sqlpp::detail::make_joined_set::type; struct _value_type: public First::_value_type::_base_value_type diff --git a/include/sqlpp11/vendor/expression.h b/include/sqlpp11/vendor/expression.h index 77f155be..455aebb7 100644 --- a/include/sqlpp11/vendor/expression.h +++ b/include/sqlpp11/vendor/expression.h @@ -58,7 +58,7 @@ namespace sqlpp ~binary_expression_t() = default; Lhs _lhs; - tvin_wrap_t _rhs; + maybe_tvin_t _rhs; }; template @@ -103,7 +103,7 @@ namespace sqlpp ~binary_expression_t() = default; Lhs _lhs; - tvin_wrap_t _rhs; + maybe_tvin_t _rhs; }; template @@ -209,6 +209,7 @@ namespace sqlpp { using _value_type = typename O::_value_type; using _parameter_tuple_t = std::tuple; + using _table_set = typename Rhs::_table_set; unary_expression_t(Rhs rhs): _rhs(rhs) diff --git a/include/sqlpp11/vendor/field.h b/include/sqlpp11/vendor/field.h index ca8847ec..a931df63 100644 --- a/include/sqlpp11/vendor/field.h +++ b/include/sqlpp11/vendor/field.h @@ -33,11 +33,12 @@ namespace sqlpp { namespace vendor { - template + template struct field_t { using _name_t = NameType; using _value_type = ValueType; + static constexpr bool _trivial_value_is_null = TrivialValueIsNull; }; template @@ -50,7 +51,9 @@ namespace sqlpp template struct make_field_t_impl { - using type = field_t; + using type = field_t::value>; }; template diff --git a/include/sqlpp11/vendor/from.h b/include/sqlpp11/vendor/from.h index ce9dc50b..87ae0c7a 100644 --- a/include/sqlpp11/vendor/from.h +++ b/include/sqlpp11/vendor/from.h @@ -49,7 +49,7 @@ namespace sqlpp // FIXME: Joins contain two tables. This is not being dealt with at the moment when looking at duplicates, for instance static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in from()"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a table or join in from()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a table or join in from()"); using _table_set = typename ::sqlpp::detail::make_joined_set; diff --git a/include/sqlpp11/vendor/group_by.h b/include/sqlpp11/vendor/group_by.h index d67764b7..cefd2c8d 100644 --- a/include/sqlpp11/vendor/group_by.h +++ b/include/sqlpp11/vendor/group_by.h @@ -51,7 +51,7 @@ namespace sqlpp static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in group_by()"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an expression in group_by()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not an expression in group_by()"); group_by_t(Expressions... expressions): _expressions(expressions...) diff --git a/include/sqlpp11/vendor/having.h b/include/sqlpp11/vendor/having.h index 0a3fd34e..904e13d8 100644 --- a/include/sqlpp11/vendor/having.h +++ b/include/sqlpp11/vendor/having.h @@ -47,7 +47,7 @@ namespace sqlpp using _parameter_tuple_t = std::tuple; static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in having()"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an expression in having()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not an expression in having()"); using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; diff --git a/include/sqlpp11/vendor/insert_value_list.h b/include/sqlpp11/vendor/insert_value_list.h index 74ffecdc..c04ed95a 100644 --- a/include/sqlpp11/vendor/insert_value_list.h +++ b/include/sqlpp11/vendor/insert_value_list.h @@ -61,15 +61,15 @@ namespace sqlpp static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in set()"); - static_assert(sqlpp::detail::and_t::value, "at least one argument is not an assignment in set()"); + static_assert(sqlpp::detail::all_t::value, "at least one argument is not an assignment in set()"); - static_assert(not sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); + static_assert(not sqlpp::detail::any_t::value, "at least one assignment is prohibited by its column definition in set()"); using _column_table_set = typename ::sqlpp::detail::make_joined_set::type; using _value_table_set = typename ::sqlpp::detail::make_joined_set::type; using _table_set = typename ::sqlpp::detail::make_joined_set<_column_table_set, _value_table_set>::type; static_assert(sizeof...(Assignments) ? (_column_table_set::size::value == 1) : true, "set() contains assignments for tables from several columns"); - static_assert(_value_table_set::template is_subset_of<_column_table_set>::value, "set() contains values from foreign tables"); + static_assert(::sqlpp::detail::is_subset_of<_value_table_set, _column_table_set>::value, "set() contains values from foreign tables"); insert_list_t(Assignments... assignment): _assignments(assignment...), @@ -90,8 +90,8 @@ namespace sqlpp static_assert(not must_not_insert_t::value, "add_set() argument must not be used in insert"); using _column_table_set = typename Assignment::_column_t::_table_set; using _value_table_set = typename Assignment::value_type::_table_set; - static_assert(_value_table_set::template is_subset_of::value, "add_set() contains a column from a foreign table"); - static_assert(_column_table_set::template is_subset_of::value, "add_set() contains a value from a foreign table"); + static_assert(::sqlpp::detail::is_subset_of<_value_table_set, typename Insert::_table_set>::value, "add_set() contains a column from a foreign table"); + static_assert(::sqlpp::detail::is_subset_of<_column_table_set, typename Insert::_table_set>::value, "add_set() contains a value from a foreign table"); _dynamic_columns.emplace_back(simple_column_t{assignment._lhs}); _dynamic_values.emplace_back(assignment._rhs); } @@ -114,9 +114,9 @@ namespace sqlpp static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in columns()"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a column in columns()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a column in columns()"); - static_assert(not ::sqlpp::detail::or_t::value, "at least one column argument has a must_not_insert flag in its definition"); + static_assert(not ::sqlpp::detail::any_t::value, "at least one column argument has a must_not_insert flag in its definition"); using _value_tuple_t = std::tuple...>; using _table_set = typename ::sqlpp::detail::make_joined_set::type; @@ -136,7 +136,7 @@ namespace sqlpp template void add_values(Assignments... assignments) { - static_assert(::sqlpp::detail::and_t::value, "add_values() arguments have to be assignments"); + static_assert(::sqlpp::detail::all_t::value, "add_values() arguments have to be assignments"); using _arg_value_tuple = std::tuple...>; using _args_correct = std::is_same<_arg_value_tuple, _value_tuple_t>; static_assert(_args_correct::value, "add_values() arguments do not match columns() arguments"); diff --git a/include/sqlpp11/vendor/interpretable.h b/include/sqlpp11/vendor/interpretable.h index d919406d..17c4676c 100644 --- a/include/sqlpp11/vendor/interpretable.h +++ b/include/sqlpp11/vendor/interpretable.h @@ -59,9 +59,13 @@ namespace sqlpp return _impl->serialize(context); } - _serializer_context_t& serialize(_serializer_context_t& context) const + // This method only exists if Db::_serializer_context_t and sqlpp::serializer_context_t are not the same + template + auto serialize(Context& context) const + -> typename std::enable_if::value + and not std::is_same::value, Context&>::type { - return _impl->serialize(context); + return _impl->db_serialize(context); } _interpreter_context_t& interpret(_interpreter_context_t& context) const @@ -73,7 +77,7 @@ namespace sqlpp struct _impl_base { virtual sqlpp::serializer_context_t& serialize(sqlpp::serializer_context_t& context) const = 0; - virtual _serializer_context_t& serialize(_serializer_context_t& context) const = 0; + virtual _serializer_context_t& db_serialize(_serializer_context_t& context) const = 0; virtual _interpreter_context_t& interpret(_interpreter_context_t& context) const = 0; }; @@ -91,7 +95,7 @@ namespace sqlpp return context; } - _serializer_context_t& serialize(_serializer_context_t& context) const + _serializer_context_t& db_serialize(_serializer_context_t& context) const { Db::_serialize_interpretable(_t, context); return context; diff --git a/include/sqlpp11/vendor/named_interpretable.h b/include/sqlpp11/vendor/named_interpretable.h index 69de2d21..f3aa2fdc 100644 --- a/include/sqlpp11/vendor/named_interpretable.h +++ b/include/sqlpp11/vendor/named_interpretable.h @@ -57,9 +57,13 @@ namespace sqlpp return _impl->serialize(context); } - _serializer_context_t& serialize(_serializer_context_t& context) const + // This method only exists if Db::_serializer_context_t and sqlpp::serializer_context_t are not the same + template + auto serialize(Context& context) const + -> typename std::enable_if::value + and not std::is_same::value, Context&>::type { - return _impl->serialize(context); + return _impl->db_serialize(context); } _interpreter_context_t& interpret(_interpreter_context_t& context) const @@ -76,7 +80,7 @@ namespace sqlpp struct _impl_base { virtual sqlpp::serializer_context_t& serialize(sqlpp::serializer_context_t& context) const = 0; - virtual _serializer_context_t& serialize(_serializer_context_t& context) const = 0; + virtual _serializer_context_t& db_serialize(_serializer_context_t& context) const = 0; virtual _interpreter_context_t& interpret(_interpreter_context_t& context) const = 0; virtual std::string _get_name() const = 0; }; @@ -95,7 +99,7 @@ namespace sqlpp return context; } - _serializer_context_t& serialize(_serializer_context_t& context) const + _serializer_context_t& db_serialize(_serializer_context_t& context) const { Db::_serialize_interpretable(_t, context); return context; diff --git a/include/sqlpp11/vendor/order_by.h b/include/sqlpp11/vendor/order_by.h index 391bd1dc..a96813c7 100644 --- a/include/sqlpp11/vendor/order_by.h +++ b/include/sqlpp11/vendor/order_by.h @@ -49,7 +49,7 @@ namespace sqlpp static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in order_by()"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a sort order expression in order_by()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a sort order expression in order_by()"); order_by_t(Expressions... expressions): _expressions(expressions...) diff --git a/include/sqlpp11/vendor/select_column_list.h b/include/sqlpp11/vendor/select_column_list.h index 53f4f79e..d3dd2130 100644 --- a/include/sqlpp11/vendor/select_column_list.h +++ b/include/sqlpp11/vendor/select_column_list.h @@ -143,7 +143,7 @@ namespace sqlpp template using is_valid_expression_t = std::integral_constant::value or is_multi_column_t::value>; - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a named expression"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a named expression"); static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate name detected"); @@ -156,9 +156,10 @@ namespace sqlpp }; using _name_t = typename ::sqlpp::detail::get_first_argument_if_unique::_name_t; + template using _result_row_t = typename std::conditional<_is_dynamic::value, - dynamic_result_row_t...>, - result_row_t...>>::type; + dynamic_result_row_t...>, + result_row_t...>>::type; using _dynamic_names_t = typename dynamic_select_column_list::_names_t; @@ -198,7 +199,8 @@ namespace sqlpp struct no_select_column_list_t { using _is_noop = std::true_type; - using _result_row_t = ::sqlpp::result_row_t<>; + template + using _result_row_t = ::sqlpp::result_row_t; using _dynamic_names_t = typename dynamic_select_column_list::_names_t; using _value_type = no_value_t; struct _name_t {}; diff --git a/include/sqlpp11/vendor/select_flag_list.h b/include/sqlpp11/vendor/select_flag_list.h index ea4ce0db..54975094 100644 --- a/include/sqlpp11/vendor/select_flag_list.h +++ b/include/sqlpp11/vendor/select_flag_list.h @@ -49,7 +49,7 @@ namespace sqlpp static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in select flag list"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not a select flag in select flag list"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a select flag in select flag list"); select_flag_list_t(Flags... flags): _flags(flags...) diff --git a/include/sqlpp11/vendor/update_list.h b/include/sqlpp11/vendor/update_list.h index bd4530e0..f2684628 100644 --- a/include/sqlpp11/vendor/update_list.h +++ b/include/sqlpp11/vendor/update_list.h @@ -48,15 +48,15 @@ namespace sqlpp static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in set()"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an assignment in set()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not an assignment in set()"); - static_assert(not ::sqlpp::detail::or_t::value, "at least one assignment is prohibited by its column definition in set()"); + static_assert(not ::sqlpp::detail::any_t::value, "at least one assignment is prohibited by its column definition in set()"); using _column_table_set = typename ::sqlpp::detail::make_joined_set::type; using _value_table_set = typename ::sqlpp::detail::make_joined_set::type; using _table_set = typename ::sqlpp::detail::make_joined_set<_column_table_set, _value_table_set>::type; static_assert(sizeof...(Assignments) ? (_column_table_set::size::value == 1) : true, "set() contains assignments for tables from several columns"); - static_assert(_value_table_set::template is_subset_of<_column_table_set>::value, "set() contains values from foreign tables"); + static_assert(::sqlpp::detail::is_subset_of<_value_table_set, _column_table_set>::value, "set() contains values from foreign tables"); update_list_t(Assignments... assignments): _assignments(assignments...) diff --git a/include/sqlpp11/vendor/using.h b/include/sqlpp11/vendor/using.h index 3ef79454..940cfca9 100644 --- a/include/sqlpp11/vendor/using.h +++ b/include/sqlpp11/vendor/using.h @@ -49,7 +49,7 @@ namespace sqlpp static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in using()"); - static_assert(::sqlpp::detail::and_t::value, "at least one argument is not an table in using()"); + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not an table in using()"); using_t(Tables... tables): _tables(tables...) diff --git a/include/sqlpp11/vendor/where.h b/include/sqlpp11/vendor/where.h index 63cf763b..2177ec59 100644 --- a/include/sqlpp11/vendor/where.h +++ b/include/sqlpp11/vendor/where.h @@ -47,8 +47,8 @@ namespace sqlpp using _parameter_tuple_t = std::tuple; static_assert(_is_dynamic::value or sizeof...(Expressions), "at least one expression argument required in where()"); - static_assert(not sqlpp::detail::or_t::value, "at least one argument is an assignment in where()"); - static_assert(sqlpp::detail::and_t::value, "at least one argument is not valid expression in where()"); + static_assert(not sqlpp::detail::any_t::value, "at least one argument is an assignment in where()"); + static_assert(sqlpp::detail::all_t::value, "at least one argument is not valid expression in where()"); using _parameter_list_t = typename make_parameter_list_t<_parameter_tuple_t>::type; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8d04a9e3..350602ec 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,6 +11,7 @@ build_and_run(InsertTest) build_and_run(RemoveTest) build_and_run(UpdateTest) build_and_run(SelectTest) +build_and_run(SelectTypeTest) build_and_run(FunctionTest) build_and_run(PreparedTest) diff --git a/tests/FunctionTest.cpp b/tests/FunctionTest.cpp index 632875b0..1b37be29 100644 --- a/tests/FunctionTest.cpp +++ b/tests/FunctionTest.cpp @@ -32,7 +32,7 @@ #include -DbMock db = {}; +MockDb db = {}; SQLPP_ALIAS_PROVIDER(kaesekuchen); int main() diff --git a/tests/InsertTest.cpp b/tests/InsertTest.cpp index dd7ce4d0..ebe64982 100644 --- a/tests/InsertTest.cpp +++ b/tests/InsertTest.cpp @@ -29,8 +29,8 @@ #include #include -DbMock db; -DbMock::_serializer_context_t printer(std::cerr); +MockDb db; +MockDb::_serializer_context_t printer; int main() { @@ -58,16 +58,22 @@ int main() static_assert(sqlpp::is_regular::value, "type requirement"); } - serialize(insert_into(t).default_values(), printer).flush(); - serialize(insert_into(t), printer).flush(); - serialize(insert_into(t).set(t.beta = "kirschauflauf"), printer).flush(); - serialize(insert_into(t).columns(t.beta), printer).flush(); + db(insert_into(t).default_values()); + db(insert_into(t).set(t.beta = "kirschauflauf")); + + serialize(insert_into(t).default_values(), printer).str(); + + serialize(insert_into(t), printer).str(); + serialize(insert_into(t).set(t.beta = "kirschauflauf"), printer).str(); + serialize(insert_into(t).columns(t.beta), printer).str(); auto multi_insert = insert_into(t).columns(t.beta, t.delta); multi_insert.add_values(t.beta = "cheesecake", t.delta = 1); multi_insert.add_values(t.beta = sqlpp::default_value, t.delta = sqlpp::default_value); auto i = dynamic_insert_into(db, t).dynamic_set(); i.add_set(t.beta = "kirschauflauf"); - serialize(i, printer).flush(); + serialize(i, printer).str(); + + db(multi_insert); return 0; } diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 29b66dd4..1f02f33d 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -34,8 +34,8 @@ #include -DbMock db = {}; -DbMock::_serializer_context_t printer(std::cerr); +MockDb db = {}; +MockDb::_serializer_context_t printer; SQLPP_ALIAS_PROVIDER(kaesekuchen); int main() @@ -43,122 +43,123 @@ int main() test::TabFoo f; test::TabBar t; - serialize(insert_into(t).columns(t.beta, t.gamma), printer).flush(); + serialize(insert_into(t).columns(t.beta, t.gamma), printer).str(); { auto i = insert_into(t).columns(t.gamma, t.beta); i.add_values(t.gamma = true, t.beta = "cheesecake"); - serialize(i, printer).flush(); + serialize(i, printer).str(); i.add_values(t.gamma = false, t.beta = sqlpp::tvin("coffee")); i.add_values(t.gamma = false, t.beta = sqlpp::tvin(std::string())); - serialize(i, printer).flush(); + serialize(i, printer).str(); i.add_values(t.gamma = sqlpp::default_value, t.beta = sqlpp::null); - serialize(i, printer).flush(); + serialize(i, printer).str(); } - serialize(t.alpha = sqlpp::null, printer).flush(); - serialize(t.alpha = sqlpp::default_value, printer).flush(); - serialize(t.alpha, printer).flush(); - serialize(-t.alpha, printer).flush(); - serialize(+t.alpha, printer).flush(); - serialize(-(t.alpha + 7), printer).flush(); - serialize(t.alpha = 0, printer).flush(); - serialize(t.alpha = sqlpp::tvin(0), printer).flush(); - serialize(t.alpha == 0, printer).flush(); - serialize(t.alpha == sqlpp::tvin(0), printer).flush(); - serialize(t.alpha != 0, printer).flush(); - serialize(t.gamma != sqlpp::tvin(false), printer).flush(); - serialize(t.alpha == 7, printer).flush(); - serialize(t.beta + "kaesekuchen", printer).flush(); + serialize(t.alpha = sqlpp::null, printer).str(); + serialize(t.alpha = sqlpp::default_value, printer).str(); + serialize(t.alpha, printer).str(); + serialize(-t.alpha, printer).str(); + serialize(+t.alpha, printer).str(); + serialize(-(t.alpha + 7), printer).str(); + serialize(t.alpha = 0, printer).str(); + serialize(t.alpha = sqlpp::tvin(0), printer).str(); + serialize(t.alpha == 0, printer).str(); + serialize(t.alpha == sqlpp::tvin(0), printer).str(); + serialize(t.alpha != 0, printer).str(); + serialize(t.gamma != sqlpp::tvin(false), printer).str(); + serialize(t.alpha == 7, printer).str(); + serialize(t.beta + "kaesekuchen", printer).str(); - serialize(sqlpp::select(), printer).flush(); - serialize(sqlpp::select().flags(sqlpp::distinct), printer).flush(); - serialize(select(t.alpha, t.beta).flags(sqlpp::distinct), printer).flush(); - serialize(select(t.alpha, t.beta), printer).flush(); - serialize(select(t.alpha, t.beta).from(t), printer).flush(); - serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3), printer).flush(); - serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma), printer).flush(); - serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")), printer).flush(); - serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()), printer).flush(); - serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()).limit(17).offset(3), printer).flush(); + serialize(sqlpp::select(), printer).str(); + serialize(sqlpp::select().flags(sqlpp::distinct), printer).str(); + serialize(select(t.alpha, t.beta).flags(sqlpp::distinct), printer).str(); + serialize(select(t.alpha, t.beta), printer).str(); + serialize(select(t.alpha, t.beta).from(t), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()), printer).str(); + serialize(select(t.alpha, t.beta).from(t).where(t.alpha == 3).group_by(t.gamma).having(t.beta.like("%kuchen")).order_by(t.beta.asc()).limit(17).offset(3), printer).str(); - serialize(parameter(sqlpp::bigint(), t.alpha), printer).flush(); - serialize(parameter(t.alpha), printer).flush(); - serialize(t.alpha == parameter(t.alpha), printer).flush(); - serialize(t.alpha == parameter(t.alpha) and (t.beta + "gimmick").like(parameter(t.beta)), printer).flush(); + serialize(parameter(sqlpp::bigint(), t.alpha), printer).str(); + serialize(parameter(t.alpha), printer).str(); + serialize(t.alpha == parameter(t.alpha), printer).str(); + serialize(t.alpha == parameter(t.alpha) and (t.beta + "gimmick").like(parameter(t.beta)), printer).str(); - serialize(insert_into(t), printer).flush(); - serialize(insert_into(f).default_values(), printer).flush(); - serialize(insert_into(t).set(t.gamma = true), printer).flush(); - //serialize(insert_into(t).set(t.gamma = sqlpp::tvin(false)), printer).flush(); cannot test this since gamma cannot be null and a static assert is thrown + serialize(insert_into(t), printer).str(); + serialize(insert_into(f).default_values(), printer).str(); + serialize(insert_into(t).set(t.gamma = true), printer).str(); + //serialize(insert_into(t).set(t.gamma = sqlpp::tvin(false)), printer).str(); cannot test this since gamma cannot be null and a static assert is thrown - serialize(update(t), printer).flush(); - serialize(update(t).set(t.gamma = true), printer).flush(); - serialize(update(t).set(t.gamma = true).where(t.beta.in("kaesekuchen", "cheesecake")), printer).flush(); + serialize(update(t), printer).str(); + serialize(update(t).set(t.gamma = true), printer).str(); + serialize(update(t).set(t.gamma = true).where(t.beta.in("kaesekuchen", "cheesecake")), printer).str(); - serialize(remove_from(t), printer).flush(); - serialize(remove_from(t).using_(t), printer).flush(); - serialize(remove_from(t).where(t.alpha == sqlpp::tvin(0)), printer).flush(); - serialize(remove_from(t).using_(t).where(t.alpha == sqlpp::tvin(0)), printer).flush(); + serialize(remove_from(t), printer).str(); + serialize(remove_from(t).using_(t), printer).str(); + serialize(remove_from(t).where(t.alpha == sqlpp::tvin(0)), printer).str(); + serialize(remove_from(t).using_(t).where(t.alpha == sqlpp::tvin(0)), printer).str(); // functions - serialize(sqlpp::value(7), printer).flush(); - serialize(sqlpp::verbatim("irgendwas integrales"), printer).flush(); - serialize(sqlpp::value_list(std::vector({1,2,3,4,5,6,8})), printer).flush(); - serialize(exists(select(t.alpha).from(t)), printer).flush(); - serialize(any(select(t.alpha).from(t)), printer).flush(); - serialize(some(select(t.alpha).from(t)), printer).flush(); - serialize(count(t.alpha), printer).flush(); - serialize(min(t.alpha), printer).flush(); - serialize(max(t.alpha), printer).flush(); - serialize(avg(t.alpha), printer).flush(); - serialize(sum(t.alpha), printer).flush(); - serialize(sqlpp::verbatim_table("whatever"), printer).flush(); + sqlpp::serialize(sqlpp::value(7), printer).str();// FIXME: Maybe the vendor namespace is not a good idea? argument lives in namespace vendor + 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(); + serialize(some(select(t.alpha).from(t)), printer).str(); + serialize(count(t.alpha), printer).str(); + serialize(min(t.alpha), printer).str(); + serialize(max(t.alpha), printer).str(); + serialize(avg(t.alpha), printer).str(); + serialize(sum(t.alpha), printer).str(); + serialize(sqlpp::verbatim_table("whatever"), printer).str(); // alias - serialize(t.as(t.alpha), printer).flush(); - serialize(t.as(t.alpha).beta, printer).flush(); + serialize(t.as(t.alpha), printer).str(); + serialize(t.as(t.alpha).beta, printer).str(); // select alias - serialize(select(t.alpha).from(t).where(t.beta > "kaesekuchen").as(t.gamma), printer).flush(); + serialize(select(t.alpha).from(t).where(t.beta > "kaesekuchen").as(t.gamma), printer).str(); - serialize(t.alpha.is_null(), printer).flush(); + serialize(t.alpha.is_null(), printer).str(); // join - serialize(t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta), printer).flush(); + serialize(t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta), printer).str(); // multi_column - serialize(multi_column(t.alpha, (t.beta + "cake").as(t.gamma)).as(t.alpha), printer).flush(); - serialize(multi_column(all_of(t)).as(t), printer).flush(); - serialize(all_of(t).as(t), printer).flush(); + serialize(multi_column(t.alpha, (t.beta + "cake").as(t.gamma)).as(t.alpha), printer).str(); + serialize(multi_column(all_of(t)).as(t), printer).str(); + serialize(all_of(t).as(t), printer).str(); // dynamic select { auto s = dynamic_select(db).dynamic_flags().dynamic_columns(); s.add_column(t.beta); s.add_column(t.gamma); - serialize(s, printer).flush(); + serialize(s, printer).str(); } { auto s = dynamic_select(db).dynamic_flags().dynamic_columns(); s.add_flag(sqlpp::distinct); s.add_column(t.beta); s.add_column(t.gamma); - serialize(s, printer).flush(); + serialize(s, printer).str(); } { auto s = dynamic_select(db).dynamic_flags(sqlpp::distinct).dynamic_columns(t.alpha); s.add_flag(sqlpp::all); s.add_column(t.beta); s.add_column(t.gamma); - serialize(s, printer).flush(); + serialize(s, printer).str(); } // distinct aggregate - serialize(count(sqlpp::distinct, t.alpha % 7), printer).flush(); - serialize(avg(sqlpp::distinct, t.alpha - 7), printer).flush(); - serialize(sum(sqlpp::distinct, t.alpha + 7), printer).flush(); + serialize(count(sqlpp::distinct, t.alpha % 7), printer).str(); + serialize(avg(sqlpp::distinct, t.alpha - 7), printer).str(); + serialize(sum(sqlpp::distinct, t.alpha + 7), printer).str(); + + serialize(select(all_of(t)).from(t).where(true), printer).str(); + serialize(select(all_of(t)).from(t).where(false), printer).str(); - serialize(select(all_of(t)).from(t).where(true), printer).flush(); - serialize(select(all_of(t)).from(t).where(false), printer).flush(); return 0; } diff --git a/tests/MockDb.h b/tests/MockDb.h index 8d377a78..4cd8b384 100644 --- a/tests/MockDb.h +++ b/tests/MockDb.h @@ -24,17 +24,38 @@ */ #ifndef SQLPP_MOCK_DB_H -#define SQLPP_MOCK_DB_H +#define SQLPP_MOCK_DB_H -#include +#include #include -#include +#include -struct DbMock: public sqlpp::connection +struct MockDb: public sqlpp::connection { - struct _serializer_context_t : public sqlpp::serializer_context_t + struct _serializer_context_t { - _serializer_context_t(std::ostream& os): sqlpp::serializer_context_t(os) {} + std::ostringstream _os; + + std::string str() const + { + return _os.str(); + } + + void reset() + { + _os.clear(); + } + + template + std::ostream& operator<<(T t) + { + return _os << t; + } + + static std::string escape(std::string arg) + { + return sqlpp::serializer_context_t::escape(arg); + } }; using _interpreter_context_t = _serializer_context_t; @@ -42,14 +63,97 @@ struct DbMock: public sqlpp::connection template static _serializer_context_t& _serialize_interpretable(const T& t, _serializer_context_t& context) { - return ::sqlpp::serialize(t, context); + sqlpp::serialize(t, context); + return context; } template - static _interpreter_context_t& _interpret_interpretable(const T& t, _interpreter_context_t& context) + static _serializer_context_t& _interpret_interpretable(const T& t, _interpreter_context_t& context) { - return ::sqlpp::serialize(t, context); + sqlpp::serialize(t, context); + return context; } + + class result_t + { + public: + constexpr bool operator==(const result_t& rhs) const + { + return true; + } + + template + void next(ResultRow& result_row) + { + result_row.invalidate(); + }; + }; + + // Directly executed statements start here + template + auto operator() (const T& t) -> decltype(t._run(*this)) + { + return t._run(*this); + } + + template + size_t insert(const Insert& x) + { + return 0; + } + + template + size_t update(const Update& x) + { + return 0; + } + + template + size_t remove(const Remove& x) + { + return 0; + } + + template + result_t select(const Select& s) + { + return {}; + } + + // Prepared statements start here + using _prepared_statement_t = std::nullptr_t; + + template + auto prepare(const T& t) -> decltype(t._prepare(*this)) + { + return t._prepare(*this); + } + + + template + _prepared_statement_t prepare_insert(Insert& x) + { + return nullptr; + } + + template + size_t run_prepared_insert(const PreparedInsert& x) + { + return 0; + } + + template + _prepared_statement_t prepare_select(Select& x) + { + return nullptr; + } + + template + result_t run_prepared_select(PreparedSelect& x) + { + return {}; + } + }; #endif diff --git a/tests/PreparedTest.cpp b/tests/PreparedTest.cpp index 2dc53876..b39b037c 100644 --- a/tests/PreparedTest.cpp +++ b/tests/PreparedTest.cpp @@ -31,7 +31,7 @@ #include -DbMock db = {}; +MockDb db = {}; int main() { @@ -88,6 +88,7 @@ int main() // Wonderful, now take a look at the parameter list of a select { auto s = select(all_of(t)).from(t).where(t.beta.like(parameter(t.beta)) and t.alpha == parameter(t.alpha) or t.gamma != parameter(t.gamma)); + auto p = db.prepare(s); using S = decltype(s); using T = sqlpp::make_parameter_list_t::type; T npl; diff --git a/tests/RemoveTest.cpp b/tests/RemoveTest.cpp index 625a49c6..48485886 100644 --- a/tests/RemoveTest.cpp +++ b/tests/RemoveTest.cpp @@ -30,8 +30,8 @@ #include "is_regular.h" -DbMock db; -DbMock::_serializer_context_t printer(std::cerr); +MockDb db; +MockDb::_serializer_context_t printer; int main() { @@ -56,13 +56,15 @@ int main() static_assert(sqlpp::is_regular::value, "type requirement"); } - serialize(remove_from(t), printer).flush(); - serialize(remove_from(t).where(t.beta != "transparent"), printer).flush(); - serialize(remove_from(t).using_(t), printer).flush(); + serialize(remove_from(t), printer).str(); + serialize(remove_from(t).where(t.beta != "transparent"), printer).str(); + serialize(remove_from(t).using_(t), printer).str(); auto r = dynamic_remove_from(db, t).dynamic_using().dynamic_where(); r.add_using(t); r.add_where(t.beta != "transparent"); - serialize(r, printer).flush(); + serialize(r, printer).str(); + + db(r); return 0; } diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 6c5bc922..194cd800 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -33,8 +33,8 @@ #include -DbMock db = {}; -DbMock::_serializer_context_t printer(std::cerr); +MockDb db = {}; +MockDb::_serializer_context_t printer; namespace alias { @@ -49,323 +49,26 @@ int main() test::TabFoo f; test::TabBar t; - // Test a table + for (const auto& row : db(select(all_of(t)).from(t).where(true))) { - using T = decltype(t); - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_integral_t::value, "type requirement"); - static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); + int64_t a = row.alpha; + const std::string b = row.beta; } - // Test an alias of table + for (const auto& row : db(select(all_of(t).as(t)).from(t).where(true))) { - using T = decltype(t.as(alias::a)); - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_integral_t::value, "type requirement"); - static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(sqlpp::is_alias_t::value, "type requirement"); - static_assert(sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); + int64_t a = row.tabBar.alpha; + const std::string b = row.tabBar.beta; } - // Test an integral column of an alias of table +#warning this should fail because f is not in from() + for (const auto& row : db(select(f.omega, all_of(t).as(t), t.gamma).from(t).where(true))) { - using T = decltype(t.as(alias::a).alpha); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_integral_t::value, "type requirement"); - static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); + int64_t a = row.tabBar.alpha; + const std::string b = row.tabBar.beta; + const bool g = row.gamma; + const float o = row.omega; } - - // Test an integral table column - { - using T = decltype(t.alpha); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_integral_t::value, "type requirement"); - static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test a floating point table column - { - using T = decltype(f.omega); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_integral_t::value, "type requirement"); - static_assert(sqlpp::is_floating_point_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test a an alias of a numeric table column - { - using T = decltype(t.alpha.as(alias::a)); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test a select of a single column without a from - { - using T = decltype(select(t.alpha)); // Hint: The current rule is pretty crude (a from is required), but certainly better than nothing - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test a select of a single numeric table column - { - using T = decltype(select(t.alpha).from(t)); - static_assert(sqlpp::is_select_column_list_t::value, "Must not be noop"); - static_assert(sqlpp::is_from_t::value, "Must not be noop"); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test a select of an alias of a single numeric table column - { - using T = decltype(select(t.alpha.as(alias::a)).from(t)); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test an alias of a select of a single numeric table column - { - using T = decltype(select(t.alpha).from(t).as(alias::b)); - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "red to not be boolean"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(sqlpp::is_alias_t::value, "type requirement"); - static_assert(sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test the column of an alias of a select of an alias of a single numeric table column - { - using T = decltype(select(t.alpha.as(alias::a)).from(t).as(alias::b)); - static_assert(not sqlpp::is_numeric_t::value, "type requirement"); - static_assert(not sqlpp::is_expression_t::value, "type requirement"); - static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(sqlpp::is_alias_t::value, "type requirement"); - static_assert(sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test the column of an alias of a select of a single numeric table column - { - using T = decltype(select(t.alpha).from(t).as(alias::b).alpha); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test an alias of a select of an alias of a single numeric table column - { - using T = decltype(select(t.alpha.as(alias::a)).from(t).as(alias::b).a); - static_assert(sqlpp::is_numeric_t::value, "type requirement"); - static_assert(sqlpp::is_expression_t::value, "type requirement"); - static_assert(sqlpp::is_named_expression_t::value, "type requirement"); - static_assert(not sqlpp::require_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); - static_assert(not sqlpp::must_not_update_t::value, "type requirement"); - static_assert(not sqlpp::is_boolean_t::value, "type requirement"); - static_assert(not sqlpp::is_text_t::value, "type requirement"); - static_assert(not sqlpp::is_alias_t::value, "type requirement"); - static_assert(not sqlpp::is_table_t::value, "type requirement"); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test that select(all_of(tab)) is expanded in select - { - auto a = select(all_of(t)); - auto b = select(t.alpha, t.beta, t.gamma, t.delta); - //auto c = select(t); - static_assert(std::is_same::value, "all_of(t) has to be expanded by select()"); - //static_assert(std::is_same::value, "t has to be expanded by select()"); - } - - // Test that select(all_of(tab)) is expanded in multi_column - { - auto a = multi_column(all_of(t)).as(alias::a); - auto b = multi_column(t.alpha, t.beta, t.gamma, t.delta).as(alias::a); - static_assert(std::is_same::value, "all_of(t) has to be expanded by multi_column"); - } - - // Test that a multicolumn is not a value - { - auto m = multi_column(t.alpha, t.beta).as(alias::a); - auto a = select(m).from(t).as(alias::b).a; - static_assert(not sqlpp::is_value_t::value, "a multi_column is not a value"); - } - // Test that result sets with identical name/value combinations have identical types - { - auto a = select(t.alpha); - auto b = select(f.epsilon.as(t.alpha)); - using A = typename decltype(a)::_result_row_t; - using B = typename decltype(b)::_result_row_t; - static_assert(std::is_same< - decltype(t.alpha)::_value_type::_base_value_type, - decltype(f.epsilon)::_value_type::_base_value_type>::value, "Two bigint columns must have identical base_value_type"); - static_assert(std::is_same::value, "select with identical columns(name/value_type) need to have identical result_types"); - } - - { - auto s = dynamic_select(db, all_of(t)).dynamic_from().dynamic_where().dynamic_limit().dynamic_offset(); - s.add_from(t); - s.add_where(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3))); - s.set_limit(30); - s.set_limit(3); - std::cerr << "------------------------\n"; - serialize(s, printer).flush(); - std::cerr << "------------------------\n"; - using T = decltype(s); - static_assert(sqlpp::is_regular::value, "type requirement"); - } - - // Test that select can be called with zero columns if it is used with dynamic columns. - { - auto s = dynamic_select(db).dynamic_columns(); - s.add_column(t.alpha); - serialize(s, printer).flush(); - } - - // Test that verbatim_table compiles - { - auto s = select(t.alpha).from(sqlpp::verbatim_table("my_unknown_table")); - serialize(s, printer).flush(); - } - - - static_assert(sqlpp::is_select_flag_t::value, "sqlpp::all has to be a select_flag"); - using T = sqlpp::vendor::wrap_operand::type; - static_assert(sqlpp::is_regular::value, "type requirement"); - static_assert(T::_is_expression, "T has to be an expression"); - static_assert(std::is_same::value, "T has to be a numeric"); - static_assert(sqlpp::is_numeric_t::value, "T has to be a numeric"); - static_assert(sqlpp::is_numeric_t::value, "TabBar.alpha has to be a numeric"); - ((t.alpha + 7) + 4).asc(); - static_assert(sqlpp::is_boolean_t::value, "Comparison expression have to be boolean"); - auto x = (t.gamma == true) and (t.alpha == 7); - auto y = t.gamma and true and t.gamma; - !t.gamma; - t.beta < "kaesekuchen"; - serialize(t.beta + "hallenhalma", printer).flush(); - static_assert(sqlpp::must_not_insert_t::value, "alpha must not be inserted"); - serialize(t.alpha, printer).flush(); - std::cerr << "\n" << sizeof(test::TabBar) << std::endl; - static_assert(std::is_same::value, "alpha should be a named expression"); - static_assert(sqlpp::is_named_expression_t::value, "alpha should be a named expression"); - static_assert(sqlpp::is_named_expression_t::value, "an alias of alpha should be a named expression"); - static_assert(sqlpp::is_alias_t::value, "an alias of alpha should be an alias"); - auto z = select(t.alpha).from(t) == 7; - auto l = t.as(alias::left); - auto r = select(t.gamma.as(alias::a)).from(t).where(t.gamma == true).as(alias::right); - static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool"); - serialize(sqlpp::select().flags(sqlpp::distinct, sqlpp::straight_join).columns(l.alpha, l.beta, select(r.a).from(r)) - .from(l, r) - .where(t.beta == "hello world" and select(t.gamma).from(t))// .as(alias::right)) - .group_by(l.gamma, r.a) - .having(r.a != true) - .order_by(l.beta.asc()) - .limit(17) - .offset(3) - .as(alias::a) - , printer).flush(); - return 0; } diff --git a/tests/SelectTypeTest.cpp b/tests/SelectTypeTest.cpp new file mode 100644 index 00000000..fbe41a62 --- /dev/null +++ b/tests/SelectTypeTest.cpp @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2013, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "Sample.h" +#include "MockDb.h" +#include "is_regular.h" +#include +#include +#include +#include + + +MockDb db = {}; +MockDb::_serializer_context_t printer; + +namespace alias +{ + SQLPP_ALIAS_PROVIDER(a); + SQLPP_ALIAS_PROVIDER(b); + SQLPP_ALIAS_PROVIDER(left); + SQLPP_ALIAS_PROVIDER(right); +} + +int main() +{ + test::TabFoo f; + test::TabBar t; + + // Test a table + { + using T = decltype(t); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test an alias of table + { + using T = decltype(t.as(alias::a)); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_alias_t::value, "type requirement"); + static_assert(sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test an integral column of an alias of table + { + using T = decltype(t.as(alias::a).alpha); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + + // Test an integral table column + { + using T = decltype(t.alpha); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_integral_t::value, "type requirement"); + static_assert(not sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a floating point table column + { + using T = decltype(f.omega); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_integral_t::value, "type requirement"); + static_assert(sqlpp::is_floating_point_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a an alias of a numeric table column + { + using T = decltype(t.alpha.as(alias::a)); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a select of a single column without a from + { + using T = decltype(select(t.alpha)); // Hint: The current rule is pretty crude (a from is required), but certainly better than nothing + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a select of a single numeric table column + { + using T = decltype(select(t.alpha).from(t)); + static_assert(sqlpp::is_select_column_list_t::value, "Must not be noop"); + static_assert(sqlpp::is_from_t::value, "Must not be noop"); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test a select of an alias of a single numeric table column + { + using T = decltype(select(t.alpha.as(alias::a)).from(t)); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test an alias of a select of a single numeric table column + { + using T = decltype(select(t.alpha).from(t).as(alias::b)); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "red to not be boolean"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_alias_t::value, "type requirement"); + static_assert(sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test the column of an alias of a select of an alias of a single numeric table column + { + using T = decltype(select(t.alpha.as(alias::a)).from(t).as(alias::b)); + static_assert(not sqlpp::is_numeric_t::value, "type requirement"); + static_assert(not sqlpp::is_expression_t::value, "type requirement"); + static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(sqlpp::is_alias_t::value, "type requirement"); + static_assert(sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test the column of an alias of a select of a single numeric table column + { + using T = decltype(select(t.alpha).from(t).as(alias::b).alpha); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test an alias of a select of an alias of a single numeric table column + { + using T = decltype(select(t.alpha.as(alias::a)).from(t).as(alias::b).a); + static_assert(sqlpp::is_numeric_t::value, "type requirement"); + static_assert(sqlpp::is_expression_t::value, "type requirement"); + static_assert(sqlpp::is_named_expression_t::value, "type requirement"); + static_assert(not sqlpp::require_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_insert_t::value, "type requirement"); + static_assert(not sqlpp::must_not_update_t::value, "type requirement"); + static_assert(not sqlpp::is_boolean_t::value, "type requirement"); + static_assert(not sqlpp::is_text_t::value, "type requirement"); + static_assert(not sqlpp::is_alias_t::value, "type requirement"); + static_assert(not sqlpp::is_table_t::value, "type requirement"); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test that select(all_of(tab)) is expanded in select + { + auto a = select(all_of(t)); + auto b = select(t.alpha, t.beta, t.gamma, t.delta); + //auto c = select(t); + static_assert(std::is_same::value, "all_of(t) has to be expanded by select()"); + //static_assert(std::is_same::value, "t has to be expanded by select()"); + } + + // Test that select(all_of(tab)) is expanded in multi_column + { + auto a = multi_column(all_of(t)).as(alias::a); + auto b = multi_column(t.alpha, t.beta, t.gamma, t.delta).as(alias::a); + static_assert(std::is_same::value, "all_of(t) has to be expanded by multi_column"); + } + + // Test that a multicolumn is not a value + { + auto m = multi_column(t.alpha, t.beta).as(alias::a); + auto a = select(m).from(t).as(alias::b).a; + static_assert(not sqlpp::is_value_t::value, "a multi_column is not a value"); + } + // Test that result sets with identical name/value combinations have identical types + { + auto a = select(t.alpha); + auto b = select(f.epsilon.as(t.alpha)); + using A = typename decltype(a)::_result_row_t; + using B = typename decltype(b)::_result_row_t; + static_assert(std::is_same< + decltype(t.alpha)::_value_type::_base_value_type, + decltype(f.epsilon)::_value_type::_base_value_type>::value, "Two bigint columns must have identical base_value_type"); + static_assert(std::is_same::value, "select with identical columns(name/value_type) need to have identical result_types"); + } + + for (const auto& row : db(select(all_of(t)).from(t).where(true))) + { + int64_t a = row.alpha; + } + + { + auto s = dynamic_select(db, all_of(t)).dynamic_from().dynamic_where().dynamic_limit().dynamic_offset(); + s.add_from(t); + s.add_where(t.alpha > 7 and t.alpha == any(select(t.alpha).from(t).where(t.alpha < 3))); + s.set_limit(30); + s.set_limit(3); + std::cerr << "------------------------\n"; + serialize(s, printer).str(); + std::cerr << "------------------------\n"; + using T = decltype(s); + static_assert(sqlpp::is_regular::value, "type requirement"); + } + + // Test that select can be called with zero columns if it is used with dynamic columns. + { + auto s = dynamic_select(db).dynamic_columns(); + s.add_column(t.alpha); + serialize(s, printer).str(); + } + + // Test that verbatim_table compiles + { + auto s = select(t.alpha).from(sqlpp::verbatim_table("my_unknown_table")); + serialize(s, printer).str(); + } + + + static_assert(sqlpp::is_select_flag_t::value, "sqlpp::all has to be a select_flag"); + using T = sqlpp::vendor::wrap_operand::type; + static_assert(sqlpp::is_regular::value, "type requirement"); + static_assert(T::_is_expression, "T has to be an expression"); + static_assert(std::is_same::value, "T has to be a numeric"); + static_assert(sqlpp::is_numeric_t::value, "T has to be a numeric"); + static_assert(sqlpp::is_numeric_t::value, "TabBar.alpha has to be a numeric"); + ((t.alpha + 7) + 4).asc(); + static_assert(sqlpp::is_boolean_t::value, "Comparison expression have to be boolean"); + auto x = (t.gamma == true) and (t.alpha == 7); + auto y = t.gamma and true and t.gamma; + !t.gamma; + t.beta < "kaesekuchen"; + serialize(t.beta + "hallenhalma", printer).str(); + static_assert(sqlpp::must_not_insert_t::value, "alpha must not be inserted"); + serialize(t.alpha, printer).str(); + std::cerr << "\n" << sizeof(test::TabBar) << std::endl; + static_assert(std::is_same::value, "alpha should be a named expression"); + static_assert(sqlpp::is_named_expression_t::value, "alpha should be a named expression"); + static_assert(sqlpp::is_named_expression_t::value, "an alias of alpha should be a named expression"); + static_assert(sqlpp::is_alias_t::value, "an alias of alpha should be an alias"); + auto z = select(t.alpha).from(t) == 7; + auto l = t.as(alias::left); + auto r = select(t.gamma.as(alias::a)).from(t).where(t.gamma == true).as(alias::right); + static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool"); + serialize(sqlpp::select().flags(sqlpp::distinct, sqlpp::straight_join).columns(l.alpha, l.beta, select(r.a).from(r)) + .from(l, r) + .where(t.beta == "hello world" and select(t.gamma).from(t))// .as(alias::right)) + .group_by(l.gamma, r.a) + .having(r.a != true) + .order_by(l.beta.asc()) + .limit(17) + .offset(3) + .as(alias::a) + , printer).str(); + + return 0; +} diff --git a/tests/UpdateTest.cpp b/tests/UpdateTest.cpp index aa121c87..113bc8c2 100644 --- a/tests/UpdateTest.cpp +++ b/tests/UpdateTest.cpp @@ -29,8 +29,8 @@ #include "MockDb.h" #include "is_regular.h" -DbMock db; -DbMock::_serializer_context_t printer(std::cerr); +MockDb db; +MockDb::_serializer_context_t printer; int main() { @@ -56,13 +56,15 @@ int main() static_assert(sqlpp::is_regular::value, "type requirement"); } - serialize(update(t), printer).flush(); - serialize(update(t).set(t.gamma = false), printer).flush(); - serialize(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).flush(); - serialize(update(t).set(t.beta = "opaque").where(t.beta != t.beta), printer).flush(); + serialize(update(t), printer).str(); + serialize(update(t).set(t.gamma = false), printer).str(); + serialize(update(t).set(t.gamma = false).where(t.beta != "transparent"), printer).str(); + serialize(update(t).set(t.beta = "opaque").where(t.beta != t.beta), printer).str(); auto u = dynamic_update(db, t).dynamic_set(t.gamma = false).dynamic_where(); u.add_set(t.gamma = false); - serialize(u, printer).flush(); + serialize(u, printer).str(); + + db(u); return 0; }