/* * 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_FROM_H #define SQLPP_FROM_H #include #include #include #include #include #include #include #include #include namespace sqlpp { // FROM DATA template struct from_data_t { from_data_t(Table table) : _table(table) { } from_data_t(const from_data_t&) = default; from_data_t(from_data_t&&) = default; from_data_t& operator=(const from_data_t&) = default; from_data_t& operator=(from_data_t&&) = default; ~from_data_t() = default; Table _table; interpretable_list_t _dynamic_tables; }; SQLPP_PORTABLE_STATIC_ASSERT(assert_from_add_dynamic, "from::add() requires a dynamic_from"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_add_not_dynamic_pre_join, "join condition missing"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_add_dynamic_join, "from::add(X) requires X to be a dynamic join"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_add_unique_names, "from::add() must not add table names already used in from"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_add_no_required_tables, "from::add():dynamic join condition depends on " "tables not statically known, use " "without_table_check() to express the intent"); template struct check_from_add { using _known_tables = provided_tables_of; // Hint: Joins contain more than one table // workaround for msvc bug https://connect.microsoft.com/VisualStudio/feedback/details/2173198 // using _known_table_names = detail::transform_set_t; using _known_table_names = detail::make_name_of_set_t<_known_tables>; using _joined_tables = provided_tables_of; using _joined_table_names = detail::make_name_of_set_t<_joined_tables>; using _required_tables = required_tables_of; using type = static_combined_check_t< static_check_t, static_check_t::value, assert_from_add_not_dynamic_pre_join>, static_check_t::value, assert_from_add_dynamic_join>, static_check_t::value, assert_from_add_unique_names>, static_check_t::value, assert_from_add_no_required_tables>, sqlpp::serialize_check_t, DynamicJoin>>; }; template using check_from_add_t = typename check_from_add::type; // FROM template struct from_t { using _traits = make_traits; using _nodes = detail::type_vector; // Data using _data_t = from_data_t; // Member implementation with data and methods template struct _impl_t { using _database_t = Database; using _is_dynamic = is_database<_database_t>; using _table_t = Table; // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069 _impl_t() = default; _impl_t(const _data_t& data) : _data(data) { } template auto add(DynamicJoin dynamicJoin) -> typename std::conditional::value, void, bad_statement>::type { using Check = check_from_add_t<_impl_t, DynamicJoin>; Check::_(); return _add_impl(dynamicJoin, Check{}); } private: template auto _add_impl(DynamicJoin dynamicJoin, const std::true_type&) -> void { _data._dynamic_tables.emplace_back(from_table(dynamicJoin)); } template auto _add_impl(DynamicJoin dynamicJoin, const std::false_type&) -> bad_statement; public: _data_t _data; }; // Base template to be inherited by the statement template struct _base_t { using _data_t = from_data_t; // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069 template _base_t(Args&&... args) : from{std::forward(args)...} { } _impl_t from; _impl_t& operator()() { return from; } const _impl_t& operator()() const { return from; } template static auto _get_member(T t) -> decltype(t.from) { return t.from; } // FIXME: We might want to check if we have too many tables define in the FROM using _consistency_check = consistent_t; }; }; SQLPP_PORTABLE_STATIC_ASSERT( assert_from_not_pre_join_t, "from() argument is a pre join, please use an explicit on() condition or unconditionally()"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_table_t, "from() argument has to be a table or join expression"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_dependency_free_t, "at least one table depends on another table in from()"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_no_duplicates_t, "at least one duplicate table name detected in from()"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_dynamic_statement_dynamic_t, "dynamic_from must not be called in a static statement"); template struct check_from { using type = static_combined_check_t< static_check_t::value, assert_from_not_pre_join_t>, static_check_t::value, assert_from_table_t>, static_check_t::size::value == 0, assert_from_dependency_free_t>, static_check_t::size::value == detail::make_name_of_set_t>::size::value, assert_from_no_duplicates_t>>; }; template using check_from_t = typename check_from
::type; template using check_from_static_t = check_from_t
; template using check_from_dynamic_t = static_combined_check_t< static_check_t::value, assert_from_dynamic_statement_dynamic_t>, check_from_t
>; struct no_from_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/2091069 _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/2091069 template _base_t(Args&&... args) : no_from{std::forward(args)...} { } _impl_t no_from; _impl_t& operator()() { return no_from; } const _impl_t& operator()() const { return no_from; } template static auto _get_member(T t) -> decltype(t.no_from) { return t.no_from; } using _database_t = typename Policies::_database_t; template using _new_statement_t = new_statement_t; using _consistency_check = consistent_t; template auto from(Table table) const -> _new_statement_t, from_t>> { using Check = check_from_static_t
; Check{}._(); return _from_impl(Check{}, table); } template auto dynamic_from(Table table) const -> _new_statement_t, from_t<_database_t, from_table_t
>> { using Check = check_from_dynamic_t<_database_t, Table>; Check{}._(); return _from_impl<_database_t>(Check{}, table); } private: template auto _from_impl(const std::false_type&, Table table) const -> bad_statement; template auto _from_impl(const std::true_type&, Table table) const -> _new_statement_t>> { return {static_cast&>(*this), from_data_t>{from_table(table)}}; } }; }; // Interpreters template struct serializer_t> { using _serialize_check = serialize_check_of; using T = from_data_t; static Context& _(const T& t, Context& context) { context << " FROM "; serialize(t._table, context); if (not t._dynamic_tables.empty()) { interpret_list(t._dynamic_tables, "", context); } return context; } }; template auto from(T&& t) -> decltype(statement_t().from(std::forward(t))) { return statement_t().from(std::forward(t)); } template auto dynamic_from(const Database&, T&& t) -> decltype(statement_t().dynamic_from(std::forward(t))) { return statement_t().dynamic_from(std::forward(t)); } } #endif