@@ -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>;
@@ -1828,30 +1829,33 @@ namespace sqlite_orm {
18281829 }
18291830 };
18301831
1831- template <class O >
1832- struct statement_serializer <cross_join_t <O>, void > {
1833- using statement_type = cross_join_t <O>;
1832+ template <class Join >
1833+ struct statement_serializer <
1834+ Join,
1835+ std::enable_if_t <polyfill::disjunction_v<polyfill::is_specialization_of<Join, cross_join_t >,
1836+ polyfill::is_specialization_of<Join, natural_join_t >>>> {
1837+ using statement_type = Join;
18341838
18351839 template <class Ctx >
1836- std::string operator ()(const statement_type& c , const Ctx& context) const {
1840+ std::string operator ()(const statement_type& join , const Ctx& context) const {
18371841 std::stringstream ss;
1838- ss << static_cast <std::string>(c ) << " "
1839- << streaming_identifier (lookup_table_name<O >(context.db_objects ));
1842+ ss << static_cast <std::string>(join ) << " "
1843+ << streaming_identifier (lookup_table_name<type_t <Join> >(context.db_objects ));
18401844 return ss.str ();
18411845 }
18421846 };
18431847
1844- template <class T , class O >
1845- struct statement_serializer <inner_join_t <T, O>, void > {
1846- using statement_type = inner_join_t <T, O> ;
1848+ template <class Join >
1849+ struct statement_serializer <Join, match_if<is_constrained_join, Join> > {
1850+ using statement_type = Join ;
18471851
18481852 template <class Ctx >
1849- std::string operator ()(const statement_type& l , const Ctx& context) const {
1853+ std::string operator ()(const statement_type& join , const Ctx& context) const {
18501854 std::stringstream ss;
1851- ss << static_cast <std::string>(l ) << " "
1852- << streaming_identifier (lookup_table_name<mapped_type_proxy_t <T >>(context.db_objects ),
1853- alias_extractor<T >::as_alias ())
1854- << serialize (l .constraint , context);
1855+ ss << static_cast <std::string>(join ) << " "
1856+ << streaming_identifier (lookup_table_name<mapped_type_proxy_t <type_t <Join> >>(context.db_objects ),
1857+ alias_extractor<type_t <Join> >::as_alias ())
1858+ << " " << serialize (join .constraint , context);
18551859 return ss.str ();
18561860 }
18571861 };
@@ -1861,69 +1865,11 @@ namespace sqlite_orm {
18611865 using statement_type = on_t <T>;
18621866
18631867 template <class Ctx >
1864- std::string operator ()(const statement_type& t , const Ctx& context) const {
1868+ std::string operator ()(const statement_type& on , const Ctx& context) const {
18651869 std::stringstream ss;
18661870 auto newContext = context;
18671871 newContext.skip_table_name = false ;
1868- ss << static_cast <std::string>(t) << " " << serialize (t.arg , newContext) << " " ;
1869- return ss.str ();
1870- }
1871- };
1872-
1873- template <class T , class O >
1874- struct statement_serializer <join_t <T, O>, void > {
1875- using statement_type = join_t <T, O>;
1876-
1877- template <class Ctx >
1878- std::string operator ()(const statement_type& l, const Ctx& context) const {
1879- std::stringstream ss;
1880- ss << static_cast <std::string>(l) << " "
1881- << streaming_identifier (lookup_table_name<mapped_type_proxy_t <T>>(context.db_objects ),
1882- alias_extractor<T>::as_alias ())
1883- << " " << serialize (l.constraint , context);
1884- return ss.str ();
1885- }
1886- };
1887-
1888- template <class T , class O >
1889- struct statement_serializer <left_join_t <T, O>, void > {
1890- using statement_type = left_join_t <T, O>;
1891-
1892- template <class Ctx >
1893- std::string operator ()(const statement_type& l, const Ctx& context) const {
1894- std::stringstream ss;
1895- ss << static_cast <std::string>(l) << " "
1896- << streaming_identifier (lookup_table_name<mapped_type_proxy_t <T>>(context.db_objects ),
1897- alias_extractor<T>::as_alias ())
1898- << " " << serialize (l.constraint , context);
1899- return ss.str ();
1900- }
1901- };
1902-
1903- template <class T , class O >
1904- struct statement_serializer <left_outer_join_t <T, O>, void > {
1905- using statement_type = left_outer_join_t <T, O>;
1906-
1907- template <class Ctx >
1908- std::string operator ()(const statement_type& l, const Ctx& context) const {
1909- std::stringstream ss;
1910- ss << static_cast <std::string>(l) << " "
1911- << streaming_identifier (lookup_table_name<mapped_type_proxy_t <T>>(context.db_objects ),
1912- alias_extractor<T>::as_alias ())
1913- << " " << serialize (l.constraint , context);
1914- return ss.str ();
1915- }
1916- };
1917-
1918- template <class O >
1919- struct statement_serializer <natural_join_t <O>, void > {
1920- using statement_type = natural_join_t <O>;
1921-
1922- template <class Ctx >
1923- std::string operator ()(const statement_type& c, const Ctx& context) const {
1924- std::stringstream ss;
1925- ss << static_cast <std::string>(c) << " "
1926- << streaming_identifier (lookup_table_name<O>(context.db_objects ));
1872+ ss << static_cast <std::string>(on) << " " << serialize (on.arg , newContext) << " " ;
19271873 return ss.str ();
19281874 }
19291875 };
0 commit comments