6#include "../SqlQueryFormatter.hpp"
47 std::convertible_to<T, std::string_view> || std::convertible_to<T, std::string> || std::same_as<T, AliasedTableName>;
52 struct RawSqlCondition
54 std::string condition;
64template <Reflection::StringLiteral columnLiteral>
65constexpr SqlQualifiedTableColumnName QualifiedColumnName = []()
consteval {
69 !std::ranges::any_of(columnLiteral,
70 [](
char c)
consteval {
return c ==
'\\' || c ==
'[' || c ==
']' || c ==
'"' || c ==
'\''; }),
71 "QualifiedColumnName should not contain symbols \\ [ ] \" '");
74 static_assert(std::ranges::count(columnLiteral,
'.') == 1,
75 "QualifiedColumnName requires a column name with a single '.' to separate table and column name");
76 constexpr auto column = columnLiteral.sv();
77 auto dotPos = column.find(
'.');
78 return SqlQualifiedTableColumnName { .
tableName = column.substr(0, dotPos), .columnName = column.substr(dotPos + 1) };
84 template <
typename ColumnName>
85 std::string MakeSqlColumnName(ColumnName
const& columnName)
87 using namespace std::string_view_literals;
90 if constexpr (std::is_same_v<ColumnName, SqlQualifiedTableColumnName>)
92 output.reserve(columnName.tableName.size() + columnName.columnName.size() + 5);
94 output += columnName.tableName;
96 output += columnName.columnName;
99 else if constexpr (std::is_same_v<ColumnName, SqlWildcardType>)
106 output += columnName;
112 template <
typename T>
113 std::string MakeEscapedSqlString(T
const& value)
115 std::string escapedValue;
116 escapedValue +=
'\'';
118 for (
auto const ch: value)
122 escapedValue +=
'\'';
125 escapedValue +=
'\'';
131struct [[nodiscard]] SqlSearchCondition
133 std::string tableName;
134 std::string tableAlias;
135 std::string tableJoins;
136 std::string condition;
137 std::vector<SqlVariant>* inputBindings =
nullptr;
147 _referenceTable { referenceTable },
148 _condition { *condition }
155 return Operator(joinColumnName, onOtherColumn,
"AND");
161 return Operator(joinColumnName, onOtherColumn,
"OR");
170 _firstCall = !_firstCall;
172 _condition += std::format(
" {} ", op);
175 _condition += _referenceTable;
176 _condition +=
"\".\"";
177 _condition += joinColumnName;
178 _condition +=
"\" = \"";
180 _condition +=
"\".\"";
188 std::string_view _referenceTable;
189 std::string& _condition;
190 bool _firstCall =
true;
198template <
typename Derived>
203 [[nodiscard]] Derived&
And() noexcept;
206 [[nodiscard]] Derived& Or() noexcept;
209 [[nodiscard]] Derived& Not() noexcept;
212 [[nodiscard]] Derived& WhereRaw(std::string_view sqlConditionExpression);
238 template <typename T>
239 [[nodiscard]] auto If(std::optional<T> const& value) noexcept;
242 template <typename ColumnName, typename T>
243 [[nodiscard]] Derived& Where(ColumnName const& columnName, std::string_view binaryOp, T const& value);
246 template <typename ColumnName, typename SubSelectQuery>
247 requires(std::is_invocable_r_v<std::
string, decltype(&SubSelectQuery::ToSql), SubSelectQuery const&>)
248 [[nodiscard]] Derived& Where(ColumnName const& columnName, std::string_view binaryOp, SubSelectQuery const& value);
251 template <typename ColumnName, typename T>
252 [[nodiscard]] Derived& OrWhere(ColumnName const& columnName, std::string_view binaryOp, T const& value);
255 template <typename ColumnName, std::
size_t N>
256 Derived& Where(ColumnName const& columnName, std::string_view binaryOp,
char const (&value)[N]);
259 template <typename ColumnName, typename T>
260 [[nodiscard]] Derived& Where(ColumnName const& columnName, T const& value);
263 template <typename ColumnName, typename T>
264 [[nodiscard]] Derived& OrWhere(ColumnName const& columnName, T const& value);
267 template <typename Callable>
269 [[nodiscard]] Derived& Where(Callable const& callable);
272 template <typename Callable>
274 [[nodiscard]] Derived& OrWhere(Callable const& callable);
277 template <typename ColumnName, std::ranges::input_range InputRange>
278 [[nodiscard]] Derived& WhereIn(ColumnName const& columnName, InputRange const& values);
281 template <typename ColumnName, typename T>
282 [[nodiscard]] Derived& WhereIn(ColumnName const& columnName, std::initializer_list<T> const& values);
285 template <typename ColumnName, typename SubSelectQuery>
286 requires(std::is_invocable_r_v<std::
string, decltype(&SubSelectQuery::ToSql), SubSelectQuery const&>)
287 [[nodiscard]] Derived& WhereIn(ColumnName const& columnName, SubSelectQuery const& subSelectQuery);
290 template <typename ColumnName>
291 [[nodiscard]] Derived& WhereNull(ColumnName const& columnName);
294 template <typename ColumnName>
295 [[nodiscard]] Derived& WhereNotNull(ColumnName const& columnName);
298 template <typename ColumnName, typename T>
299 [[nodiscard]] Derived& WhereNotEqual(ColumnName const& columnName, T const& value);
302 template <typename ColumnName>
303 [[nodiscard]] Derived& WhereTrue(ColumnName const& columnName);
306 template <typename ColumnName>
307 [[nodiscard]] Derived& WhereFalse(ColumnName const& columnName);
310 template <typename LeftColumn, typename RightColumn>
311 [[nodiscard]] Derived& WhereColumn(LeftColumn const& left, std::string_view binaryOp, RightColumn const& right);
318 [[nodiscard]] Derived& InnerJoin(TableName auto joinTable,
319 std::string_view joinColumnName,
323 [[nodiscard]] Derived& InnerJoin(TableName auto joinTable,
324 std::string_view joinColumnName,
325 std::string_view onMainTableColumn);
328 template <typename OnChainCallable>
330 [[nodiscard]] Derived& InnerJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
344 template <auto LeftField, auto RightField>
345 [[nodiscard]] Derived& InnerJoin();
348 [[nodiscard]] Derived& LeftOuterJoin(TableName auto joinTable,
349 std::string_view joinColumnName,
353 [[nodiscard]] Derived& LeftOuterJoin(TableName auto joinTable,
354 std::string_view joinColumnName,
355 std::string_view onMainTableColumn);
358 template <typename OnChainCallable>
360 [[nodiscard]] Derived& LeftOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
363 [[nodiscard]] Derived& RightOuterJoin(TableName auto joinTable,
364 std::string_view joinColumnName,
368 [[nodiscard]] Derived& RightOuterJoin(TableName auto joinTable,
369 std::string_view joinColumnName,
370 std::string_view onMainTableColumn);
373 template <typename OnChainCallable>
375 [[nodiscard]] Derived& RightOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
378 [[nodiscard]] Derived& FullOuterJoin(TableName auto joinTable,
379 std::string_view joinColumnName,
383 [[nodiscard]] Derived& FullOuterJoin(TableName auto joinTable,
384 std::string_view joinColumnName,
385 std::string_view onMainTableColumn);
388 template <typename OnChainCallable>
390 [[nodiscard]] Derived& FullOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
393 SqlSearchCondition& SearchCondition() noexcept;
396 enum class WhereJunctor : uint8_t
404 WhereJunctor m_nextWhereJunctor = WhereJunctor::Where;
405 bool m_nextIsNot =
false;
407 void AppendWhereJunctor();
410 template <
typename ColumnName>
411 requires(std::same_as<ColumnName, SqlQualifiedTableColumnName> || std::convertible_to<ColumnName, std::string_view>
412 || std::convertible_to<ColumnName, std::string>)
413 void AppendColumnName(ColumnName
const& columnName);
416 template <
typename LiteralType>
417 void AppendLiteralValue(LiteralType
const& value);
420 template <
typename LiteralType,
typename TargetType>
421 void PopulateLiteralValueInto(LiteralType
const& value, TargetType& target);
423 template <
typename LiteralType>
424 detail::RawSqlCondition PopulateSqlSetExpression(LiteralType
const& values);
426 enum class JoinType : uint8_t
435 [[nodiscard]] Derived& Join(JoinType joinType,
436 TableName
auto joinTable,
437 std::string_view joinColumnName,
438 SqlQualifiedTableColumnName onOtherColumn);
441 [[nodiscard]] Derived& Join(JoinType joinType,
442 TableName
auto joinTable,
443 std::string_view joinColumnName,
444 std::string_view onMainTableColumn);
447 template <
typename OnChainCallable>
448 [[nodiscard]] Derived& Join(JoinType joinType, TableName
auto joinTable, OnChainCallable
const& onClauseBuilder);
451enum class SqlResultOrdering : uint8_t
459 enum class SelectType : std::uint8_t
470 SelectType selectType = SelectType::Undefined;
471 SqlQueryFormatter
const* formatter =
nullptr;
473 bool distinct =
false;
474 SqlSearchCondition searchCondition {};
482 size_t limit = (std::numeric_limits<size_t>::max)();
484 [[nodiscard]] LIGHTWEIGHT_API std::string
ToSql()
const;
488template <
typename Derived>
489class [[nodiscard]] SqlBasicSelectQueryBuilder:
public SqlWhereClauseBuilder<Derived>
493 Derived& Distinct() noexcept;
496 Derived& OrderBy(SqlQualifiedTableColumnName const& columnName,
497 SqlResultOrdering ordering = SqlResultOrdering::ASCENDING);
500 Derived& OrderBy(std::string_view columnName, SqlResultOrdering ordering = SqlResultOrdering::ASCENDING);
503 Derived& GroupBy(std::string_view columnName);
506 Derived& GroupBy(SqlQualifiedTableColumnName const& columnName);
508 using ComposedQuery = detail::ComposedQuery;
514 mutable ComposedQuery _query {};
517template <
typename Derived>
518inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::Distinct() noexcept
520 _query.distinct =
true;
521 return static_cast<Derived&
>(*this);
524template <
typename Derived>
525inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::OrderBy(std::string_view columnName,
526 SqlResultOrdering ordering)
528 if (_query.orderBy.empty())
529 _query.orderBy +=
"\n ORDER BY ";
531 _query.orderBy +=
", ";
533 _query.orderBy +=
'"';
534 _query.orderBy += columnName;
535 _query.orderBy +=
'"';
537 if (ordering == SqlResultOrdering::DESCENDING)
538 _query.orderBy +=
" DESC";
539 else if (ordering == SqlResultOrdering::ASCENDING)
540 _query.orderBy +=
" ASC";
542 return static_cast<Derived&
>(*this);
545template <
typename Derived>
546inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::OrderBy(
547 SqlQualifiedTableColumnName
const& columnName, SqlResultOrdering ordering)
549 if (_query.orderBy.empty())
550 _query.orderBy +=
"\n ORDER BY ";
552 _query.orderBy +=
", ";
554 _query.orderBy +=
'"';
555 _query.orderBy += columnName.tableName;
556 _query.orderBy +=
"\".\"";
557 _query.orderBy += columnName.columnName;
558 _query.orderBy +=
'"';
560 if (ordering == SqlResultOrdering::DESCENDING)
561 _query.orderBy +=
" DESC";
562 else if (ordering == SqlResultOrdering::ASCENDING)
563 _query.orderBy +=
" ASC";
565 return static_cast<Derived&
>(*this);
568template <
typename Derived>
569inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::GroupBy(std::string_view columnName)
571 if (_query.groupBy.empty())
572 _query.groupBy +=
"\n GROUP BY ";
574 _query.groupBy +=
", ";
576 _query.groupBy +=
'"';
577 _query.groupBy += columnName;
578 _query.groupBy +=
'"';
580 return static_cast<Derived&
>(*this);
583template <
typename Derived>
584inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::GroupBy(
585 SqlQualifiedTableColumnName
const& columnName)
587 if (_query.groupBy.empty())
588 _query.groupBy +=
"\n GROUP BY ";
590 _query.groupBy +=
", ";
592 _query.groupBy +=
'"';
593 _query.groupBy += columnName.tableName;
594 _query.groupBy +=
"\".\"";
595 _query.groupBy += columnName.columnName;
596 _query.groupBy +=
'"';
598 return static_cast<Derived&
>(*this);
601template <
typename Derived>
604 m_nextWhereJunctor = WhereJunctor::And;
605 return static_cast<Derived&
>(*this);
608template <
typename Derived>
611 m_nextWhereJunctor = WhereJunctor::Or;
612 return static_cast<Derived&
>(*this);
615template <
typename Derived>
618 m_nextIsNot = !m_nextIsNot;
619 return static_cast<Derived&
>(*this);
623template <
typename Derived>
624template <
typename ColumnName,
typename T>
627 if constexpr (detail::OneOf<T, SqlNullType, std::nullopt_t>)
632 return Where(columnName,
"IS NOT", value);
635 return Where(columnName,
"IS", value);
638 return Where(columnName,
"=", value);
642template <
typename Derived>
643template <
typename ColumnName,
typename T>
647 return Or().Where(columnName, value);
651template <
typename Derived>
652template <
typename Callable>
653 requires std::invocable<Callable, SqlWhereClauseBuilder<Derived>&>
656 return Or().Where(callable);
660template <
typename Derived>
661template <
typename Callable>
662 requires std::invocable<Callable, SqlWhereClauseBuilder<Derived>&>
665 auto& condition = SearchCondition().condition;
667 auto const originalSize = condition.size();
669 AppendWhereJunctor();
670 m_nextWhereJunctor = WhereJunctor::Null;
673 auto const sizeBeforeCallable = condition.size();
675 (void) callable(*
this);
677 if (condition.size() == sizeBeforeCallable)
678 condition.resize(originalSize);
682 return static_cast<Derived&
>(*this);
686template <
typename Derived>
687template <
typename ColumnName, std::ranges::input_range InputRange>
689 InputRange
const& values)
692 return static_cast<Derived&
>(*this);
693 return Where(columnName,
"IN", PopulateSqlSetExpression(values));
697template <
typename Derived>
698template <
typename ColumnName,
typename T>
700 std::initializer_list<T>
const& values)
702 if (values.begin() == values.end())
703 return static_cast<Derived&
>(*this);
704 return Where(columnName,
"IN", PopulateSqlSetExpression(values));
708template <
typename Derived>
709template <
typename ColumnName,
typename SubSelectQuery>
710 requires(std::is_invocable_r_v<std::string,
decltype(&SubSelectQuery::ToSql), SubSelectQuery
const&>)
712 SubSelectQuery
const& subSelectQuery)
714 return Where(columnName,
"IN", detail::RawSqlCondition {
"(" + subSelectQuery.ToSql() +
")" });
718template <
typename Derived>
719template <
typename ColumnName>
722 return Where(columnName,
"IS NOT", detail::RawSqlCondition {
"NULL" });
726template <
typename Derived>
727template <
typename ColumnName>
730 return Where(columnName,
"IS", detail::RawSqlCondition {
"NULL" });
734template <
typename Derived>
735template <
typename ColumnName,
typename T>
739 if constexpr (detail::OneOf<T, SqlNullType, std::nullopt_t>)
740 return Where(columnName,
"IS NOT", value);
742 return Where(columnName,
"!=", value);
746template <
typename Derived>
747template <
typename ColumnName>
750 return Where(columnName,
"=",
true);
754template <
typename Derived>
755template <
typename ColumnName>
758 return Where(columnName,
"=",
false);
762template <
typename Derived>
763template <
typename LeftColumn,
typename RightColumn>
765 std::string_view binaryOp,
766 RightColumn
const& right)
768 AppendWhereJunctor();
770 AppendColumnName(left);
771 SearchCondition().condition +=
' ';
772 SearchCondition().condition += binaryOp;
773 SearchCondition().condition +=
' ';
774 AppendColumnName(right);
776 return static_cast<Derived&
>(*this);
780struct WhereConditionLiteralType
782 constexpr static bool needsQuotes = !std::is_integral_v<T> && !std::is_floating_point_v<T> && !std::same_as<T, bool>
783 && !std::same_as<T, SqlWildcardType>;
787template <
typename Derived>
788template <
typename ColumnName, std::
size_t N>
790 std::string_view binaryOp,
791 char const (&value)[N])
793 return Where(columnName, binaryOp, std::string_view { value, N - 1 });
797template <
typename Derived>
798template <
typename ColumnName,
typename T>
800 std::string_view binaryOp,
803 auto& searchCondition = SearchCondition();
805 AppendWhereJunctor();
806 AppendColumnName(columnName);
807 searchCondition.condition +=
' ';
808 searchCondition.condition += binaryOp;
809 searchCondition.condition +=
' ';
810 AppendLiteralValue(value);
812 return static_cast<Derived&
>(*this);
816template <
typename Derived>
817template <
typename ColumnName,
typename SubSelectQuery>
818 requires(std::is_invocable_r_v<std::string,
decltype(&SubSelectQuery::ToSql), SubSelectQuery
const&>)
820 std::string_view binaryOp,
821 SubSelectQuery
const& value)
823 return Where(columnName, binaryOp, detail::RawSqlCondition {
"(" + value.ToSql() +
")" });
827template <
typename Derived>
828template <
typename ColumnName,
typename T>
830 std::string_view binaryOp,
833 return Or().
Where(columnName, binaryOp, value);
836template <
typename Derived>
838 std::string_view joinColumnName,
841 return Join(JoinType::INNER, joinTable, joinColumnName, onOtherColumn);
844template <
typename Derived>
846 std::string_view joinColumnName,
847 std::string_view onMainTableColumn)
849 return Join(JoinType::INNER, joinTable, joinColumnName, onMainTableColumn);
852template <
typename Derived>
853template <auto LeftField, auto RightField>
856#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
857 return Join(JoinType::INNER,
859 FieldNameOf<LeftField>,
865 FieldNameOf<LeftField>,
870template <
typename Derived>
871template <
typename OnChainCallable>
872 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
875 return Join(JoinType::INNER, joinTable, onClauseBuilder);
878template <
typename Derived>
882 return Join(JoinType::LEFT, joinTable, joinColumnName, onOtherColumn);
885template <
typename Derived>
887 std::string_view joinColumnName,
888 std::string_view onMainTableColumn)
890 return Join(JoinType::LEFT, joinTable, joinColumnName, onMainTableColumn);
893template <
typename Derived>
894template <
typename OnChainCallable>
895 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
898 return Join(JoinType::LEFT, joinTable, onClauseBuilder);
901template <
typename Derived>
905 return Join(JoinType::RIGHT, joinTable, joinColumnName, onOtherColumn);
908template <
typename Derived>
910 std::string_view joinColumnName,
911 std::string_view onMainTableColumn)
913 return Join(JoinType::RIGHT, joinTable, joinColumnName, onMainTableColumn);
916template <
typename Derived>
917template <
typename OnChainCallable>
918 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
921 return Join(JoinType::RIGHT, joinTable, onClauseBuilder);
924template <
typename Derived>
928 return Join(JoinType::FULL, joinTable, joinColumnName, onOtherColumn);
931template <
typename Derived>
933 std::string_view joinColumnName,
934 std::string_view onMainTableColumn)
936 return Join(JoinType::FULL, joinTable, joinColumnName, onMainTableColumn);
939template <
typename Derived>
940template <
typename OnChainCallable>
941 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
944 return Join(JoinType::FULL, joinTable, onClauseBuilder);
958 template <
typename Derived,
typename T>
959 class [[nodiscard]] ConditionalWhereBuilder
963 constexpr ConditionalWhereBuilder(Derived& builder, std::optional<T>
const& value)
noexcept:
964 _builder { builder },
974 template <
typename ColumnName>
975 [[nodiscard]] Derived& ThenWhere(ColumnName
const& column)
const
977 if (_value.has_value())
978 return _builder.Where(column, *_value);
1000 template <
typename ColumnName>
1001 [[nodiscard]] Derived& ThenWhere(ColumnName
const& column, std::string_view binaryOp)
const
1003 if (_value.has_value())
1004 return _builder.Where(column, binaryOp, *_value);
1010 std::optional<T>
const& _value;
1016template <
typename Derived>
1017template <
typename T>
1020 return detail::ConditionalWhereBuilder<Derived, T> {
static_cast<Derived&
>(*this), value };
1023template <
typename Derived>
1026 AppendWhereJunctor();
1028 auto& condition = SearchCondition().condition;
1029 condition += sqlConditionExpression;
1031 return static_cast<Derived&
>(*this);
1034template <
typename Derived>
1037 return static_cast<Derived*
>(
this)->SearchCondition();
1040template <
typename Derived>
1041inline LIGHTWEIGHT_FORCE_INLINE SqlQueryFormatter
const& SqlWhereClauseBuilder<Derived>::Formatter() const noexcept
1043 return static_cast<Derived const*
>(
this)->Formatter();
1046template <
typename Derived>
1047inline LIGHTWEIGHT_FORCE_INLINE
void SqlWhereClauseBuilder<Derived>::AppendWhereJunctor()
1049 using namespace std::string_view_literals;
1051 auto& condition = SearchCondition().condition;
1053 switch (m_nextWhereJunctor)
1055 case WhereJunctor::Null:
1057 case WhereJunctor::Where:
1058 condition +=
"\n WHERE "sv;
1060 case WhereJunctor::And:
1061 condition +=
" AND "sv;
1063 case WhereJunctor::Or:
1064 condition +=
" OR "sv;
1070 condition +=
"NOT "sv;
1071 m_nextIsNot =
false;
1074 m_nextWhereJunctor = WhereJunctor::And;
1078template <
typename Derived>
1079template <
typename ColumnName>
1080 requires(std::same_as<ColumnName, SqlQualifiedTableColumnName> || std::convertible_to<ColumnName, std::string_view>
1081 || std::convertible_to<ColumnName, std::string>)
1084 SearchCondition().condition += detail::MakeSqlColumnName(columnName);
1088template <
typename Derived>
1089template <
typename LiteralType>
1092 auto& searchCondition = SearchCondition();
1094 if constexpr (std::is_same_v<LiteralType, SqlQualifiedTableColumnName>
1095 || detail::OneOf<LiteralType, SqlNullType, std::nullopt_t> || std::is_same_v<LiteralType, SqlWildcardType>
1096 || std::is_same_v<LiteralType, detail::RawSqlCondition>)
1098 PopulateLiteralValueInto(value, searchCondition.condition);
1100 else if (searchCondition.inputBindings)
1102 searchCondition.condition +=
'?';
1103 searchCondition.inputBindings->emplace_back(value);
1105 else if constexpr (std::is_same_v<LiteralType, bool>)
1107 searchCondition.condition += Formatter().BooleanLiteral(value);
1109 else if constexpr (!WhereConditionLiteralType<LiteralType>::needsQuotes)
1111 searchCondition.condition += std::format(
"{}", value);
1115 searchCondition.condition += detail::MakeEscapedSqlString(std::format(
"{}", value));
1120template <
typename Derived>
1121template <
typename LiteralType,
typename TargetType>
1125 if constexpr (std::is_same_v<LiteralType, SqlQualifiedTableColumnName>)
1128 target += value.tableName;
1130 target += value.columnName;
1133 else if constexpr (detail::OneOf<LiteralType, SqlNullType, std::nullopt_t>)
1137 else if constexpr (std::is_same_v<LiteralType, SqlWildcardType>)
1141 else if constexpr (std::is_same_v<LiteralType, detail::RawSqlCondition>)
1143 target += value.condition;
1145 else if constexpr (std::is_same_v<LiteralType, bool>)
1147 target += Formatter().BooleanLiteral(value);
1149 else if constexpr (!WhereConditionLiteralType<LiteralType>::needsQuotes)
1151 target += std::format(
"{}", value);
1155 target += detail::MakeEscapedSqlString(std::format(
"{}", value));
1159template <
typename Derived>
1160template <
typename LiteralType>
1163 using namespace std::string_view_literals;
1164 std::ostringstream fragment;
1166#if !defined(__cpp_lib_ranges_enumerate)
1168 for (
auto const& value: values)
1172 for (
auto const&& [index, value]: values | std::views::enumerate)
1178 std::string valueString;
1179 PopulateLiteralValueInto(value, valueString);
1180 fragment << valueString;
1183 return detail::RawSqlCondition { fragment.str() };
1186template <
typename Derived>
1187inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Join(JoinType joinType,
1188 TableName
auto joinTable,
1189 std::string_view joinColumnName,
1190 SqlQualifiedTableColumnName onOtherColumn)
1192 static constexpr std::array<std::string_view, 4> JoinTypeStrings = {
1199 if constexpr (std::is_same_v<std::remove_cvref_t<
decltype(joinTable)>, AliasedTableName>)
1201 SearchCondition().tableJoins += std::format(
"\n"
1202 R
"( {0} JOIN "{1}" AS "{2}" ON "{2}"."{3}" = "{4}"."{5}")",
1203 JoinTypeStrings[static_cast<std::size_t
>(joinType)],
1204 joinTable.tableName,
1207 onOtherColumn.tableName,
1208 onOtherColumn.columnName);
1212 SearchCondition().tableJoins += std::format(
"\n"
1213 R
"( {0} JOIN "{1}" ON "{1}"."{2}" = "{3}"."{4}")",
1214 JoinTypeStrings[static_cast<std::size_t
>(joinType)],
1217 onOtherColumn.tableName,
1218 onOtherColumn.columnName);
1220 return static_cast<Derived&
>(*this);
1223template <
typename Derived>
1224inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Join(JoinType joinType,
1225 TableName
auto joinTable,
1226 std::string_view joinColumnName,
1227 std::string_view onMainTableColumn)
1229 return Join(joinType,
1232 SqlQualifiedTableColumnName { .tableName = SearchCondition().tableName, .columnName = onMainTableColumn });
1236template <
typename Derived>
1237template <
typename Callable>
1239 TableName
auto joinTable,
1240 Callable
const& onClauseBuilder)
1242 static constexpr std::array<std::string_view, 4> JoinTypeStrings = {
1249 size_t const originalSize = SearchCondition().tableJoins.size();
1250 SearchCondition().tableJoins +=
1251 std::format(
"\n {0} JOIN \"{1}\" ON ", JoinTypeStrings[
static_cast<std::size_t
>(joinType)], joinTable);
1252 size_t const sizeBefore = SearchCondition().tableJoins.size();
1254 size_t const sizeAfter = SearchCondition().tableJoins.size();
1255 if (sizeBefore == sizeAfter)
1256 SearchCondition().tableJoins.resize(originalSize);
1258 return static_cast<Derived&
>(*this);
Query builder for building JOIN conditions.
SqlJoinConditionBuilder & On(std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
Adds an AND join condition.
SqlJoinConditionBuilder(std::string_view referenceTable, std::string *condition) noexcept
Constructs a new SqlJoinConditionBuilder.
SqlJoinConditionBuilder & Operator(std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn, std::string_view op)
Adds a join condition with a custom operator.
SqlJoinConditionBuilder & OrOn(std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
Adds an OR join condition.
Derived & FullOuterJoin(TableName auto joinTable, std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
Constructs an FULL OUTER JOIN clause.
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.
Derived & LeftOuterJoin(TableName auto joinTable, std::string_view joinColumnName, SqlQualifiedTableColumnName onOtherColumn)
Constructs an LEFT OUTER JOIN clause.
Derived & Not() noexcept
Indicates, that the next WHERE clause should be negated.
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.
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.
auto If(std::optional< T > const &value) noexcept
Starts a conditional WHERE chain driven by a std::optional<T> value.
Derived & And() noexcept
Indicates, that the next WHERE clause should be AND-ed (default).
Derived & Or() noexcept
Indicates, that the next WHERE clause should be OR-ed.
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.
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.
std::string_view alias
The alias for the table.
std::weak_ordering operator<=>(AliasedTableName const &) const =default
Three-way comparison operator.
std::string_view tableName
The table name.
SqlQualifiedTableColumnName represents a column name qualified with a table name.
std::string_view tableName
The table name.
std::string_view columnName
The column name.
SqlWildcardType is a placeholder for an explicit wildcard input parameter in a SQL query.