0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 12:51:13 +08:00

Rewrite select_as and add type tests

This commit is contained in:
Roland Bock 2024-07-23 20:27:06 +02:00
parent 4630bf7f0c
commit 5578cce232
21 changed files with 351 additions and 140 deletions

View File

@ -67,7 +67,8 @@ namespace sqlpp
template <typename T = _table> template <typename T = _table>
auto table() const -> _table auto table() const -> _table
{ {
static_assert(is_table_t<T>::value, "cannot call get_table for columns of a sub-selects or cte"); #warning: subselects use pseudo-columns, cte should do the same, I guess?
static_assert(is_table<T>::value, "cannot call get_table for columns of a sub-select or cte");
return _table{}; return _table{};
} }

View File

@ -150,7 +150,7 @@ namespace sqlpp
template <typename AliasProvider, typename Statement, typename... FieldSpecs> template <typename AliasProvider, typename Statement, typename... FieldSpecs>
struct cte_t : public cte_base<AliasProvider, FieldSpecs>::type... struct cte_t : public cte_base<AliasProvider, FieldSpecs>::type...
{ {
using _traits = make_traits<no_value_t, tag::is_cte, tag::is_table>; // FIXME: is table? really? using _traits = make_traits<no_value_t, tag::is_cte>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _provided_tables = detail::type_set<cte_t>; using _provided_tables = detail::type_set<cte_t>;
using _required_ctes = detail::make_joined_set_t<required_ctes_of<Statement>, detail::type_set<AliasProvider>>; using _required_ctes = detail::make_joined_set_t<required_ctes_of<Statement>, detail::type_set<AliasProvider>>;
@ -216,8 +216,16 @@ namespace sqlpp
Statement _statement; Statement _statement;
}; };
template<typename AliasProvider, typename Statement, typename... ColumnSpecs> #warning: is table? really?
struct name_tag_of<cte_t<AliasProvider, Statement, ColumnSpecs...>> : public name_tag_of<AliasProvider>{}; template <typename AliasProvider, typename Statement, typename... ColumnSpecs>
struct is_table<cte_t<AliasProvider, Statement, ColumnSpecs...>> : public std::true_type
{
};
template <typename AliasProvider, typename Statement, typename... ColumnSpecs>
struct name_tag_of<cte_t<AliasProvider, Statement, ColumnSpecs...>> : public name_tag_of<AliasProvider>
{
};
template <typename Context, typename AliasProvider, typename Statement, typename... ColumnSpecs> template <typename Context, typename AliasProvider, typename Statement, typename... ColumnSpecs>
Context& serialize(Context& context, const cte_t<AliasProvider, Statement, ColumnSpecs...>& t) Context& serialize(Context& context, const cte_t<AliasProvider, Statement, ColumnSpecs...>& t)
@ -235,7 +243,7 @@ namespace sqlpp
template <typename AliasProvider> template <typename AliasProvider>
struct cte_ref_t struct cte_ref_t
{ {
using _traits = make_traits<no_value_t, tag::is_alias, tag::is_cte, tag::is_table>; // FIXME: is table? really? using _traits = make_traits<no_value_t, tag::is_alias, tag::is_cte>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _required_ctes = detail::make_type_set_t<AliasProvider>; using _required_ctes = detail::make_type_set_t<AliasProvider>;
using _provided_tables = detail::type_set<AliasProvider>; using _provided_tables = detail::type_set<AliasProvider>;
@ -253,7 +261,11 @@ namespace sqlpp
} }
}; };
template<typename AliasProvider> #warning: is table? really?
template<typename AliasProvider>
struct is_table<cte_ref_t<AliasProvider>> : public std::true_type{};
template<typename AliasProvider>
struct name_tag_of<cte_ref_t<AliasProvider>> : public name_tag_of<AliasProvider>{}; struct name_tag_of<cte_ref_t<AliasProvider>> : public name_tag_of<AliasProvider>{};
template <typename Context, typename AliasProvider> template <typename Context, typename AliasProvider>

View File

@ -98,9 +98,8 @@ namespace sqlpp
return context; return context;
} }
template <typename T> auto for_update() -> decltype(statement_t<no_for_update_t>().for_update())
auto for_update(T&& t) -> decltype(statement_t<no_for_update_t>().for_update(std::forward<T>(t)))
{ {
return statement_t<no_for_update_t>().for_update(std::forward<T>(t)); return statement_t<no_for_update_t>().for_update();
} }
} // namespace sqlpp } // namespace sqlpp

