Skip to content

Commit cd04472

Browse files
committed
Tests for constrained join clauses with regard to table collection
1 parent d0462cd commit cd04472

File tree

4 files changed

+53
-6
lines changed

4 files changed

+53
-6
lines changed

dev/conditions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,7 @@ namespace sqlite_orm {
813813
using is_from = polyfill::is_specialization_of<T, from_t>;
814814

815815
template<class T>
816-
using is_any_join = polyfill::is_detected<on_type_t, T>;
816+
using is_constrained_join = polyfill::is_detected<on_type_t, T>;
817817
}
818818

819819
/**

dev/statement_serializer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,7 +1506,8 @@ namespace sqlite_orm {
15061506
constexpr bool hasExplicitFrom = tuple_has<is_from, conditions_tuple>::value;
15071507
if(!hasExplicitFrom) {
15081508
auto tableNames = collect_table_names(sel, context);
1509-
using joins_index_sequence = filter_tuple_sequence_t<conditions_tuple, is_any_join>;
1509+
using joins_index_sequence = filter_tuple_sequence_t<conditions_tuple, is_constrained_join>;
1510+
// deduplicate table names of constrained join statements
15101511
iterate_tuple(sel.conditions, joins_index_sequence{}, [&tableNames, &context](auto& join) {
15111512
using original_join_type = typename std::decay_t<decltype(join)>::type;
15121513
using cross_join_type = mapped_type_proxy_t<original_join_type>;
@@ -1851,7 +1852,7 @@ namespace sqlite_orm {
18511852
ss << static_cast<std::string>(l) << " "
18521853
<< streaming_identifier(lookup_table_name<mapped_type_proxy_t<T>>(context.db_objects),
18531854
alias_extractor<T>::as_alias())
1854-
<< serialize(l.constraint, context);
1855+
<< " " << serialize(l.constraint, context);
18551856
return ss.str();
18561857
}
18571858
};

include/sqlite_orm/sqlite_orm.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3775,7 +3775,7 @@ namespace sqlite_orm {
37753775
using is_from = polyfill::is_specialization_of<T, from_t>;
37763776

37773777
template<class T>
3778-
using is_any_join = polyfill::is_detected<on_type_t, T>;
3778+
using is_constrained_join = polyfill::is_detected<on_type_t, T>;
37793779
}
37803780

37813781
/**
@@ -16965,7 +16965,8 @@ namespace sqlite_orm {
1696516965
constexpr bool hasExplicitFrom = tuple_has<is_from, conditions_tuple>::value;
1696616966
if(!hasExplicitFrom) {
1696716967
auto tableNames = collect_table_names(sel, context);
16968-
using joins_index_sequence = filter_tuple_sequence_t<conditions_tuple, is_any_join>;
16968+
using joins_index_sequence = filter_tuple_sequence_t<conditions_tuple, is_constrained_join>;
16969+
// deduplicate table names of constrained join statements
1696916970
iterate_tuple(sel.conditions, joins_index_sequence{}, [&tableNames, &context](auto& join) {
1697016971
using original_join_type = typename std::decay_t<decltype(join)>::type;
1697116972
using cross_join_type = mapped_type_proxy_t<original_join_type>;
@@ -17310,7 +17311,7 @@ namespace sqlite_orm {
1731017311
ss << static_cast<std::string>(l) << " "
1731117312
<< streaming_identifier(lookup_table_name<mapped_type_proxy_t<T>>(context.db_objects),
1731217313
alias_extractor<T>::as_alias())
17313-
<< serialize(l.constraint, context);
17314+
<< " " << serialize(l.constraint, context);
1731417315
return ss.str();
1731517316
}
1731617317
};

tests/statement_serializer_tests/select_constraints.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,51 @@ TEST_CASE("statement_serializer select constraints") {
8686
}
8787
#endif
8888
}
89+
// tests whether the statement serializer for a select with joins
90+
// properly deduplicates the table names when no explicit from is used
91+
SECTION("deduplicated table names") {
92+
struct UserProps {
93+
int id = 0;
94+
std::string name;
95+
};
96+
auto table2 =
97+
make_table("user_props", make_column("id", &UserProps::id), make_column("name", &UserProps::name));
98+
using db_objects_t = internal::db_objects_tuple<decltype(table), decltype(table2)>;
99+
auto dbObjects = db_objects_t{table, table2};
100+
internal::serializer_context<db_objects_t> context{dbObjects};
101+
context.use_parentheses = false;
102+
103+
SECTION("left join") {
104+
auto expression = select(asterisk<User>(), left_join<UserProps>(using_(&UserProps::id)));
105+
value = serialize(expression, context);
106+
expected = R"(SELECT "users".* FROM "users" LEFT JOIN "user_props" USING ("id"))";
107+
}
108+
SECTION("join") {
109+
auto expression = select(asterisk<User>(), join<UserProps>(using_(&UserProps::id)));
110+
value = serialize(expression, context);
111+
expected = R"(SELECT "users".* FROM "users" JOIN "user_props" USING ("id"))";
112+
}
113+
SECTION("left outer join") {
114+
auto expression = select(asterisk<User>(), left_outer_join<UserProps>(using_(&UserProps::id)));
115+
value = serialize(expression, context);
116+
expected = R"(SELECT "users".* FROM "users" LEFT OUTER JOIN "user_props" USING ("id"))";
117+
}
118+
SECTION("inner join") {
119+
auto expression = select(asterisk<User>(), inner_join<UserProps>(using_(&UserProps::id)));
120+
value = serialize(expression, context);
121+
expected = R"(SELECT "users".* FROM "users" INNER JOIN "user_props" USING ("id"))";
122+
}
123+
SECTION("cross join") {
124+
auto expression = select(asterisk<User>(), cross_join<UserProps>());
125+
value = serialize(expression, context);
126+
expected = R"(SELECT "users".* FROM "users" CROSS JOIN "user_props")";
127+
}
128+
SECTION("natural join") {
129+
auto expression = select(asterisk<User>(), natural_join<UserProps>());
130+
value = serialize(expression, context);
131+
expected = R"(SELECT "users".* FROM "users" NATURAL JOIN "user_props")";
132+
}
133+
}
89134
SECTION("function_call") {
90135
struct Func {
91136
bool operator()(int arg) const {

0 commit comments

Comments
 (0)