Lightweight 0.20260303.0
Loading...
Searching...
No Matches
Core.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "../Api.hpp"
6#include "../SqlQueryFormatter.hpp"
7
8#include <algorithm>
9#include <concepts>
10#include <ranges>
11
12namespace Lightweight
13{
14
15/// @defgroup QueryBuilder Query Builder
16///
17/// @brief The query builder is a high level API for building SQL queries using high level C++ syntax.
18
19/// @brief SqlWildcardType is a placeholder for an explicit wildcard input parameter in a SQL query.
20///
21/// Use this in the SqlQueryBuilder::Where method to insert a '?' placeholder for a wildcard.
22///
23/// @ingroup QueryBuilder
25{
26};
27
28/// @brief SqlWildcard is a placeholder for an explicit wildcard input parameter in a SQL query.
29constexpr inline auto SqlWildcard = SqlWildcardType {};
30
31/// @brief Name of table in a SQL query, where the table's name is aliased.
33{
34 /// The table name.
35 std::string_view tableName;
36 /// The alias for the table.
37 std::string_view alias;
38
39 /// Three-way comparison operator.
40 std::weak_ordering operator<=>(AliasedTableName const&) const = default;
41};
42
43template <typename T>
44concept TableName =
45 std::convertible_to<T, std::string_view> || std::convertible_to<T, std::string> || std::same_as<T, AliasedTableName>;
46
47namespace detail
48{
49
50 struct RawSqlCondition
51 {
52 std::string condition;
53 };
54
55} // namespace detail
56
57/// @brief SqlQualifiedTableColumnName represents a column name qualified with a table name.
58/// @ingroup QueryBuilder
60{
61 /// The table name.
62 std::string_view tableName;
63 /// The column name.
64 std::string_view columnName;
65};
66
67/// @brief Helper function to create a SqlQualifiedTableColumnName from string_view
68///
69/// @param column The column name, which must be qualified with a table name.
70/// Example QualifiedColumnName<"Table.Column"> will create a SqlQualifiedTableColumnName with
71/// tableName = "Table" and columnName = "Column".
72template <Reflection::StringLiteral columnLiteral>
73constexpr SqlQualifiedTableColumnName QualifiedColumnName = []() consteval {
74#if !defined(_MSC_VER)
75 // enforce that we do not have symbols \ [ ] " '
76 static_assert(
77 !std::ranges::any_of(columnLiteral,
78 [](char c) consteval { return c == '\\' || c == '[' || c == ']' || c == '"' || c == '\''; }),
79 "QualifiedColumnName should not contain symbols \\ [ ] \" '");
80#endif
81
82 static_assert(std::ranges::count(columnLiteral, '.') == 1,
83 "QualifiedColumnName requires a column name with a single '.' to separate table and column name");
84 constexpr auto column = columnLiteral.sv();
85 auto dotPos = column.find('.');
86 return SqlQualifiedTableColumnName { .tableName = column.substr(0, dotPos), .columnName = column.substr(dotPos + 1) };
87}();
88
89namespace detail
90{
91
92 template <typename ColumnName>
93 std::string MakeSqlColumnName(ColumnName const& columnName)
94 {
95 using namespace std::string_view_literals;
96 std::string output;
97
98 if constexpr (std::is_same_v<ColumnName, SqlQualifiedTableColumnName>)
99 {
100 output.reserve(columnName.tableName.size() + columnName.columnName.size() + 5);
101 output += '"';
102 output += columnName.tableName;
103 output += R"(".")"sv;
104 output += columnName.columnName;
105 output += '"';
106 }
107 else if constexpr (std::is_same_v<ColumnName, SqlRawColumnNameView>)
108 {
109 output += columnName.value;
110 }
111 else if constexpr (std::is_same_v<ColumnName, SqlWildcardType>)
112 {
113 output += '?';
114 }
115 else
116 {
117 output += '"';
118 output += columnName;
119 output += '"';
120 }
121 return output;
122 }
123
124 template <typename T>
125 std::string MakeEscapedSqlString(T const& value)
126 {
127 std::string escapedValue;
128 escapedValue += '\'';
129
130 for (auto const ch: value)
131 {
132 // In SQL strings, single quotes are escaped by doubling them.
133 if (ch == '\'')
134 escapedValue += '\'';
135 escapedValue += ch;
136 }
137 escapedValue += '\'';
138 return escapedValue;
139 }
140
141} // namespace detail
142
143struct [[nodiscard]] SqlSearchCondition
144{
145 std::string tableName;
146 std::string tableAlias;
147 std::string tableJoins;
148 std::string condition;
149 std::vector<SqlVariant>* inputBindings = nullptr;
150};
151
152/// @brief Query builder for building JOIN conditions.
153/// @ingroup QueryBuilder
155{
156 public:
157 /// Constructs a new SqlJoinConditionBuilder.
158 explicit SqlJoinConditionBuilder(std::string_view referenceTable, std::string* condition) noexcept:
159 _referenceTable { referenceTable },
160 _condition { *condition }
161 {
162 }
163
164 /// Adds an AND join condition.
165 SqlJoinConditionBuilder& On(std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
166 {
167 return Operator(joinColumnName, onOtherColumn, "AND");
168 }
169
170 /// Adds an OR join condition.
171 SqlJoinConditionBuilder& OrOn(std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
172 {
173 return Operator(joinColumnName, onOtherColumn, "OR");
174 }
175
176 /// Adds a join condition with a custom operator.
177 SqlJoinConditionBuilder& Operator(std::string_view joinColumnName,
178 SqlQualifiedTableColumnName onOtherColumn,
179 std::string_view op)
180 {
181 if (_firstCall)
182 _firstCall = !_firstCall;
183 else
184 _condition += std::format(" {} ", op);
185
186 _condition += '"';
187 _condition += _referenceTable;
188 _condition += "\".\"";
189 _condition += joinColumnName;
190 _condition += "\" = \"";
191 _condition += onOtherColumn.tableName;
192 _condition += "\".\"";
193 _condition += onOtherColumn.columnName;
194 _condition += '"';
195
196 return *this;
197 }
198
199 private:
200 std::string_view _referenceTable;
201 std::string& _condition;
202 bool _firstCall = true;
203};
204
205/// Helper CRTP-based class for building WHERE clauses.
206///
207/// This class is inherited by the SqlSelectQueryBuilder, SqlUpdateQueryBuilder, and SqlDeleteQueryBuilder
208///
209/// @ingroup QueryBuilder
210template <typename Derived>
211class [[nodiscard]] SqlWhereClauseBuilder
212{
213 public:
214 /// Indicates, that the next WHERE clause should be AND-ed (default).
215 [[nodiscard]] Derived& And() noexcept;
216
217 /// Indicates, that the next WHERE clause should be OR-ed.
218 [[nodiscard]] Derived& Or() noexcept;
219
220 /// Indicates, that the next WHERE clause should be negated.
221 [[nodiscard]] Derived& Not() noexcept;
222
223 /// Constructs or extends a raw WHERE clause.
224 [[nodiscard]] Derived& WhereRaw(std::string_view sqlConditionExpression);
225
226 /// Constructs or extends a WHERE clause to test for a binary operation.
227 template <typename ColumnName, typename T>
228 [[nodiscard]] Derived& Where(ColumnName const& columnName, std::string_view binaryOp, T const& value);
229
230 /// Constructs or extends a WHERE clause to test for a binary operation for RHS as sub-select query.
231 template <typename ColumnName, typename SubSelectQuery>
232 requires(std::is_invocable_r_v<std::string, decltype(&SubSelectQuery::ToSql), SubSelectQuery const&>)
233 [[nodiscard]] Derived& Where(ColumnName const& columnName, std::string_view binaryOp, SubSelectQuery const& value);
234
235 /// Constructs or extends a WHERE/OR clause to test for a binary operation.
236 template <typename ColumnName, typename T>
237 [[nodiscard]] Derived& OrWhere(ColumnName const& columnName, std::string_view binaryOp, T const& value);
238
239 /// Constructs or extends a WHERE clause to test for a binary operation for RHS as string literal.
240 template <typename ColumnName, std::size_t N>
241 Derived& Where(ColumnName const& columnName, std::string_view binaryOp, char const (&value)[N]);
242
243 /// Constructs or extends a WHERE clause to test for equality.
244 template <typename ColumnName, typename T>
245 [[nodiscard]] Derived& Where(ColumnName const& columnName, T const& value);
246
247 /// Constructs or extends an WHERE/OR clause to test for equality.
248 template <typename ColumnName, typename T>
249 [[nodiscard]] Derived& OrWhere(ColumnName const& columnName, T const& value);
250
251 /// Constructs or extends a WHERE/AND clause to test for a group of values.
252 template <typename Callable>
253 requires std::invocable<Callable, SqlWhereClauseBuilder<Derived>&>
254 [[nodiscard]] Derived& Where(Callable const& callable);
255
256 /// Constructs or extends an WHERE/OR clause to test for a group of values.
257 template <typename Callable>
258 requires std::invocable<Callable, SqlWhereClauseBuilder<Derived>&>
259 [[nodiscard]] Derived& OrWhere(Callable const& callable);
260
261 /// Constructs or extends an WHERE/OR clause to test for a value, satisfying std::ranges::input_range.
262 template <typename ColumnName, std::ranges::input_range InputRange>
263 [[nodiscard]] Derived& WhereIn(ColumnName const& columnName, InputRange const& values);
264
265 /// Constructs or extends an WHERE/OR clause to test for a value, satisfying std::initializer_list.
266 template <typename ColumnName, typename T>
267 [[nodiscard]] Derived& WhereIn(ColumnName const& columnName, std::initializer_list<T> const& values);
268
269 /// Constructs or extends an WHERE/OR clause to test for a value, satisfying a sub-select query.
270 template <typename ColumnName, typename SubSelectQuery>
271 requires(std::is_invocable_r_v<std::string, decltype(&SubSelectQuery::ToSql), SubSelectQuery const&>)
272 [[nodiscard]] Derived& WhereIn(ColumnName const& columnName, SubSelectQuery const& subSelectQuery);
273
274 /// Constructs or extends an WHERE/OR clause to test for a value to be NULL.
275 template <typename ColumnName>
276 [[nodiscard]] Derived& WhereNull(ColumnName const& columnName);
277
278 /// Constructs or extends a WHERE clause to test for a value being not null.
279 template <typename ColumnName>
280 [[nodiscard]] Derived& WhereNotNull(ColumnName const& columnName);
281
282 /// Constructs or extends a WHERE clause to test for a value being equal to another column.
283 template <typename ColumnName, typename T>
284 [[nodiscard]] Derived& WhereNotEqual(ColumnName const& columnName, T const& value);
285
286 /// Constructs or extends a WHERE clause to test for a value being true.
287 template <typename ColumnName>
288 [[nodiscard]] Derived& WhereTrue(ColumnName const& columnName);
289
290 /// Constructs or extends a WHERE clause to test for a value being false.
291 template <typename ColumnName>
292 [[nodiscard]] Derived& WhereFalse(ColumnName const& columnName);
293
294 /// Construts or extends a WHERE clause to test for a binary operation between two columns.
295 template <typename LeftColumn, typename RightColumn>
296 [[nodiscard]] Derived& WhereColumn(LeftColumn const& left, std::string_view binaryOp, RightColumn const& right);
297
298 /// Constructs an INNER JOIN clause.
299 ///
300 /// @param joinTable The table's name to join with. This can be a string, a string_view, or an AliasedTableName.
301 /// @param joinColumnName The name of the column in the main table to join on.
302 /// @param onOtherColumn The column in the join table to compare against.
303 [[nodiscard]] Derived& InnerJoin(TableName auto joinTable,
304 std::string_view joinColumnName,
305 SqlQualifiedTableColumnName onOtherColumn);
306
307 /// Constructs an INNER JOIN clause.
308 [[nodiscard]] Derived& InnerJoin(TableName auto joinTable,
309 std::string_view joinColumnName,
310 std::string_view onMainTableColumn);
311
312 /// Constructs an INNER JOIN clause with a custom ON clause.
313 template <typename OnChainCallable>
314 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
315 [[nodiscard]] Derived& InnerJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
316
317 /// Constructs an `INNER JOIN` clause given two fields from different records
318 /// using the field name as join column.
319 ///
320 /// @tparam LeftField The field name to join on, such as `JoinTestB::a_id`, which will join on table `JoinTestB` with
321 /// the column `a_id` to be compared against right field's column.
322 /// @tparam RightField The other column to compare and join against.
323 ///
324 /// Example:
325 /// @code
326 /// InnerJoin<&JoinTestB::a_id, &JoinTestA::id>()
327 /// // This will generate a INNER JOIN "JoinTestB" ON "InnerTestB"."a_id" = "JoinTestA"."id"
328 /// @endcode
329 template <auto LeftField, auto RightField>
330 [[nodiscard]] Derived& InnerJoin();
331
332 /// Constructs an LEFT OUTER JOIN clause.
333 [[nodiscard]] Derived& LeftOuterJoin(TableName auto joinTable,
334 std::string_view joinColumnName,
335 SqlQualifiedTableColumnName onOtherColumn);
336
337 /// Constructs an LEFT OUTER JOIN clause.
338 [[nodiscard]] Derived& LeftOuterJoin(TableName auto joinTable,
339 std::string_view joinColumnName,
340 std::string_view onMainTableColumn);
341
342 /// Constructs an LEFT OUTER JOIN clause with a custom ON clause.
343 template <typename OnChainCallable>
344 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
345 [[nodiscard]] Derived& LeftOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
346
347 /// Constructs an RIGHT OUTER JOIN clause.
348 [[nodiscard]] Derived& RightOuterJoin(TableName auto joinTable,
349 std::string_view joinColumnName,
350 SqlQualifiedTableColumnName onOtherColumn);
351
352 /// Constructs an RIGHT OUTER JOIN clause.
353 [[nodiscard]] Derived& RightOuterJoin(TableName auto joinTable,
354 std::string_view joinColumnName,
355 std::string_view onMainTableColumn);
356
357 /// Constructs an RIGHT OUTER JOIN clause with a custom ON clause.
358 template <typename OnChainCallable>
359 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
360 [[nodiscard]] Derived& RightOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
361
362 /// Constructs an FULL OUTER JOIN clause.
363 [[nodiscard]] Derived& FullOuterJoin(TableName auto joinTable,
364 std::string_view joinColumnName,
365 SqlQualifiedTableColumnName onOtherColumn);
366
367 /// Constructs an FULL OUTER JOIN clause.
368 [[nodiscard]] Derived& FullOuterJoin(TableName auto joinTable,
369 std::string_view joinColumnName,
370 std::string_view onMainTableColumn);
371
372 /// Constructs an FULL OUTER JOIN clause with a custom ON clause.
373 template <typename OnChainCallable>
374 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
375 [[nodiscard]] Derived& FullOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
376
377 private:
378 SqlSearchCondition& SearchCondition() noexcept;
379 [[nodiscard]] SqlQueryFormatter const& Formatter() const noexcept;
380
381 enum class WhereJunctor : uint8_t
382 {
383 Null,
384 Where,
385 And,
386 Or,
387 };
388
389 WhereJunctor m_nextWhereJunctor = WhereJunctor::Where;
390 bool m_nextIsNot = false;
391
392 void AppendWhereJunctor();
393
394 /// Appends a column name to the WHERE condition.
395 template <typename ColumnName>
396 requires(std::same_as<ColumnName, SqlQualifiedTableColumnName> || std::convertible_to<ColumnName, std::string_view>
397 || std::same_as<ColumnName, SqlRawColumnNameView> || std::convertible_to<ColumnName, std::string>)
398 void AppendColumnName(ColumnName const& columnName);
399
400 /// Appends a literal value to the WHERE condition.
401 template <typename LiteralType>
402 void AppendLiteralValue(LiteralType const& value);
403
404 /// Populates a literal value into the target string.
405 template <typename LiteralType, typename TargetType>
406 void PopulateLiteralValueInto(LiteralType const& value, TargetType& target);
407
408 template <typename LiteralType>
409 detail::RawSqlCondition PopulateSqlSetExpression(LiteralType const& values);
410
411 enum class JoinType : uint8_t
412 {
413 INNER,
414 LEFT,
415 RIGHT,
416 FULL
417 };
418
419 /// Constructs a JOIN clause.
420 [[nodiscard]] Derived& Join(JoinType joinType,
421 TableName auto joinTable,
422 std::string_view joinColumnName,
423 SqlQualifiedTableColumnName onOtherColumn);
424
425 /// Constructs a JOIN clause.
426 [[nodiscard]] Derived& Join(JoinType joinType,
427 TableName auto joinTable,
428 std::string_view joinColumnName,
429 std::string_view onMainTableColumn);
430
431 /// Constructs a JOIN clause.
432 template <typename OnChainCallable>
433 [[nodiscard]] Derived& Join(JoinType joinType, TableName auto joinTable, OnChainCallable const& onClauseBuilder);
434};
435
436enum class SqlResultOrdering : uint8_t
437{
438 ASCENDING,
439 DESCENDING
440};
441
442namespace detail
443{
444 enum class SelectType : std::uint8_t
445 {
446 Undefined,
447 Count,
448 All,
449 First,
450 Range
451 };
452
453 struct ComposedQuery
454 {
455 SelectType selectType = SelectType::Undefined;
456 SqlQueryFormatter const* formatter = nullptr;
457
458 bool distinct = false;
459 SqlSearchCondition searchCondition {};
460
461 std::string fields;
462
463 std::string orderBy;
464 std::string groupBy;
465
466 size_t offset = 0;
467 size_t limit = (std::numeric_limits<size_t>::max)();
468
469 [[nodiscard]] LIGHTWEIGHT_API std::string ToSql() const;
470 };
471} // namespace detail
472
473template <typename Derived>
474class [[nodiscard]] SqlBasicSelectQueryBuilder: public SqlWhereClauseBuilder<Derived>
475{
476 public:
477 /// Adds a DISTINCT clause to the SELECT query.
478 Derived& Distinct() noexcept;
479
480 /// Constructs or extends a ORDER BY clause.
481 Derived& OrderBy(SqlQualifiedTableColumnName const& columnName,
482 SqlResultOrdering ordering = SqlResultOrdering::ASCENDING);
483
484 /// Constructs or extends a ORDER BY clause.
485 Derived& OrderBy(std::string_view columnName, SqlResultOrdering ordering = SqlResultOrdering::ASCENDING);
486
487 /// Constructs or extends a GROUP BY clause.
488 Derived& GroupBy(std::string_view columnName);
489
490 using ComposedQuery = detail::ComposedQuery;
491
492 protected:
493 ComposedQuery _query {}; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
494};
495
496template <typename Derived>
497inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::Distinct() noexcept
498{
499 _query.distinct = true;
500 return static_cast<Derived&>(*this);
501}
502
503template <typename Derived>
504inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::OrderBy(std::string_view columnName,
505 SqlResultOrdering ordering)
506{
507 if (_query.orderBy.empty())
508 _query.orderBy += "\n ORDER BY ";
509 else
510 _query.orderBy += ", ";
511
512 _query.orderBy += '"';
513 _query.orderBy += columnName;
514 _query.orderBy += '"';
515
516 if (ordering == SqlResultOrdering::DESCENDING)
517 _query.orderBy += " DESC";
518 else if (ordering == SqlResultOrdering::ASCENDING)
519 _query.orderBy += " ASC";
520
521 return static_cast<Derived&>(*this);
522}
523
524template <typename Derived>
525inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::OrderBy(
526 SqlQualifiedTableColumnName const& columnName, SqlResultOrdering ordering)
527{
528 if (_query.orderBy.empty())
529 _query.orderBy += "\n ORDER BY ";
530 else
531 _query.orderBy += ", ";
532
533 _query.orderBy += '"';
534 _query.orderBy += columnName.tableName;
535 _query.orderBy += "\".\"";
536 _query.orderBy += columnName.columnName;
537 _query.orderBy += '"';
538
539 if (ordering == SqlResultOrdering::DESCENDING)
540 _query.orderBy += " DESC";
541 else if (ordering == SqlResultOrdering::ASCENDING)
542 _query.orderBy += " ASC";
543
544 return static_cast<Derived&>(*this);
545}
546
547template <typename Derived>
548inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::GroupBy(std::string_view columnName)
549{
550 if (_query.groupBy.empty())
551 _query.groupBy += "\n GROUP BY ";
552 else
553 _query.groupBy += ", ";
554
555 _query.groupBy += '"';
556 _query.groupBy += columnName;
557 _query.groupBy += '"';
558
559 return static_cast<Derived&>(*this);
560}
561
562template <typename Derived>
563inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::And() noexcept
564{
565 m_nextWhereJunctor = WhereJunctor::And;
566 return static_cast<Derived&>(*this);
567}
568
569template <typename Derived>
570inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Or() noexcept
571{
572 m_nextWhereJunctor = WhereJunctor::Or;
573 return static_cast<Derived&>(*this);
574}
575
576template <typename Derived>
577inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Not() noexcept
578{
579 m_nextIsNot = !m_nextIsNot;
580 return static_cast<Derived&>(*this);
581}
582
583/// Constructs or extends a WHERE clause to test for equality.
584template <typename Derived>
585template <typename ColumnName, typename T>
586inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Where(ColumnName const& columnName, T const& value)
587{
588 if constexpr (detail::OneOf<T, SqlNullType, std::nullopt_t>)
589 {
590 if (m_nextIsNot)
591 {
592 m_nextIsNot = false;
593 return Where(columnName, "IS NOT", value);
594 }
595 else
596 return Where(columnName, "IS", value);
597 }
598 else
599 return Where(columnName, "=", value);
600}
601
602/// Constructs or extends a WHERE/OR clause to test for equality.
603template <typename Derived>
604template <typename ColumnName, typename T>
605inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::OrWhere(ColumnName const& columnName,
606 T const& value)
607{
608 return Or().Where(columnName, value);
609}
610
611/// Constructs or extends a WHERE/OR clause to test for a group of values.
612template <typename Derived>
613template <typename Callable>
614 requires std::invocable<Callable, SqlWhereClauseBuilder<Derived>&>
615inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::OrWhere(Callable const& callable)
616{
617 return Or().Where(callable);
618}
619
620/// Constructs or extends a WHERE/AND clause to test for a group of values.
621template <typename Derived>
622template <typename Callable>
623 requires std::invocable<Callable, SqlWhereClauseBuilder<Derived>&>
624inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Where(Callable const& callable)
625{
626 auto& condition = SearchCondition().condition;
627
628 auto const originalSize = condition.size();
629
630 AppendWhereJunctor();
631 m_nextWhereJunctor = WhereJunctor::Null;
632 condition += '(';
633
634 auto const sizeBeforeCallable = condition.size();
635
636 (void) callable(*this);
637
638 if (condition.size() == sizeBeforeCallable)
639 condition.resize(originalSize);
640 else
641 condition += ')';
642
643 return static_cast<Derived&>(*this);
644}
645
646/// Constructs or extends a WHERE IN clause with an input range.
647template <typename Derived>
648template <typename ColumnName, std::ranges::input_range InputRange>
649inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereIn(ColumnName const& columnName,
650 InputRange const& values)
651{
652 if (values.empty())
653 return static_cast<Derived&>(*this);
654 return Where(columnName, "IN", PopulateSqlSetExpression(values));
655}
656
657/// Constructs or extends a WHERE IN clause with an initializer list.
658template <typename Derived>
659template <typename ColumnName, typename T>
660inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereIn(ColumnName const& columnName,
661 std::initializer_list<T> const& values)
662{
663 if (values.begin() == values.end())
664 return static_cast<Derived&>(*this);
665 return Where(columnName, "IN", PopulateSqlSetExpression(values));
666}
667
668/// Constructs or extends a WHERE IN clause with a sub-select query.
669template <typename Derived>
670template <typename ColumnName, typename SubSelectQuery>
671 requires(std::is_invocable_r_v<std::string, decltype(&SubSelectQuery::ToSql), SubSelectQuery const&>)
672inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereIn(ColumnName const& columnName,
673 SubSelectQuery const& subSelectQuery)
674{
675 return Where(columnName, "IN", detail::RawSqlCondition { "(" + subSelectQuery.ToSql() + ")" });
676}
677
678/// Constructs or extends a WHERE clause to test for a value being not null.
679template <typename Derived>
680template <typename ColumnName>
681inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereNotNull(ColumnName const& columnName)
682{
683 return Where(columnName, "IS NOT", detail::RawSqlCondition { "NULL" });
684}
685
686/// Constructs or extends a WHERE clause to test for a value being null.
687template <typename Derived>
688template <typename ColumnName>
689inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereNull(ColumnName const& columnName)
690{
691 return Where(columnName, "IS", detail::RawSqlCondition { "NULL" });
692}
693
694/// Constructs or extends a WHERE clause to test for inequality.
695template <typename Derived>
696template <typename ColumnName, typename T>
697inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereNotEqual(ColumnName const& columnName,
698 T const& value)
699{
700 if constexpr (detail::OneOf<T, SqlNullType, std::nullopt_t>)
701 return Where(columnName, "IS NOT", value);
702 else
703 return Where(columnName, "!=", value);
704}
705
706/// Constructs or extends a WHERE clause to test for a value being true.
707template <typename Derived>
708template <typename ColumnName>
709inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereTrue(ColumnName const& columnName)
710{
711 return Where(columnName, "=", true);
712}
713
714/// Constructs or extends a WHERE clause to test for a value being false.
715template <typename Derived>
716template <typename ColumnName>
717inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereFalse(ColumnName const& columnName)
718{
719 return Where(columnName, "=", false);
720}
721
722/// Constructs or extends a WHERE clause to compare two columns.
723template <typename Derived>
724template <typename LeftColumn, typename RightColumn>
725inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereColumn(LeftColumn const& left,
726 std::string_view binaryOp,
727 RightColumn const& right)
728{
729 AppendWhereJunctor();
730
731 AppendColumnName(left);
732 SearchCondition().condition += ' ';
733 SearchCondition().condition += binaryOp;
734 SearchCondition().condition += ' ';
735 AppendColumnName(right);
736
737 return static_cast<Derived&>(*this);
738}
739
740template <typename T>
741struct WhereConditionLiteralType
742{
743 constexpr static bool needsQuotes = !std::is_integral_v<T> && !std::is_floating_point_v<T> && !std::same_as<T, bool>
744 && !std::same_as<T, SqlWildcardType>;
745};
746
747/// Constructs or extends a WHERE clause with a string literal value.
748template <typename Derived>
749template <typename ColumnName, std::size_t N>
750inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Where(ColumnName const& columnName,
751 std::string_view binaryOp,
752 char const (&value)[N])
753{
754 return Where(columnName, binaryOp, std::string_view { value, N - 1 });
755}
756
757/// Constructs or extends a WHERE clause to test for a binary operation.
758template <typename Derived>
759template <typename ColumnName, typename T>
760inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Where(ColumnName const& columnName,
761 std::string_view binaryOp,
762 T const& value)
763{
764 auto& searchCondition = SearchCondition();
765
766 AppendWhereJunctor();
767 AppendColumnName(columnName);
768 searchCondition.condition += ' ';
769 searchCondition.condition += binaryOp;
770 searchCondition.condition += ' ';
771 AppendLiteralValue(value);
772
773 return static_cast<Derived&>(*this);
774}
775
776/// Constructs or extends a WHERE clause with a sub-select query.
777template <typename Derived>
778template <typename ColumnName, typename SubSelectQuery>
779 requires(std::is_invocable_r_v<std::string, decltype(&SubSelectQuery::ToSql), SubSelectQuery const&>)
780inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Where(ColumnName const& columnName,
781 std::string_view binaryOp,
782 SubSelectQuery const& value)
783{
784 return Where(columnName, binaryOp, detail::RawSqlCondition { "(" + value.ToSql() + ")" });
785}
786
787/// Constructs or extends a WHERE/OR clause with a binary operation.
788template <typename Derived>
789template <typename ColumnName, typename T>
790inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::OrWhere(ColumnName const& columnName,
791 std::string_view binaryOp,
792 T const& value)
793{
794 return Or().Where(columnName, binaryOp, value);
795}
796
797template <typename Derived>
798inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::InnerJoin(TableName auto joinTable,
799 std::string_view joinColumnName,
800 SqlQualifiedTableColumnName onOtherColumn)
801{
802 return Join(JoinType::INNER, joinTable, joinColumnName, onOtherColumn);
803}
804
805template <typename Derived>
806inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::InnerJoin(TableName auto joinTable,
807 std::string_view joinColumnName,
808 std::string_view onMainTableColumn)
809{
810 return Join(JoinType::INNER, joinTable, joinColumnName, onMainTableColumn);
811}
812
813template <typename Derived>
814template <auto LeftField, auto RightField>
816{
817#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
818 return Join(JoinType::INNER,
819 RecordTableName<MemberClassType<LeftField>>,
820 FieldNameOf<LeftField>,
821 SqlQualifiedTableColumnName { RecordTableName<MemberClassType<RightField>>, FieldNameOf<RightField> });
822#else
823 return Join(
824 JoinType::INNER,
825 RecordTableName<Reflection::MemberClassType<LeftField>>,
826 FieldNameOf<LeftField>,
827 SqlQualifiedTableColumnName { RecordTableName<Reflection::MemberClassType<RightField>>, FieldNameOf<RightField> });
828#endif
829}
830
831template <typename Derived>
832template <typename OnChainCallable>
833 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
834Derived& SqlWhereClauseBuilder<Derived>::InnerJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder)
835{
836 return Join(JoinType::INNER, joinTable, onClauseBuilder);
837}
838
839template <typename Derived>
840inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::LeftOuterJoin(
841 TableName auto joinTable, std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
842{
843 return Join(JoinType::LEFT, joinTable, joinColumnName, onOtherColumn);
844}
845
846template <typename Derived>
847inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::LeftOuterJoin(TableName auto joinTable,
848 std::string_view joinColumnName,
849 std::string_view onMainTableColumn)
850{
851 return Join(JoinType::LEFT, joinTable, joinColumnName, onMainTableColumn);
852}
853
854template <typename Derived>
855template <typename OnChainCallable>
856 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
857Derived& SqlWhereClauseBuilder<Derived>::LeftOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder)
858{
859 return Join(JoinType::LEFT, joinTable, onClauseBuilder);
860}
861
862template <typename Derived>
863inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::RightOuterJoin(
864 TableName auto joinTable, std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
865{
866 return Join(JoinType::RIGHT, joinTable, joinColumnName, onOtherColumn);
867}
868
869template <typename Derived>
870inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::RightOuterJoin(TableName auto joinTable,
871 std::string_view joinColumnName,
872 std::string_view onMainTableColumn)
873{
874 return Join(JoinType::RIGHT, joinTable, joinColumnName, onMainTableColumn);
875}
876
877template <typename Derived>
878template <typename OnChainCallable>
879 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
880Derived& SqlWhereClauseBuilder<Derived>::RightOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder)
881{
882 return Join(JoinType::RIGHT, joinTable, onClauseBuilder);
883}
884
885template <typename Derived>
886inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::FullOuterJoin(
887 TableName auto joinTable, std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
888{
889 return Join(JoinType::FULL, joinTable, joinColumnName, onOtherColumn);
890}
891
892template <typename Derived>
893inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::FullOuterJoin(TableName auto joinTable,
894 std::string_view joinColumnName,
895 std::string_view onMainTableColumn)
896{
897 return Join(JoinType::FULL, joinTable, joinColumnName, onMainTableColumn);
898}
899
900template <typename Derived>
901template <typename OnChainCallable>
902 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
903Derived& SqlWhereClauseBuilder<Derived>::FullOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder)
904{
905 return Join(JoinType::FULL, joinTable, onClauseBuilder);
906}
907
908template <typename Derived>
909inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::WhereRaw(std::string_view sqlConditionExpression)
910{
911 AppendWhereJunctor();
912
913 auto& condition = SearchCondition().condition;
914 condition += sqlConditionExpression;
915
916 return static_cast<Derived&>(*this);
917}
918
919template <typename Derived>
920inline LIGHTWEIGHT_FORCE_INLINE SqlSearchCondition& SqlWhereClauseBuilder<Derived>::SearchCondition() noexcept
921{
922 return static_cast<Derived*>(this)->SearchCondition();
923}
924
925template <typename Derived>
926inline LIGHTWEIGHT_FORCE_INLINE SqlQueryFormatter const& SqlWhereClauseBuilder<Derived>::Formatter() const noexcept
927{
928 return static_cast<Derived const*>(this)->Formatter();
929}
930
931template <typename Derived>
932inline LIGHTWEIGHT_FORCE_INLINE void SqlWhereClauseBuilder<Derived>::AppendWhereJunctor()
933{
934 using namespace std::string_view_literals;
935
936 auto& condition = SearchCondition().condition;
937
938 switch (m_nextWhereJunctor)
939 {
940 case WhereJunctor::Null:
941 break;
942 case WhereJunctor::Where:
943 condition += "\n WHERE "sv;
944 break;
945 case WhereJunctor::And:
946 condition += " AND "sv;
947 break;
948 case WhereJunctor::Or:
949 condition += " OR "sv;
950 break;
951 }
952
953 if (m_nextIsNot)
954 {
955 condition += "NOT "sv;
956 m_nextIsNot = false;
957 }
958
959 m_nextWhereJunctor = WhereJunctor::And;
960}
961
962/// Appends a column name to the WHERE condition.
963template <typename Derived>
964template <typename ColumnName>
965 requires(std::same_as<ColumnName, SqlQualifiedTableColumnName> || std::convertible_to<ColumnName, std::string_view>
966 || std::same_as<ColumnName, SqlRawColumnNameView> || std::convertible_to<ColumnName, std::string>)
967inline LIGHTWEIGHT_FORCE_INLINE void SqlWhereClauseBuilder<Derived>::AppendColumnName(ColumnName const& columnName)
968{
969 SearchCondition().condition += detail::MakeSqlColumnName(columnName);
970}
971
972/// Appends a literal value to the WHERE condition.
973template <typename Derived>
974template <typename LiteralType>
975inline LIGHTWEIGHT_FORCE_INLINE void SqlWhereClauseBuilder<Derived>::AppendLiteralValue(LiteralType const& value)
976{
977 auto& searchCondition = SearchCondition();
978
979 if constexpr (std::is_same_v<LiteralType, SqlQualifiedTableColumnName>
980 || detail::OneOf<LiteralType, SqlNullType, std::nullopt_t> || std::is_same_v<LiteralType, SqlWildcardType>
981 || std::is_same_v<LiteralType, detail::RawSqlCondition>)
982 {
983 PopulateLiteralValueInto(value, searchCondition.condition);
984 }
985 else if (searchCondition.inputBindings)
986 {
987 searchCondition.condition += '?';
988 searchCondition.inputBindings->emplace_back(value);
989 }
990 else if constexpr (std::is_same_v<LiteralType, bool>)
991 {
992 searchCondition.condition += Formatter().BooleanLiteral(value);
993 }
994 else if constexpr (!WhereConditionLiteralType<LiteralType>::needsQuotes)
995 {
996 searchCondition.condition += std::format("{}", value);
997 }
998 else
999 {
1000 searchCondition.condition += detail::MakeEscapedSqlString(std::format("{}", value));
1001 }
1002}
1003
1004/// Populates a literal value into the target string.
1005template <typename Derived>
1006template <typename LiteralType, typename TargetType>
1007inline LIGHTWEIGHT_FORCE_INLINE void SqlWhereClauseBuilder<Derived>::PopulateLiteralValueInto(LiteralType const& value,
1008 TargetType& target)
1009{
1010 if constexpr (std::is_same_v<LiteralType, SqlQualifiedTableColumnName>)
1011 {
1012 target += '"';
1013 target += value.tableName;
1014 target += "\".\"";
1015 target += value.columnName;
1016 target += '"';
1017 }
1018 else if constexpr (detail::OneOf<LiteralType, SqlNullType, std::nullopt_t>)
1019 {
1020 target += "NULL";
1021 }
1022 else if constexpr (std::is_same_v<LiteralType, SqlWildcardType>)
1023 {
1024 target += '?';
1025 }
1026 else if constexpr (std::is_same_v<LiteralType, detail::RawSqlCondition>)
1027 {
1028 target += value.condition;
1029 }
1030 else if constexpr (std::is_same_v<LiteralType, bool>)
1031 {
1032 target += Formatter().BooleanLiteral(value);
1033 }
1034 else if constexpr (!WhereConditionLiteralType<LiteralType>::needsQuotes)
1035 {
1036 target += std::format("{}", value);
1037 }
1038 else
1039 {
1040 target += detail::MakeEscapedSqlString(std::format("{}", value));
1041 }
1042}
1043
1044template <typename Derived>
1045template <typename LiteralType>
1046detail::RawSqlCondition SqlWhereClauseBuilder<Derived>::PopulateSqlSetExpression(LiteralType const& values)
1047{
1048 using namespace std::string_view_literals;
1049 std::ostringstream fragment;
1050 fragment << '(';
1051#if !defined(__cpp_lib_ranges_enumerate)
1052 int index { -1 };
1053 for (auto const& value: values)
1054 {
1055 ++index;
1056#else
1057 for (auto const&& [index, value]: values | std::views::enumerate)
1058 {
1059#endif
1060 if (index > 0)
1061 fragment << ", "sv;
1062
1063 std::string valueString;
1064 PopulateLiteralValueInto(value, valueString);
1065 fragment << valueString;
1066 }
1067 fragment << ')';
1068 return detail::RawSqlCondition { fragment.str() };
1069}
1070
1071template <typename Derived>
1072inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Join(JoinType joinType,
1073 TableName auto joinTable,
1074 std::string_view joinColumnName,
1075 SqlQualifiedTableColumnName onOtherColumn)
1076{
1077 static constexpr std::array<std::string_view, 4> JoinTypeStrings = {
1078 "INNER",
1079 "LEFT OUTER",
1080 "RIGHT OUTER",
1081 "FULL OUTER",
1082 };
1083
1084 if constexpr (std::is_same_v<std::remove_cvref_t<decltype(joinTable)>, AliasedTableName>)
1085 {
1086 SearchCondition().tableJoins += std::format("\n"
1087 R"( {0} JOIN "{1}" AS "{2}" ON "{2}"."{3}" = "{4}"."{5}")",
1088 JoinTypeStrings[static_cast<std::size_t>(joinType)],
1089 joinTable.tableName,
1090 joinTable.alias,
1091 joinColumnName,
1092 onOtherColumn.tableName,
1093 onOtherColumn.columnName);
1094 }
1095 else
1096 {
1097 SearchCondition().tableJoins += std::format("\n"
1098 R"( {0} JOIN "{1}" ON "{1}"."{2}" = "{3}"."{4}")",
1099 JoinTypeStrings[static_cast<std::size_t>(joinType)],
1100 joinTable,
1101 joinColumnName,
1102 onOtherColumn.tableName,
1103 onOtherColumn.columnName);
1104 }
1105 return static_cast<Derived&>(*this);
1106}
1107
1108template <typename Derived>
1109inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Join(JoinType joinType,
1110 TableName auto joinTable,
1111 std::string_view joinColumnName,
1112 std::string_view onMainTableColumn)
1113{
1114 return Join(joinType,
1115 joinTable,
1116 joinColumnName,
1117 SqlQualifiedTableColumnName { .tableName = SearchCondition().tableName, .columnName = onMainTableColumn });
1118}
1119
1120/// Constructs a JOIN clause with a custom ON clause builder.
1121template <typename Derived>
1122template <typename Callable>
1123inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Join(JoinType joinType,
1124 TableName auto joinTable,
1125 Callable const& onClauseBuilder)
1126{
1127 static constexpr std::array<std::string_view, 4> JoinTypeStrings = {
1128 "INNER",
1129 "LEFT OUTER",
1130 "RIGHT OUTER",
1131 "FULL OUTER",
1132 };
1133
1134 size_t const originalSize = SearchCondition().tableJoins.size();
1135 SearchCondition().tableJoins +=
1136 std::format("\n {0} JOIN \"{1}\" ON ", JoinTypeStrings[static_cast<std::size_t>(joinType)], joinTable);
1137 size_t const sizeBefore = SearchCondition().tableJoins.size();
1138 onClauseBuilder(SqlJoinConditionBuilder { joinTable, &SearchCondition().tableJoins });
1139 size_t const sizeAfter = SearchCondition().tableJoins.size();
1140 if (sizeBefore == sizeAfter)
1141 SearchCondition().tableJoins.resize(originalSize);
1142
1143 return static_cast<Derived&>(*this);
1144}
1145
1146} // namespace Lightweight
Query builder for building JOIN conditions.
Definition Core.hpp:155
SqlJoinConditionBuilder & On(std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
Adds an AND join condition.
Definition Core.hpp:165
SqlJoinConditionBuilder(std::string_view referenceTable, std::string *condition) noexcept
Constructs a new SqlJoinConditionBuilder.
Definition Core.hpp:158
SqlJoinConditionBuilder & Operator(std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn, std::string_view op)
Adds a join condition with a custom operator.
Definition Core.hpp:177
SqlJoinConditionBuilder & OrOn(std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
Adds an OR join condition.
Definition Core.hpp:171
API to format SQL queries for different SQL dialects.
Derived & FullOuterJoin(TableName auto joinTable, std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
Constructs an FULL OUTER JOIN clause.
Definition Core.hpp:886
Derived & WhereTrue(ColumnName const &columnName)
Constructs or extends a WHERE clause to test for a value being true.
Derived & WhereIn(ColumnName const &columnName, InputRange const &values)
Constructs or extends an WHERE/OR clause to test for a value, satisfying std::ranges::input_range.
Derived & WhereNotNull(ColumnName const &columnName)
Constructs or extends a WHERE clause to test for a value being not null.
Derived & Where(ColumnName const &columnName, std::string_view binaryOp, T const &value)
Constructs or extends a WHERE clause to test for a binary operation.
Derived & WhereRaw(std::string_view sqlConditionExpression)
Constructs or extends a raw WHERE clause.
Definition Core.hpp:909
Derived & LeftOuterJoin(TableName auto joinTable, std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
Constructs an LEFT OUTER JOIN clause.
Definition Core.hpp:840
Derived & Not() noexcept
Indicates, that the next WHERE clause should be negated.
Definition Core.hpp:577
Derived & WhereNull(ColumnName const &columnName)
Constructs or extends an WHERE/OR clause to test for a value to be NULL.
Derived & WhereNotEqual(ColumnName const &columnName, T const &value)
Constructs or extends a WHERE clause to test for a value being equal to another column.
Derived & RightOuterJoin(TableName auto joinTable, std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
Constructs an RIGHT OUTER JOIN clause.
Definition Core.hpp:863
Derived & OrWhere(ColumnName const &columnName, std::string_view binaryOp, T const &value)
Constructs or extends a WHERE/OR clause to test for a binary operation.
Derived & WhereColumn(LeftColumn const &left, std::string_view binaryOp, RightColumn const &right)
Construts or extends a WHERE clause to test for a binary operation between two columns.
Derived & And() noexcept
Indicates, that the next WHERE clause should be AND-ed (default).
Definition Core.hpp:563
Derived & Or() noexcept
Indicates, that the next WHERE clause should be OR-ed.
Definition Core.hpp:570
Derived & WhereFalse(ColumnName const &columnName)
Constructs or extends a WHERE clause to test for a value being false.
constexpr std::string_view RecordTableName
Holds the SQL tabl ename for the given record type.
Definition Utils.hpp:176
LIGHTWEIGHT_API std::vector< std::string > ToSql(SqlQueryFormatter const &formatter, SqlMigrationPlanElement const &element)
Name of table in a SQL query, where the table's name is aliased.
Definition Core.hpp:33
std::string_view alias
The alias for the table.
Definition Core.hpp:37
std::weak_ordering operator<=>(AliasedTableName const &) const =default
Three-way comparison operator.
std::string_view tableName
The table name.
Definition Core.hpp:35
SqlQualifiedTableColumnName represents a column name qualified with a table name.
Definition Core.hpp:60
std::string_view tableName
The table name.
Definition Core.hpp:62
std::string_view columnName
The column name.
Definition Core.hpp:64
SqlWildcardType is a placeholder for an explicit wildcard input parameter in a SQL query.
Definition Core.hpp:25