0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-15 20:31:16 +08:00

Remove multi_column.

While a nice feature in theory, this was extremely rarely used
and added quite a bit of complexity to the code.
This commit is contained in:
Roland Bock 2021-07-30 21:05:36 +02:00
parent 77db53436d
commit 34a8f34821
11 changed files with 15 additions and 401 deletions

View File

@ -75,7 +75,7 @@ Using aliases also comes in handy when you join tables and have several columns
select(foo.id, bar.id); // compile error
```
One of the columns needs an alias (or you use multi-columns as shown below).
One of the columns needs an alias.
```C++
SQLPP_ALIAS_PROVIDER(barId);
select(foo.id, bar.id.as(barId));
@ -129,28 +129,6 @@ Statements like `SELECT * from foo` is used pretty often in SQL. sqlpp11 offers
```C++
select(all_of(foo));
```
### Multi-Columns
Sometimes, when you join tables `foo`, `bar` and `baz`, you might want to select several columns of the same name. As shown above, you could use aliases to resolve name clashes. Another option is to group columns together in multi-columns. Here is an example:
```
SQLPP_ALIAS_PROVIDER_GENERATOR(left);
for(const auto& row : db(
select(foo.id,
multi_column(left, foo.id, foo.name, foo.hasFun),
multi_column(foo, all_of(foo)))
.from(foo)))
{
std::cerr << "row.left.id: " << row.left.id
<< ", row.left.name: " << row.left.name
<< ", row.left.hasFun: " << row.left.hasFun << std::endl;
std::cerr << "row.foo.id: " << row.foo.id
<< ", row.foo.name: " << row.foo.name
<< ", row.foo.hasFun: " << row.foo.hasFun << std::endl;
};
```
That might not be the most creative example in the world, but it shows how to use multi-columns. The first argument is an alias provider. In the cases shown above, the alias provider `left` is created using the `SQLPP_ALIAS_PROVIDER` macro. Tables also have a name and can provide an alias.
In the result rows, the multi-columns are accessed by their name. Their members in turn are accessed by their names.
## From
The `from` method expects one argument. The following subsections expand on the types of valid arguments:

View File

@ -29,7 +29,6 @@
#include <sqlpp11/alias.h>
#include <sqlpp11/interpret.h>
#include <sqlpp11/multi_column.h>
#include <sqlpp11/portable_static_assert.h>
namespace sqlpp
@ -38,12 +37,6 @@ namespace sqlpp
struct all_of_t
{
using _column_tuple_t = typename Table::_column_tuple_t;
template <typename AliasProvider>
detail::copy_tuple_args_t<multi_column_alias_t, AliasProvider, _column_tuple_t> as(const AliasProvider& alias)
{
return multi_column(_column_tuple_t{}).as(alias);
}
};
template <typename Table>

View File

