0
0
mirror of https://github.com/rbock/sqlpp11.git synced 2024-11-16 04:47:18 +08:00

Merge branch 'feature/fix_left_and_right_outer_join' into develop

This commit is contained in:
rbock 2016-03-15 08:10:34 +01:00
commit 84d281ebb9
8 changed files with 281 additions and 7 deletions

View File

@ -65,6 +65,7 @@ target_compile_features(sqlpp11 INTERFACE
endif () endif ()
add_subdirectory(tests) add_subdirectory(tests)
add_subdirectory(test_types)
add_subdirectory(test_serializer) add_subdirectory(test_serializer)
add_subdirectory(test_static_asserts) add_subdirectory(test_static_asserts)
add_subdirectory(test_constraints) add_subdirectory(test_constraints)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2015, Roland Bock * Copyright (c) 2013-2016, Roland Bock
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
@ -111,7 +111,7 @@ namespace sqlpp
{ {
static_assert(not contains_aggregate_function_t<wrap_operand_t<T>>::value, static_assert(not contains_aggregate_function_t<wrap_operand_t<T>>::value,
"avg() cannot be used on an aggregate function"); "avg() cannot be used on an aggregate function");
static_assert(is_numeric_t<wrap_operand_t<T>>::value, "avg() requires a value expression as argument"); static_assert(is_numeric_t<wrap_operand_t<T>>::value, "avg() requires a numeric value expression as argument");
return {t}; return {t};
} }
@ -120,7 +120,7 @@ namespace sqlpp
{ {
static_assert(not contains_aggregate_function_t<wrap_operand_t<T>>::value, static_assert(not contains_aggregate_function_t<wrap_operand_t<T>>::value,
"avg() cannot be used on an aggregate function"); "avg() cannot be used on an aggregate function");
static_assert(is_numeric_t<wrap_operand_t<T>>::value, "avg() requires a value expression as argument"); static_assert(is_numeric_t<wrap_operand_t<T>>::value, "avg() requires a numeric value expression as argument");
return {t}; return {t};
} }
} }

View File

@ -49,14 +49,14 @@ namespace sqlpp
struct left_outer_join_t struct left_outer_join_t
{ {
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of<Lhs>, provided_outer_tables_of<Rhs>>; using _provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Lhs>, provided_tables_of<Rhs>>;
static constexpr const char* _name = " LEFT OUTER"; static constexpr const char* _name = " LEFT OUTER";
}; };
struct right_outer_join_t struct right_outer_join_t
{ {
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>
using _provided_outer_tables = detail::make_joined_set_t<provided_outer_tables_of<Lhs>, provided_tables_of<Rhs>>; using _provided_outer_tables = detail::make_joined_set_t<provided_tables_of<Lhs>, provided_outer_tables_of<Rhs>>;
static constexpr const char* _name = " RIGHT OUTER"; static constexpr const char* _name = " RIGHT OUTER";
}; };

View File

