Skip to content

Commit 5e21e5a

Browse files
authored
Merge pull request #1380 from fnc12/corrected_rowset_deduplicators
Corrected rowset deduplicators DISTINCT and ALL
2 parents ad4e253 + 140f65b commit 5e21e5a

File tree

13 files changed

+215
-155
lines changed

13 files changed

+215
-155
lines changed

dev/ast_iterator.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ namespace sqlite_orm {
7171

7272
template<class L>
7373
void operator()(const node_type& node, L& lambda) const {
74-
iterate_ast(node.value, lambda);
74+
iterate_ast(node.expression, lambda);
7575
}
7676
};
7777
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
@@ -637,7 +637,7 @@ namespace sqlite_orm {
637637

638638
template<class L>
639639
void operator()(const node_type& a, L& lambda) const {
640-
iterate_ast(a.value, lambda);
640+
iterate_ast(a.expression, lambda);
641641
}
642642
};
643643

@@ -647,7 +647,7 @@ namespace sqlite_orm {
647647

648648
template<class L>
649649
void operator()(const node_type& a, L& lambda) const {
650-
iterate_ast(a.value, lambda);
650+
iterate_ast(a.expression, lambda);
651651
}
652652
};
653653

dev/column_names_getter.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ namespace sqlite_orm {
2121

2222
namespace internal {
2323

24-
template<class T, class C>
25-
auto serialize(const T& t, const C& context);
24+
template<class T, class Ctx>
25+
auto serialize(const T& t, const Ctx& context);
2626

2727
template<class T, class Ctx>
2828
std::vector<std::string>& collect_table_column_names(std::vector<std::string>& collectedExpressions,
@@ -123,9 +123,9 @@ namespace sqlite_orm {
123123
};
124124

125125
template<class T, class Ctx>
126-
std::vector<std::string> get_column_names(const T& t, const Ctx& context) {
126+
std::vector<std::string> get_column_names(const T& expression, const Ctx& context) {
127127
column_names_getter serializer;
128-
return serializer(t, context);
128+
return serializer(access_column_expression(expression), context);
129129
}
130130
}
131131
}

dev/cte_column_names_collector.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
namespace sqlite_orm {
2020
namespace internal {
2121
// collecting column names utilizes the statement serializer
22-
template<class T, class C>
23-
auto serialize(const T& t, const C& context);
22+
template<class T, class Ctx>
23+
auto serialize(const T& t, const Ctx& context);
2424

2525
inline void unquote_identifier(std::string& identifier) {
2626
if (!identifier.empty()) {
@@ -67,7 +67,7 @@ namespace sqlite_orm {
6767
template<class T, class Ctx>
6868
std::vector<std::string> get_cte_column_names(const T& t, const Ctx& context) {
6969
cte_column_names_collector<T> collector;
70-
return collector(t, context);
70+
return collector(access_column_expression(t), context);
7171
}
7272

7373
template<class As>

dev/default_value_extractor.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ namespace sqlite_orm {
1010

1111
namespace internal {
1212

13-
template<class T, class C>
14-
auto serialize(const T& t, const C& context);
13+
template<class T, class Ctx>
14+
auto serialize(const T& t, const Ctx& context);
1515

1616
/**
17-
* Serialize default value of a column's default valu
17+
* Serialize a column's default value.
1818
*/
1919
template<class T>
2020
std::string serialize_default_value(const default_t<T>& dft) {

dev/select_constraints.h

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
44
#include <concepts>
55
#endif
6-
#include <type_traits> // std::remove_cvref, std::is_convertible, std::is_same, std::is_member_pointer
6+
#include <type_traits> // std::enable_if, std::remove_cvref, std::is_convertible, std::is_same, std::is_member_pointer
77
#include <string> // std::string
88
#include <utility> // std::move
99
#include <tuple> // std::tuple, std::get, std::tuple_size
@@ -28,9 +28,9 @@ namespace sqlite_orm {
2828
#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED
2929
template<class T>
3030
struct as_optional_t {
31-
using value_type = T;
31+
using expression_type = T;
3232

33-
value_type value;
33+
expression_type expression;
3434
};
3535
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
3636

@@ -45,11 +45,11 @@ namespace sqlite_orm {
4545
*/
4646
template<class T>
4747
struct distinct_t : distinct_string {
48-
using value_type = T;
48+
using expression_type = T;
4949

50-
value_type value;
50+
expression_type expression;
5151

52-
distinct_t(value_type value_) : value(std::move(value_)) {}
52+
distinct_t(expression_type expression) : expression(std::move(expression)) {}
5353
};
5454

5555
struct all_string {
@@ -63,17 +63,29 @@ namespace sqlite_orm {
6363
*/
6464
template<class T>
6565
struct all_t : all_string {
66-
T value;
66+
using expression_type = T;
6767

68-
all_t(T value_) : value(std::move(value_)) {}
68+
expression_type expression;
69+
70+
all_t(expression_type expression) : expression(std::move(expression)) {}
6971
};
7072

73+
/**
74+
* Whether a type represents a keyword for a result set modifier (as part of a simple select expression).
75+
*/
76+
template<class T>
77+
SQLITE_ORM_INLINE_VAR constexpr bool is_rowset_deduplicator_v =
78+
polyfill::disjunction<polyfill::is_specialization_of<T, distinct_t>,
79+
polyfill::is_specialization_of<T, all_t>>::value;
80+
81+
template<class T>
82+
struct is_rowset_deduplicator : polyfill::bool_constant<is_rowset_deduplicator_v<T>> {};
83+
7184
template<class... Args>
7285
struct columns_t {
7386
using columns_type = std::tuple<Args...>;
7487

7588
columns_type columns;
76-
bool distinct = false;
7789

7890
static constexpr int count = std::tuple_size<columns_type>::value;
7991

@@ -98,7 +110,6 @@ namespace sqlite_orm {
98110
using columns_type = std::tuple<Args...>;
99111

100112
columns_type columns;
101-
bool distinct = false;
102113

103114
static constexpr int count = std::tuple_size<columns_type>::value;
104115

@@ -323,24 +334,6 @@ namespace sqlite_orm {
323334
};
324335
#endif
325336

326-
/**
327-
* Generic way to get DISTINCT value from any type.
328-
*/
329-
template<class T>
330-
bool get_distinct(const T&) {
331-
return false;
332-
}
333-
334-
template<class... Args>
335-
bool get_distinct(const columns_t<Args...>& cols) {
336-
return cols.distinct;
337-
}
338-
339-
template<class T, class... Args>
340-
bool get_distinct(const struct_t<T, Args...>& cols) {
341-
return cols.distinct;
342-
}
343-
344337
template<class T>
345338
struct asterisk_t {
346339
using type = T;
@@ -417,6 +410,19 @@ namespace sqlite_orm {
417410
}
418411
};
419412

413+
template<class T, std::enable_if_t<!is_rowset_deduplicator_v<T>, bool> = true>
414+
const T& access_column_expression(const T& expression) {
415+
return expression;
416+
}
417+
418+
/*
419+
* Access a column expression prefixed by a result set deduplicator (as part of a simple select expression, i.e. distinct, all)
420+
*/
421+
template<class D, std::enable_if_t<is_rowset_deduplicator_v<D>, bool> = true>
422+
const typename D::expression_type& access_column_expression(const D& modifier) {
423+
return modifier.expression;
424+
}
425+
420426
template<class T>
421427
constexpr void validate_conditions() {
422428
static_assert(count_tuple<T, is_where>::value <= 1, "a single query cannot contain > 1 WHERE blocks");
@@ -433,6 +439,7 @@ namespace sqlite_orm {
433439
return {std::move(value)};
434440
}
435441
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
442+
436443
template<class T>
437444
internal::then_t<T> then(T t) {
438445
return {std::move(t)};
@@ -458,18 +465,12 @@ namespace sqlite_orm {
458465
return {std::move(t)};
459466
}
460467

461-
template<class... Args>
462-
internal::columns_t<Args...> distinct(internal::columns_t<Args...> cols) {
463-
cols.distinct = true;
464-
return cols;
465-
}
466-
467468
/*
468469
* Combine multiple columns in a tuple.
469470
*/
470471
template<class... Args>
471472
constexpr internal::columns_t<Args...> columns(Args... args) {
472-
return {std::make_tuple<Args...>(std::forward<Args>(args)...)};
473+
return {{std::forward<Args>(args)...}};
473474
}
474475

475476
/*
@@ -478,7 +479,7 @@ namespace sqlite_orm {
478479
*/
479480
template<class T, class... Args>
480481
constexpr internal::struct_t<T, Args...> struct_(Args... args) {
481-
return {std::make_tuple<Args...>(std::forward<Args>(args)...)};
482+
return {{std::forward<Args>(args)...}};
482483
}
483484

484485
/**
@@ -539,7 +540,7 @@ namespace sqlite_orm {
539540
* Example:
540541
* 1_ctealias().as<materialized()>(select(1));
541542
*/
542-
inline consteval internal::materialized_t materialized() {
543+
consteval internal::materialized_t materialized() {
543544
return {};
544545
}
545546

@@ -549,7 +550,7 @@ namespace sqlite_orm {
549550
* Example:
550551
* 1_ctealias().as<not_materialized()>(select(1));
551552
*/
552-
inline consteval internal::not_materialized_t not_materialized() {
553+
consteval internal::not_materialized_t not_materialized() {
553554
return {};
554555
}
555556
#endif

dev/serializing_util.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ namespace sqlite_orm {
2222
template<class O>
2323
struct order_by_t;
2424

25-
template<class T, class C>
26-
auto serialize(const T& t, const C& context);
25+
template<class T, class Ctx>
26+
auto serialize(const T& t, const Ctx& context);
2727

2828
template<class T, class Ctx>
2929
std::string serialize_order_by(const T&, const Ctx&);

dev/statement_serializer.h

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ namespace sqlite_orm {
6060
template<class T, class SFINAE = void>
6161
struct statement_serializer;
6262

63-
template<class T, class C>
64-
auto serialize(const T& t, const C& context) {
63+
template<class T, class Ctx>
64+
auto serialize(const T& t, const Ctx& context) {
6565
statement_serializer<T> serializer;
6666
return serializer(t, context);
6767
}
@@ -264,7 +264,7 @@ namespace sqlite_orm {
264264

265265
template<class Ctx>
266266
std::string operator()(const statement_type& statement, const Ctx& context) const {
267-
return serialize(statement.value, context);
267+
return serialize(statement.expression, context);
268268
}
269269
};
270270
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
@@ -549,28 +549,21 @@ namespace sqlite_orm {
549549
}
550550
};
551551

552+
// note (internal): this is a serializer for the deduplicator in an aggregate function;
553+
// the result set deduplicators in a simple-select are treated by the select serializer.
552554
template<class T>
553555
struct statement_serializer<distinct_t<T>, void> {
554556
using statement_type = distinct_t<T>;
555557

556558
template<class Ctx>
557559
std::string operator()(const statement_type& c, const Ctx& context) const {
558-
std::stringstream ss;
559-
auto expr = serialize(c.value, context);
560-
ss << static_cast<std::string>(c) << "(" << expr << ")";
561-
return ss.str();
562-
}
563-
};
564-
565-
template<class T>
566-
struct statement_serializer<all_t<T>, void> {
567-
using statement_type = all_t<T>;
560+
// DISTINCT introduces no parentheses
561+
auto subCtx = context;
562+
subCtx.use_parentheses = false;
568563

569-
template<class Ctx>
570-
std::string operator()(const statement_type& c, const Ctx& context) const {
571564
std::stringstream ss;
572-
auto expr = serialize(c.value, context);
573-
ss << static_cast<std::string>(c) << "(" << expr << ")";
565+
auto expr = serialize(c.expression, subCtx);
566+
ss << static_cast<std::string>(c) << " " << expr;
574567
return ss.str();
575568
}
576569
};
@@ -1771,9 +1764,11 @@ namespace sqlite_orm {
17711764
}
17721765
};
17731766
#endif // SQLITE_ORM_OPTIONAL_SUPPORTED
1767+
17741768
template<class T, class... Args>
17751769
struct statement_serializer<select_t<T, Args...>, void> {
17761770
using statement_type = select_t<T, Args...>;
1771+
using return_type = typename statement_type::return_type;
17771772

17781773
template<class Ctx>
17791774
std::string operator()(const statement_type& sel, Ctx context) const {
@@ -1788,10 +1783,14 @@ namespace sqlite_orm {
17881783
ss << "(";
17891784
}
17901785
ss << "SELECT ";
1786+
call_if_constexpr<is_rowset_deduplicator_v<return_type>>(
1787+
// note: make use of implicit to-string conversion
1788+
[&ss](std::string keyword) {
1789+
ss << keyword << ' ';
1790+
},
1791+
sel.col);
17911792
}
1792-
if (get_distinct(sel.col)) {
1793-
ss << static_cast<std::string>(distinct(0)) << " ";
1794-
}
1793+
17951794
ss << streaming_serialized(get_column_names(sel.col, subCtx));
17961795
using conditions_tuple = typename statement_type::conditions_type;
17971796
constexpr bool hasExplicitFrom = tuple_has<conditions_tuple, is_from>::value;

0 commit comments

Comments
 (0)