@ -1,85 +0,0 @@
/*
* Copyright (c) 2013-2015, 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 SQLPP11_DETAIL_FIELD_INDEX_SEQUENCE_H
#define SQLPP11_DETAIL_FIELD_INDEX_SEQUENCE_H
#include <type_traits>
#include <sqlpp11/field_spec.h>
namespace sqlpp
{
namespace detail
{
template <std::size_t NextIndex, std::size_t... Ints>
struct field_index_sequence
{
static constexpr std::size_t _next_index = NextIndex;
};
template <typename T, typename... Fields>
struct make_field_index_sequence_impl
{
static_assert(wrong_t<make_field_index_sequence_impl>::value, "invalid field index sequence arguments");
};
template <std::size_t NextIndex,
std::size_t... Ints,
typename NameType,
typename ValueType,
bool CanBeNull,
typename... Rest>
struct make_field_index_sequence_impl<field_index_sequence<NextIndex, Ints...>,
field_spec_t<NameType, ValueType, CanBeNull>,
Rest...>
{
using type = typename make_field_index_sequence_impl<field_index_sequence<NextIndex + 1, Ints..., NextIndex>,
Rest...>::type;
};
template <std::size_t NextIndex, std::size_t... Ints, typename AliasProvider, typename FieldTuple, typename... Rest>
struct make_field_index_sequence_impl<field_index_sequence<NextIndex, Ints...>,
multi_field_spec_t<AliasProvider, FieldTuple>,
Rest...>
{
using type = typename make_field_index_sequence_impl<
field_index_sequence<NextIndex + std::tuple_size<FieldTuple>::value, Ints..., NextIndex>,
Rest...>::type;
};
template <std::size_t NextIndex, std::size_t... Ints>
struct make_field_index_sequence_impl<field_index_sequence<NextIndex, Ints...>>
{
using type = field_index_sequence<NextIndex, Ints...>;
};
template <std::size_t StartIndex, typename... Fields>
using make_field_index_sequence =
typename make_field_index_sequence_impl<field_index_sequence<StartIndex>, Fields...>::type;
} // namespace detail
} // namespace sqlpp
#endif

View File

@ -27,7 +27,7 @@
#ifndef SQLPP11_FIELD_SPEC_H
#define SQLPP11_FIELD_SPEC_H
#include <sqlpp11/multi_column.h>
#include <sqlpp11/type_traits.h>
namespace sqlpp
{
@ -42,18 +42,6 @@ namespace sqlpp
using _alias_t = NameType;
};
template <typename AliasProvider, typename FieldSpecTuple>
struct multi_field_spec_t
{
static_assert(wrong_t<AliasProvider, FieldSpecTuple>::value,
"multi_field_spec_t needs to be specialized with a tuple");
};
template <typename AliasProvider, typename... FieldSpecs>
struct multi_field_spec_t<AliasProvider, std::tuple<FieldSpecs...>>
{
};
template <typename Left, typename Right, typename Enable = void>
struct is_field_compatible
{
@ -76,14 +64,6 @@ namespace sqlpp
// NULL if the right hand side allows it
};
template <typename LeftAlias, typename... LeftFields, typename RightAlias, typename... RightFields>
struct is_field_compatible<multi_field_spec_t<LeftAlias, std::tuple<LeftFields...>>,
multi_field_spec_t<RightAlias, std::tuple<RightFields...>>,
typename std::enable_if<sizeof...(LeftFields) == sizeof...(RightFields)>::type>
{
static constexpr auto value = logic::all_t<is_field_compatible<LeftFields, RightFields>::value...>::value;
};
namespace detail
{
template <typename Select, typename NamedExpr>
@ -98,13 +78,6 @@ namespace sqlpp
value_type_of<NamedExpr>,
logic::any_t<_can_be_null, _depends_on_outer_table>::value>;
};
template <typename Select, typename AliasProvider, typename... NamedExprs>
struct make_field_spec_impl<Select, multi_column_alias_t<AliasProvider, NamedExprs...>>
{
using type =
multi_field_spec_t<AliasProvider, std::tuple<typename make_field_spec_impl<Select, NamedExprs>::type...>>;
};
} // namespace detail
template <typename Select, typename NamedExpr>

View File

@ -1,145 +0,0 @@
/*
* Copyright (c) 2013-2015, 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 SQLPP11_MULTI_COLUMN_H
#define SQLPP11_MULTI_COLUMN_H
#include <sqlpp11/logic.h>
#include <sqlpp11/detail/type_set.h>
#include <sqlpp11/detail/copy_tuple_args.h>
namespace sqlpp
{
struct no_value_t;
template <typename AliasProvider, typename... Columns>
struct multi_column_alias_t;
template <typename Unused, typename... Columns>
struct multi_column_t
{
using _traits = make_traits<no_value_t>;
using _nodes = detail::type_vector<Columns...>;
static_assert(logic::all_t<is_selectable_t<Columns>::value...>::value,
"multi_column parameters need to be named expressions");
multi_column_t(std::tuple<Columns...> columns) : _columns(columns)
{
}
multi_column_t(Columns... columns) : _columns(columns...)
{
}
multi_column_t(const multi_column_t&) = default;
multi_column_t(multi_column_t&&) = default;
multi_column_t& operator=(const multi_column_t&) = default;
multi_column_t& operator=(multi_column_t&&) = default;
~multi_column_t() = default;
template <typename AliasProvider>
multi_column_alias_t<AliasProvider, Columns...> as(const AliasProvider& /*unused*/)
{
return {*this};
}
std::tuple<Columns...> _columns;
};
template <typename AliasProvider, typename... Columns>
struct multi_column_alias_t
{
using _traits = make_traits<no_value_t, tag::is_alias, tag::is_multi_column, tag::is_selectable>;
using _nodes = detail::type_vector<Columns...>;
static_assert(logic::all_t<is_selectable_t<Columns>::value...>::value,
"multi_column parameters need to be named expressions");
using _alias_t = typename AliasProvider::_alias_t;
multi_column_alias_t(multi_column_t<void, Columns...> multi_column) : _columns(multi_column._columns)
{
}
multi_column_alias_t(std::tuple<Columns...> 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;
std::tuple<Columns...> _columns;
};
template <typename Context, typename... Columns>
struct serializer_t<Context, multi_column_t<void, Columns...>>
{
using _serialize_check = serialize_check_of<Context, Columns...>;
using T = multi_column_t<void, Columns...>;
static void _(const T& /*unused*/, Context& /*unused*/)
{
static_assert(wrong_t<serializer_t>::value, "multi_column must be used with an alias");
}
};
template <typename Context, typename AliasProvider, typename... Columns>
struct serializer_t<Context, multi_column_alias_t<AliasProvider, Columns...>>
{
using _serialize_check = serialize_check_of<Context, Columns...>;
using T = multi_column_alias_t<AliasProvider, Columns...>;
static Context& _(const T& t, Context& context)
{
interpret_tuple(t._columns, ',', context);
return context;
}
};
namespace detail
{
template <typename... Columns>
using make_multi_column_t =
copy_tuple_args_t<multi_column_t, void, decltype(column_tuple_merge(std::declval<Columns>()...))>;
} // namespace detail
template <typename... Columns>
auto multi_column(Columns... columns) -> detail::make_multi_column_t<Columns...>
{
return detail::make_multi_column_t<Columns...>(std::tuple_cat(detail::as_column_tuple<Columns>::_(columns)...));
}
} // namespace sqlpp
#endif