@ -91,6 +91,7 @@ namespace sqlpp
using _traits = make_traits<no_value_t, tag::is_pre_join>; using _traits = make_traits<no_value_t, tag::is_pre_join>;
using _nodes = detail::type_vector<Lhs, Rhs>; using _nodes = detail::type_vector<Lhs, Rhs>;
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>;
static_assert(is_table_t<Lhs>::value, "lhs argument for join() has to be a table or join"); static_assert(is_table_t<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_t<Rhs>::value, "rhs argument for join() has to be a table");
@ -185,7 +186,7 @@ namespace sqlpp
template <typename Lhs, typename Rhs> template <typename Lhs, typename Rhs>
auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_pre_join_t<Lhs, Rhs>::value, auto outer_join(Lhs lhs, Rhs rhs) -> typename std::conditional<check_pre_join_t<Lhs, Rhs>::value,
pre_join_t<right_outer_join_t, Lhs, Rhs>, pre_join_t<outer_join_t, Lhs, Rhs>,
bad_statement>::type bad_statement>::type
{ {
check_pre_join_t<Lhs, Rhs>::_(); check_pre_join_t<Lhs, Rhs>::_();

View File

@ -48,6 +48,14 @@ int From(int, char* [])
compare(__LINE__, from(foo.cross_join(bar)), " FROM tab_foo CROSS JOIN tab_bar"); compare(__LINE__, from(foo.cross_join(bar)), " FROM tab_foo CROSS JOIN tab_bar");
compare(__LINE__, from(foo.join(bar).on(foo.omega > bar.alpha)), compare(__LINE__, from(foo.join(bar).on(foo.omega > bar.alpha)),
" FROM tab_foo INNER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)"); " FROM tab_foo INNER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)");
compare(__LINE__, from(foo.inner_join(bar).on(foo.omega > bar.alpha)),
" FROM tab_foo INNER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)");
compare(__LINE__, from(foo.outer_join(bar).on(foo.omega > bar.alpha)),
" FROM tab_foo OUTER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)");
compare(__LINE__, from(foo.left_outer_join(bar).on(foo.omega > bar.alpha)),
" FROM tab_foo LEFT OUTER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)");
compare(__LINE__, from(foo.right_outer_join(bar).on(foo.omega > bar.alpha)),
" FROM tab_foo RIGHT OUTER JOIN tab_bar ON (tab_foo.omega>tab_bar.alpha)");
compare(__LINE__, from(aFoo.join(bFoo).on(aFoo.omega > bFoo.omega)), compare(__LINE__, from(aFoo.join(bFoo).on(aFoo.omega > bFoo.omega)),
" FROM tab_foo AS a INNER JOIN tab_foo AS b ON (a.omega>b.omega)"); " FROM tab_foo AS a INNER JOIN tab_foo AS b ON (a.omega>b.omega)");
compare( compare(
@ -62,11 +70,31 @@ int From(int, char* [])
dfa.from.add(dynamic_cross_join(bar)); dfa.from.add(dynamic_cross_join(bar));
compare(__LINE__, dfa, " FROM tab_foo CROSS JOIN tab_bar"); compare(__LINE__, dfa, " FROM tab_foo CROSS JOIN tab_bar");
} }
{
auto dfa = df;
dfa.from.add(dynamic_join(bar).on(bar.alpha > foo.omega));
compare(__LINE__, dfa, " FROM tab_foo INNER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)");
}
{ {
auto dfa = df; auto dfa = df;
dfa.from.add(dynamic_inner_join(bar).on(bar.alpha > foo.omega)); dfa.from.add(dynamic_inner_join(bar).on(bar.alpha > foo.omega));
compare(__LINE__, dfa, " FROM tab_foo INNER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)"); compare(__LINE__, dfa, " FROM tab_foo INNER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)");
} }
{
auto dfa = df;
dfa.from.add(dynamic_outer_join(bar).on(bar.alpha > foo.omega));
compare(__LINE__, dfa, " FROM tab_foo OUTER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)");
}
{
auto dfa = df;
dfa.from.add(dynamic_left_outer_join(bar).on(bar.alpha > foo.omega));
compare(__LINE__, dfa, " FROM tab_foo LEFT OUTER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)");
}
{
auto dfa = df;
dfa.from.add(dynamic_right_outer_join(bar).on(bar.alpha > foo.omega));
compare(__LINE__, dfa, " FROM tab_foo RIGHT OUTER JOIN tab_bar ON (tab_bar.alpha>tab_foo.omega)");
}
{ {
auto dfa = df; auto dfa = df;
dfa.from.add(dynamic_inner_join(bar).on(bar.alpha > foo.omega)); dfa.from.add(dynamic_inner_join(bar).on(bar.alpha > foo.omega));

32
test_types/CMakeLists.txt Normal file
View File

@ -0,0 +1,32 @@
# Copyright (c) 2016-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.
function(test_compile name)
set(target sqlpp11_${name})
add_executable(${target} ${name}.cpp)
target_link_libraries(${target} PRIVATE sqlpp11 sqlpp11_testing)
endfunction()
test_compile(result_row)

212
test_types/result_row.cpp Normal file
View File

@ -0,0 +1,212 @@
/*
* Copyright (c) 2016-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 "MockDb.h"
#include "Sample.h"
#include <sqlpp11/sqlpp11.h>
namespace
{
constexpr auto bar = test::TabBar{};
constexpr auto foo = test::TabFoo{};
static_assert(sqlpp::can_be_null_t<decltype(bar.alpha)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(foo.omega)>::value, "");
static_assert(not sqlpp::can_be_null_t<decltype(foo.delta)>::value, "");
static_assert(not sqlpp::can_be_null_t<decltype(bar.gamma)>::value, "");
const auto seven = sqlpp::value(7).as(sqlpp::alias::s);
static_assert(not sqlpp::can_be_null_t<decltype(seven)>::value, "");
auto db = MockDb{};
void single_table()
{
{
// result fields are as nullable as the expressions they represent
const auto& x = db(select(bar.alpha, bar.gamma, seven).from(bar).unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "");
}
}
void join()
{
// Join
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(foo.join(bar).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of (inner) join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of (inner) join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.join(foo).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of (inner) join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of (inner) join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
// Inner join
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(foo.inner_join(bar).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of inner join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of inner join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.inner_join(foo).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of inner join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of inner join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
// Left outer join
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(foo.left_outer_join(bar).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of left outer join cannot be null");
static_assert(sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of left outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.left_outer_join(foo).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of left outer join cannot be null");
static_assert(sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of left outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
// Right outer join
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(foo.right_outer_join(bar).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of right outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value,
"right side of right outer join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.right_outer_join(foo).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of right outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value,
"right side of right outer join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
// Outer join
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(foo.outer_join(bar).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of outer join can be null");
static_assert(sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto& x = db(select(bar.alpha, foo.delta, bar.gamma, seven)
.from(bar.outer_join(foo).on(foo.omega > bar.alpha))
.unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of outer join can be null");
static_assert(sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of outer join can be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
// Cross join
{
const auto& x =
db(select(bar.alpha, foo.delta, bar.gamma, seven).from(foo.cross_join(bar)).unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "left side of cross join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "right side of cross join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
{
const auto& x =
db(select(bar.alpha, foo.delta, bar.gamma, seven).from(bar.cross_join(foo)).unconditionally()).front();
static_assert(sqlpp::can_be_null_t<decltype(x.alpha)>::value, "nullable value can always be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.gamma)>::value, "left side of cross join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.delta)>::value, "right side of cross join cannot be null");
static_assert(not sqlpp::can_be_null_t<decltype(x.s)>::value, "constant non-null value can not be null");
}
}
void aggregates()
{
{
// aggregates of nullable values
const auto a = bar.alpha;
static_assert(sqlpp::can_be_null_t<decltype(bar.alpha)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(a)>::value, "");
const auto& x = db(select(count(a), avg(a), max(a), min(a), sum(a)).from(bar).unconditionally()).front();
static_assert(not sqlpp::can_be_null_t<decltype(x.count)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.avg)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.sum)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.max)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.min)>::value, "");
}
{
// aggregates of nullable values
const auto o = foo.omega;
static_assert(sqlpp::can_be_null_t<decltype(foo.omega)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(o)>::value, "");
const auto& x = db(select(count(o), avg(o), max(o), min(o), sum(o)).from(foo).unconditionally()).front();
static_assert(not sqlpp::can_be_null_t<decltype(x.count)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.avg)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.sum)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.max)>::value, "");
static_assert(sqlpp::can_be_null_t<decltype(x.min)>::value, "");
}
}
}
int main(int, char* [])
{
single_table();
join();
aggregates();
}

View File

@ -29,7 +29,7 @@ namespace test
} }
}; };
}; };
using _traits = sqlpp::make_traits<sqlpp::varchar, sqlpp::tag::can_be_null>; using _traits = sqlpp::make_traits<sqlpp::varchar>;
}; };
struct Epsilon struct Epsilon
{ {