4
4
#include < utility> // std::make_index_sequence, std::move
5
5
#include < string> // std::string
6
6
#include < sstream> // std::stringstream
7
+ #ifdef SQLITE_ORM_WITH_CTE
8
+ #include < array>
9
+ #endif
7
10
8
11
#include " functional/cxx_type_traits_polyfill.h"
9
12
#include " functional/cstring_literal.h"
10
13
#include " type_traits.h"
11
14
#include " alias_traits.h"
12
15
#include " table_type_of.h"
13
16
#include " tags.h"
17
+ #include " column_pointer.h"
14
18
15
19
namespace sqlite_orm {
16
20
@@ -78,8 +82,8 @@ namespace sqlite_orm {
78
82
/*
79
83
* Encapsulates extracting the alias identifier of an alias.
80
84
*
81
- * `extract()` always returns the alias identifier.
82
- * `as_alias()` is used in contexts where a table is aliased, and the alias identifier is returned.
85
+ * `extract()` always returns the alias identifier or CTE moniker .
86
+ * `as_alias()` is used in contexts where a recordset is aliased, and the alias identifier is returned.
83
87
* `as_qualifier()` is used in contexts where a table is aliased, and the alias identifier is returned.
84
88
*/
85
89
template <class A >
@@ -96,6 +100,14 @@ namespace sqlite_orm {
96
100
return alias_extractor::extract ();
97
101
}
98
102
103
+ #ifdef SQLITE_ORM_WITH_CTE
104
+ // for CTE monikers -> empty
105
+ template <class T = A, satisfies<std::is_same, polyfill::detected_t <type_t , T>, A> = true >
106
+ static std::string as_alias () {
107
+ return {};
108
+ }
109
+ #endif
110
+
99
111
// for regular table aliases -> alias identifier
100
112
template <class T = A, satisfies<is_table_alias, T> = true >
101
113
static std::string as_qualifier (const basic_table&) {
@@ -131,6 +143,8 @@ namespace sqlite_orm {
131
143
using type = T;
132
144
133
145
alias_holder () = default ;
146
+ // CTE feature needs it to implicitly convert a column alias to an alias_holder; see `cte()` factory function
147
+ alias_holder (const T&) noexcept {}
134
148
};
135
149
136
150
template <class T >
@@ -144,8 +158,31 @@ namespace sqlite_orm {
144
158
[[nodiscard]] consteval recordset_alias<T, A, X...> for_ () const {
145
159
return {};
146
160
}
161
+
162
+ template <auto t>
163
+ [[nodiscard]] consteval auto for_ () const {
164
+ using T = std::remove_const_t <decltype (t)>;
165
+ return recordset_alias<T, A, X...>{};
166
+ }
147
167
};
148
168
#endif
169
+
170
+ #ifdef SQLITE_ORM_WITH_CTE
171
+ template <size_t n, char ... C>
172
+ SQLITE_ORM_CONSTEVAL auto n_to_colalias () {
173
+ constexpr column_alias<' 1' + n % 10 , C...> colalias{};
174
+ if constexpr (n > 10 ) {
175
+ return n_to_colalias<n / 10 , ' 1' + n % 10 , C...>();
176
+ } else {
177
+ return colalias;
178
+ }
179
+ }
180
+
181
+ template <class T >
182
+ inline constexpr bool is_builtin_numeric_column_alias_v = false ;
183
+ template <char ... C>
184
+ inline constexpr bool is_builtin_numeric_column_alias_v<column_alias<C...>> = ((C >= ' 0' && C <= ' 9' ) && ...);
185
+ #endif
149
186
}
150
187
151
188
/* *
@@ -155,7 +192,12 @@ namespace sqlite_orm {
155
192
* using als = alias_u<User>;
156
193
* select(alias_column<als>(column<User>(&User::id)))
157
194
*/
158
- template <class A , class C , std::enable_if_t <internal::is_table_alias<A>::value, bool > = true >
195
+ template <class A ,
196
+ class C ,
197
+ std::enable_if_t <
198
+ polyfill::conjunction<internal::is_table_alias<A>,
199
+ polyfill::negation<internal::is_cte_moniker<internal::type_t <A>>>>::value,
200
+ bool > = true >
159
201
constexpr auto alias_column (C field) {
160
202
using namespace ::sqlite_orm::internal;
161
203
using aliased_type = type_t <A>;
@@ -173,7 +215,13 @@ namespace sqlite_orm {
173
215
* using als = alias_u<User>;
174
216
* select(alias_column<als>(&User::id))
175
217
*/
176
- template <class A , class F , class O , std::enable_if_t <internal::is_table_alias<A>::value, bool > = true >
218
+ template <class A ,
219
+ class F ,
220
+ class O ,
221
+ std::enable_if_t <
222
+ polyfill::conjunction<internal::is_table_alias<A>,
223
+ polyfill::negation<internal::is_cte_moniker<internal::type_t <A>>>>::value,
224
+ bool > = true >
177
225
constexpr auto alias_column (F O::*field) {
178
226
using namespace ::sqlite_orm::internal;
179
227
using aliased_type = type_t <A>;
@@ -195,6 +243,7 @@ namespace sqlite_orm {
195
243
* select(alias_column<als>(&User::id))
196
244
*/
197
245
template <orm_table_alias auto als, class C >
246
+ requires (!orm_cte_moniker<internal::auto_type_t <als>>)
198
247
constexpr auto alias_column(C field) {
199
248
using namespace ::sqlite_orm::internal;
200
249
using A = decltype (als);
@@ -225,11 +274,60 @@ namespace sqlite_orm {
225
274
* select(als->*&User::id)
226
275
*/
227
276
template <orm_table_alias A, class F >
277
+ requires (!orm_cte_moniker<internal::type_t <A>>)
228
278
constexpr auto operator->*(const A& /* tableAlias*/ , F field) {
229
279
return alias_column<A>(std::move (field));
230
280
}
231
281
#endif
232
282
283
+ #ifdef SQLITE_ORM_WITH_CTE
284
+ /* *
285
+ * Create a column reference to an aliased CTE column.
286
+ */
287
+ template <class A ,
288
+ class C ,
289
+ std::enable_if_t <
290
+ polyfill::conjunction_v<internal::is_table_alias<A>, internal::is_cte_moniker<internal::type_t <A>>>,
291
+ bool > = true >
292
+ constexpr auto alias_column (C c) {
293
+ using namespace internal ;
294
+ using cte_moniker_t = type_t <A>;
295
+
296
+ if constexpr (is_column_pointer_v<C>) {
297
+ static_assert (std::is_same<table_type_of_t <C>, cte_moniker_t >::value,
298
+ " Column pointer must match aliased CTE" );
299
+ return alias_column_t <A, C>{c};
300
+ } else {
301
+ auto cp = column<cte_moniker_t >(c);
302
+ return alias_column_t <A, decltype (cp)>{std::move (cp)};
303
+ }
304
+ }
305
+
306
+ #ifdef SQLITE_ORM_WITH_CPP20_ALIASES
307
+ /* *
308
+ * Create a column reference to an aliased CTE column.
309
+ *
310
+ * @note (internal) Intentionally place in the sqlite_orm namespace for ADL (Argument Dependent Lookup)
311
+ * because recordset aliases are derived from `sqlite_orm::alias_tag`
312
+ */
313
+ template <orm_table_alias A, class C >
314
+ requires (orm_cte_moniker<internal::type_t <A>>)
315
+ constexpr auto operator->*(const A& /* tableAlias*/ , C c) {
316
+ return alias_column<A>(std::move (c));
317
+ }
318
+
319
+ /* *
320
+ * Create a column reference to an aliased CTE column.
321
+ */
322
+ template <orm_table_alias auto als, class C >
323
+ requires (orm_cte_moniker<internal::auto_type_t <als>>)
324
+ constexpr auto alias_column(C c) {
325
+ using A = std::remove_const_t <decltype (als)>;
326
+ return alias_column<A>(std::move (c));
327
+ }
328
+ #endif
329
+ #endif
330
+
233
331
/* *
234
332
* Alias a column expression.
235
333
*/
@@ -247,17 +345,29 @@ namespace sqlite_orm {
247
345
return internal::as_t <decltype (als), E>{std::move (expression)};
248
346
}
249
347
250
- /* *
348
+ /* *
251
349
* Alias a column expression.
252
350
*/
253
351
template <orm_column_alias A, class E >
254
352
internal::as_t <A, E> operator >>=(E expression, const A&) {
255
353
return {std::move (expression)};
256
354
}
355
+ #else
356
+ /* *
357
+ * Alias a column expression.
358
+ */
359
+ template <class A , class E , internal::satisfies<internal::is_column_alias, A> = true >
360
+ internal::as_t <A, E> operator >>=(E expression, const A&) {
361
+ return {std::move (expression)};
362
+ }
257
363
#endif
258
364
259
- template <class A , internal::satisfies<internal::is_column_alias, A> = true >
260
- internal::alias_holder<A> get () {
365
+ /* *
366
+ * Wrap a column alias in an alias holder.
367
+ */
368
+ template <class T >
369
+ internal::alias_holder<T> get () {
370
+ static_assert (internal::is_column_alias_v<T>, " " );
261
371
return {};
262
372
}
263
373
@@ -362,4 +472,18 @@ namespace sqlite_orm {
362
472
}
363
473
}
364
474
#endif
475
+
476
+ #ifdef SQLITE_ORM_WITH_CTE
477
+ /* *
478
+ * column_alias<'1'[, ...]> from a numeric literal.
479
+ * E.g. 1_colalias, 2_colalias
480
+ */
481
+ template <char ... Chars>
482
+ [[nodiscard]] SQLITE_ORM_CONSTEVAL auto operator " " _colalias() {
483
+ // numeric identifiers are used for automatically assigning implicit aliases to unaliased column expressions,
484
+ // which start at "1".
485
+ static_assert (std::array{Chars...}[0 ] > ' 0' );
486
+ return internal::column_alias<Chars...>{};
487
+ }
488
+ #endif
365
489
}
0 commit comments