View File

@ -30,7 +30,7 @@
#include <map>
#include <utility>
#include <sqlpp11/data_types/text.h>
#include <sqlpp11/detail/field_index_sequence.h>
#include <sqlpp11/detail/index_sequence.h>
#include <sqlpp11/dynamic_select_column_list.h>
#include <sqlpp11/field_spec.h>
#include <sqlpp11/no_name.h>
@ -85,54 +85,8 @@ namespace sqlpp
}
};
template <std::size_t index, typename AliasProvider, typename Db, typename... FieldSpecs>
struct result_field<Db, index, multi_field_spec_t<AliasProvider, std::tuple<FieldSpecs...>>>
: public member_t<AliasProvider,
result_row_impl<Db, detail::make_field_index_sequence<index, FieldSpecs...>, FieldSpecs...>>
{
using _multi_field =
member_t<AliasProvider,
result_row_impl<Db, detail::make_field_index_sequence<index, FieldSpecs...>, FieldSpecs...>>;
result_field() = default;
void _validate()
{
_multi_field::operator()()._validate();
}
void _invalidate()
{
_multi_field::operator()()._invalidate();
}
template <typename Target>
void _bind(Target& target)
{
_multi_field::operator()()._bind(target);
}
template <typename Target>
void _post_bind(Target& target)
{
_multi_field::operator()()._post_bind(target);
}
template <typename Callable>
void _apply(Callable& callable) const
{
_multi_field::operator()()._apply(callable);
}
template <typename Callable>
void _apply(const Callable& callable) const
{
_multi_field::operator()()._apply(callable);
}
};
template <typename Db, std::size_t NextIndex, std::size_t... Is, typename... FieldSpecs>
struct result_row_impl<Db, detail::field_index_sequence<NextIndex, Is...>, FieldSpecs...>
template <typename Db, std::size_t... Is, typename... FieldSpecs>
struct result_row_impl<Db, detail::index_sequence<Is...>, FieldSpecs...>
: public result_field<Db, Is, FieldSpecs>...
{
result_row_impl() = default;
@ -181,10 +135,9 @@ namespace sqlpp
template <typename Db, typename... FieldSpecs>
struct result_row_t
: public detail::result_row_impl<Db, detail::make_field_index_sequence<0, FieldSpecs...>, FieldSpecs...>
: public detail::result_row_impl<Db, detail::make_index_sequence<sizeof...(FieldSpecs)>, FieldSpecs...>
{
using _field_index_sequence = detail::make_field_index_sequence<0, FieldSpecs...>;
using _impl = detail::result_row_impl<Db, _field_index_sequence, FieldSpecs...>;
using _impl = detail::result_row_impl<Db, detail::make_index_sequence<sizeof...(FieldSpecs)>, FieldSpecs...>;
bool _is_valid{false};
result_row_t() : _impl()
@ -224,7 +177,7 @@ namespace sqlpp
static constexpr size_t static_size()
{
return _field_index_sequence::_next_index;
return sizeof...(FieldSpecs);
}
template <typename Target>
@ -268,10 +221,9 @@ namespace sqlpp
template <typename Db, typename... FieldSpecs>
struct dynamic_result_row_t
: public detail::result_row_impl<Db, detail::make_field_index_sequence<0, FieldSpecs...>, FieldSpecs...>
: public detail::result_row_impl<Db, detail::make_index_sequence<sizeof...(FieldSpecs)>, FieldSpecs...>
{
using _field_index_sequence = detail::make_field_index_sequence<0, FieldSpecs...>;
using _impl = detail::result_row_impl<Db, _field_index_sequence, FieldSpecs...>;
using _impl = detail::result_row_impl<Db, detail::make_index_sequence<sizeof...(FieldSpecs)>, FieldSpecs...>;
using _field_type = result_field_t<Db, field_spec_t<no_name_t, text, true>>;
bool _is_valid{false};
@ -336,7 +288,7 @@ namespace sqlpp
{
_impl::_bind(target);
std::size_t index = _field_index_sequence::_next_index;
std::size_t index = sizeof...(FieldSpecs);
for (const auto& field_name : _dynamic_field_names)
{
_dynamic_fields.at(field_name)._bind(target, index);
@ -349,7 +301,7 @@ namespace sqlpp
{
_impl::_post_bind(target);
std::size_t index = _field_index_sequence::_next_index;
std::size_t index = sizeof...(FieldSpecs);
for (const auto& field_name : _dynamic_field_names)
{
_dynamic_fields.at(field_name)._post_bind(target, index);
@ -362,7 +314,7 @@ namespace sqlpp
{
_impl::_apply(callable);
std::size_t index = _field_index_sequence::_next_index;
std::size_t index = sizeof...(FieldSpecs);
for (const auto& field_name : _dynamic_field_names)
{
_dynamic_fields.at(field_name)._apply(callable);
@ -375,7 +327,7 @@ namespace sqlpp
{
_impl::_apply(callable);
std::size_t index = _field_index_sequence::_next_index;
std::size_t index = sizeof...(FieldSpecs);
for (const auto& field_name : _dynamic_field_names)
{
_dynamic_fields.at(field_name)._apply(callable);

View File

@ -251,8 +251,6 @@ namespace sqlpp
consistency_check_t<_statement_t>{};
static_assert(_statement_t::_can_be_used_as_table(),
"statement cannot be used as table, e.g. due to missing tables");
static_assert(logic::none_t<is_multi_column_t<Columns>::value...>::value,
"cannot use multi-columns in sub selects");
return _table_t<AliasProvider>(_get_statement()).as(aliasProvider);
}
@ -306,8 +304,7 @@ namespace sqlpp
struct check_selected_columns
{
using type = static_combined_check_t<
static_check_t<logic::all_t<(is_selectable_t<T>::value or is_multi_column_t<T>::value)...>::value,
assert_selected_colums_are_selectable_t>>;
static_check_t<logic::all_t<is_selectable_t<T>::value...>::value, assert_selected_colums_are_selectable_t>>;
};
template <typename... T>
using check_selected_columns_t = typename check_selected_columns<T...>::type;

View File

@ -206,7 +206,6 @@ namespace sqlpp
SQLPP_VALUE_TRAIT_GENERATOR(is_offset)
SQLPP_VALUE_TRAIT_GENERATOR(is_using_)
SQLPP_VALUE_TRAIT_GENERATOR(is_column_list)
SQLPP_VALUE_TRAIT_GENERATOR(is_multi_column)
SQLPP_VALUE_TRAIT_GENERATOR(is_value_list)
SQLPP_VALUE_TRAIT_GENERATOR(is_assignment)
SQLPP_VALUE_TRAIT_GENERATOR(is_update_list)

View File

@ -135,11 +135,6 @@ int Interpret(int, char* [])
serialize(select(t.alpha).from(inner), printer).str();
}
// multi_column
serialize(multi_column(t.alpha, (t.beta + "cake").as(t.gamma)).as(t.alpha), printer).str();
serialize(multi_column(all_of(t)).as(t), printer).str();
serialize(all_of(t).as(t), printer).str();
// dynamic select
{
auto s = dynamic_select(db).dynamic_flags().dynamic_columns().from(t);

View File

@ -92,21 +92,6 @@ int Select(int, char*[])
std::cout << a << ", " << b << std::endl;
}
for (const auto& row : db(select(all_of(t).as(t)).from(t).unconditionally()))
{
int64_t a = row.tabBar.alpha;
const std::string b = row.tabBar.beta;
std::cout << a << ", " << b << std::endl;
}
for (const auto& row : db(select(all_of(t).as(t), t.gamma).from(t).where(t.alpha > 7)))
{
int64_t a = row.tabBar.alpha;
const std::string b = row.tabBar.beta;
const bool g = row.gamma;
std::cout << a << ", " << b << ", " << g << std::endl;
}
for (const auto& row :
db(select(all_of(t), t.gamma.as(t)).from(t).where(t.alpha > 7 and trim(t.beta) == "test").for_update()))
{

View File

@ -330,34 +330,6 @@ int SelectType(int, char*[])
// static_assert(std::is_same<decltype(b), decltype(c)>::value, "t has to be expanded by select()");
}
// Test that all_of(tab) is expanded in multi_column
{
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<decltype(a), decltype(b)>::value, "all_of(t) has to be expanded by multi_column");
}
// Test that a multicolumn is not a value
{
auto m = multi_column(t.alpha, t.beta).as(alias::a);
static_assert(not sqlpp::is_expression_t<decltype(m)>::value, "a multi_column is not a value");
}
// Test result field indices
{
using Select = decltype(select(all_of(t), // index 0, 1, 2, 3 (alpha, beta, gamma, delta)
multi_column(all_of(t)).as(alias::left), // index 4 (including 4, 5, 6, 7)
multi_column(all_of(t)).as(alias::right), // index 8 (including 8, 9, 10, 11)
t.alpha.as(alias::a) // index 12
)
.from(t)
.unconditionally()); // next index is 13
using ResultRow = typename Select::_result_methods_t<Select>::template _result_row_t<MockDb>;
using IndexSequence = ResultRow::_field_index_sequence;
static_assert(std::is_same<IndexSequence, sqlpp::detail::field_index_sequence<13, 0, 1, 2, 3, 4, 8, 12>>::value,
"invalid field sequence");
}
// Test that result sets with identical name/value combinations have identical types
{
auto a = select(t.alpha);