mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 12:51:13 +08:00
Introduce optional select columns
Basic functionality seems to work, more tests needed.
This commit is contained in:
parent
b869cbe5b2
commit
c70ceaceb0
@ -86,6 +86,11 @@ namespace sqlpp
|
||||
return {*this};
|
||||
}
|
||||
|
||||
sqlpp::compat::optional<column_t> if_(bool condition) const
|
||||
{
|
||||
return condition ? sqlpp::compat::make_optional(*this) : sqlpp::compat::nullopt;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto operator=(T t) const -> assignment_t<column_t, wrap_operand_t<T>>
|
||||
{
|
||||
|
@ -45,6 +45,8 @@ namespace sqlpp
|
||||
using std::nullopt;
|
||||
|
||||
using std::bad_optional_access;
|
||||
using std::make_optional;
|
||||
|
||||
} // namespace compat
|
||||
} // namespace sqlpp
|
||||
|
||||
@ -249,6 +251,12 @@ namespace sqlpp
|
||||
return !right;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr optional<typename std::decay<T>::type> make_optional(T&& value)
|
||||
{
|
||||
return optional<typename std::decay<T>::type>(std::forward<T>(value));
|
||||
}
|
||||
|
||||
} // namespace compat
|
||||
} // namespace sqlpp
|
||||
|
||||
|
@ -76,13 +76,14 @@ namespace sqlpp
|
||||
template <typename Select, typename NamedExpr>
|
||||
struct make_field_spec_impl
|
||||
{
|
||||
static constexpr bool _can_be_null = can_be_null_t<NamedExpr>::value;
|
||||
using RawNamedExpr = remove_optional_t<NamedExpr>;
|
||||
static constexpr bool _can_be_null = is_optional<NamedExpr>::value or can_be_null_t<RawNamedExpr>::value;
|
||||
static constexpr bool _depends_on_outer_table =
|
||||
detail::make_intersect_set_t<required_tables_of<NamedExpr>,
|
||||
detail::make_intersect_set_t<required_tables_of<RawNamedExpr>,
|
||||
typename Select::_used_outer_tables>::size::value > 0;
|
||||
|
||||
using type = field_spec_t<typename NamedExpr::_alias_t,
|
||||
value_type_of<NamedExpr>,
|
||||
using type = field_spec_t<typename RawNamedExpr::_alias_t,
|
||||
value_type_of<RawNamedExpr>,
|
||||
logic::any_t<_can_be_null, _depends_on_outer_table>::value>;
|
||||
};
|
||||
} // namespace detail
|
||||
|
@ -55,36 +55,44 @@ namespace sqlpp
|
||||
template <typename Column>
|
||||
struct select_traits<Column>
|
||||
{
|
||||
using _traits = make_traits<value_type_of<Column>,
|
||||
using _traits = make_traits<value_type_of<remove_optional_t<Column>>,
|
||||
tag::is_select_column_list,
|
||||
tag::is_return_value,
|
||||
tag::is_expression,
|
||||
tag::is_selectable>;
|
||||
using _alias_t = typename Column::_alias_t;
|
||||
using _alias_t = typename remove_optional_t<Column>::_alias_t;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// SELECTED COLUMNS DATA
|
||||
template <typename... Columns>
|
||||
struct select_column_list_data_t
|
||||
template <typename Column>
|
||||
struct select_column_t
|
||||
{
|
||||
select_column_list_data_t(Columns... columns) : _columns(columns...)
|
||||
constexpr select_column_t(Column column) : _column(column)
|
||||
{
|
||||
}
|
||||
|
||||
select_column_list_data_t(std::tuple<Columns...> columns) : _columns(columns)
|
||||
{
|
||||
}
|
||||
constexpr select_column_t(const select_column_t&) = default;
|
||||
constexpr select_column_t(select_column_t&&) = default;
|
||||
select_column_t& operator=(const select_column_t&) = default;
|
||||
select_column_t& operator=(select_column_t&&) = default;
|
||||
~select_column_t() = default;
|
||||
|
||||
select_column_list_data_t(const select_column_list_data_t&) = default;
|
||||
select_column_list_data_t(select_column_list_data_t&&) = default;
|
||||
select_column_list_data_t& operator=(const select_column_list_data_t&) = default;
|
||||
select_column_list_data_t& operator=(select_column_list_data_t&&) = default;
|
||||
~select_column_list_data_t() = default;
|
||||
|
||||
std::tuple<Columns...> _columns;
|
||||
Column _column;
|
||||
};
|
||||
|
||||
template <typename Context, typename Column>
|
||||
Context& serialize(const select_column_t<Column>& t, Context& context)
|
||||
{
|
||||
if (has_value(t._column))
|
||||
{
|
||||
return serialize(get_value(t._column), context);
|
||||
}
|
||||
|
||||
context << "NULL AS " << name_of<remove_optional_t<Column>>::template char_ptr<Context>();
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
SQLPP_PORTABLE_STATIC_ASSERT(
|
||||
assert_no_unknown_tables_in_selected_columns_t,
|
||||
"at least one selected column requires a table which is otherwise not known in the statement");
|
||||
@ -103,7 +111,7 @@ namespace sqlpp
|
||||
|
||||
using _alias_t = typename detail::select_traits<Columns...>::_alias_t;
|
||||
|
||||
using _data_t = select_column_list_data_t<Columns...>;
|
||||
using _data_t = std::tuple<select_column_t<Columns>...>;
|
||||
|
||||
struct _column_type
|
||||
{
|
||||
@ -231,8 +239,9 @@ namespace sqlpp
|
||||
template <typename... T>
|
||||
struct check_selected_columns
|
||||
{
|
||||
using type = static_combined_check_t<
|
||||
static_check_t<logic::all_t<is_selectable_t<T>::value...>::value, assert_selected_colums_are_selectable_t>>;
|
||||
using type =
|
||||
static_combined_check_t<static_check_t<logic::all_t<is_selectable_t<remove_optional_t<T>>::value...>::value,
|
||||
assert_selected_colums_are_selectable_t>>;
|
||||
};
|
||||
template <typename... T>
|
||||
using check_selected_columns_t = typename check_selected_columns<T...>::type;
|
||||
@ -299,9 +308,9 @@ namespace sqlpp
|
||||
|
||||
// Interpreters
|
||||
template <typename Context, typename... Columns>
|
||||
Context& serialize(const select_column_list_data_t<Columns...>& t, Context& context)
|
||||
Context& serialize(const std::tuple<select_column_t<Columns>...>& t, Context& context)
|
||||
{
|
||||
interpret_tuple(t._columns, ',', context);
|
||||
interpret_tuple(t, ',', context);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#include <type_traits>
|
||||
#include <tuple>
|
||||
|
||||
#include <sqlpp11/compat/optional.h>
|
||||
#include <sqlpp11/consistent.h>
|
||||
#include <sqlpp11/portable_static_assert.h>
|
||||
#include <sqlpp11/detail/type_vector.h>
|
||||
@ -37,6 +39,55 @@
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename T>
|
||||
struct is_optional : public std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_optional<sqlpp::compat::optional<T>> : public std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct remove_optional
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct remove_optional<sqlpp::compat::optional<T>>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const T& get_value(const T& t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& get_value(const sqlpp::compat::optional<T>& t)
|
||||
{
|
||||
return t.value();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto has_value(const T&) -> bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto has_value(const sqlpp::compat::optional<T>& t) -> bool
|
||||
{
|
||||
return t.has_value();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using remove_optional_t = typename remove_optional<T>::type;
|
||||
|
||||
struct no_value_t;
|
||||
namespace detail
|
||||
{
|
||||
|
@ -39,21 +39,37 @@ int SelectColumns(int, char*[])
|
||||
compare(__LINE__, select(foo.doubleN, bar.id), "SELECT tab_foo.double_n,tab_bar.id");
|
||||
|
||||
// All columns of a table
|
||||
compare(__LINE__, select(all_of(foo)), "SELECT tab_foo.id,tab_foo.text_nn_d,tab_foo.int_n,tab_foo.double_n,tab_foo.u_int_n,tab_foo.blob_n");
|
||||
compare(__LINE__, select(all_of(foo)),
|
||||
"SELECT tab_foo.id,tab_foo.text_nn_d,tab_foo.int_n,tab_foo.double_n,tab_foo.u_int_n,tab_foo.blob_n");
|
||||
|
||||
// All columns of a table plus one more
|
||||
compare(__LINE__, select(all_of(foo), bar.id), "SELECT tab_foo.id,tab_foo.text_nn_d,tab_foo.int_n,tab_foo.double_n,tab_foo.u_int_n,tab_foo.blob_n,tab_bar.id");
|
||||
compare(
|
||||
__LINE__, select(all_of(foo), bar.id),
|
||||
"SELECT tab_foo.id,tab_foo.text_nn_d,tab_foo.int_n,tab_foo.double_n,tab_foo.u_int_n,tab_foo.blob_n,tab_bar.id");
|
||||
|
||||
// One more, plus all columns of a table
|
||||
compare(__LINE__, select(bar.id, all_of(foo)), "SELECT tab_bar.id,tab_foo.id,tab_foo.text_nn_d,tab_foo.int_n,tab_foo.double_n,tab_foo.u_int_n,tab_foo.blob_n");
|
||||
compare(
|
||||
__LINE__, select(bar.id, all_of(foo)),
|
||||
"SELECT tab_bar.id,tab_foo.id,tab_foo.text_nn_d,tab_foo.int_n,tab_foo.double_n,tab_foo.u_int_n,tab_foo.blob_n");
|
||||
|
||||
// Column and aggregate function
|
||||
compare(__LINE__, select(foo.doubleN, count(bar.id)), "SELECT tab_foo.double_n,COUNT(tab_bar.id) AS count_");
|
||||
|
||||
// Column aliases
|
||||
compare(__LINE__, select(foo.doubleN.as(sqlpp::alias::o), count(bar.id).as(sqlpp::alias::a)), "SELECT tab_foo.double_n AS o,COUNT(tab_bar.id) AS a");
|
||||
compare(__LINE__, select(foo.doubleN.as(sqlpp::alias::o), count(bar.id).as(sqlpp::alias::a)),
|
||||
"SELECT tab_foo.double_n AS o,COUNT(tab_bar.id) AS a");
|
||||
|
||||
#warning: add optional column tests
|
||||
// Optional column manually
|
||||
compare(__LINE__, select(sqlpp::compat::make_optional(bar.id)), "SELECT tab_bar.id");
|
||||
auto opt_id = sqlpp::compat::make_optional(bar.id);
|
||||
opt_id.reset();
|
||||
compare(__LINE__, select(opt_id), "SELECT NULL AS id");
|
||||
|
||||
// Optional column using `if_`
|
||||
compare(__LINE__, select(bar.id.if_(true)), "SELECT tab_bar.id");
|
||||
compare(__LINE__, select(bar.id.if_(false)), "SELECT NULL AS id");
|
||||
|
||||
#warning: add more optional column tests
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -55,6 +55,21 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void optional_columns()
|
||||
{
|
||||
{
|
||||
// result fields are as nullable as the expressions they represent
|
||||
#warning: add `if_` to other expressions, too
|
||||
#warning: test with nullable columns, too.
|
||||
#warning: test with all kinds of functions as well.
|
||||
#warning: We should actually test for the exact type!
|
||||
const auto rows = db(select(bar.id.if_(true), bar.boolNn.if_(true)/*, seven*/).from(bar).unconditionally());
|
||||
auto& x = rows.front();
|
||||
static_assert(is_optional<decltype(x.id)>::value, "");
|
||||
static_assert(is_optional<decltype(x.boolNn)>::value, "");
|
||||
}
|
||||
}
|
||||
|
||||
void join()
|
||||
{
|
||||
// Join
|
||||
@ -233,6 +248,7 @@ namespace
|
||||
int main(int, char* [])
|
||||
{
|
||||
single_table();
|
||||
optional_columns();
|
||||
join();
|
||||
aggregates();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user