From 7050491bf0e5a0ffc46a5cbee3acc30a81650c0f Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Tue, 29 Oct 2013 19:32:52 +0100 Subject: [PATCH] Added support for dynamic columns --- include/sqlpp11/detail/basic_operators.h | 2 +- include/sqlpp11/result.h | 9 ++- include/sqlpp11/result_row.h | 93 +++++++++++++++++++++++- include/sqlpp11/select.h | 12 +-- include/sqlpp11/select_expression_list.h | 6 +- 5 files changed, 102 insertions(+), 20 deletions(-) diff --git a/include/sqlpp11/detail/basic_operators.h b/include/sqlpp11/detail/basic_operators.h index 0011329a..1b60933a 100644 --- a/include/sqlpp11/detail/basic_operators.h +++ b/include/sqlpp11/detail/basic_operators.h @@ -27,7 +27,7 @@ #ifndef SQLPP_DETAIL_BASIC_OPERATORS_H #define SQLPP_DETAIL_BASIC_OPERATORS_H -#include +#include #include #include #include diff --git a/include/sqlpp11/result.h b/include/sqlpp11/result.h index 0629ef7f..bddba2c7 100644 --- a/include/sqlpp11/result.h +++ b/include/sqlpp11/result.h @@ -41,20 +41,23 @@ namespace sqlpp db_result_t _result; raw_result_row_t _raw_result_row; raw_result_row_t _end; + std::vector _dynamic_columns; // only needed in case of dynamic columns in the select ResultRow _result_row; public: result_t(): _raw_result_row({}), _end({}), - _result_row(_raw_result_row) + _dynamic_columns(), + _result_row(_raw_result_row, _dynamic_columns) {} - result_t(db_result_t&& result): + result_t(db_result_t&& result, std::vector dynamic_columns): _result(std::move(result)), _raw_result_row(_result.next()), _end({}), - _result_row(_raw_result_row) + _dynamic_columns(dynamic_columns), + _result_row(_raw_result_row, _dynamic_columns) {} result_t(const result_t&) = delete; diff --git a/include/sqlpp11/result_row.h b/include/sqlpp11/result_row.h index a96fc6dd..ff418472 100644 --- a/include/sqlpp11/result_row.h +++ b/include/sqlpp11/result_row.h @@ -29,7 +29,10 @@ #include #include +#include #include +#include + namespace sqlpp { namespace detail @@ -44,6 +47,7 @@ namespace sqlpp { using _field = typename NamedExpr::_name_t::template _member_t>; using _rest = result_row_impl; + static constexpr size_t _last_index = _rest::_last_index; result_row_impl(const raw_result_row_t& raw_result_row): _field({raw_result_row}), @@ -65,6 +69,7 @@ namespace sqlpp { using _multi_field = typename AliasProvider::_name_t::template _member_t>; using _rest = result_row_impl; + static constexpr size_t _last_index = _rest::_last_index; result_row_impl(const raw_result_row_t& raw_result_row): _multi_field({raw_result_row}), @@ -82,6 +87,7 @@ namespace sqlpp template struct result_row_impl { + static constexpr size_t _last_index = index; result_row_impl(const raw_result_row_t& raw_result_row) {} @@ -95,16 +101,18 @@ namespace sqlpp template struct result_row_t: public detail::result_row_impl<0, 0, NamedExpr...> { + using _impl = detail::result_row_impl<0, 0, NamedExpr...>; bool _is_row; - result_row_t(const raw_result_row_t& raw_result_row): - detail::result_row_impl<0, 0, NamedExpr...>(raw_result_row), + result_row_t(const raw_result_row_t& raw_result_row, const std::vector&): // FIXME: it hurts a bit to always transport the dynamic part as well + _impl(raw_result_row), _is_row(raw_result_row.data != nullptr) - {} + { + } result_row_t& operator=(const raw_result_row_t& raw_result_row) { - detail::result_row_impl<0, 0, NamedExpr...>::operator=(raw_result_row); + _impl::operator=(raw_result_row); _is_row = raw_result_row.data != nullptr; return *this; } @@ -114,6 +122,83 @@ namespace sqlpp return _is_row; } }; + + template + struct dynamic_result_row_t: public detail::result_row_impl<0, 0, NamedExpr...> + { + using _impl = detail::result_row_impl<0, 0, NamedExpr...>; + using _field_type = detail::text::_result_entry_t<0>; + static constexpr size_t _last_static_index = _impl::_last_index; + + bool _is_row; + std::vector _dynamic_columns; + std::map _dynamic_fields; + + dynamic_result_row_t(const raw_result_row_t& raw_result_row, std::vector dynamic_columns): + detail::result_row_impl<0, 0, NamedExpr...>(raw_result_row), + _is_row(raw_result_row.data != nullptr) + { + raw_result_row_t dynamic_row = raw_result_row; + if (_is_row) + { + dynamic_row.data += _last_static_index; + dynamic_row.len += _last_static_index; + for (const auto& column : _dynamic_columns) + { + _dynamic_fields.insert(std::make_pair(column, _field_type(dynamic_row))); + ++dynamic_row.data; + ++dynamic_row.len; + } + } + else + { + for (const auto& column : _dynamic_columns) + { + _dynamic_fields.insert(std::make_pair(column, _field_type(dynamic_row))); + } + } + + } + + dynamic_result_row_t& operator=(const raw_result_row_t& raw_result_row) + { + detail::result_row_impl<0, 0, NamedExpr...>::operator=(raw_result_row); + _is_row = raw_result_row.data != nullptr; + + raw_result_row_t dynamic_row = raw_result_row; + if (_is_row) + { + dynamic_row.data += _last_static_index; + dynamic_row.len += _last_static_index; + for (const auto& column : _dynamic_columns) + { + _dynamic_fields.at(column) = dynamic_row; + ++dynamic_row.data; + ++dynamic_row.len; + } + } + else + { + for (const auto& column : _dynamic_columns) + { + _dynamic_fields.at(column) = dynamic_row; + } + } + + return *this; + } + + const _field_type& at(const std::string& field_name) const + { + return _dynamic_fields.at(field_name); + } + + explicit operator bool() const + { + return _is_row; + } + + }; } #endif diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 62d4fa91..57928ecb 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -572,7 +572,7 @@ namespace sqlpp std::ostringstream oss; serialize(oss, db); - return {db.select(oss.str())}; + return {db.select(oss.str()), _expression_list._dynamic_expression_names}; } Flags _flags; @@ -621,15 +621,5 @@ namespace sqlpp }; } -#warning: need to add dynamic fields - /* Idea: Use a vector of serializable or similar for select. - * Translate the vector into a map, first = name, second = something similar to text which knows its index - * - * What about default constructing the result? Not a problem. The map is empty then. - * - * But how to transport the vector of serializables from the select into the result? - * - * Maybe store the names of the map content in a field in the query? - */ } #endif diff --git a/include/sqlpp11/select_expression_list.h b/include/sqlpp11/select_expression_list.h index 1c84628b..5d11f0ed 100644 --- a/include/sqlpp11/select_expression_list.h +++ b/include/sqlpp11/select_expression_list.h @@ -100,7 +100,9 @@ namespace sqlpp }; using _name_t = typename detail::get_first_argument_if_unique::_name_t; - using _result_row_t = result_row_t...>; + using _result_row_t = typename std::conditional<_is_dynamic::value, + dynamic_result_row_t...>, + result_row_t...>>::type; template using _pseudo_table_t = select_pseudo_table_t; @@ -113,6 +115,7 @@ namespace sqlpp { static_assert(is_named_expression_t::type>::value, "select() arguments require to be named expressions"); _dynamic_expressions.push_back(std::forward(namedExpr)); + _dynamic_expression_names.push_back(std::decay::type::_name_t::_get_name()); } template @@ -134,6 +137,7 @@ namespace sqlpp std::tuple _expressions; typename detail::dynamic_select_expression_list::type _dynamic_expressions; + std::vector _dynamic_expression_names; }; }