/* * Copyright (c) 2013-2016, Roland Bock * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SQLPP_WHERE_H #define SQLPP_WHERE_H #include #include #include #include #include #include #include #include #include namespace sqlpp { // WHERE DATA template struct where_data_t { where_data_t(Expression expression) : _expression(expression) { } where_data_t(const where_data_t&) = default; where_data_t(where_data_t&&) = default; where_data_t& operator=(const where_data_t&) = default; where_data_t& operator=(where_data_t&&) = default; ~where_data_t() = default; Expression _expression; interpretable_list_t _dynamic_expressions; }; SQLPP_PORTABLE_STATIC_ASSERT( assert_no_unknown_tables_in_where_t, "at least one expression in where() requires a table which is otherwise not known in the statement"); // WHERE(EXPR) template struct where_t { using _traits = make_traits; using _nodes = detail::type_vector; using _is_dynamic = is_database; // Data using _data_t = where_data_t; // Member implementation with data and methods template struct _impl_t { // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 _impl_t() = default; _impl_t(const _data_t& data) : _data(data) { } template void add(Expr expression) { static_assert(_is_dynamic::value, "where::add() can only be called for dynamic_where"); static_assert(is_expression_t::value, "invalid expression argument in where::add()"); static_assert(is_boolean_t::value, "invalid expression argument in where::add()"); static_assert(Policies::template _no_unknown_tables::value, "expression uses tables unknown to this statement in where::add()"); static_assert(not contains_aggregate_function_t::value, "where expression must not contain aggregate functions"); using _serialize_check = sqlpp::serialize_check_t; _serialize_check{}; using ok = logic::all_t<_is_dynamic::value, is_expression_t::value, _serialize_check::type::value>; _add_impl(expression, ok()); // dispatch to prevent compile messages after the static_assert } private: template void _add_impl(Expr expression, const std::true_type&) { return _data._dynamic_expressions.emplace_back(expression); } template void _add_impl(Expr expression, const std::false_type&); public: _data_t _data; }; // Base template to be inherited by the statement template struct _base_t { using _data_t = where_data_t; // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 template _base_t(Args&&... args) : where{std::forward(args)...} { } _impl_t where; _impl_t& operator()() { return where; } const _impl_t& operator()() const { return where; } template static auto _get_member(T t) -> decltype(t.where) { return t.where; } using _consistency_check = typename std::conditional::value, consistent_t, assert_no_unknown_tables_in_where_t>::type; }; }; template <> struct where_data_t { }; // WHERE() UNCONDITIONALLY template <> struct where_t { using _traits = make_traits; using _nodes = detail::type_vector<>; // Data using _data_t = where_data_t; // Member implementation with data and methods template struct _impl_t { // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 _impl_t() = default; _impl_t(const _data_t& data) : _data(data) { } _data_t _data; }; // Base template to be inherited by the statement template struct _base_t { using _data_t = where_data_t; // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 template _base_t(Args&&... args) : where{std::forward(args)...} { } _impl_t where; _impl_t& operator()() { return where; } const _impl_t& operator()() const { return where; } template static auto _get_member(T t) -> decltype(t.where) { return t.where; } using _consistency_check = consistent_t; }; }; SQLPP_PORTABLE_STATIC_ASSERT(assert_where_or_unconditionally_called_t, "calling where() or unconditionally() required"); SQLPP_PORTABLE_STATIC_ASSERT(assert_where_arg_is_not_cpp_bool_t, "where() argument has to be an sqlpp boolean expression. Please use " ".unconditionally() instead of .where(true), or sqlpp::value(bool)"); SQLPP_PORTABLE_STATIC_ASSERT(assert_where_arg_is_boolean_expression_t, "where() argument has to be an sqlpp boolean expression."); SQLPP_PORTABLE_STATIC_ASSERT(assert_where_arg_contains_no_aggregate_functions_t, "at least one aggregate function used in where()"); SQLPP_PORTABLE_STATIC_ASSERT(assert_where_dynamic_used_with_dynamic_statement_t, "dynamic_where() must not be called in a static statement"); // workaround for msvc bugs https://connect.microsoft.com/VisualStudio/Feedback/Details/2086629 & // https://connect.microsoft.com/VisualStudio/feedback/details/2173198 // template // using check_where_t = static_combined_check_t< // static_check_t::value...>::value, // assert_where_arg_is_not_cpp_bool_t>, // static_check_t::value...>::value, // assert_where_boolean_expressions_t>, // static_check_t::value...>::value, // assert_where_arg_is_boolean_expression_t>, // static_check_t::value)...>::value, // assert_where_arg_contains_no_aggregate_functions_t>>; template struct check_where { using type = static_combined_check_t< static_check_t::value, assert_where_arg_is_not_cpp_bool_t>, static_check_t::value, assert_where_arg_is_boolean_expression_t>, static_check_t::value, assert_where_arg_is_boolean_expression_t>, static_check_t::value, assert_where_arg_contains_no_aggregate_functions_t>>; }; template using check_where_t = typename check_where::type; template using check_where_static_t = check_where_t; template using check_where_dynamic_t = static_combined_check_t< static_check_t::value, assert_where_dynamic_used_with_dynamic_statement_t>, check_where_t>; // NO WHERE YET template struct no_where_t { using _traits = make_traits; using _nodes = detail::type_vector<>; // Data using _data_t = no_data_t; // Member implementation with data and methods template struct _impl_t { // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 _impl_t() = default; _impl_t(const _data_t& data) : _data(data) { } _data_t _data; }; // Base template to be inherited by the statement template struct _base_t { using _data_t = no_data_t; // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2173269 template _base_t(Args&&... args) : no_where{std::forward(args)...} { } _impl_t no_where; _impl_t& operator()() { return no_where; } const _impl_t& operator()() const { return no_where; } template static auto _get_member(T t) -> decltype(t.no_where) { return t.no_where; } using _database_t = typename Policies::_database_t; template using _new_statement_t = new_statement_t; using _consistency_check = typename std::conditional 0), assert_where_or_unconditionally_called_t, consistent_t>::type; auto unconditionally() const -> _new_statement_t> { return {static_cast&>(*this), where_data_t{}}; } template auto where(Expression expression) const -> _new_statement_t, where_t> { using Check = check_where_static_t; return _where_impl(Check{}, expression); } template auto dynamic_where(Expression expression) const -> _new_statement_t, where_t<_database_t, Expression>> { using Check = check_where_dynamic_t<_database_t, Expression>; return _where_impl<_database_t>(Check{}, expression); } auto dynamic_where() const -> _new_statement_t, where_t<_database_t, boolean_operand>> { return dynamic_where(::sqlpp::value(true)); } private: template auto _where_impl(Check, Expression expression) const -> inconsistent; template auto _where_impl(consistent_t, Expression expression) const -> _new_statement_t> { return {static_cast&>(*this), where_data_t{expression}}; } }; }; // Interpreters template struct serializer_t> { using _serialize_check = serialize_check_of; using T = where_data_t; static Context& _(const T& t, Context& context) { context << " WHERE "; serialize(t._expression, context); if (not t._dynamic_expressions.empty()) context << " AND "; interpret_list(t._dynamic_expressions, " AND ", context); return context; } }; template struct serializer_t> { using _serialize_check = consistent_t; using T = where_data_t; static Context& _(const T&, Context& context) { return context; } }; template auto where(T&& t) -> decltype(statement_t>().where(std::forward(t))) { return statement_t>().where(std::forward(t)); } template auto dynamic_where(const Database&, T&& t) -> decltype(statement_t>().dynamic_where(std::forward(t))) { return statement_t>().dynamic_where(std::forward(t)); } inline auto unconditionally() -> decltype(statement_t>().unconditionally()) { return statement_t>().unconditionally(); } } #endif