diff --git a/include/sqlpp11/any.h b/include/sqlpp11/any.h index 94fb4cd7..1f8a55b5 100644 --- a/include/sqlpp11/any.h +++ b/include/sqlpp11/any.h @@ -37,9 +37,6 @@ namespace sqlpp template struct any_t { - static_assert(is_select_t::value, "any() requires a single column select expression as argument"); - struct _value_type: public Select::_value_type::_base_value_type { using _is_expression = std::false_type; @@ -94,6 +91,7 @@ namespace sqlpp auto any(T t) -> typename vendor::any_t> { static_assert(is_select_t>::value, "any() requires a select expression as argument"); + static_assert(is_value_t>::value, "any() requires a single column select expression as argument"); return { t }; } diff --git a/include/sqlpp11/no_value.h b/include/sqlpp11/no_value.h index cad3b6e9..2079c5d7 100644 --- a/include/sqlpp11/no_value.h +++ b/include/sqlpp11/no_value.h @@ -36,6 +36,8 @@ namespace sqlpp template using _constraint = std::false_type; + using _base_value_type = no_value_t; + template struct _is_valid_operand { diff --git a/include/sqlpp11/select.h b/include/sqlpp11/select.h index 3331fdd0..d1052935 100644 --- a/include/sqlpp11/select.h +++ b/include/sqlpp11/select.h @@ -108,8 +108,36 @@ namespace sqlpp static_assert(is_noop_t::value or sqlpp::is_select_column_list_t::value, "column list of select is neither naught nor a valid column list"); static_assert(is_noop_t::value or sqlpp::is_from_t::value, "from() part of select is neither naught nor a valid from()"); + + using _required_tables = + detail::make_joined_set_t< + typename _flag_list_t::_table_set, + typename _column_list_t::_table_set, + typename _where_t::_table_set, + typename _group_by_t::_table_set, + typename _having_t::_table_set, + typename _order_by_t::_table_set, + typename _limit_t::_table_set, + typename _offset_t::_table_set + >; + + // The tables not covered by the from. + using _table_set = detail::make_difference_set_t< + _required_tables, + typename _from_t::_table_set // Hint: extra_tables are not used here because they are just helpers for dynamic .add_*() methods + >; + + // A select can be used as a pseudo table if + // - at least one column is selected + // - the select is complete (leaks no tables) + using _can_be_used_as_table = typename std::conditional< + is_select_column_list_t<_column_list_t>::value and _table_set::size::value == 0, + std::true_type, + std::false_type + >::type; + using _value_type = typename std::conditional< - _column_list_t::_table_set::size::value ? sqlpp::is_from_t::value : true, + is_select_column_list_t<_column_list_t>::value and is_subset_of::value, typename ColumnList::_value_type, no_value_t // If something is selected that requires a table, then we require a from for this to be a value >::type; @@ -140,18 +168,7 @@ namespace sqlpp using _parameter_tuple_t = std::tuple; using _parameter_list_t = typename make_parameter_list_t::type; - using _table_set = detail::make_difference_set_t< - typename _from_t::_table_set, - detail::make_joined_set_t< // Hint: extra_tables are not used here because they are just helpers for dynamic .add_*() methods - typename _flag_list_t::_table_set, - typename _column_list_t::_table_set, - typename _where_t::_table_set, - typename _group_by_t::_table_set, - typename _having_t::_table_set, - typename _order_by_t::_table_set, - typename _limit_t::_table_set, - typename _offset_t::_table_set - >>; + using _table_set = typename _policies_t::_table_set; template using _result_row_t = typename _column_list_t::template _result_row_t; @@ -197,6 +214,7 @@ namespace sqlpp template typename _pseudo_table_t::alias as(const AliasProvider& aliasProvider) const { + static_assert(_policies_t::_can_be_used_as_table::value, "select cannot be used as table, incomplete from()"); return typename _pseudo_table_t::table( *this).as(aliasProvider); } diff --git a/include/sqlpp11/some.h b/include/sqlpp11/some.h index e15683d9..cd5e63cc 100644 --- a/include/sqlpp11/some.h +++ b/include/sqlpp11/some.h @@ -37,9 +37,6 @@ namespace sqlpp template struct some_t { - static_assert(is_select_t::value, "some() requires a single column select expression as argument"); - struct _value_type: public Select::_value_type::_base_value_type { using _is_expression = std::false_type; @@ -93,7 +90,8 @@ namespace sqlpp template auto some(T t) -> typename vendor::some_t> { - static_assert(is_select_t>::value, "some() requires a select expression as argument"); + static_assert(is_select_t>::value, "some() requires a single column select expression as argument"); + static_assert(is_value_t>::value, "some() requires a single column select expression as argument"); return { t }; } diff --git a/include/sqlpp11/table_alias.h b/include/sqlpp11/table_alias.h index 2f51903a..273b2d90 100644 --- a/include/sqlpp11/table_alias.h +++ b/include/sqlpp11/table_alias.h @@ -42,7 +42,7 @@ namespace sqlpp { //FIXME: Need to add join functionality using _is_table = std::true_type; - using _table_set = detail::type_set; + using _table_set = detail::type_set; struct _value_type: Table::_value_type { diff --git a/tests/FunctionTest.cpp b/tests/FunctionTest.cpp index 3284daa7..04aa8f52 100644 --- a/tests/FunctionTest.cpp +++ b/tests/FunctionTest.cpp @@ -185,11 +185,13 @@ int main() static_assert(not sqlpp::is_text_t::value, "type requirement"); } + // Test any { + using TI = decltype(any(select(t.alpha).from(t))); using TT = decltype(any(select(t.beta).from(t))); - using TF = decltype(any(select(f.omega).from(t))); + using TF = decltype(any(select(f.omega).from(f))); static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_multi_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); @@ -212,7 +214,7 @@ int main() { using TI = decltype(some(select(t.alpha).from(t))); using TT = decltype(some(select(t.beta).from(t))); - using TF = decltype(some(select(f.omega).from(t))); + using TF = decltype(some(select(f.omega).from(f))); static_assert(not sqlpp::is_named_expression_t::value, "type requirement"); static_assert(sqlpp::is_multi_expression_t::value, "type requirement"); static_assert(sqlpp::is_numeric_t::value, "type requirement"); diff --git a/tests/SelectTypeTest.cpp b/tests/SelectTypeTest.cpp index bc224e87..e0a4af64 100644 --- a/tests/SelectTypeTest.cpp +++ b/tests/SelectTypeTest.cpp @@ -357,12 +357,27 @@ int main() static_assert(sqlpp::is_named_expression_t::value, "alpha should be a named expression"); static_assert(sqlpp::is_named_expression_t::value, "an alias of alpha should be a named expression"); static_assert(sqlpp::is_alias_t::value, "an alias of alpha should be an alias"); + auto z = select(t.alpha).from(t) == 7; auto l = t.as(alias::left); auto r = select(t.gamma.as(alias::a)).from(t).where(t.gamma == true).as(alias::right); + using R = decltype(r); static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool"); - serialize(sqlpp::select().flags(sqlpp::distinct, sqlpp::straight_join).columns(l.alpha, l.beta, select(r.a).from(r)) - .from(l, r) + auto s = select(r.a).from(r); + using RA = decltype(r.a); + using S = decltype(s); + using SCL = typename S::_column_list_t; + using SF = typename S::_from_t; + static_assert(sqlpp::is_select_column_list_t::value, "no column list"); + static_assert(sqlpp::is_from_t::value, "no from list"); + using SCL_T = typename SCL::_table_set; + using SF_T = typename SF::_table_set; + static_assert(SCL_T::size::value == 1, "unexpected table_set in column_list"); + static_assert(SF_T::size::value == 1, "unexpected table_set in from"); + static_assert(std::is_same::value, "should be the same"); + static_assert(sqlpp::is_boolean_t::value, "select(bool) has to be a bool"); + auto s1 = sqlpp::select().flags(sqlpp::distinct, sqlpp::straight_join).columns(l.alpha, l.beta, select(r.a).from(r)) + .from(r,t,l) .where(t.beta == "hello world" and select(t.gamma).from(t))// .as(alias::right)) .group_by(l.gamma, r.a) .having(r.a != true) @@ -370,7 +385,8 @@ int main() .limit(17) .offset(3) .as(alias::a) - , printer).str(); + ; + return 0; }