diff --git a/include/sqlpp11/all_of.h b/include/sqlpp11/all_of.h new file mode 100644 index 00000000..fb4f50b3 --- /dev/null +++ b/include/sqlpp11/all_of.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#ifndef SQLPP_ALL_OF_H +#define SQLPP_ALL_OF_H + +#include +#include +#include + +namespace sqlpp +{ + template + struct all_of_t + { + using _column_tuple_t = typename Table::_column_tuple_t; + + template + detail::copy_tuple_args_t as(const AliasProvider& alias) + { + return ::sqlpp::multi_column(_column_tuple_t{}).as(alias); + } + }; + + template + auto all_of(Table t) -> all_of_t + { + return {}; + } + + namespace vendor + { + template + struct interpreter_t> + { + using T = all_of_t
; + + static Context& _(const T& t, const Context&) + { + static_assert(wrong_t::value, "all_of(table) does not seem to be used in select"); + } + }; + } + +} + +#endif + diff --git a/include/sqlpp11/detail/copy_tuple_args.h b/include/sqlpp11/detail/copy_tuple_args.h index f41d2443..644424e6 100644 --- a/include/sqlpp11/detail/copy_tuple_args.h +++ b/include/sqlpp11/detail/copy_tuple_args.h @@ -31,12 +31,21 @@ namespace sqlpp { + template + struct all_of_t; + namespace detail { template struct as_tuple { - static std::tuple _(T t) { return std::tuple{ t }; }; + static std::tuple _(T t) { return std::tuple{ t }; } + }; + + template + struct as_tuple<::sqlpp::all_of_t> + { + static typename ::sqlpp::all_of_t::_column_tuple_t _(::sqlpp::all_of_t) { return { }; } }; template diff --git a/include/sqlpp11/multi_column.h b/include/sqlpp11/multi_column.h index c60ee57d..f75169e7 100644 --- a/include/sqlpp11/multi_column.h +++ b/include/sqlpp11/multi_column.h @@ -35,12 +35,13 @@ namespace sqlpp { template + struct multi_column_alias_t; + + template struct multi_column_t { static_assert(detail::and_t::value, "multi_column parameters need to be named expressions"); - using _name_t = typename AliasProvider::_name_t; - multi_column_t(std::tuple columns): _columns(columns) {} @@ -55,6 +56,43 @@ namespace sqlpp multi_column_t& operator=(multi_column_t&&) = default; ~multi_column_t() = default; + template + multi_column_alias_t as(const AliasProvider&) + { + return { *this }; + } + + + using _value_type = no_value_t; + using _is_multi_column = std::true_type; + + std::tuple _columns; + }; + + template + struct multi_column_alias_t + { + static_assert(detail::and_t::value, "multi_column parameters need to be named expressions"); + + using _name_t = typename AliasProvider::_name_t; + + multi_column_alias_t(multi_column_t multi_column): + _columns(multi_column._columns) + {} + + multi_column_alias_t(std::tuple columns): + _columns(columns) + {} + + multi_column_alias_t(Columns... columns): + _columns(columns...) + {} + + multi_column_alias_t(const multi_column_alias_t&) = default; + multi_column_alias_t(multi_column_alias_t&&) = default; + multi_column_alias_t& operator=(const multi_column_alias_t&) = default; + multi_column_alias_t& operator=(multi_column_alias_t&&) = default; + ~multi_column_alias_t() = default; struct _value_type: public no_value_t { @@ -67,10 +105,21 @@ namespace sqlpp namespace vendor { - template - struct interpreter_t> + template + struct interpreter_t> { - using T = multi_column_t; + using T = multi_column_t; + + static void _(const T& t, Context& context) + { + static_assert(wrong_t::value, "multi_column must be used with an alias"); + } + }; + + template + struct interpreter_t> + { + using T = multi_column_alias_t; static Context& _(const T& t, Context& context) { @@ -82,17 +131,17 @@ namespace sqlpp namespace detail { - template + template using make_multi_column_t = - detail::copy_tuple_args_t::_(std::declval())...))>; } - template - auto multi_column(const AliasProvider&, Columns... columns) - -> detail::make_multi_column_t + template + auto multi_column(Columns... columns) + -> detail::make_multi_column_t { - return detail::make_multi_column_t(std::tuple_cat(detail::as_tuple::_(columns)...)); + return detail::make_multi_column_t(std::tuple_cat(detail::as_tuple::_(columns)...)); } diff --git a/include/sqlpp11/table.h b/include/sqlpp11/table.h index afa9f95e..d8930c73 100644 --- a/include/sqlpp11/table.h +++ b/include/sqlpp11/table.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -42,10 +43,9 @@ namespace sqlpp struct table_t: public table_base_t, public ColumnSpec::_name_t::template _member_t>... { 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) - using _all_columns = typename detail::make_set...>::type; - static_assert(_all_columns::size::value, "at least one column required per table"); + static_assert(sizeof...(ColumnSpec), "at least one column required per table"); using _required_insert_columns = typename detail::make_set_if...>::type; - using _all_of_t = std::tuple...>; + using _column_tuple_t = std::tuple...>; template using _alias_t = table_alias_t; @@ -93,12 +93,6 @@ namespace sqlpp } }; - template - auto all_of(Table t) -> typename Table::_all_of_t - { - return {}; - } - namespace vendor { template diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index 269d80b1..f4760eed 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -52,7 +52,7 @@ namespace sqlpp }; using _name_t = typename AliasProvider::_name_t; - using _all_of_t = std::tuple...>; + using _column_tuple_t = std::tuple...>; table_alias_t(Table table): _table(table) diff --git a/include/sqlpp11/vendor/field.h b/include/sqlpp11/vendor/field.h index 33dad90e..ca8847ec 100644 --- a/include/sqlpp11/vendor/field.h +++ b/include/sqlpp11/vendor/field.h @@ -54,7 +54,7 @@ namespace sqlpp }; template - struct make_field_t_impl> + struct make_field_t_impl> { using type = multi_field_t::type...>>; }; diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 9772e10f..729091e0 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -127,8 +127,9 @@ int main() interpret(t.inner_join(t.as(t.alpha)).on(t.beta == t.as(t.alpha).beta), printer).flush(); // multi_column - interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); - interpret(multi_column(t, all_of(t)), printer).flush(); + interpret(multi_column(t.alpha, (t.beta + "cake").as(t.gamma)).as(t.alpha), printer).flush(); + interpret(multi_column(all_of(t)).as(t), printer).flush(); + interpret(all_of(t).as(t), printer).flush(); // dynamic select { diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index c41c4d85..56c3fbd4 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -281,21 +281,14 @@ int main() // Test that select(all_of(tab)) is expanded in multi_column { - auto a = multi_column(alias::a, all_of(t)); - auto b = multi_column(alias::a, t.alpha, t.beta, t.gamma, t.delta); + 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 select(tab) is expanded in multi_column - { - auto a = multi_column(alias::a, all_of(t)); - auto b = multi_column(alias::a, t.alpha, t.beta, t.gamma, t.delta); - static_assert(std::is_same::value, "t has to be expanded by multi_column"); - } - // Test that a multicolumn is not a value { - auto m = multi_column(alias::a, t.alpha, t.beta); + 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"); }