mirror of
https://github.com/rbock/sqlpp11.git
synced 2024-11-16 04:47:18 +08:00
Introduce dynamic
This allows to select columns dynamically
This commit is contained in:
parent
25200ba4cb
commit
700c263f90
@ -38,4 +38,27 @@ SQLPP_ALIAS_PROVIDER(max_price);
|
||||
}
|
||||
```
|
||||
|
||||
# Dynamic queries
|
||||
We don't always have a completely fixed structure for our queries. For instance, there might columns that we only want to select under certain circumstances. In version 1.0, this was handled by dynamic queries. Now we introduce conditional query parts that may or may not be used at runtime:
|
||||
|
||||
## Select optional columns
|
||||
select(tab.id, dynamic(condition, tab.bigData)).from(tab).where(tab.id == 17);
|
||||
|
||||
If `condition == true` then `bigData` will be selected, otherwise `NULL` will be selected.
|
||||
|
||||
## Join optional table
|
||||
select(tabA.id).from(tabA.cross_join(dynamic(condition, tabB))).where(tab.id == 17);
|
||||
|
||||
If `condition == true` then the cross join will be part of the query, otherwise not. Obviously, that means that you need to make sure that query parts that rely on `tabB` in this example also depend on the same condition.
|
||||
|
||||
## Optional AND operand
|
||||
select(tab.id).from(tab).where(tab.id == 17 and dynamic(condition, tab.desert != "cheesecake"));
|
||||
|
||||
If `condition == true`, then the dynamic part will evaluate to `tab.desert != "cheesecake")`. Otherwise it will be treated as `true` (and the AND expression will be collapsed).
|
||||
|
||||
## Optional OR operand
|
||||
select(tab.id).from(tab).where(tab.id == 17 or dynamic(condition, tab.desert != "cheesecake"));
|
||||
|
||||
If `condition == true`, then the dynamic part will evaluate to `tab.desert != "cheesecake")`. Otherwise it will be treated as `false` (and the OR expression will be collapsed).
|
||||
|
||||
|
||||
|
@ -1,62 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sqlpp11/operator/as_expression.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_auto_alias_t
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_auto_alias_t<T, typename std::enable_if<not wrong_t<typename T::_auto_alias_t>::value>::type>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, typename Enable = void>
|
||||
struct auto_alias_impl
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct auto_alias_impl<T, typename std::enable_if<has_auto_alias_t<T>::value>::type>
|
||||
{
|
||||
using type = as_expression<T, typename T::_auto_alias_t>;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
using auto_alias_t = typename detail::auto_alias_impl<T>::type;
|
||||
} // namespace sqlpp
|
@ -71,12 +71,6 @@ namespace sqlpp
|
||||
return _table{};
|
||||
}
|
||||
|
||||
#warning: Let's do if_(condition, expression) -> if_t<Expression>, which can be used exclusively in SELECT, AND, OR, JOIN
|
||||
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 value) const -> assign_expression<column_t, T>
|
||||
{
|
||||
|
@ -1,55 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021-2021, 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.
|
||||
*/
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include <sqlpp11/auto_alias.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
std::tuple<auto_alias_t<T>> as_column_tuple(T t)
|
||||
{
|
||||
return std::tuple<auto_alias_t<T>>(auto_alias_t<T>{t});
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::tuple<auto_alias_t<Args>...> as_column_tuple(std::tuple<Args...> t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename... Columns>
|
||||
auto column_tuple_merge(Columns... columns) -> decltype(std::tuple_cat(as_column_tuple(columns)...))
|
||||
{
|
||||
return std::tuple_cat(as_column_tuple(columns)...);
|
||||
}
|
||||
}
|
||||
} // namespace sqlpp
|
109
include/sqlpp11/dynamic.h
Normal file
109
include/sqlpp11/dynamic.h
Normal file
@ -0,0 +1,109 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*/
|
||||
|
||||
#include <sqlpp11/type_traits.h>
|
||||
#include <sqlpp11/serialize.h>
|
||||
|
||||
namespace sqlpp
|
||||
{
|
||||
template <typename Expr>
|
||||
struct dynamic_t
|
||||
{
|
||||
using _traits = make_traits<value_type_of_t<Expr>, tag::is_multi_expression>;
|
||||
using _nodes = detail::type_vector<Expr>;
|
||||
|
||||
dynamic_t(bool condition, Expr expr) : _condition(condition), _expr(expr)
|
||||
{
|
||||
}
|
||||
|
||||
dynamic_t(const dynamic_t&) = default;
|
||||
dynamic_t(dynamic_t&&) = default;
|
||||
dynamic_t& operator=(const dynamic_t&) = default;
|
||||
dynamic_t& operator=(dynamic_t&&) = default;
|
||||
~dynamic_t() = default;
|
||||
|
||||
bool _condition;
|
||||
Expr _expr;
|
||||
};
|
||||
|
||||
// No value_type_of defined for dynamic_t, because it is to be used in very specific contexts in which _expr may be
|
||||
// used depending on the value of _condition.
|
||||
|
||||
template <typename T>
|
||||
struct remove_dynamic
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename Expr>
|
||||
struct remove_dynamic<dynamic_t<Expr>>
|
||||
{
|
||||
using type = Expr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_dynamic_t = typename remove_dynamic<T>::type;
|
||||
|
||||
template <typename T>
|
||||
struct dynamic_to_optional
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename Expr>
|
||||
struct dynamic_to_optional<dynamic_t<Expr>>
|
||||
{
|
||||
using type = force_optional_t<Expr>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using dynamic_to_optional_t = typename dynamic_to_optional<T>::type;
|
||||
|
||||
template <typename Context, typename Select>
|
||||
Context& serialize(const dynamic_t<Select>& t, Context& context)
|
||||
{
|
||||
if (t._condition)
|
||||
{
|
||||
serialize(t._expr, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
context << NULL;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
template <typename Expr>
|
||||
using check_dynamic_args = std::enable_if_t<has_value_type<Expr>::value>;
|
||||
|
||||
template <typename Expr, typename = check_dynamic_args<Expr>>
|
||||
auto dynamic(bool condition, Expr t) -> dynamic_t<Expr>
|
||||
{
|
||||
return {condition, std::move(t)};
|
||||
}
|
||||
} // namespace sqlpp
|
@ -26,6 +26,7 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sqlpp11/dynamic.h>
|
||||
#include <sqlpp11/noop.h>
|
||||
#include <sqlpp11/parameter.h>
|
||||
#include <sqlpp11/parameter_list.h>
|
||||
|
@ -47,11 +47,6 @@ namespace sqlpp
|
||||
|
||||
using _alias_t = typename AliasProvider::_alias_t;
|
||||
|
||||
sqlpp::compat::optional<as_expression> if_(bool condition) const
|
||||
{
|
||||
return condition ? sqlpp::compat::make_optional(*this) : sqlpp::compat::nullopt;
|
||||
}
|
||||
|
||||
as_expression(Expression expression) : _expression(expression)
|
||||
{
|
||||
}
|
||||
|
@ -26,9 +26,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sqlpp11/auto_alias.h>
|
||||
#include <sqlpp11/detail/column_tuple_merge.h>
|
||||
#include <sqlpp11/detail/type_set.h>
|
||||
#include <sqlpp11/dynamic.h>
|
||||
#include <sqlpp11/expression_fwd.h>
|
||||
#include <sqlpp11/field_spec.h>
|
||||
#include <sqlpp11/interpret_tuple.h>
|
||||
@ -63,35 +62,6 @@ namespace sqlpp
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename Column>
|
||||
struct select_column_t
|
||||
{
|
||||
constexpr select_column_t(Column column) : _column(column)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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");
|
||||
@ -110,7 +80,7 @@ namespace sqlpp
|
||||
|
||||
using _alias_t = typename detail::select_traits<Columns...>::_alias_t;
|
||||
|
||||
using _data_t = std::tuple<select_column_t<Columns>...>;
|
||||
using _data_t = std::tuple<Columns...>;
|
||||
|
||||
struct _column_type
|
||||
{
|
||||
@ -171,7 +141,7 @@ namespace sqlpp
|
||||
using _field_t = typename _deferred_field_t<Db, Column>::type;
|
||||
|
||||
template <typename Db>
|
||||
using _result_row_t = result_row_t<Db, _field_t<Db, Columns>...>;
|
||||
using _result_row_t = result_row_t<Db, _field_t<Db, dynamic_to_optional_t<Columns>>...>;
|
||||
|
||||
template <typename AliasProvider>
|
||||
struct _deferred_table_t
|
||||
@ -231,18 +201,12 @@ namespace sqlpp
|
||||
template <typename Column>
|
||||
struct value_type_of<select_column_list_t<Column>> : public value_type_of<Column> {};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename... Columns>
|
||||
select_column_list_t<Columns...> make_column_list(std::tuple<Columns...> columns);
|
||||
} // namespace detail
|
||||
|
||||
SQLPP_PORTABLE_STATIC_ASSERT(assert_selected_colums_are_selectable_t, "selected columns must be selectable");
|
||||
template <typename... T>
|
||||
struct check_selected_columns
|
||||
{
|
||||
using type =
|
||||
static_combined_check_t<static_check_t<logic::all_t<is_selectable_t<remove_optional_t<T>>::value...>::value,
|
||||
static_combined_check_t<static_check_t<logic::all_t<is_selectable_t<T>::value...>::value,
|
||||
assert_selected_colums_are_selectable_t>>;
|
||||
};
|
||||
template <typename... T>
|
||||
@ -270,12 +234,6 @@ namespace sqlpp
|
||||
|
||||
_data_t _data;
|
||||
|
||||
template <typename... T>
|
||||
static constexpr auto _check_args(std::tuple<T...> /*args*/) -> check_selected_columns_t<T...>
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename Check, typename T>
|
||||
using _new_statement_t = new_statement_t<Check, Policies, no_select_column_list_t, T>;
|
||||
|
||||
@ -283,15 +241,15 @@ namespace sqlpp
|
||||
|
||||
template <typename... Args>
|
||||
auto columns(Args... args) const
|
||||
-> _new_statement_t<decltype(_check_args(detail::column_tuple_merge(args...))),
|
||||
decltype(detail::make_column_list(detail::column_tuple_merge(args...)))>
|
||||
-> _new_statement_t<check_selected_columns_t<remove_dynamic_t<Args>...>,
|
||||
select_column_list_t<Args...>>
|
||||
{
|
||||
static_assert(sizeof...(Args), "at least one selectable expression (e.g. a column) required in columns()");
|
||||
using check = decltype(_check_args(detail::column_tuple_merge(args...)));
|
||||
using check = check_selected_columns_t<remove_dynamic_t<Args>...>;
|
||||
static_assert(check::value,
|
||||
"at least one argument is not a selectable expression in columns()");
|
||||
|
||||
return _columns_impl(check{}, detail::column_tuple_merge(args...));
|
||||
return _columns_impl(check{}, std::make_tuple(std::move(args)...));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -303,14 +261,14 @@ namespace sqlpp
|
||||
-> _new_statement_t<consistent_t, select_column_list_t<Args...>>
|
||||
{
|
||||
return {static_cast<const derived_statement_t<Policies>&>(*this),
|
||||
typename select_column_list_t<Args...>::_data_t{args}};
|
||||
typename select_column_list_t<Args...>::_data_t{std::move(args)}};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Interpreters
|
||||
template <typename Context, typename... Columns>
|
||||
Context& serialize(const std::tuple<select_column_t<Columns>...>& t, Context& context)
|
||||
Context& serialize(const std::tuple<Columns...>& t, Context& context)
|
||||
{
|
||||
interpret_tuple(t, ',', context);
|
||||
return context;
|
||||
|
@ -57,8 +57,8 @@ void test_result_row(Value v)
|
||||
const auto v_maybe_null = sqlpp::value(sqlpp::compat::make_optional(v)).as(r_maybe_null);
|
||||
|
||||
// Optional selectable values.
|
||||
const auto v_opt_not_null = sqlpp::value(v).as(r_opt_not_null).if_(true);
|
||||
const auto v_opt_maybe_null = sqlpp::value(sqlpp::compat::make_optional(v)).as(r_opt_maybe_null).if_(true);
|
||||
const auto v_opt_not_null = dynamic(true, sqlpp::value(v).as(r_opt_not_null));
|
||||
const auto v_opt_maybe_null = dynamic(true, sqlpp::value(sqlpp::compat::make_optional(v)).as(r_opt_maybe_null));
|
||||
|
||||
for (const auto& row : db(select(v_not_null, v_maybe_null, v_opt_not_null, v_opt_maybe_null)))
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user