diff --git a/include/sqlpp11/from.h b/include/sqlpp11/from.h index 751e41e7..4968acbe 100644 --- a/include/sqlpp11/from.h +++ b/include/sqlpp11/from.h @@ -58,6 +58,7 @@ namespace sqlpp }; SQLPP_PORTABLE_STATIC_ASSERT(assert_from_add_dynamic, "from::add() requires a dynamic_from"); + SQLPP_PORTABLE_STATIC_ASSERT(assert_from_add_not_dynamic_pre_join, "join condition missing"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_add_dynamic_join, "from::add(X) requires X to be a dynamic join"); SQLPP_PORTABLE_STATIC_ASSERT(assert_from_add_unique_names, "from::add() must not add table names already used in from"); @@ -66,44 +67,48 @@ namespace sqlpp "tables not statically known, use " "without_table_check() to express the intent"); + template + struct check_from_add + { + using _known_tables = provided_tables_of; // Hint: Joins contain more than one table + // workaround for msvc bug https://connect.microsoft.com/VisualStudio/feedback/details/2173198 + // using _known_table_names = detail::transform_set_t; + using _known_table_names = detail::make_name_of_set_t<_known_tables>; + using _joined_tables = provided_tables_of; + using _joined_table_names = detail::make_name_of_set_t<_joined_tables>; + using _required_tables = required_tables_of; + using type = static_combined_check_t< + static_check_t, + static_check_t::value, assert_from_add_not_dynamic_pre_join>, + static_check_t::value, assert_from_add_dynamic_join>, + static_check_t::value, + assert_from_add_unique_names>, + static_check_t::value, + assert_from_add_no_required_tables>, + sqlpp::serialize_check_t, DynamicJoin>>; + }; + + template + using check_from_add_t = typename check_from_add::type; + // FROM template struct from_t { using _traits = make_traits; using _nodes = detail::type_vector; - using _is_dynamic = is_database; // Data using _data_t = from_data_t; - template - struct check_add - { - using _known_tables = provided_tables_of
; // Hint: Joins contain more than one table - // workaround for msvc bug https://connect.microsoft.com/VisualStudio/feedback/details/2173198 - // using _known_table_names = detail::transform_set_t; - using _known_table_names = detail::make_name_of_set_t<_known_tables>; - using _joined_tables = provided_tables_of; - using _joined_table_names = detail::make_name_of_set_t<_joined_tables>; - using _required_tables = required_tables_of; - using type = static_combined_check_t< - static_check_t<_is_dynamic::value, assert_from_add_dynamic>, - static_check_t::value, assert_from_add_dynamic_join>, - static_check_t::value, - assert_from_add_unique_names>, - static_check_t::value, - assert_from_add_no_required_tables>, - sqlpp::serialize_check_t>; - }; - - template - using check_add_t = typename check_add::type; - // Member implementation with data and methods template struct _impl_t { + using _database_t = Database; + using _is_dynamic = is_database<_database_t>; + using _table_t = Table; + // workaround for msvc bug https://connect.microsoft.com/VisualStudio/Feedback/Details/2091069 _impl_t() = default; _impl_t(const _data_t& data) : _data(data) @@ -112,9 +117,9 @@ namespace sqlpp template auto add(DynamicJoin dynamicJoin) -> - typename std::conditional::value, void, bad_statement>::type + typename std::conditional::value, void, bad_statement>::type { - using Check = check_add_t; + using Check = check_from_add_t<_impl_t, DynamicJoin>; Check::_(); return _add_impl(dynamicJoin, Check{}); } diff --git a/include/sqlpp11/type_traits.h b/include/sqlpp11/type_traits.h index d8f3fd9e..1b2d33ea 100644 --- a/include/sqlpp11/type_traits.h +++ b/include/sqlpp11/type_traits.h @@ -502,6 +502,24 @@ namespace sqlpp template class Predicate> using has_policy_t = typename has_policy_impl::type; + + struct no_context_t + { + }; + template + struct serializer_context_of_impl + { + using type = no_context_t; + }; + + template + struct serializer_context_of_impl> + { + using type = typename Db::_serializer_context_t; + }; + + template + using serializer_context_of = typename serializer_context_of_impl::type; } #endif diff --git a/test_static_asserts/from.cpp b/test_static_asserts/from.cpp index eb288a12..53fc9231 100644 --- a/test_static_asserts/from.cpp +++ b/test_static_asserts/from.cpp @@ -111,9 +111,56 @@ namespace from_dynamic_check(t.join(f)); } + template + void dynamic_from_add_check(FromImpl from, const Expression& expression) + { + using CheckResult = sqlpp::check_from_add_t; + using ExpectedCheckResult = std::is_same; + print_type_on_error(ExpectedCheckResult{}); + static_assert(ExpectedCheckResult::value, "Unexpected check result"); + + using ReturnType = decltype(from.add(expression)); + using ExpectedReturnType = + sqlpp::logic::all_t::value>; + print_type_on_error(ExpectedReturnType{}); + static_assert(ExpectedReturnType::value, "Unexpected return type"); + } + void dynamic_from_add() { -#warning : need to add tests for dynamic_from(xxx).add(yyy) + static auto db = MockDb{}; + auto fromT = dynamic_select(db, t.alpha).dynamic_from(t).from; + auto staticFrom = dynamic_select(db, t.alpha).from(t).from; + const auto fa = f.as(sqlpp::alias::a); + + // OK + dynamic_from_add_check(fromT, dynamic_join(f).on(t.alpha > f.omega)); + dynamic_from_add_check(fromT, dynamic_inner_join(f).on(t.alpha > f.omega)); + dynamic_from_add_check(fromT, dynamic_left_outer_join(f).on(t.alpha > f.omega)); + dynamic_from_add_check(fromT, dynamic_right_outer_join(f).on(t.alpha > f.omega)); + dynamic_from_add_check(fromT, dynamic_outer_join(f).on(t.alpha > f.omega)); + dynamic_from_add_check(fromT, dynamic_cross_join(f)); + + // Try a bunch of non dynamic joins + dynamic_from_add_check(staticFrom, 7); + + // Try a bunch of non dynamic joins + dynamic_from_add_check(fromT, 7); + dynamic_from_add_check(fromT, t.gamma); + dynamic_from_add_check(fromT, join(f, f.as(sqlpp::alias::a))); + + // Try incomplete dynamic join + dynamic_from_add_check(fromT, dynamic_join(f)); + + // Try joining the same table name + dynamic_from_add_check(fromT, dynamic_cross_join(t)); + dynamic_from_add_check(fromT, dynamic_cross_join(f.as(t))); + + // Try joining with a condition that requires other tables + dynamic_from_add_check(fromT, dynamic_join(f).on(t.alpha > fa.omega)); + + // If you really think you know what you are doing, use without_table_check + dynamic_from_add_check(fromT, dynamic_join(f).on(t.alpha > without_table_check(fa.omega))); } }