diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index 6d34b994..41a932d3 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -193,7 +193,7 @@ namespace sqlpp private: template auto _from_impl(const std::false_type&, Tables... tables) const - -> _new_statement_t>; + -> bad_statement; template auto _from_impl(const std::true_type&, Tables... tables) const diff --git a/include/sqlpp11/group_by.h b/include/sqlpp11/group_by.h index acb2833d..65e8d5ff 100644 --- a/include/sqlpp11/group_by.h +++ b/include/sqlpp11/group_by.h @@ -178,34 +178,45 @@ namespace sqlpp struct _methods_t { using _database_t = typename Policies::_database_t; - template - using _new_statement_t = new_statement; + + template + using _check = detail::all_t::value...>; + + template + using _new_statement_t = new_statement_t; using _consistency_check = consistent_t; template auto group_by(Expressions... expressions) const - -> _new_statement_t> + -> _new_statement_t<_check, group_by_t> { static_assert(sizeof...(Expressions), "at least one expression (e.g. a column) required in group_by()"); - return _group_by_impl(expressions...); + static_assert(detail::all_t::value...>::value, "at least one argument is not an expression in group_by()"); + + return _group_by_impl(_check{}, expressions...); } template auto dynamic_group_by(Expressions... expressions) const - -> _new_statement_t> + -> _new_statement_t<_check, group_by_t<_database_t, Expressions...>> { static_assert(not std::is_same<_database_t, void>::value, "dynamic_group_by must not be called in a static statement"); - return _group_by_impl<_database_t>(expressions...); + static_assert(detail::all_t::value...>::value, "at least one argument is not an expression in group_by()"); + + return _group_by_impl<_database_t>(_check{}, expressions...); } private: template - auto _group_by_impl(Expressions... expressions) const - -> _new_statement_t> + auto _group_by_impl(const std::false_type&, Expressions... expressions) const + -> bad_statement; + + template + auto _group_by_impl(const std::true_type&, Expressions... expressions) const + -> _new_statement_t> { static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected in group_by()"); - static_assert(detail::all_t::value...>::value, "at least one argument is not an expression in group_by()"); return { static_cast&>(*this), group_by_data_t{expressions...} }; }; diff --git a/include/sqlpp11/insert_value_list.h b/include/sqlpp11/insert_value_list.h index 077af67d..2e136716 100644 --- a/include/sqlpp11/insert_value_list.h +++ b/include/sqlpp11/insert_value_list.h @@ -41,20 +41,20 @@ namespace sqlpp { namespace detail { - template - struct first_arg_impl + template + struct have_all_required_columns { - static_assert(wrong_t::value, "At least one argument required"); + static constexpr bool value = false; }; - template - struct first_arg_impl + template + struct have_all_required_columns { - using type = T; + using _table = typename First::_table; + using required_columns = typename _table::_required_insert_columns; + using set_columns = detail::make_type_set_t; + static constexpr bool value = detail::is_subset_of::value; }; - - template - using first_arg_t = typename first_arg_impl::type; } struct insert_default_values_data_t @@ -369,62 +369,79 @@ namespace sqlpp struct _methods_t { using _database_t = typename Policies::_database_t; - template - using _new_statement_t = new_statement; + + template + using _column_check = detail::all_t::value...>; + + template + using _assignment_check = detail::all_t::value...>; + + template + using _new_statement_t = new_statement_t; using _consistency_check = assert_insert_values_t; auto default_values() const - -> _new_statement_t + -> _new_statement_t { return { static_cast&>(*this), insert_default_values_data_t{} }; } template auto columns(Columns... columns) const - -> _new_statement_t> + -> _new_statement_t<_column_check, column_list_t> { - static_assert(sizeof...(Columns), "at least one column required in columns()"); - static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected in columns()"); static_assert(detail::all_t::value...>::value, "at least one argument is not a column in columns()"); - static_assert(detail::none_t::value...>::value, "at least one column argument has a must_not_insert tag in its definition"); - using _column_required_tables = detail::make_joined_set_t...>; - static_assert(_column_required_tables::size::value == 1, "columns() contains columns from several tables"); + static_assert(sizeof...(Columns), "at least one column required in columns()"); - using _table = typename detail::first_arg_t::_table; - using required_columns = typename _table::_required_insert_columns; - using set_columns = detail::make_type_set_t; - static_assert(detail::is_subset_of::value, "At least one required column is missing in columns()"); - - return { static_cast&>(*this), column_list_data_t{columns...} }; + return _columns_impl(_column_check{}, columns...); } template auto set(Assignments... assignments) const - -> _new_statement_t> + -> _new_statement_t<_assignment_check, insert_list_t> { + static_assert(_assignment_check::value, "at least one argument is not an assignment in set()"); static_assert(sizeof...(Assignments), "at least one assignment expression required in set()"); - static_assert(detail::all_t::value...>::value, "at least one argument is not an assignment in set()"); - using _table = typename lhs_t>::_table; - using required_columns = typename _table::_required_insert_columns; - using columns = detail::make_type_set_t...>; - static_assert(detail::is_subset_of::value, "At least one required column is missing in set()"); - return _set_impl(assignments...); + return _set_impl(_assignment_check{}, assignments...); } template auto dynamic_set(Assignments... assignments) const - -> _new_statement_t> + -> _new_statement_t<_assignment_check, insert_list_t<_database_t, Assignments...>> { + static_assert(_assignment_check::value, "at least one argument is not an assignment in set()"); static_assert(not std::is_same<_database_t, void>::value, "dynamic_set must not be called in a static statement"); - static_assert(detail::all_t::value...>::value, "at least one argument is not an assignment in set()"); - return _set_impl<_database_t>(assignments...); + + return _set_impl<_database_t>(_assignment_check{}, assignments...); } private: + template + auto _columns_impl(const std::false_type&, Columns... columns) const + -> bad_statement; + + template + auto _columns_impl(const std::true_type&, Columns... columns) const + -> _new_statement_t> + { + static_assert(not detail::has_duplicates::value, "at least one duplicate argument detected in columns()"); + static_assert(detail::none_t::value...>::value, "at least one column argument has a must_not_insert tag in its definition"); + using _column_required_tables = detail::make_joined_set_t...>; + static_assert(_column_required_tables::size::value == 1, "columns() contains columns from several tables"); + + static_assert(detail::have_all_required_columns::value, "At least one required column is missing in columns()"); + + return { static_cast&>(*this), column_list_data_t{columns...} }; + } + template - auto _set_impl(Assignments... assignments) const - -> _new_statement_t> + auto _set_impl(const std::false_type&, Assignments... assignments) const + -> bad_statement; + + template + auto _set_impl(const std::true_type&, Assignments... assignments) const + -> _new_statement_t> { static_assert(not detail::has_duplicates...>::value, "at least one duplicate column detected in set()"); static_assert(detail::none_t>::value...>::value, "at least one assignment is prohibited by its column definition in set()"); @@ -432,6 +449,8 @@ namespace sqlpp using _column_required_tables = detail::make_joined_set_t>...>; static_assert(sizeof...(Assignments) ? (_column_required_tables::size::value == 1) : true, "set() contains assignments for columns from several tables"); + static_assert(not std::is_same<_database_t, void>::value or detail::have_all_required_columns...>::value, "At least one required column is missing in set()"); + return { static_cast&>(*this), insert_list_data_t{assignments...} }; } };