From 5576df1775d40e8111eed3388e036ab97d15914d Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sun, 22 Sep 2013 12:16:28 +0200 Subject: [PATCH] Cleaned up select_pseudo_table and started to prepare for dynamic select parts --- include/sqlpp11/detail/serializable.h | 85 ++++++++++ include/sqlpp11/from.h | 40 ++++- include/sqlpp11/select.h | 191 ++++++++++------------- include/sqlpp11/select_expression_list.h | 16 -- include/sqlpp11/select_fwd.h | 1 + include/sqlpp11/select_pseudo_table.h | 69 ++------ tests/SelectTest.cpp | 11 ++ 7 files changed, 228 insertions(+), 185 deletions(-) create mode 100644 include/sqlpp11/detail/serializable.h diff --git a/include/sqlpp11/detail/serializable.h b/include/sqlpp11/detail/serializable.h new file mode 100644 index 00000000..84b7294b --- /dev/null +++ b/include/sqlpp11/detail/serializable.h @@ -0,0 +1,85 @@ +/* + * 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_SERIALIZABLE_H +#define SQLPP_SERIALIZABLE_H + +#include +#include + +namespace sqlpp +{ + namespace detail + { + template + struct serializable_t + { + template + serializable_t(T&& t): + _impl(std::make_shared<_impl_t::type>>(std::forward(t))) + {} + + serializable_t(const serializable_t&) = default; + serializable_t(serializable_t&&) = default; + serializable_t& operator=(const serializable_t&) = default; + serializable_t& operator=(serializable_t&&) = default; + ~serializable_t() = default; + + void serialize(std::ostream& os, Db& db) const + { + _impl->serialize(os, db); + } + + private: + struct _impl_base + { + virtual void serialize(std::ostream& os, Db& db) const = 0; + }; + + template + struct _impl_t: public _impl_base + { + _impl_t(const T& t): + _t(t) + {} + + _impl_t(T&& t): + _t(std::move(t)) + {} + + void serialize(std::ostream& os, Db& db) const + { + _t.serialize(os, db); + } + T _t; + }; + + std::shared_ptr _impl; + }; + } +} + +#endif diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index 59424074..91688ea5 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -27,10 +27,12 @@ #ifndef SQLPP_FROM_H #define SQLPP_FROM_H +#include +#include #include #include +#include #include -#include namespace sqlpp { @@ -49,11 +51,43 @@ namespace sqlpp void serialize(std::ostream& os, Db& db) const { os << " FROM "; - detail::serialize_tuple(os, db, _tables_and_joins, ','); + detail::serialize_tuple(os, db, _tables, ','); } - std::tuple _tables_and_joins; + std::tuple _tables; }; + + template + struct dynamic_from_t + { + using _is_from = tag_yes; + using _is_dynamic_from = tag_yes; + + template + void add(Table&& table) + { + _dynamic_tables.push_back(std::forward(table)); + } + + void serialize(std::ostream& os, Db& db, bool has_static_from) const + { + if (sizeof...(TableOrJoin) == 0 and _dynamic_tables.empty()) + return; + os << " FROM "; + detail::serialize_tuple(os, db, _tables, ','); + bool first = sizeof...(TableOrJoin) == 0; + for (const auto& table : _dynamic_tables) + { + if (not first) + os << ','; + table.serialize(os, db); + first = false; + } + } + + std::tuple _tables; + std::vector> _dynamic_tables; + }; } #endif diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 722d4e40..f2d59b53 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -51,8 +51,8 @@ namespace sqlpp { - // select template, to be used as an r_value template< + typename Database, typename Flags, typename... NamedExpr, typename From, @@ -63,8 +63,9 @@ namespace sqlpp typename Limit, typename Offset > - struct select_t>, From, Where, GroupBy, Having, OrderBy, Limit, Offset> + struct select_t>, From, Where, GroupBy, Having, OrderBy, Limit, Offset> : public select_expression_list_t>::_value_type::template operators>, From, @@ -75,6 +76,8 @@ namespace sqlpp Limit, Offset>> { + using _Database = Database; + using _From = From; using ExpressionList = select_expression_list_t>; static_assert(is_noop::value or is_select_flag_list_t::value, "invalid list of select flags"); @@ -91,17 +94,17 @@ namespace sqlpp using _requires_braces = tag_yes; template - using add_from_t = select_t::type...>, Where, GroupBy, Having, OrderBy, Limit, Offset>; + using set_from_t = select_t::type...>, Where, GroupBy, Having, OrderBy, Limit, Offset>; template - using add_where_t = select_t::type>, GroupBy, Having, OrderBy, Limit, Offset>; + using set_where_t = select_t::type>, GroupBy, Having, OrderBy, Limit, Offset>; template - using add_group_by_t = select_t::type...>, Having, OrderBy, Limit, Offset>; + using set_group_by_t = select_t::type...>, Having, OrderBy, Limit, Offset>; template - using add_having_t = select_t::type>, OrderBy, Limit, Offset>; + using set_having_t = select_t::type>, OrderBy, Limit, Offset>; template - using add_order_by_t = select_t::type...>, Limit, Offset>; - using add_limit_t = select_t; - using add_offset_t = select_t; + using set_order_by_t = select_t::type...>, Limit, Offset>; + using set_limit_t = select_t; + using set_offset_t = select_t; using _result_row_t = result_row_t...>; @@ -118,62 +121,14 @@ namespace sqlpp _flags(std::move(flags)), _expression_list(std::move(expression_list)) { - static_assert(std::is_same>::value, + static_assert(std::is_same>::value, "basic constructor only available for select_t (default template parameters)"); } - constexpr select_t(const select_t& rhs): - _flags(rhs._flags), - _expression_list(rhs._expression_list), - _from(rhs._from), - _where(rhs._where), - _group_by(rhs._group_by), - _having(rhs._having), - _order_by(rhs._order_by), - _limit(rhs._limit), - _offset(rhs._offset) - { - } - - constexpr select_t(select_t&& rhs): - _flags(std::move(rhs._flags)), - _expression_list(std::move(rhs._expression_list)), - _from(std::move(rhs._from)), - _where(std::move(rhs._where)), - _group_by(std::move(rhs._group_by)), - _having(std::move(rhs._having)), - _order_by(std::move(rhs._order_by)), - _limit(std::move(rhs._limit)), - _offset(std::move(rhs._offset)) - { - } - - select_t& operator=(const select_t& rhs) - { - _flags = rhs._flags; - _expression_list = rhs._expression_list; - _from = rhs._from; - _where = rhs._where; - _group_by = rhs._group_by; - _having = rhs._having; - _order_by = rhs._order_by; - _offset = rhs._offset; - _limit = rhs._limit; - } - - select_t& operator=(select_t&& rhs) - { - _flags = std::move(rhs._flags); - _expression_list = std::move(rhs._expression_list); - _from = std::move(rhs._from); - _where = std::move(rhs._where); - _group_by = std::move(rhs._group_by); - _having = std::move(rhs._having); - _order_by = std::move(rhs._order_by); - _limit = std::move(rhs._limit); - _offset = std::move(rhs._offset); - } - + select_t(const select_t& rhs) = default; + select_t(select_t&& rhs) = default; + select_t& operator=(const select_t& rhs) = default; + select_t& operator=(select_t&& rhs) = default; ~select_t() = default; // Other constructors @@ -210,7 +165,7 @@ namespace sqlpp // sqlpp functions template - add_from_t from(Table&&... table) + set_from_t from(Table&&... table) { static_assert(not is_noop::value, "cannot call from() without having selected anything"); static_assert(is_noop::value, "cannot call from() twice for a single select"); @@ -227,8 +182,21 @@ namespace sqlpp }; } + /* + template + select_t& add_from(Table&& table) + { + static_assert(not is_noop::value, "cannot call add_from() without having selected anything"); + static_assert(not std::is_same::value, "cannot call add_from() in a non-dynamic select"); + + _dynamic._from.add(std::forward
(table)); + + return *this; + } + */ + template - add_where_t where(Expr&& expr) + set_where_t where(Expr&& expr) { static_assert(not is_noop::value, "cannot call where() without a from()"); static_assert(is_noop::value, "cannot call where() twice for a single select"); @@ -241,12 +209,12 @@ namespace sqlpp _having, _order_by, _limit, - _offset + _offset, }; } template - add_group_by_t group_by(Col&&... column) + set_group_by_t group_by(Col&&... column) { static_assert(not is_noop::value, "cannot call group_by() without a from()"); static_assert(is_noop::value, "cannot call group_by() twice for a single select"); @@ -259,12 +227,12 @@ namespace sqlpp _having, _order_by, _limit, - _offset + _offset, }; } template - add_having_t having(Expr&& expr) + set_having_t having(Expr&& expr) { static_assert(not is_noop::value, "cannot call having() without a group_by"); static_assert(is_noop::value, "cannot call having() twice for a single select"); @@ -277,12 +245,12 @@ namespace sqlpp {std::forward(expr)}, _order_by, _limit, - _offset + _offset, }; } template - add_order_by_t order_by(OrderExpr&&... expr) + set_order_by_t order_by(OrderExpr&&... expr) { static_assert(not is_noop::value, "cannot call order_by() without a from()"); static_assert(is_noop::value, "cannot call order_by() twice for a single select"); @@ -295,11 +263,11 @@ namespace sqlpp _having, {std::tuple::type...>{std::forward(expr)...}}, _limit, - _offset + _offset, }; } - add_limit_t limit(std::size_t limit) + set_limit_t limit(std::size_t limit) { static_assert(not is_noop::value, "cannot call limit() without a from()"); static_assert(is_noop::value, "cannot call limit() twice for a single select"); @@ -312,11 +280,11 @@ namespace sqlpp _having, _order_by, {limit}, - _offset + _offset, }; } - add_offset_t offset(std::size_t offset) + set_offset_t offset(std::size_t offset) { static_assert(not is_noop::value, "cannot call offset() without a limit"); static_assert(is_noop::value, "cannot call offset() twice for a single select"); @@ -329,53 +297,47 @@ namespace sqlpp _having, _order_by, _limit, - {offset} + {offset}, }; } - // Turn into pseudo table or named expression - using pseudo_table_t = select_pseudo_table_t< - Flags, - ExpressionList, - From, - Where, - GroupBy, - Having, - OrderBy, - Limit, - Offset, - NamedExpr...>; - template - using alias_t = typename pseudo_table_t::template alias_t; - - template - typename std::enable_if::value, alias_t>::type as(const AliasProvider& aliasProvider) const + struct _pseudo_table_t { - return pseudo_table_t( - _flags, - _expression_list, - _from, - _where, - _group_by, - _having, - _order_by, - _limit, - _offset).as(aliasProvider); + using table = select_pseudo_table_t; + using alias = typename table::template alias_t; + }; + + template + typename _pseudo_table_t::alias as(const AliasProvider& aliasProvider) const + { + return typename _pseudo_table_t::table( + *this).as(aliasProvider); } // Serialize template - select_t& serialize(std::ostream& os, Db& db) + const select_t& serialize(std::ostream& os, Db& db) const { - detail::serialize_select(os, db, *this); + os << "SELECT "; + + _flags.serialize(os, db); + _expression_list.serialize(os, db); + _from.serialize(os, db); + _where.serialize(os, db); + _group_by.serialize(os, db); + _having.serialize(os, db); + _order_by.serialize(os, db); + _limit.serialize(os, db); + _offset.serialize(os, db); + return *this; } template - const select_t& serialize(std::ostream& os, Db& db) const + select_t& serialize(std::ostream& os, Db& db) { - detail::serialize_select(os, db, *this); + const_cast(this)->serialize(os, db); return *this; } @@ -387,14 +349,11 @@ namespace sqlpp static_assert(not is_noop::value, "cannot run select without having selected anything"); static_assert(is_from_t::value, "cannot run select without a from()"); // FIXME: Check for missing aliases (if references are used) - // FIXME: Check for missing tables + // FIXME: Check for missing tables, well, actually, check for missing tables at the where(), order_by(), etc. std::ostringstream oss; serialize(oss, db); return {db.select(oss.str())}; - - //serialize using db - //run using db and return result_set } Flags _flags; @@ -425,12 +384,22 @@ namespace sqlpp } template - select_t, detail::make_select_expression_list_t> select(NamedExpr&&... namedExpr) + select_t, detail::make_select_expression_list_t> select(NamedExpr&&... namedExpr) { return { { detail::make_flag_tuple(std::forward(namedExpr)...) }, { detail::make_expression_tuple(std::forward(namedExpr)...) } }; } + /* + template + select_t::type, detail::make_select_flag_list_t, detail::make_select_expression_list_t> dynamic_select(const Db& db, NamedExpr&&... namedExpr) + { + return { + { detail::make_flag_tuple(std::forward(namedExpr)...) }, + { detail::make_expression_tuple(std::forward(namedExpr)...) } + }; + } + */ } #endif diff --git a/include/sqlpp11/select_expression_list.h b/include/sqlpp11/select_expression_list.h index 9e4b2389..8a0ef866 100644 --- a/include/sqlpp11/select_expression_list.h +++ b/include/sqlpp11/select_expression_list.h @@ -40,22 +40,6 @@ namespace sqlpp { namespace detail { - template - void serialize_select(std::ostream& os, Db& db, const Select& select) - { - os << "SELECT "; - - select._flags.serialize(os, db); - select._expression_list.serialize(os, db); - select._from.serialize(os, db); - select._where.serialize(os, db); - select._group_by.serialize(os, db); - select._having.serialize(os, db); - select._order_by.serialize(os, db); - select._limit.serialize(os, db); - select._offset.serialize(os, db); - }; - template struct get_first_argument { diff --git a/include/sqlpp11/select_fwd.h b/include/sqlpp11/select_fwd.h index d7d21eba..e77143fd 100644 --- a/include/sqlpp11/select_fwd.h +++ b/include/sqlpp11/select_fwd.h @@ -55,6 +55,7 @@ namespace sqlpp struct offset_t; template< + typename Db, typename Flags = noop, typename ExpressionList = noop, typename From = noop, diff --git a/include/sqlpp11/select_pseudo_table.h b/include/sqlpp11/select_pseudo_table.h index f0a663f0..b90759bd 100644 --- a/include/sqlpp11/select_pseudo_table.h +++ b/include/sqlpp11/select_pseudo_table.h @@ -41,79 +41,38 @@ namespace sqlpp }; template< - typename Flags, - typename ExpressionList, - typename From, - typename Where, - typename GroupBy, - typename Having, - typename OrderBy, - typename Limit, - typename Offset, + typename Select, typename... NamedExpr > struct select_pseudo_table_t: public sqlpp::table_base_t, select_column_spec_t...> { using _value_type = no_value_t; - select_pseudo_table_t(const Flags& flags, const ExpressionList& expression_list, const From& from, - const Where& where, const GroupBy& group_by, const Having& having, - const OrderBy& order_by, const Limit& limit, const Offset& offset): - _flags(flags), - _expression_list(expression_list), - _from(from), - _where(where), - _group_by(group_by), - _having(having), - _order_by(order_by), - _limit(limit), - _offset(offset) + select_pseudo_table_t(const Select& select): + _select(select) { - std::cerr << "Copying arguments into pseudo_table" << std::endl; - //std::cerr << _limit._limit << std::endl; } - select_pseudo_table_t(const select_pseudo_table_t& rhs): - _flags(rhs._flags), - _expression_list(rhs._expression_list), - _from(rhs._from), - _where(rhs._where), - _group_by(rhs._group_by), - _having(rhs._having), - _order_by(rhs._order_by), - _limit(rhs._limit), - _offset(rhs._offset) + select_pseudo_table_t(Select&& select): + _select(std::move(select)) { - std::cerr << "Copying pseudo_table" << std::endl; - //std::cerr << _limit._limit << std::endl; } + select_pseudo_table_t(const select_pseudo_table_t& rhs) = default; + select_pseudo_table_t(select_pseudo_table_t&& rhs) = default; + select_pseudo_table_t& operator=(const select_pseudo_table_t& rhs) = default; + select_pseudo_table_t& operator=(select_pseudo_table_t&& rhs) = default; + ~select_pseudo_table_t() = default; + template void serialize(std::ostream& os, Db& db) const { - //std::cerr << "pseudo_table::serialize: " << _limit._limit << std::endl; - detail::serialize_select(os, db, *this); + _select.serialize(os, db); } - Flags _flags; - ExpressionList _expression_list; - From _from; - Where _where; - GroupBy _group_by; - Having _having; - OrderBy _order_by; - Limit _limit; - Offset _offset; + Select _select; }; } diff --git a/tests/SelectTest.cpp b/tests/SelectTest.cpp index a0c4f4e2..4a6c6c0a 100644 --- a/tests/SelectTest.cpp +++ b/tests/SelectTest.cpp @@ -262,6 +262,17 @@ int main() static_assert(std::is_same::value, "select with identical columns(name/value_type) need to have identical result_types"); } +#if 0 + { + auto s = dynamic_select(db, t); + s = s.add_from(t); + s = s.add_from(t); // This will not be accepted by the SQL server, but it is dynamic and this kind of test is not possible at compile time, I guess + std::cerr << "------------------------\n"; + s.serialize(std::cerr, db); + std::cerr << "------------------------\n"; + } +#endif + static_assert(sqlpp::is_select_flag_t::value, "sqlpp::all has to be a select_flag"); using T = sqlpp::detail::wrap_operand::type;