From 7992a8261569e8369d32c95b10960778b6c00ce1 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 20 Jan 2014 10:48:28 +0100 Subject: [PATCH 1/5] Some notes --- include/sqlpp11/select.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index b937eeed..720018e5 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -82,7 +82,7 @@ namespace sqlpp using _From = From; static_assert(vendor::is_noop::value or is_select_flag_list_t::value, "invalid list of select flags"); - static_assert(is_select_expression_list_t::value, "invalid list of select expressions"); + static_assert(vendor::is_noop or is_select_expression_list_t::value, "invalid list of select expressions"); static_assert(vendor::is_noop::value or is_from_t::value, "invalid 'from' argument"); static_assert(vendor::is_noop::value or is_where_t::value, "invalid 'where' argument"); static_assert(vendor::is_noop::value or is_group_by_t::value, "invalid 'group by' arguments"); @@ -171,6 +171,14 @@ namespace sqlpp { } +Idea: + lets add methods flags(...) and dynamic_flags(...) + add method columns(...) and make dynamic_columns(...) take arguments + offer empty select() and dynamic_select(db) to call *flags() and *columns() later + continue to offer select(...) and dynamic_select(db, ...) for convenience + + also: have ONE constructor, taking values + auto dynamic_columns() -> set_expression_list_t> { From ee7cda0a5d52f1e46b9abcc1cf6dca15aac3d1b8 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 20 Jan 2014 21:26:16 +0100 Subject: [PATCH 2/5] Started to change the way dynamic columns and flags are specified --- include/sqlpp11/count.h | 1 + include/sqlpp11/select.h | 262 ++++++++++-------- include/sqlpp11/type_traits.h | 2 +- ...expression_list.h => select_column_list.h} | 53 ++-- include/sqlpp11/vendor/select_flag_list.h | 12 +- tests/InterpretTest.cpp | 2 +- 6 files changed, 185 insertions(+), 147 deletions(-) rename include/sqlpp11/vendor/{select_expression_list.h => select_column_list.h} (79%) diff --git a/include/sqlpp11/count.h b/include/sqlpp11/count.h index f973e533..98c24cba 100644 --- a/include/sqlpp11/count.h +++ b/include/sqlpp11/count.h @@ -91,6 +91,7 @@ namespace sqlpp }; } +#warning: Add optional distinct flag to aggregate functions template auto count(T&& t) -> typename vendor::count_t::type> { diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 720018e5..51a4bdab 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include @@ -55,8 +55,8 @@ namespace sqlpp { template< typename Database, - typename Flags, - typename ExpressionList, + typename FlagList, + typename ColumnList, typename From, typename Where, typename GroupBy, @@ -66,10 +66,10 @@ namespace sqlpp typename Offset > struct select_t - : public ExpressionList::_value_type::template operators::value or is_select_flag_list_t::value, "invalid list of select flags"); - static_assert(vendor::is_noop or is_select_expression_list_t::value, "invalid list of select expressions"); + static_assert(is_select_flag_list_t::value, "invalid list of select flags"); + static_assert(is_select_column_list_t::value, "invalid list of select expressions"); static_assert(vendor::is_noop::value or is_from_t::value, "invalid 'from' argument"); static_assert(vendor::is_noop::value or is_where_t::value, "invalid 'where' argument"); static_assert(vendor::is_noop::value or is_group_by_t::value, "invalid 'group by' arguments"); @@ -94,73 +94,44 @@ namespace sqlpp using _is_select = std::true_type; using _requires_braces = std::true_type; - template - using set_expression_list_t = select_t; + template + using set_flag_list_t = select_t; + template + using set_column_list_t = select_t; template - using set_from_t = select_t; + using set_from_t = select_t; template - using set_where_t = select_t; + using set_where_t = select_t; template - using set_group_by_t = select_t; + using set_group_by_t = select_t; template - using set_having_t = select_t; + using set_having_t = select_t; template - using set_order_by_t = select_t; + using set_order_by_t = select_t; template - using set_limit_t = select_t; + using set_limit_t = select_t; template - using set_offset_t = select_t; + using set_offset_t = select_t; - using _result_row_t = typename ExpressionList::_result_row_t; - using _dynamic_names_t = typename ExpressionList::_dynamic_names_t; - using _parameter_tuple_t = std::tuple; + using _result_row_t = typename ColumnList::_result_row_t; + using _dynamic_names_t = typename ColumnList::_dynamic_names_t; + using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; // Indicators using _value_type = typename std::conditional< vendor::is_noop::value, no_value_t, // If there is no from, the select is not complete (this logic is a bit simple, but better than nothing) - typename ExpressionList::_value_type>::type; + typename ColumnList::_value_type>::type; - using _name_t = typename ExpressionList::_name_t; + using _name_t = typename ColumnList::_name_t; // The standard constructors, assigment operators and destructor - select_t(Flags&& flags, ExpressionList&& expression_list): - _flags(std::move(flags)), - _expression_list(std::move(expression_list)) - { - static_assert(std::is_same>::value, - "basic constructor only available for select_t (default template parameters)"); - } - - 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 - - select_t(Flags&& flags, ExpressionList&& expression_list, From&& from, - Where&& where, GroupBy&& group_by, Having&& having, - OrderBy&& order_by, Limit&& limit, Offset&& offset): - _flags(std::move(flags)), - _expression_list(std::move(expression_list)), - _from(std::move(from)), - _where(std::move(where)), - _group_by(std::move(group_by)), - _having(std::move(having)), - _order_by(std::move(order_by)), - _limit(std::move(limit)), - _offset(std::move(offset)) - { - } - - select_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), + constexpr select_t(FlagList flag_list, ColumnList column_list, From from, + Where where, GroupBy group_by, Having having, + OrderBy order_by, Limit limit, Offset offset): + _flags(flag_list), + _column_list(column_list), _from(from), _where(where), _group_by(group_by), @@ -171,22 +142,79 @@ namespace sqlpp { } -Idea: - lets add methods flags(...) and dynamic_flags(...) - add method columns(...) and make dynamic_columns(...) take arguments - offer empty select() and dynamic_select(db) to call *flags() and *columns() later - continue to offer select(...) and dynamic_select(db, ...) for convenience + 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; - also: have ONE constructor, taking values - - auto dynamic_columns() - -> set_expression_list_t> + // select functions + template + auto flags(Flag&&... flag) + -> set_flag_list_t::type...>> { - static_assert(not std::is_same::value, "cannot call dynamic_from() in a non-dynamic select"); - static_assert(vendor::is_noop::value, "cannot call dynamic_columns() after from()"); + static_assert(vendor::is_noop::value, "cannot call flags() after specifying them the first time"); + static_assert(vendor::is_noop::value, "cannot call dynamic_flags() after specifying columns"); + return { + {flag...}, + _column_list, + _from, + _where, + _group_by, + _having, + _order_by, + _limit, + _offset + }; + } + + template + auto dynamic_flags(Flag&&... flag) + -> set_flag_list_t::type...>> + { + static_assert(not std::is_same::value, "cannot call dynamic_flags() in a non-dynamic select"); + static_assert(vendor::is_noop::value, "cannot call dynamic_flags() after specifying them the first time"); + static_assert(vendor::is_noop::value, "cannot call dynamic_flags() after specifying columns"); + return { + {flag...}, + _column_list, + _from, + _where, + _group_by, + _having, + _order_by, + _limit, + _offset + }; + } + + template + auto columns(Column&&... column) + -> set_column_list_t::type...>> + { + static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); return { _flags, - {_expression_list._expressions}, + {std::tuple::type...>{std::forward(column)...}}, + _from, + _where, + _group_by, + _having, + _order_by, + _limit, + _offset + }; + } + + template + auto dynamic_columns(Column&&... column) + -> set_column_list_t::type...>>> + { + static_assert(not std::is_same::value, "cannot call dynamic_columns() in a non-dynamic select"); + static_assert(not ColumnList::size::value, "cannot call dynamic_columns() after specifying them the first time"); + return { + _flags, + {std::tuple::type...>{std::forward(column)...}}, _from, _where, _group_by, @@ -200,23 +228,22 @@ Idea: template select_t& add_column(NamedExpr&& namedExpr) { - static_assert(is_dynamic_t::value, "cannot call add_column() in a non-dynamic column list"); + static_assert(is_dynamic_t::value, "cannot call add_column() in a non-dynamic column list"); - _expression_list.add(std::forward(namedExpr)); + _column_list.add(std::forward(namedExpr)); return *this; } - // sqlpp functions template auto from(Table&&... table) -> set_from_t::type...>> { - static_assert(not vendor::is_noop::value, "cannot call from() without having selected anything"); + static_assert(not vendor::is_noop::value, "cannot call from() without having selected anything"); static_assert(vendor::is_noop::value, "cannot call from() twice for a single select"); return { _flags, - _expression_list, + _column_list, {std::tuple::type...>{std::forward(table)...}}, _where, _group_by, @@ -232,11 +259,11 @@ Idea: -> set_from_t::type...>> { static_assert(not std::is_same::value, "cannot call dynamic_from() in a non-dynamic select"); - static_assert(not vendor::is_noop::value, "cannot call from() without having selected anything"); + static_assert(not vendor::is_noop::value, "cannot call from() without having selected anything"); static_assert(vendor::is_noop::value, "cannot call from() twice for a single select"); return { _flags, - _expression_list, + _column_list, {std::tuple::type...>{std::forward
(table)...}}, _where, _group_by, @@ -250,7 +277,7 @@ Idea: template select_t& add_from(Table&& table) { - static_assert(not vendor::is_noop::value, "cannot call add_from() without having selected anything"); + static_assert(not vendor::is_noop::value, "cannot call add_from() without having selected anything"); static_assert(is_dynamic_t::value, "cannot call add_from() in a non-dynamic from"); _from.add(std::forward
(table)); @@ -266,7 +293,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call where() or dynamic_where() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, {std::tuple::type...>{std::forward(expr)...}}, _group_by, @@ -285,7 +312,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call where() or dynamic_where() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, {std::tuple::type...>{std::forward(expr)...}}, _group_by, @@ -314,7 +341,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call group_by() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, {std::tuple::type...>{std::forward(column)...}}, @@ -333,7 +360,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call group_by() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, {std::tuple::type...>{std::forward(column)...}}, @@ -362,7 +389,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call having() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, _group_by, @@ -381,7 +408,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call having() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, _group_by, @@ -410,7 +437,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call order_by() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, _group_by, @@ -429,7 +456,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call order_by() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, _group_by, @@ -458,7 +485,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call limit() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, _group_by, @@ -476,7 +503,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call limit() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, _group_by, @@ -504,7 +531,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call offset() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, _group_by, @@ -522,7 +549,7 @@ Idea: static_assert(vendor::is_noop::value, "cannot call offset() twice for a single select"); return { _flags, - _expression_list, + _column_list, _from, _where, _group_by, @@ -545,7 +572,7 @@ Idea: template struct _pseudo_table_t { - using table = typename ExpressionList::template _pseudo_table_t; + using table = typename ColumnList::template _pseudo_table_t; using alias = typename table::template _alias_t; }; @@ -556,9 +583,9 @@ Idea: *this).as(aliasProvider); } - const typename ExpressionList::_dynamic_names_t& get_dynamic_names() const + const typename ColumnList::_dynamic_names_t& get_dynamic_names() const { - return _expression_list._dynamic_expressions._dynamic_expression_names; + return _column_list._dynamic_expressions._dynamic_expression_names; } static constexpr size_t _get_static_no_of_parameters() @@ -581,7 +608,7 @@ Idea: auto run(Db& db) const -> result_t { - static_assert(not vendor::is_noop::value, "cannot run select without having selected anything"); + static_assert(not vendor::is_noop::value, "cannot run select without having selected anything"); static_assert(is_from_t::value, "cannot run select without a from()"); static_assert(_get_static_no_of_parameters() == 0, "cannot run select directly with parameters, use prepare instead"); // FIXME: Check for missing aliases (if references are used) @@ -595,7 +622,7 @@ Idea: auto prepare(Db& db) const -> prepared_select_t::type, select_t> { - static_assert(not vendor::is_noop::value, "cannot run select without having selected anything"); + static_assert(not vendor::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, well, actually, check for missing tables at the where(), order_by(), etc. @@ -603,8 +630,8 @@ Idea: return {{}, get_dynamic_names(), db.prepare_select(*this)}; } - Flags _flags; - ExpressionList _expression_list; + FlagList _flags; + ColumnList _column_list; From _from; Where _where; GroupBy _group_by; @@ -618,8 +645,8 @@ Idea: { template struct interpreter_t> { using T = select_t + template using make_select_flag_list_t = - vendor::select_flag_list_t()...))>; + vendor::select_flag_list_t()...))>; } // construct select expression list namespace detail { - template - using make_select_expression_list_t = - vendor::select_expression_list_t()...))>; + template + using make_select_column_list_t = + vendor::select_column_list_t()...))>; } + auto select() + -> select_t>, vendor::select_column_list_t>> + { + return { {}, vendor::select_column_list_t>{}, {}, {}, {}, {}, {}, {}, {} }; + } + template auto select(NamedExpr&&... namedExpr) - -> select_t, detail::make_select_expression_list_t> + -> select_t, detail::make_select_column_list_t> { return { { detail::make_flag_tuple(std::forward(namedExpr)...) }, - { detail::make_expression_tuple(std::forward(namedExpr)...) } + { detail::make_expression_tuple(std::forward(namedExpr)...) }, + {}, {}, {}, {}, {}, {}, {} }; } + template auto dynamic_select(const Db& db, NamedExpr&&... namedExpr) - -> select_t::type, detail::make_select_flag_list_t, detail::make_select_expression_list_t> + -> select_t::type, detail::make_select_flag_list_t::type, NamedExpr...>, detail::make_select_column_list_t::type, NamedExpr...>> { return { { detail::make_flag_tuple(std::forward(namedExpr)...) }, - { detail::make_expression_tuple(std::forward(namedExpr)...) } + { detail::make_expression_tuple(std::forward(namedExpr)...) }, + {}, {}, {}, {}, {}, {}, {} }; } diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index 3cba4240..f2b3c36e 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -97,7 +97,7 @@ namespace sqlpp SQLPP_TYPE_TRAIT_GENERATOR(is_pseudo_table); SQLPP_TYPE_TRAIT_GENERATOR(is_select); SQLPP_TYPE_TRAIT_GENERATOR(is_select_flag_list); - SQLPP_TYPE_TRAIT_GENERATOR(is_select_expression_list); + SQLPP_TYPE_TRAIT_GENERATOR(is_select_column_list); SQLPP_TYPE_TRAIT_GENERATOR(is_from); SQLPP_TYPE_TRAIT_GENERATOR(is_on); SQLPP_TYPE_TRAIT_GENERATOR(is_dynamic); diff --git a/include/sqlpp11/vendor/select_expression_list.h b/include/sqlpp11/vendor/select_column_list.h similarity index 79% rename from include/sqlpp11/vendor/select_expression_list.h rename to include/sqlpp11/vendor/select_column_list.h index ab9d06f6..e71f961f 100644 --- a/include/sqlpp11/vendor/select_expression_list.h +++ b/include/sqlpp11/vendor/select_column_list.h @@ -24,8 +24,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SQLPP_SELECT_EXPRESSION_LIST_H -#define SQLPP_SELECT_EXPRESSION_LIST_H +#ifndef SQLPP_SELECT_COLUMN_LIST_H +#define SQLPP_SELECT_COLUMN_LIST_H #include #include @@ -61,27 +61,27 @@ namespace sqlpp namespace vendor { template - struct dynamic_select_expression_list + struct dynamic_select_column_list { using _names_t = std::vector; - std::vector> _dynamic_expressions; + std::vector> _dynamic_columns; _names_t _dynamic_expression_names; template void push_back(Expr&& expr) { _dynamic_expression_names.push_back(std::decay::type::_name_t::_get_name()); - _dynamic_expressions.emplace_back(std::forward(expr)); + _dynamic_columns.emplace_back(std::forward(expr)); } bool empty() const { - return _dynamic_expressions.empty(); + return _dynamic_columns.empty(); } }; template<> - struct dynamic_select_expression_list + struct dynamic_select_column_list { struct _names_t {}; _names_t _dynamic_expression_names; @@ -96,13 +96,13 @@ namespace sqlpp }; template - struct interpreter_t> + struct interpreter_t> { - using T = dynamic_select_expression_list; + using T = dynamic_select_column_list; static Context& _(const T& t, Context& context) { - for (const auto column : t._dynamic_expressions) + for (const auto column : t._dynamic_columns) { interpret(column, context); } @@ -111,9 +111,9 @@ namespace sqlpp }; template - struct interpreter_t> + struct interpreter_t> { - using T = dynamic_select_expression_list; + using T = dynamic_select_column_list; static Context& _(const T& t, Context& context) { @@ -123,17 +123,18 @@ namespace sqlpp template - struct select_expression_list_t + struct select_column_list_t { - static_assert(::sqlpp::detail::wrong::value, "invalid template argument for select_expression_list"); + static_assert(::sqlpp::detail::wrong::value, "invalid template argument for select_column_list"); }; template - struct select_expression_list_t> + struct select_column_list_t> { - using _is_select_expression_list = std::true_type; + using _is_select_column_list = std::true_type; using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; using _parameter_tuple_t = std::tuple; + using size = std::tuple_size<_parameter_tuple_t>; // check for duplicate select expressions static_assert(not ::sqlpp::detail::has_duplicates::value, "at least one duplicate argument detected"); @@ -161,40 +162,40 @@ namespace sqlpp dynamic_result_row_t...>, result_row_t...>>::type; - using _dynamic_names_t = typename dynamic_select_expression_list::_names_t; + using _dynamic_names_t = typename dynamic_select_column_list::_names_t; template using _pseudo_table_t = select_pseudo_table_t; template - using _dynamic_t = select_expression_list_t>; + using _dynamic_t = select_column_list_t>; template void add(Expr&& namedExpr) { static_assert(is_named_expression_t::type>::value, "select() arguments require to be named expressions"); static_assert(_is_dynamic::value, "cannot add columns to a non-dynamic column list"); - _dynamic_expressions.push_back(std::forward(namedExpr)); + _dynamic_columns.push_back(std::forward(namedExpr)); } - _parameter_tuple_t _expressions; - dynamic_select_expression_list _dynamic_expressions; + _parameter_tuple_t _columns; + dynamic_select_column_list _dynamic_columns; }; template - struct interpreter_t> + struct interpreter_t> { - using T = select_expression_list_t; + using T = select_column_list_t; static Context& _(const T& t, Context& context) { // check for at least one expression static_assert(T::_is_dynamic::value or sizeof...(NamedExpr), "at least one select expression required"); - interpret_tuple(t._expressions, ',', context); - if (sizeof...(NamedExpr) and not t._dynamic_expressions.empty()) + interpret_tuple(t._columns, ',', context); + if (sizeof...(NamedExpr) and not t._dynamic_columns.empty()) context << ','; - interpret(t._dynamic_expressions, context); + interpret(t._dynamic_columns, context); return context; } }; diff --git a/include/sqlpp11/vendor/select_flag_list.h b/include/sqlpp11/vendor/select_flag_list.h index 62630b88..bf281a22 100644 --- a/include/sqlpp11/vendor/select_flag_list.h +++ b/include/sqlpp11/vendor/select_flag_list.h @@ -104,15 +104,15 @@ namespace sqlpp namespace vendor { - template + template struct select_flag_list_t { static_assert(detail::wrong::value, "invalid argument for select_flag_list"); }; // select_flag_list_t - template - struct select_flag_list_t> + template + struct select_flag_list_t> { // check for duplicate order expressions static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected in select flag list"); @@ -126,10 +126,10 @@ namespace sqlpp std::tuple _flags; }; - template - struct interpreter_t>> + template + struct interpreter_t>> { - using T = select_flag_list_t>; + using T = select_flag_list_t>; static Context& _(const T& t, Context& context) { diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index da620dba..74904e21 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -110,7 +110,7 @@ int main() interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); // dynamic select - interpret(dynamic_select(db, t.alpha).dynamic_columns().add_column(t.beta), printer).flush(); + interpret(dynamic_select(db).dynamic_columns(t.alpha).add_column(t.beta), printer).flush(); return 0; } From 075e63c48680f014bfecb49363368cd1dc6ce468 Mon Sep 17 00:00:00 2001 From: rbock Date: Mon, 20 Jan 2014 23:17:07 +0100 Subject: [PATCH 3/5] Added test for (empty) dynamic select flag list --- include/sqlpp11/select.h | 18 +++++++++--------- include/sqlpp11/vendor/select_flag_list.h | 18 ++++++++++++++++-- tests/InterpretTest.cpp | 2 +- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 51a4bdab..3e78758c 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -151,12 +151,12 @@ namespace sqlpp // select functions template auto flags(Flag&&... flag) - -> set_flag_list_t::type...>> + -> set_flag_list_t::type...>>> { - static_assert(vendor::is_noop::value, "cannot call flags() after specifying them the first time"); - static_assert(vendor::is_noop::value, "cannot call dynamic_flags() after specifying columns"); + static_assert(not FlagList::size::value, "cannot call dynamic_flags() after specifying them the first time"); + static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); return { - {flag...}, + {std::tuple::type...>{std::forward(flag)...}}, _column_list, _from, _where, @@ -170,13 +170,13 @@ namespace sqlpp template auto dynamic_flags(Flag&&... flag) - -> set_flag_list_t::type...>> + -> set_flag_list_t::type...>>> { static_assert(not std::is_same::value, "cannot call dynamic_flags() in a non-dynamic select"); - static_assert(vendor::is_noop::value, "cannot call dynamic_flags() after specifying them the first time"); - static_assert(vendor::is_noop::value, "cannot call dynamic_flags() after specifying columns"); + static_assert(not FlagList::size::value, "cannot call dynamic_flags() after specifying them the first time"); + static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); return { - {flag...}, + {std::tuple::type...>{std::forward(flag)...}}, _column_list, _from, _where, @@ -190,7 +190,7 @@ namespace sqlpp template auto columns(Column&&... column) - -> set_column_list_t::type...>> + -> set_column_list_t::type...>>> { static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); return { diff --git a/include/sqlpp11/vendor/select_flag_list.h b/include/sqlpp11/vendor/select_flag_list.h index bf281a22..83cdef0d 100644 --- a/include/sqlpp11/vendor/select_flag_list.h +++ b/include/sqlpp11/vendor/select_flag_list.h @@ -114,6 +114,11 @@ namespace sqlpp template struct select_flag_list_t> { + using _is_select_flag_list = std::true_type; + using _is_dynamic = typename std::conditional::value, std::false_type, std::true_type>::type; + using _parameter_tuple_t = std::tuple; + using size = std::tuple_size<_parameter_tuple_t>; + // check for duplicate order expressions static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected in select flag list"); @@ -121,9 +126,15 @@ namespace sqlpp using _valid_flags = typename detail::make_set_if::type; static_assert(_valid_flags::size::value == sizeof...(Flag), "at least one argument is not a select flag in select flag list"); - using _is_select_flag_list = std::true_type; + template + void add(E&& expr) + { + static_assert(is_select_flag_t::type>::value, "flag arguments require to be select flags"); + _dynamic_flags.push_back(std::forward(expr)); + } - std::tuple _flags; + _parameter_tuple_t _flags; + vendor::interpretable_list_t _dynamic_flags; }; template @@ -136,6 +147,9 @@ namespace sqlpp interpret_tuple(t._flags, ' ', context); if (sizeof...(Flag)) context << ' '; + interpret_list(t._dynamic_flags, ',', context); + if (not t._dynamic_flags.empty()) + context << ' '; return context; } }; diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 74904e21..2ce6e37a 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -110,7 +110,7 @@ int main() interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); // dynamic select - interpret(dynamic_select(db).dynamic_columns(t.alpha).add_column(t.beta), printer).flush(); + interpret(dynamic_select(db).dynamic_flags().dynamic_columns(t.alpha).add_column(t.beta), printer).flush(); return 0; } From a22b07aa036725c8a3016e552559f16f5ba8862a Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 21 Jan 2014 09:50:58 +0100 Subject: [PATCH 4/5] Added more tests (and fixes) for dynamic columns and flags --- include/sqlpp11/select.h | 52 ++++++++++++--------- include/sqlpp11/vendor/select_column_list.h | 15 ++++-- include/sqlpp11/vendor/select_flag_list.h | 2 +- tests/InterpretTest.cpp | 2 + 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 3e78758c..40c90ff9 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -131,7 +131,7 @@ namespace sqlpp Where where, GroupBy group_by, Having having, OrderBy order_by, Limit limit, Offset offset): _flags(flag_list), - _column_list(column_list), + _columns(column_list), _from(from), _where(where), _group_by(group_by), @@ -157,7 +157,7 @@ namespace sqlpp static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); return { {std::tuple::type...>{std::forward(flag)...}}, - _column_list, + _columns, _from, _where, _group_by, @@ -177,7 +177,7 @@ namespace sqlpp static_assert(not ColumnList::size::value, "cannot call columns() after specifying them the first time"); return { {std::tuple::type...>{std::forward(flag)...}}, - _column_list, + _columns, _from, _where, _group_by, @@ -188,6 +188,16 @@ namespace sqlpp }; } + template + select_t& add_flag(Flag&& flag) + { + static_assert(is_dynamic_t::value, "cannot call add_flag() in a non-dynamic column list"); + + _flags.add(std::forward(flag)); + + return *this; + } + template auto columns(Column&&... column) -> set_column_list_t::type...>>> @@ -230,7 +240,7 @@ namespace sqlpp { static_assert(is_dynamic_t::value, "cannot call add_column() in a non-dynamic column list"); - _column_list.add(std::forward(namedExpr)); + _columns.add(std::forward(namedExpr)); return *this; } @@ -243,7 +253,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call from() twice for a single select"); return { _flags, - _column_list, + _columns, {std::tuple::type...>{std::forward
(table)...}}, _where, _group_by, @@ -263,7 +273,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call from() twice for a single select"); return { _flags, - _column_list, + _columns, {std::tuple::type...>{std::forward
(table)...}}, _where, _group_by, @@ -293,7 +303,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call where() or dynamic_where() twice for a single select"); return { _flags, - _column_list, + _columns, _from, {std::tuple::type...>{std::forward(expr)...}}, _group_by, @@ -312,7 +322,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call where() or dynamic_where() twice for a single select"); return { _flags, - _column_list, + _columns, _from, {std::tuple::type...>{std::forward(expr)...}}, _group_by, @@ -341,7 +351,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call group_by() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, {std::tuple::type...>{std::forward(column)...}}, @@ -360,7 +370,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call group_by() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, {std::tuple::type...>{std::forward(column)...}}, @@ -389,7 +399,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call having() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, _group_by, @@ -408,7 +418,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call having() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, _group_by, @@ -437,7 +447,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call order_by() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, _group_by, @@ -456,7 +466,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call order_by() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, _group_by, @@ -485,7 +495,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call limit() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, _group_by, @@ -503,7 +513,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call limit() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, _group_by, @@ -531,7 +541,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call offset() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, _group_by, @@ -549,7 +559,7 @@ namespace sqlpp static_assert(vendor::is_noop::value, "cannot call offset() twice for a single select"); return { _flags, - _column_list, + _columns, _from, _where, _group_by, @@ -585,7 +595,7 @@ namespace sqlpp const typename ColumnList::_dynamic_names_t& get_dynamic_names() const { - return _column_list._dynamic_expressions._dynamic_expression_names; + return _columns._dynamic_expressions._dynamic_expression_names; } static constexpr size_t _get_static_no_of_parameters() @@ -631,7 +641,7 @@ namespace sqlpp } FlagList _flags; - ColumnList _column_list; + ColumnList _columns; From _from; Where _where; GroupBy _group_by; @@ -682,7 +692,7 @@ namespace sqlpp context << "SELECT "; interpret(t._flags, context); - interpret(t._column_list, context); + interpret(t._columns, context); interpret(t._from, context); interpret(t._where, context); interpret(t._group_by, context); diff --git a/include/sqlpp11/vendor/select_column_list.h b/include/sqlpp11/vendor/select_column_list.h index e71f961f..36efb557 100644 --- a/include/sqlpp11/vendor/select_column_list.h +++ b/include/sqlpp11/vendor/select_column_list.h @@ -102,8 +102,13 @@ namespace sqlpp static Context& _(const T& t, Context& context) { + bool first = true; for (const auto column : t._dynamic_columns) { + if (first) + first = false; + else + context << ','; interpret(column, context); } return context; @@ -182,18 +187,18 @@ namespace sqlpp dynamic_select_column_list _dynamic_columns; }; - template - struct interpreter_t> + template + struct interpreter_t> { - using T = select_column_list_t; + using T = select_column_list_t; static Context& _(const T& t, Context& context) { // check for at least one expression - static_assert(T::_is_dynamic::value or sizeof...(NamedExpr), "at least one select expression required"); + static_assert(T::_is_dynamic::value or T::size::value, "at least one select expression required"); interpret_tuple(t._columns, ',', context); - if (sizeof...(NamedExpr) and not t._dynamic_columns.empty()) + if (T::size::value and not t._dynamic_columns.empty()) context << ','; interpret(t._dynamic_columns, context); return context; diff --git a/include/sqlpp11/vendor/select_flag_list.h b/include/sqlpp11/vendor/select_flag_list.h index 83cdef0d..d0aaaedf 100644 --- a/include/sqlpp11/vendor/select_flag_list.h +++ b/include/sqlpp11/vendor/select_flag_list.h @@ -130,7 +130,7 @@ namespace sqlpp void add(E&& expr) { static_assert(is_select_flag_t::type>::value, "flag arguments require to be select flags"); - _dynamic_flags.push_back(std::forward(expr)); + _dynamic_flags.emplace_back(std::forward(expr)); } _parameter_tuple_t _flags; diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index 2ce6e37a..b3d66de5 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -111,6 +111,8 @@ int main() // dynamic select interpret(dynamic_select(db).dynamic_flags().dynamic_columns(t.alpha).add_column(t.beta), printer).flush(); + interpret(dynamic_select(db).dynamic_flags().dynamic_columns().add_column(t.gamma).add_column(t.beta), printer).flush(); + interpret(dynamic_select(db).dynamic_flags(sqlpp::distinct).add_flag(sqlpp::all).dynamic_columns(t.alpha).add_column(t.beta), printer).flush(); return 0; } From 370c61870ba91a51dcbb94c09fa303bafc242963 Mon Sep 17 00:00:00 2001 From: rbock Date: Tue, 21 Jan 2014 23:19:03 +0100 Subject: [PATCH 5/5] Updated tests a bit --- tests/InterpretTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/InterpretTest.cpp b/tests/InterpretTest.cpp index b3d66de5..d8fff6bc 100644 --- a/tests/InterpretTest.cpp +++ b/tests/InterpretTest.cpp @@ -110,8 +110,8 @@ int main() interpret(multi_column(t.alpha, t.alpha, (t.beta + "cake").as(t.gamma)), printer).flush(); // dynamic select - interpret(dynamic_select(db).dynamic_flags().dynamic_columns(t.alpha).add_column(t.beta), printer).flush(); - interpret(dynamic_select(db).dynamic_flags().dynamic_columns().add_column(t.gamma).add_column(t.beta), printer).flush(); + interpret(dynamic_select(db).dynamic_flags().dynamic_columns(t.alpha).add_column(t.beta).add_column(t.gamma), printer).flush(); + interpret(dynamic_select(db).dynamic_flags().add_flag(sqlpp::distinct).dynamic_columns().add_column(t.gamma).add_column(t.beta), printer).flush(); interpret(dynamic_select(db).dynamic_flags(sqlpp::distinct).add_flag(sqlpp::all).dynamic_columns(t.alpha).add_column(t.beta), printer).flush(); return 0;