diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index d1052935..876acc3a 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,7 @@ namespace sqlpp typename FlagList = vendor::no_select_flag_list_t, typename ColumnList = vendor::no_select_column_list_t, typename From = vendor::no_from_t, + typename ExtraTables = vendor::no_extra_tables_t, typename Where = vendor::no_where_t, typename GroupBy = vendor::no_group_by_t, typename Having = vendor::no_having_t, @@ -75,6 +77,7 @@ namespace sqlpp using _flag_list_t = FlagList; using _column_list_t = ColumnList; using _from_t = From; + using _extra_tables_t = ExtraTables; using _where_t = Where; using _group_by_t = GroupBy; using _having_t = Having; @@ -82,12 +85,13 @@ namespace sqlpp using _limit_t = Limit; using _offset_t = Offset; - using _statement_t = select_t; + using _statement_t = select_t; struct _methods_t: public _flag_list_t::template _methods_t, public _column_list_t::template _methods_t, public _from_t::template _methods_t, + public _extra_tables_t::template _methods_t, public _where_t::template _methods_t, public _group_by_t::template _methods_t, public _having_t::template _methods_t, @@ -104,7 +108,7 @@ namespace sqlpp }; template - using _new_statement_t = typename _policies_update_t::type; + using _new_statement_t = typename _policies_update_t::type; 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()"); @@ -124,7 +128,7 @@ namespace sqlpp // The tables not covered by the from. using _table_set = detail::make_difference_set_t< _required_tables, - typename _from_t::_table_set // Hint: extra_tables are not used here because they are just helpers for dynamic .add_*() methods + typename _from_t::_table_set // Hint: extra_tables_t is not used here because it is just a helper for dynamic .add_*() methods and should not change the structural integrity >; // A select can be used as a pseudo table if @@ -157,6 +161,7 @@ namespace sqlpp using _flag_list_t = typename _policies_t::_flag_list_t; using _column_list_t = typename _policies_t::_column_list_t; using _from_t = typename _policies_t::_from_t; + using _extra_tables_t = typename _policies_t::_extra_tables_t; using _where_t = typename _policies_t::_where_t; using _group_by_t = typename _policies_t::_group_by_t; using _having_t = typename _policies_t::_having_t; @@ -252,7 +257,6 @@ namespace sqlpp { #warning: need to check in add_xy method as well #warning: need add_wxy_without_table_check -#warning: might want to add an .extra_tables() method to say which tables might also be used here, say via dynamic_from or because this is a subselect static_assert(is_table_subset_of_from<_flag_list_t>::value, "flags require additional tables in from()"); static_assert(is_table_subset_of_from<_column_list_t>::value, "selected columns require additional tables in from()"); static_assert(is_table_subset_of_from<_where_t>::value, "where() expression requires additional tables in from()"); diff --git a/include/sqlpp11/vendor/extra_tables.h b/include/sqlpp11/vendor/extra_tables.h new file mode 100644 index 00000000..0b91ad7a --- /dev/null +++ b/include/sqlpp11/vendor/extra_tables.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013-2014, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_EXTRA_TABLES_H +#define SQLPP_EXTRA_TABLES_H + +#include +#include +#include + +namespace sqlpp +{ + namespace vendor + { + // EXTRA_TABLES + template + struct extra_tables_t + { + using _is_extra_tables = std::true_type; + + static_assert(sizeof...(Tables), "at least one table or join argument required in extra_tables()"); + + static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected in extra_tables()"); + + static_assert(::sqlpp::detail::all_t::value, "at least one argument is not a table or join in extra_tables()"); + + using _table_set = ::sqlpp::detail::make_joined_set_t; + + + extra_tables_t() + {} + + extra_tables_t(const extra_tables_t&) = default; + extra_tables_t(extra_tables_t&&) = default; + extra_tables_t& operator=(const extra_tables_t&) = default; + extra_tables_t& operator=(extra_tables_t&&) = default; + ~extra_tables_t() = default; + + template + struct _methods_t + { + }; + }; + + struct no_extra_tables_t + { + using _is_noop = std::true_type; + using _table_set = ::sqlpp::detail::type_set<>; + + template + struct _methods_t + { + template + using _new_statement_t = typename Policies::template _new_statement_t; + + template + auto extra_tables(Args...) + -> _new_statement_t> + { + return { *static_cast(this), extra_tables_t{} }; + } + }; + }; + + // Interpreters + template + struct serializer_t> + { + using T = extra_tables_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + + template + struct serializer_t + { + using T = no_extra_tables_t; + + static Context& _(const T& t, Context& context) + { + return context; + } + }; + + } +} + +#endif diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index 6dd02b46..ae2edeb1 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -68,7 +68,7 @@ int main() const bool g = row.gamma; } - auto s = dynamic_select(db).dynamic_columns(t.alpha).dynamic_flags().dynamic_from(t).dynamic_where().dynamic_group_by(t.alpha).dynamic_order_by().dynamic_having(t.gamma).dynamic_limit().dynamic_offset(); + auto s = dynamic_select(db).dynamic_columns(t.alpha).dynamic_flags().dynamic_from(t).extra_tables(f,t).dynamic_where().dynamic_group_by(t.alpha).dynamic_order_by().dynamic_having(t.gamma).dynamic_limit().dynamic_offset(); s.add_flag(sqlpp::distinct); s.add_column(t.beta); s.add_from(f);