View File

@ -78,7 +78,7 @@ namespace sqlpp
{ {
using type = static_combined_check_t< using type = static_combined_check_t<
static_check_t<not is_pre_join_t<Table>::value, assert_from_not_pre_join_t>, static_check_t<not is_pre_join_t<Table>::value, assert_from_not_pre_join_t>,
static_check_t<is_table_t<Table>::value, assert_from_table_t>, static_check_t<is_table<Table>::value, assert_from_table_t>,
static_check_t<required_tables_of_t<Table>::size::value == 0, assert_from_dependency_free_t>, static_check_t<required_tables_of_t<Table>::size::value == 0, assert_from_dependency_free_t>,
static_check_t<provided_tables_of<Table>::size::value == static_check_t<provided_tables_of<Table>::size::value ==
detail::make_name_of_set_t<provided_tables_of<Table>>::size::value, detail::make_name_of_set_t<provided_tables_of<Table>>::size::value,

View File

@ -35,7 +35,7 @@ namespace sqlpp
template <typename PreJoin, typename On> template <typename PreJoin, typename On>
struct join_t struct join_t
{ {
using _traits = make_traits<no_value_t, tag::is_table, tag::is_join>; using _traits = make_traits<no_value_t, tag::is_join>;
using _nodes = detail::type_vector<PreJoin, On>; using _nodes = detail::type_vector<PreJoin, On>;
using _can_be_null = std::false_type; using _can_be_null = std::false_type;
using _provided_tables = provided_tables_of<PreJoin>; using _provided_tables = provided_tables_of<PreJoin>;
@ -81,6 +81,9 @@ namespace sqlpp
On _on; On _on;
}; };
template<typename PreJoin, typename On>
struct is_table<join_t<PreJoin, On>> : public std::true_type{};
template <typename Context, typename PreJoin, typename On> template <typename Context, typename PreJoin, typename On>
Context& serialize(Context& context, const join_t<PreJoin, On>& t) Context& serialize(Context& context, const join_t<PreJoin, On>& t)
{ {

View File

@ -56,6 +56,15 @@ namespace sqlpp
std::string _verbatim_lhs, _verbatim_rhs; std::string _verbatim_lhs, _verbatim_rhs;
}; };
template <typename ValueType, typename Expr>
struct value_type_of<parameterized_verbatim_t<ValueType, Expr>>
{
using type = ValueType;
};
template <typename ValueType, typename Expr>
struct nodes_of<parameterized_verbatim_t<ValueType, Expr>> : public nodes_of<Expr>{};
template <typename Context, typename ValueType, typename Expr> template <typename Context, typename ValueType, typename Expr>
Context& serialize(Context& context, const parameterized_verbatim_t<ValueType, Expr>& t) Context& serialize(Context& context, const parameterized_verbatim_t<ValueType, Expr>& t)
{ {

View File

@ -42,8 +42,8 @@ namespace sqlpp
struct check_pre_join struct check_pre_join
{ {
using type = static_combined_check_t< using type = static_combined_check_t<
static_check_t<is_table_t<Lhs>::value, assert_pre_join_lhs_table_t>, static_check_t<is_table<Lhs>::value, assert_pre_join_lhs_table_t>,
static_check_t<is_table_t<Rhs>::value, assert_pre_join_rhs_table_t>, static_check_t<is_table<Rhs>::value, assert_pre_join_rhs_table_t>,
static_check_t<not is_join_t<Rhs>::value, assert_pre_join_rhs_no_join_t>, static_check_t<not is_join_t<Rhs>::value, assert_pre_join_rhs_no_join_t>,
static_check_t<detail::is_disjunct_from<detail::make_name_of_set_t<provided_tables_of<Lhs>>, static_check_t<detail::is_disjunct_from<detail::make_name_of_set_t<provided_tables_of<Lhs>>,
detail::make_name_of_set_t<provided_tables_of<Rhs>>>::value, detail::make_name_of_set_t<provided_tables_of<Rhs>>>::value,
@ -93,8 +93,8 @@ namespace sqlpp
using _can_be_null = std::false_type; using _can_be_null = std::false_type;
using _provided_outer_tables = typename JoinType::template _provided_outer_tables<Lhs, Rhs>; using _provided_outer_tables = typename JoinType::template _provided_outer_tables<Lhs, Rhs>;
static_assert(is_table_t<Lhs>::value, "lhs argument for join() has to be a table or join"); static_assert(is_table<Lhs>::value, "lhs argument for join() has to be a table or join");
static_assert(is_table_t<Rhs>::value, "rhs argument for join() has to be a table"); static_assert(is_table<Rhs>::value, "rhs argument for join() has to be a table");
static_assert(not is_join_t<Rhs>::value, "rhs argument for join must not be a join"); static_assert(not is_join_t<Rhs>::value, "rhs argument for join must not be a join");
static_assert(detail::is_disjunct_from<provided_tables_of<Lhs>, provided_tables_of<Rhs>>::value, static_assert(detail::is_disjunct_from<provided_tables_of<Lhs>, provided_tables_of<Rhs>>::value,

View File

@ -40,7 +40,7 @@ namespace sqlpp
template <typename Table> template <typename Table>
struct schema_qualified_table_t struct schema_qualified_table_t
{ {
using _traits = make_traits<value_type_of_t<Table>, tag::is_table>; using _traits = make_traits<value_type_of_t<Table>>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _required_ctes = detail::type_set<>; using _required_ctes = detail::type_set<>;
@ -61,6 +61,9 @@ namespace sqlpp
Table _table; Table _table;
}; };
template<typename Table>
struct is_table<schema_qualified_table_t<Table>> : public std::true_type {};
template <typename Context, typename Table> template <typename Context, typename Table>
Context& serialize(Context& context, const schema_qualified_table_t<Table>& t) Context& serialize(Context& context, const schema_qualified_table_t<Table>& t)
{ {

View File

@ -0,0 +1,92 @@
#pragma once
/*
* Copyright (c) 2013-2016, 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/enable_as.h>
namespace sqlpp
{
// pseudo_column_t is the column of a sub-select used as a table, for instance.
#warning: Maybe use this for CTE as well
#warning: Should be in its own header
template <typename TableAliasProvider, typename ColumnSpec>
struct pseudo_column_t : public enable_as<pseudo_column_t<TableAliasProvider, ColumnSpec>>
{
};
template <typename TableAliasProvider, typename ColumnSpec>
struct name_tag_of<pseudo_column_t<TableAliasProvider, ColumnSpec>> : public name_tag_of<ColumnSpec>
{
};
template <typename TableAliasProvider, typename ColumnSpec>
struct value_type_of<pseudo_column_t<TableAliasProvider, ColumnSpec>> : public value_type_of<ColumnSpec>
{
};
template <typename Select, typename AliasProvider, typename... ColumnSpecs>
struct select_as_t
: public ColumnSpecs::_alias_t::template _member_t<pseudo_column_t<AliasProvider, ColumnSpecs>>...
{
select_as_t(Select select) : _select(select)
{
}
select_as_t(const select_as_t& rhs) = default;
select_as_t(select_as_t&& rhs) = default;
select_as_t& operator=(const select_as_t& rhs) = default;
select_as_t& operator=(select_as_t&& rhs) = default;
~select_as_t() = default;
Select _select;
};
// The Select expression has a value in case it has just one column selected.
template<typename Select, typename AliasProvider, typename ColumnSpec>
struct value_type_of<select_as_t<Select, AliasProvider, ColumnSpec>> : value_type_of<Select> {};
template<typename Select, typename AliasProvider, typename... ColumnSpecs>
struct name_tag_of<select_as_t<Select, AliasProvider, ColumnSpecs...>> : name_tag_of<AliasProvider> {};
#warning: Is this (_can_be_used_as_table) required for use as a named value, too?
template <typename Select, typename AliasProvider, typename... ColumnSpecs>
struct is_table<select_as_t<Select, AliasProvider, ColumnSpecs...>>
: std::integral_constant<bool, Select::_can_be_used_as_table()>
{
};
#warning: V1.0 has empty nodes. Is that correct? In either case document the decision here.
template <typename Context, typename Select, typename AliasProvider, typename... ColumnSpecs>
Context& serialize(Context& context, const select_as_t<Select, AliasProvider, ColumnSpecs...>& t)
{
#warning: add AS Alias
serialize(context, t._select);
return context;
}
} // namespace sqlpp

View File

@ -32,7 +32,7 @@
#include <sqlpp11/interpret_tuple.h> #include <sqlpp11/interpret_tuple.h>
#include <sqlpp11/policy_update.h> #include <sqlpp11/policy_update.h>
#include <sqlpp11/result_row.h> #include <sqlpp11/result_row.h>
#include <sqlpp11/select_pseudo_table.h> #include <sqlpp11/select_as.h>
#include <sqlpp11/table.h> #include <sqlpp11/table.h>
#include <tuple> #include <tuple>
@ -78,6 +78,22 @@ namespace sqlpp
}; };
} // namespace detail } // namespace detail
// FIXME: We might use field specs here (same as with cte)
//
// provide type information for sub-selects that are used as named expressions or tables
template <typename Select, typename Column>
struct select_column_spec_t: public name_tag_base
{
using _alias_t = name_tag_of_t<Column>;
#warning: Need to test this!
static constexpr bool _depends_on_outer_table =
detail::make_intersect_set_t<required_tables_of_t<Column>, typename Select::_used_outer_tables>::size::value >
0;
};
template <typename Select, typename Column>
struct value_type_of<select_column_spec_t<Select, Column>> : public value_type_of<Column> {};
SQLPP_PORTABLE_STATIC_ASSERT( SQLPP_PORTABLE_STATIC_ASSERT(
assert_no_unknown_tables_in_selected_columns_t, assert_no_unknown_tables_in_selected_columns_t,
"at least one selected column requires a table which is otherwise not known in the statement"); "at least one selected column requires a table which is otherwise not known in the statement");
@ -158,25 +174,12 @@ namespace sqlpp
using _result_row_t = result_row_t<Db, _field_t<Db, Columns>...>; using _result_row_t = result_row_t<Db, _field_t<Db, Columns>...>;
template <typename AliasProvider> template <typename AliasProvider>
struct _deferred_table_t auto as(const AliasProvider& aliasProvider) const
{ -> select_as_t<_statement_t, AliasProvider, select_column_spec_t<_statement_t, Columns>...>
using table = select_pseudo_table_t<_statement_t, Columns...>;
using alias = typename table::template _alias_t<AliasProvider>;
};
template <typename AliasProvider>
using _table_t = typename _deferred_table_t<AliasProvider>::table;
template <typename AliasProvider>
using _alias_t = typename _deferred_table_t<AliasProvider>::alias;
template <typename AliasProvider>
_alias_t<AliasProvider> as(const AliasProvider& aliasProvider) const
{ {
consistency_check_t<_statement_t>::verify(); consistency_check_t<_statement_t>::verify();
static_assert(_statement_t::_can_be_used_as_table(), using table = select_as_t<_statement_t, AliasProvider, select_column_spec_t<_statement_t, Columns>...>;
"statement cannot be used as table, e.g. due to missing tables"); return table(_get_statement());
return _table_t<AliasProvider>(_get_statement()).as(aliasProvider);
} }
size_t get_no_of_result_columns() const size_t get_no_of_result_columns() const

View File

@ -1,100 +0,0 @@
#pragma once
/*
* Copyright (c) 2013-2016, 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/table.h>
namespace sqlpp
{
// FIXME: We might use field specs here (same as with cte)
//
// provide type information for sub-selects that are used as named expressions or tables
template <typename Select, typename NamedExpr>
struct select_column_spec_t: public name_tag_base
{
using _alias_t = name_tag_of_t<NamedExpr>;
using has_default = std::false_type;
static constexpr bool _depends_on_outer_table =
detail::make_intersect_set_t<required_tables_of_t<NamedExpr>, typename Select::_used_outer_tables>::size::value >
0;
#warning: somehow prevent insert...
#warning: may need to make value type optional for outer tables
using _traits = make_traits<value_type_of_t<NamedExpr>/*,
tag_if<tag::can_be_null, _depends_on_outer_table>*/>;
};
template<typename... NamedExpr>
struct select_expression_type {
using value_t = no_value_t;
static constexpr bool _is_expression = false;
static constexpr bool _can_be_null = false;
};
template<typename NamedExpr>
struct select_expression_type<NamedExpr> {
using value_t = value_type_of_t<NamedExpr>;
static constexpr bool _is_expression = true;
};
template <typename Select, typename... NamedExpr>
struct select_pseudo_table_t
: public table_t<select_pseudo_table_t<Select, NamedExpr...>, select_column_spec_t<Select, NamedExpr>...>
{
using _expr_t = select_expression_type<NamedExpr...>;
using _traits = make_traits<
// Usage as named expression
typename _expr_t::value_t,
tag_if<tag::is_expression, _expr_t::_is_expression>,
// Usage as table
tag::is_table,
tag::is_pseudo_table,
tag_if<tag::requires_parens, requires_parens_t<Select>::value>>;
using _nodes = detail::type_vector<>;
select_pseudo_table_t(Select select) : _select(select)
{
}
select_pseudo_table_t(const select_pseudo_table_t& rhs) = default;
select_pseudo_table_t(select_pseudo_table_t&& rhs) = default;
select_pseudo_table_t& operator=(const select_pseudo_table_t& rhs) = default;
select_pseudo_table_t& operator=(select_pseudo_table_t&& rhs) = default;
~select_pseudo_table_t() = default;
Select _select;
};
template <typename Context, typename Select, typename... NamedExpr>
Context& serialize(Context& context, const select_pseudo_table_t<Select, NamedExpr...>& t)
{
serialize(context, t._select);
return context;
}
} // namespace sqlpp

View File

@ -57,7 +57,8 @@ namespace sqlpp
using _traits = make_traits<no_value_t, tag::is_single_table>; using _traits = make_traits<no_value_t, tag::is_single_table>;
using _nodes = detail::type_vector<Table>; using _nodes = detail::type_vector<Table>;
static_assert(is_table_t<Table>::value, "argument has to be a table"); #warning: can't we do this with a table_t<> specialization
static_assert(is_table<Table>::value, "argument has to be a table");
static_assert(required_tables_of_t<Table>::size::value == 0, "table depends on another table"); static_assert(required_tables_of_t<Table>::size::value == 0, "table depends on another table");
using _data_t = single_table_data_t<Table>; using _data_t = single_table_data_t<Table>;
@ -84,7 +85,7 @@ namespace sqlpp
template <typename Table> template <typename Table>
struct check_update_table struct check_update_table
{ {
using type = static_combined_check_t<static_check_t<is_table_t<Table>::value, assert_update_table_arg_is_table_t>>; using type = static_combined_check_t<static_check_t<is_table<Table>::value, assert_update_table_arg_is_table_t>>;
}; };
template <typename Table> template <typename Table>
using check_update_table_t = typename check_update_table<Table>::type; using check_update_table_t = typename check_update_table<Table>::type;

View File

@ -41,7 +41,7 @@ namespace sqlpp
template <typename Table, typename... ColumnSpec> template <typename Table, typename... ColumnSpec>
struct table_t : public ColumnSpec::_alias_t::template _member_t<column_t<Table, ColumnSpec>>... struct table_t : public ColumnSpec::_alias_t::template _member_t<column_t<Table, ColumnSpec>>...
{ {
using _traits = make_traits<no_value_t, tag::is_raw_table, tag::is_table>; using _traits = make_traits<no_value_t, tag::is_raw_table>;
using _nodes = detail::type_vector<>; using _nodes = detail::type_vector<>;
using _provided_tables = detail::type_set<Table>; using _provided_tables = detail::type_set<Table>;
@ -102,6 +102,9 @@ namespace sqlpp
template <typename Table, typename... ColumnSpec> template <typename Table, typename... ColumnSpec>
struct name_tag_of<table_t<Table, ColumnSpec...>>: public name_tag_of<Table> {}; struct name_tag_of<table_t<Table, ColumnSpec...>>: public name_tag_of<Table> {};
template <typename Table, typename... ColumnSpec>
struct is_table<table_t<Table, ColumnSpec...>>: public std::true_type {};
template <typename Context, typename Table, typename... ColumnSpec> template <typename Context, typename Table, typename... ColumnSpec>
Context& serialize(Context& context, const table_t<Table, ColumnSpec...>& /*unused*/) Context& serialize(Context& context, const table_t<Table, ColumnSpec...>& /*unused*/)
{ {

View File

@ -42,7 +42,6 @@ namespace sqlpp
struct table_alias_t : public ColumnSpec::_alias_t::template _member_t<column_t<AliasProvider, ColumnSpec>>... struct table_alias_t : public ColumnSpec::_alias_t::template _member_t<column_t<AliasProvider, ColumnSpec>>...
{ {
using _traits = make_traits<value_type_of_t<Table>, using _traits = make_traits<value_type_of_t<Table>,
tag::is_table,
tag::is_alias, tag::is_alias,
tag_if<tag::is_selectable, is_expression_t<Table>::value>>; tag_if<tag::is_selectable, is_expression_t<Table>::value>>;
@ -97,6 +96,9 @@ namespace sqlpp
Table _table; Table _table;
}; };
template<typename AliasProvider, typename Table, typename... ColumnSpec>
struct is_table<table_alias_t<AliasProvider, Table, ColumnSpec...>> : public std::true_type{};
template<typename AliasProvider, typename Table, typename... ColumnSpec> template<typename AliasProvider, typename Table, typename... ColumnSpec>
struct name_tag_of<table_alias_t<AliasProvider, Table, ColumnSpec...>> : public name_tag_of<AliasProvider>{}; struct name_tag_of<table_alias_t<AliasProvider, Table, ColumnSpec...>> : public name_tag_of<AliasProvider>{};

View File

@ -462,7 +462,6 @@ namespace sqlpp
SQLPP_VALUE_TRAIT_GENERATOR(is_noop) SQLPP_VALUE_TRAIT_GENERATOR(is_noop)
SQLPP_VALUE_TRAIT_GENERATOR(is_missing) SQLPP_VALUE_TRAIT_GENERATOR(is_missing)
SQLPP_VALUE_TRAIT_GENERATOR(is_return_value) SQLPP_VALUE_TRAIT_GENERATOR(is_return_value)
SQLPP_VALUE_TRAIT_GENERATOR(is_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table) SQLPP_VALUE_TRAIT_GENERATOR(is_raw_table)
SQLPP_VALUE_TRAIT_GENERATOR(is_pre_join) SQLPP_VALUE_TRAIT_GENERATOR(is_pre_join)
SQLPP_VALUE_TRAIT_GENERATOR(is_join) SQLPP_VALUE_TRAIT_GENERATOR(is_join)
@ -736,6 +735,9 @@ namespace sqlpp
template<typename T> template<typename T>
struct has_name : public std::integral_constant<bool, not std::is_same<name_tag_of_t<T>, no_name_t>::value> {}; struct has_name : public std::integral_constant<bool, not std::is_same<name_tag_of_t<T>, no_name_t>::value> {};
template <typename T>
struct is_table : public std::false_type{};
template <typename ValueType, typename... Tags> template <typename ValueType, typename... Tags>
struct make_traits struct make_traits
{ {

View File

@ -79,7 +79,7 @@ namespace sqlpp
struct check_using struct check_using
{ {
using type = static_combined_check_t< using type = static_combined_check_t<
static_check_t<logic::all_t<is_table_t<Tables>::value...>::value, assert_using_args_are_tables_t>>; static_check_t<logic::all_t<is_table<Tables>::value...>::value, assert_using_args_are_tables_t>>;
}; };
template <typename... Tables> template <typename... Tables>
using check_using_t = typename check_using<Tables...>::type; using check_using_t = typename check_using<Tables...>::type;

View File

@ -31,6 +31,9 @@ int ForUpdate(int, char* [])
{ {
const auto foo = test::TabFoo{}; const auto foo = test::TabFoo{};
compare(__LINE__, sqlpp::for_update(),
" FOR UPDATE ");
compare(__LINE__, select(foo.doubleN).from(foo).unconditionally().for_update(), compare(__LINE__, select(foo.doubleN).from(foo).unconditionally().for_update(),
"SELECT tab_foo.double_n FROM tab_foo FOR UPDATE "); "SELECT tab_foo.double_n FROM tab_foo FOR UPDATE ");

View File

@ -32,12 +32,25 @@
SQLPP_ALIAS_PROVIDER(id_count) SQLPP_ALIAS_PROVIDER(id_count)
SQLPP_ALIAS_PROVIDER(cheese) SQLPP_ALIAS_PROVIDER(cheese)
using namespace sqlpp;
int SelectAs(int, char*[]) int SelectAs(int, char*[])
{ {
const auto foo = test::TabFoo{}; const auto foo = test::TabFoo{};
const auto bar = test::TabBar{}; const auto bar = test::TabBar{};
// SELECT...AS as selectable column // SELECT...AS as selectable column
//using S = table_alias_t<cheese_t, select_pseudo_table_t<statement_t<no_with_t, select_t, no_select_flag_list_t, select_column_list_t<as_expression<count_t<noop, column_t<test::TabBar, test::TabBar_::Id> >, id_count_t> >, from_t<test::TabBar>, where_t<unconditional_t>, no_group_by_t, no_having_t, no_order_by_t, no_limit_t, no_offset_t, no_union_t, no_for_update_t>, as_expression<count_t<noop, column_t<test::TabBar, test::TabBar_::Id> >, id_count_t> >, select_column_spec_t<statement_t<no_with_t, select_t, no_select_flag_list_t, select_column_list_t<as_expression<count_t<noop, column_t<test::TabBar, test::TabBar_::Id> >, id_count_t> >, from_t<test::TabBar>, where_t<unconditional_t>, no_group_by_t, no_having_t, no_order_by_t, no_limit_t, no_offset_t, no_union_t, no_for_update_t>, as_expression<count_t<noop, column_t<test::TabBar, test::TabBar_::Id> >, id_count_t> > >;
using S = select_pseudo_table_t<statement_t<no_with_t, select_t, no_select_flag_list_t, select_column_list_t<as_expression<count_t<noop, column_t<test::TabBar, test::TabBar_::Id> >, id_count_t> >, from_t<test::TabBar>, where_t<unconditional_t>, no_group_by_t, no_having_t, no_order_by_t, no_limit_t, no_offset_t, no_union_t, no_for_update_t>> ;
static_assert(sqlpp::has_value_type<S>::value, "");
/*
sqlpp::name_tag_of_t<decltype(select(count(bar.id).as(id_count)).from(bar).unconditionally())::_result_type_provider>::hansi;
sqlpp::value_type_of_t<decltype(select(count(bar.id).as(id_count)).from(bar).unconditionally())::_result_type_provider>::hansi;
static_assert(sqlpp::has_value_type<decltype(select(count(bar.id).as(id_count)).from(bar).unconditionally())>::value, "");
static_assert(sqlpp::has_name<decltype(select(count(bar.id).as(id_count)).from(bar).unconditionally())>::value, "");
*/
#error: The select itself should not offer an "as" that yields a value.
#error: The id_count should offer the alias that offers the value.
compare(__LINE__, select(foo.doubleN, select(count(bar.id).as(id_count)).from(bar).unconditionally().as(cheese)), compare(__LINE__, select(foo.doubleN, select(count(bar.id).as(id_count)).from(bar).unconditionally().as(cheese)),
"SELECT tab_foo.double_n,(SELECT COUNT(tab_bar.id) AS id_count FROM tab_bar) AS cheese"); "SELECT tab_foo.double_n,(SELECT COUNT(tab_bar.id) AS id_count FROM tab_bar) AS cheese");

View File

@ -42,5 +42,6 @@ test_compile(dynamic)
test_compile(in_expression) test_compile(in_expression)
test_compile(logical_expression) test_compile(logical_expression)
test_compile(result_row) test_compile(result_row)
test_compile(select_as)
test_compile(value) test_compile(value)

View File

@ -0,0 +1,157 @@
/*
* 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 "MockDb.h"
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
namespace
{
auto db = MockDb{};
template <typename T, typename V>
using is_same_type = std::is_same<sqlpp::value_type_of_t<T>, V>;
}
SQLPP_ALIAS_PROVIDER(always);
SQLPP_ALIAS_PROVIDER(sometimes);
SQLPP_ALIAS_PROVIDER(column)
SQLPP_ALIAS_PROVIDER(table)
SQLPP_ALIAS_PROVIDER(foo)
template <typename Value>
void test_select_as(Value v)
{
auto v_not_null = sqlpp::value(v).as(always);
auto v_maybe_null = sqlpp::value(sqlpp::compat::make_optional(v)).as(sometimes);
using ValueType = sqlpp::value_type_of_t<Value>;
using OptValueType = sqlpp::value_type_of_t<sqlpp::compat::optional<Value>>;
// SINGLE VALUE
// A select of a single value can be used as a value.
static_assert(is_same_type<decltype(select(v_not_null)), ValueType>(), "");
static_assert(is_same_type<decltype(select(v_maybe_null)), OptValueType>(), "");
// A select of a single value can be named and used as a named value.
static_assert(sqlpp::has_name<decltype(select(v_not_null).as(column))>::value, "");
static_assert(sqlpp::has_name<decltype(select(v_maybe_null).as(column))>::value, "");
static_assert(is_same_type<decltype(select(v_not_null).as(column)), ValueType>(), "");
static_assert(is_same_type<decltype(select(v_maybe_null).as(column)), OptValueType>(), "");
// A select of a single value can be named and used as a pseudo table
static_assert(sqlpp::is_table<decltype(select(v_not_null).as(column))>::value, "");
static_assert(sqlpp::is_table<decltype(select(v_maybe_null).as(column))>::value, "");
// The column of a single-value pseudo table can be used as named value
static_assert(sqlpp::has_name<decltype(select(v_not_null).as(column).always)>::value, "");
static_assert(sqlpp::has_name<decltype(select(v_maybe_null).as(column).sometimes)>::value, "");
static_assert(is_same_type<decltype(select(v_not_null).as(column).always), ValueType>(), "");
static_assert(is_same_type<decltype(select(v_maybe_null).as(column).sometimes), OptValueType>(), "");
// The column of a single-value pseudo table can be renamed and used as named value
static_assert(sqlpp::has_name<decltype(select(v_not_null).as(column).always.as(foo))>::value, "");
static_assert(sqlpp::has_name<decltype(select(v_maybe_null).as(column).sometimes.as(foo))>::value, "");
static_assert(is_same_type<decltype(select(v_not_null).as(column).always.as(foo)), ValueType>(), "");
static_assert(is_same_type<decltype(select(v_maybe_null).as(column).sometimes.as(foo)), OptValueType>(), "");
#warning: implement
// MULTIPLE VALUES
#warning: write
// A select of multiple values can not be used as a value.
static_assert(not sqlpp::has_value_type<decltype(select(v_not_null, v_maybe_null))>::value, "");
// A select of multiple values can be named and used as a named value.
static_assert(sqlpp::has_name<decltype(select(v_not_null, v_maybe_null).as(column))>::value, "");
static_assert(not sqlpp::has_value_type<decltype(select(v_not_null, v_maybe_null).as(column))>::value, "");
// A select of multiple values can be named and used as a pseudo table
static_assert(sqlpp::is_table<decltype(select(v_not_null, v_maybe_null).as(table))>::value, "");
// The column of a multi-value pseudo table can be used as named value
static_assert(sqlpp::has_name<decltype(select(v_not_null, v_maybe_null).as(table).always)>::value, "");
static_assert(sqlpp::has_name<decltype(select(v_not_null, v_maybe_null).as(table).sometimes)>::value, "");
static_assert(is_same_type<decltype(select(v_not_null, v_maybe_null).as(table).always), ValueType>(), "");
static_assert(is_same_type<decltype(select(v_not_null, v_maybe_null).as(table).sometimes), OptValueType>(), "");
// The column of a multi-value pseudo table can be renamed and used as named value
static_assert(sqlpp::has_name<decltype(select(v_not_null, v_maybe_null).as(table).always.as(foo))>::value, "");
static_assert(sqlpp::has_name<decltype(select(v_not_null, v_maybe_null).as(table).sometimes.as(foo))>::value, "");
static_assert(is_same_type<decltype(select(v_not_null, v_maybe_null).as(table).always.as(foo)), ValueType>(), "");
static_assert(is_same_type<decltype(select(v_not_null, v_maybe_null).as(table).sometimes.as(foo)), OptValueType>(), "");
}
int main()
{
// boolean
test_select_as(bool{true});
// integral
test_select_as(int8_t{7});
test_select_as(int16_t{7});
test_select_as(int32_t{7});
test_select_as(int64_t{7});
// unsigned integral
test_select_as(uint8_t{7});
test_select_as(uint16_t{7});
test_select_as(uint32_t{7});
test_select_as(uint64_t{7});
// floating point
test_select_as(float{7.7});
test_select_as(double{7.7});
// text
test_select_as('7');
test_select_as("seven");
test_select_as(std::string("seven"));
test_select_as(sqlpp::compat::string_view("seven"));
// blob
test_select_as(std::vector<uint8_t>{});
// date
test_select_as(::sqlpp::chrono::day_point{});
// timestamp
test_select_as(::sqlpp::chrono::microsecond_point{});
using minute_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
test_select_as(minute_point{});
// time_of_day
test_select_as(std::chrono::microseconds{});
}

View File

@ -187,5 +187,12 @@ int Select(int, char*[])
std::cout << row.doubleN << " " << row.cheese << std::endl; std::cout << row.doubleN << " " << row.cheese << std::endl;
} }
// checking #584
auto abs = db.prepare(select(t.alpha).from(t).where(sqlpp::parameterized_verbatim<sqlpp::unsigned_integral>(
"ABS(field1 -", sqlpp::parameter(t.alpha), ")") <=
sqlpp::parameter(sqlpp::unsigned_integral(), param2)));
abs.params.alpha = 7;
abs.params.param2 = 7;
return 0; return 0;
} }