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);
314 [[nodiscard]] Derived& InnerJoin(TableName auto joinTable,
315 std::string_view joinColumnName,
319 [[nodiscard]] Derived& InnerJoin(TableName auto joinTable,
320 std::string_view joinColumnName,
321 std::string_view onMainTableColumn);
324 template <typename OnChainCallable>
326 [[nodiscard]] Derived& InnerJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
340 template <auto LeftField, auto RightField>
341 [[nodiscard]] Derived& InnerJoin();
344 [[nodiscard]] Derived& LeftOuterJoin(TableName auto joinTable,
345 std::string_view joinColumnName,
349 [[nodiscard]] Derived& LeftOuterJoin(TableName auto joinTable,
350 std::string_view joinColumnName,
351 std::string_view onMainTableColumn);
354 template <typename OnChainCallable>
356 [[nodiscard]] Derived& LeftOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
359 [[nodiscard]] Derived& RightOuterJoin(TableName auto joinTable,
360 std::string_view joinColumnName,
364 [[nodiscard]] Derived& RightOuterJoin(TableName auto joinTable,
365 std::string_view joinColumnName,
366 std::string_view onMainTableColumn);
369 template <typename OnChainCallable>
371 [[nodiscard]] Derived& RightOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
374 [[nodiscard]] Derived& FullOuterJoin(TableName auto joinTable,
375 std::string_view joinColumnName,
379 [[nodiscard]] Derived& FullOuterJoin(TableName auto joinTable,
380 std::string_view joinColumnName,
381 std::string_view onMainTableColumn);
384 template <typename OnChainCallable>
386 [[nodiscard]] Derived& FullOuterJoin(TableName auto joinTable, OnChainCallable const& onClauseBuilder);
389 SqlSearchCondition& SearchCondition() noexcept;
392 enum class WhereJunctor : uint8_t
400 WhereJunctor m_nextWhereJunctor = WhereJunctor::Where;
401 bool m_nextIsNot =
false;
403 void AppendWhereJunctor();
406 template <
typename ColumnName>
407 requires(std::same_as<ColumnName, SqlQualifiedTableColumnName> || std::convertible_to<ColumnName, std::string_view>
408 || std::convertible_to<ColumnName, std::string>)
409 void AppendColumnName(ColumnName
const& columnName);
412 template <
typename LiteralType>
413 void AppendLiteralValue(LiteralType
const& value);
416 template <
typename LiteralType,
typename TargetType>
417 void PopulateLiteralValueInto(LiteralType
const& value, TargetType& target);
419 template <
typename LiteralType>
420 detail::RawSqlCondition PopulateSqlSetExpression(LiteralType
const& values);
422 enum class JoinType : uint8_t
431 [[nodiscard]] Derived& Join(JoinType joinType,
432 TableName
auto joinTable,
433 std::string_view joinColumnName,
434 SqlQualifiedTableColumnName onOtherColumn);
437 [[nodiscard]] Derived& Join(JoinType joinType,
438 TableName
auto joinTable,
439 std::string_view joinColumnName,
440 std::string_view onMainTableColumn);
443 template <
typename OnChainCallable>
444 [[nodiscard]] Derived& Join(JoinType joinType, TableName
auto joinTable, OnChainCallable
const& onClauseBuilder);
447enum class SqlResultOrdering : uint8_t
455 enum class SelectType : std::uint8_t
466 SelectType selectType = SelectType::Undefined;
467 SqlQueryFormatter
const* formatter =
nullptr;
469 bool distinct =
false;
470 SqlSearchCondition searchCondition {};
478 size_t limit = (std::numeric_limits<size_t>::max)();
480 [[nodiscard]] LIGHTWEIGHT_API std::string
ToSql()
const;
484template <
typename Derived>
485class [[nodiscard]] SqlBasicSelectQueryBuilder:
public SqlWhereClauseBuilder<Derived>
489 Derived& Distinct() noexcept;
492 Derived& OrderBy(SqlQualifiedTableColumnName const& columnName,
493 SqlResultOrdering ordering = SqlResultOrdering::ASCENDING);
496 Derived& OrderBy(std::string_view columnName, SqlResultOrdering ordering = SqlResultOrdering::ASCENDING);
499 Derived& GroupBy(std::string_view columnName);
502 Derived& GroupBy(SqlQualifiedTableColumnName const& columnName);
504 using ComposedQuery = detail::ComposedQuery;
510 mutable ComposedQuery _query {};
513template <
typename Derived>
514inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::Distinct() noexcept
516 _query.distinct =
true;
517 return static_cast<Derived&
>(*this);
520template <
typename Derived>
521inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::OrderBy(std::string_view columnName,
522 SqlResultOrdering ordering)
524 if (_query.orderBy.empty())
525 _query.orderBy +=
"\n ORDER BY ";
527 _query.orderBy +=
", ";
529 _query.orderBy +=
'"';
530 _query.orderBy += columnName;
531 _query.orderBy +=
'"';
533 if (ordering == SqlResultOrdering::DESCENDING)
534 _query.orderBy +=
" DESC";
535 else if (ordering == SqlResultOrdering::ASCENDING)
536 _query.orderBy +=
" ASC";
538 return static_cast<Derived&
>(*this);
541template <
typename Derived>
542inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::OrderBy(
543 SqlQualifiedTableColumnName
const& columnName, SqlResultOrdering ordering)
545 if (_query.orderBy.empty())
546 _query.orderBy +=
"\n ORDER BY ";
548 _query.orderBy +=
", ";
550 _query.orderBy +=
'"';
551 _query.orderBy += columnName.tableName;
552 _query.orderBy +=
"\".\"";
553 _query.orderBy += columnName.columnName;
554 _query.orderBy +=
'"';
556 if (ordering == SqlResultOrdering::DESCENDING)
557 _query.orderBy +=
" DESC";
558 else if (ordering == SqlResultOrdering::ASCENDING)
559 _query.orderBy +=
" ASC";
561 return static_cast<Derived&
>(*this);
564template <
typename Derived>
565inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::GroupBy(std::string_view columnName)
567 if (_query.groupBy.empty())
568 _query.groupBy +=
"\n GROUP BY ";
570 _query.groupBy +=
", ";
572 _query.groupBy +=
'"';
573 _query.groupBy += columnName;
574 _query.groupBy +=
'"';
576 return static_cast<Derived&
>(*this);
579template <
typename Derived>
580inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlBasicSelectQueryBuilder<Derived>::GroupBy(
581 SqlQualifiedTableColumnName
const& columnName)
583 if (_query.groupBy.empty())
584 _query.groupBy +=
"\n GROUP BY ";
586 _query.groupBy +=
", ";
588 _query.groupBy +=
'"';
589 _query.groupBy += columnName.tableName;
590 _query.groupBy +=
"\".\"";
591 _query.groupBy += columnName.columnName;
592 _query.groupBy +=
'"';
594 return static_cast<Derived&
>(*this);
597template <
typename Derived>
600 m_nextWhereJunctor = WhereJunctor::And;
601 return static_cast<Derived&
>(*this);
604template <
typename Derived>
607 m_nextWhereJunctor = WhereJunctor::Or;
608 return static_cast<Derived&
>(*this);
611template <
typename Derived>
614 m_nextIsNot = !m_nextIsNot;
615 return static_cast<Derived&
>(*this);
619template <
typename Derived>
620template <
typename ColumnName,
typename T>
623 if constexpr (detail::OneOf<T, SqlNullType, std::nullopt_t>)
628 return Where(columnName,
"IS NOT", value);
631 return Where(columnName,
"IS", value);
634 return Where(columnName,
"=", value);
638template <
typename Derived>
639template <
typename ColumnName,
typename T>
643 return Or().Where(columnName, value);
647template <
typename Derived>
648template <
typename Callable>
649 requires std::invocable<Callable, SqlWhereClauseBuilder<Derived>&>
652 return Or().Where(callable);
656template <
typename Derived>
657template <
typename Callable>
658 requires std::invocable<Callable, SqlWhereClauseBuilder<Derived>&>
661 auto& condition = SearchCondition().condition;
663 auto const originalSize = condition.size();
665 AppendWhereJunctor();
666 m_nextWhereJunctor = WhereJunctor::Null;
669 auto const sizeBeforeCallable = condition.size();
671 (void) callable(*
this);
673 if (condition.size() == sizeBeforeCallable)
674 condition.resize(originalSize);
678 return static_cast<Derived&
>(*this);
682template <
typename Derived>
683template <
typename ColumnName, std::ranges::input_range InputRange>
685 InputRange
const& values)
688 return static_cast<Derived&
>(*this);
689 return Where(columnName,
"IN", PopulateSqlSetExpression(values));
693template <
typename Derived>
694template <
typename ColumnName,
typename T>
696 std::initializer_list<T>
const& values)
698 if (values.begin() == values.end())
699 return static_cast<Derived&
>(*this);
700 return Where(columnName,
"IN", PopulateSqlSetExpression(values));
704template <
typename Derived>
705template <
typename ColumnName,
typename SubSelectQuery>
706 requires(std::is_invocable_r_v<std::string,
decltype(&SubSelectQuery::ToSql), SubSelectQuery
const&>)
708 SubSelectQuery
const& subSelectQuery)
710 return Where(columnName,
"IN", detail::RawSqlCondition {
"(" + subSelectQuery.ToSql() +
")" });
714template <
typename Derived>
715template <
typename ColumnName>
718 return Where(columnName,
"IS NOT", detail::RawSqlCondition {
"NULL" });
722template <
typename Derived>
723template <
typename ColumnName>
726 return Where(columnName,
"IS", detail::RawSqlCondition {
"NULL" });
730template <
typename Derived>
731template <
typename ColumnName,
typename T>
735 if constexpr (detail::OneOf<T, SqlNullType, std::nullopt_t>)
736 return Where(columnName,
"IS NOT", value);
738 return Where(columnName,
"!=", value);
742template <
typename Derived>
743template <
typename ColumnName>
746 return Where(columnName,
"=",
true);
750template <
typename Derived>
751template <
typename ColumnName>
754 return Where(columnName,
"=",
false);
758struct WhereConditionLiteralType
760 constexpr static bool needsQuotes = !std::is_integral_v<T> && !std::is_floating_point_v<T> && !std::same_as<T, bool>
761 && !std::same_as<T, SqlWildcardType>;
765template <
typename Derived>
766template <
typename ColumnName, std::
size_t N>
768 std::string_view binaryOp,
769 char const (&value)[N])
771 return Where(columnName, binaryOp, std::string_view { value, N - 1 });
775template <
typename Derived>
776template <
typename ColumnName,
typename T>
778 std::string_view binaryOp,
781 auto& searchCondition = SearchCondition();
783 AppendWhereJunctor();
784 AppendColumnName(columnName);
785 searchCondition.condition +=
' ';
786 searchCondition.condition += binaryOp;
787 searchCondition.condition +=
' ';
788 AppendLiteralValue(value);
790 return static_cast<Derived&
>(*this);
794template <
typename Derived>
795template <
typename ColumnName,
typename SubSelectQuery>
796 requires(std::is_invocable_r_v<std::string,
decltype(&SubSelectQuery::ToSql), SubSelectQuery
const&>)
798 std::string_view binaryOp,
799 SubSelectQuery
const& value)
801 return Where(columnName, binaryOp, detail::RawSqlCondition {
"(" + value.ToSql() +
")" });
805template <
typename Derived>
806template <
typename ColumnName,
typename T>
808 std::string_view binaryOp,
811 return Or().
Where(columnName, binaryOp, value);
814template <
typename Derived>
816 std::string_view joinColumnName,
819 return Join(JoinType::INNER, joinTable, joinColumnName, onOtherColumn);
822template <
typename Derived>
824 std::string_view joinColumnName,
825 std::string_view onMainTableColumn)
827 return Join(JoinType::INNER, joinTable, joinColumnName, onMainTableColumn);
830template <
typename Derived>
831template <auto LeftField, auto RightField>
834#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
835 return Join(JoinType::INNER,
837 FieldNameOf<LeftField>,
843 FieldNameOf<LeftField>,
848template <
typename Derived>
849template <
typename OnChainCallable>
850 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
853 return Join(JoinType::INNER, joinTable, onClauseBuilder);
856template <
typename Derived>
860 return Join(JoinType::LEFT, joinTable, joinColumnName, onOtherColumn);
863template <
typename Derived>
865 std::string_view joinColumnName,
866 std::string_view onMainTableColumn)
868 return Join(JoinType::LEFT, joinTable, joinColumnName, onMainTableColumn);
871template <
typename Derived>
872template <
typename OnChainCallable>
873 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
876 return Join(JoinType::LEFT, joinTable, onClauseBuilder);
879template <
typename Derived>
883 return Join(JoinType::RIGHT, joinTable, joinColumnName, onOtherColumn);
886template <
typename Derived>
888 std::string_view joinColumnName,
889 std::string_view onMainTableColumn)
891 return Join(JoinType::RIGHT, joinTable, joinColumnName, onMainTableColumn);
894template <
typename Derived>
895template <
typename OnChainCallable>
896 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
899 return Join(JoinType::RIGHT, joinTable, onClauseBuilder);
902template <
typename Derived>
906 return Join(JoinType::FULL, joinTable, joinColumnName, onOtherColumn);
909template <
typename Derived>
911 std::string_view joinColumnName,
912 std::string_view onMainTableColumn)
914 return Join(JoinType::FULL, joinTable, joinColumnName, onMainTableColumn);
917template <
typename Derived>
918template <
typename OnChainCallable>
919 requires std::invocable<OnChainCallable, SqlJoinConditionBuilder>
922 return Join(JoinType::FULL, joinTable, onClauseBuilder);
936 template <
typename Derived,
typename T>
937 class [[nodiscard]] ConditionalWhereBuilder
941 constexpr ConditionalWhereBuilder(Derived& builder, std::optional<T>
const& value)
noexcept:
942 _builder { builder },
952 template <
typename ColumnName>
953 [[nodiscard]] Derived& ThenWhere(ColumnName
const& column)
const
955 if (_value.has_value())
956 return _builder.Where(column, *_value);
978 template <
typename ColumnName>
979 [[nodiscard]] Derived& ThenWhere(ColumnName
const& column, std::string_view binaryOp)
const
981 if (_value.has_value())
982 return _builder.Where(column, binaryOp, *_value);
988 std::optional<T>
const& _value;
994template <
typename Derived>
998 return detail::ConditionalWhereBuilder<Derived, T> {
static_cast<Derived&
>(*this), value };
1001template <
typename Derived>
1004 AppendWhereJunctor();
1006 auto& condition = SearchCondition().condition;
1007 condition += sqlConditionExpression;
1009 return static_cast<Derived&
>(*this);
1012template <
typename Derived>
1015 return static_cast<Derived*
>(
this)->SearchCondition();
1018template <
typename Derived>
1019inline LIGHTWEIGHT_FORCE_INLINE SqlQueryFormatter
const& SqlWhereClauseBuilder<Derived>::Formatter() const noexcept
1021 return static_cast<Derived const*
>(
this)->Formatter();
1024template <
typename Derived>
1025inline LIGHTWEIGHT_FORCE_INLINE
void SqlWhereClauseBuilder<Derived>::AppendWhereJunctor()
1027 using namespace std::string_view_literals;
1029 auto& condition = SearchCondition().condition;
1031 switch (m_nextWhereJunctor)
1033 case WhereJunctor::Null:
1035 case WhereJunctor::Where:
1036 condition +=
"\n WHERE "sv;
1038 case WhereJunctor::And:
1039 condition +=
" AND "sv;
1041 case WhereJunctor::Or:
1042 condition +=
" OR "sv;
1048 condition +=
"NOT "sv;
1049 m_nextIsNot =
false;
1052 m_nextWhereJunctor = WhereJunctor::And;
1056template <
typename Derived>
1057template <
typename ColumnName>
1058 requires(std::same_as<ColumnName, SqlQualifiedTableColumnName> || std::convertible_to<ColumnName, std::string_view>
1059 || std::convertible_to<ColumnName, std::string>)
1062 SearchCondition().condition += detail::MakeSqlColumnName(columnName);
1066template <
typename Derived>
1067template <
typename LiteralType>
1070 auto& searchCondition = SearchCondition();
1072 if constexpr (std::is_same_v<LiteralType, SqlQualifiedTableColumnName>
1073 || detail::OneOf<LiteralType, SqlNullType, std::nullopt_t> || std::is_same_v<LiteralType, SqlWildcardType>
1074 || std::is_same_v<LiteralType, detail::RawSqlCondition>)
1076 PopulateLiteralValueInto(value, searchCondition.condition);
1078 else if (searchCondition.inputBindings)
1080 searchCondition.condition +=
'?';
1081 searchCondition.inputBindings->emplace_back(value);
1083 else if constexpr (std::is_same_v<LiteralType, bool>)
1085 searchCondition.condition += Formatter().BooleanLiteral(value);
1087 else if constexpr (!WhereConditionLiteralType<LiteralType>::needsQuotes)
1089 searchCondition.condition += std::format(
"{}", value);
1093 searchCondition.condition += detail::MakeEscapedSqlString(std::format(
"{}", value));
1098template <
typename Derived>
1099template <
typename LiteralType,
typename TargetType>
1103 if constexpr (std::is_same_v<LiteralType, SqlQualifiedTableColumnName>)
1106 target += value.tableName;
1108 target += value.columnName;
1111 else if constexpr (detail::OneOf<LiteralType, SqlNullType, std::nullopt_t>)
1115 else if constexpr (std::is_same_v<LiteralType, SqlWildcardType>)
1119 else if constexpr (std::is_same_v<LiteralType, detail::RawSqlCondition>)
1121 target += value.condition;
1123 else if constexpr (std::is_same_v<LiteralType, bool>)
1125 target += Formatter().BooleanLiteral(value);
1127 else if constexpr (!WhereConditionLiteralType<LiteralType>::needsQuotes)
1129 target += std::format(
"{}", value);
1133 target += detail::MakeEscapedSqlString(std::format(
"{}", value));
1137template <
typename Derived>
1138template <
typename LiteralType>
1141 using namespace std::string_view_literals;
1142 std::ostringstream fragment;
1144#if !defined(__cpp_lib_ranges_enumerate)
1146 for (
auto const& value: values)
1150 for (
auto const&& [index, value]: values | std::views::enumerate)
1156 std::string valueString;
1157 PopulateLiteralValueInto(value, valueString);
1158 fragment << valueString;
1161 return detail::RawSqlCondition { fragment.str() };
1164template <
typename Derived>
1165inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Join(JoinType joinType,
1166 TableName
auto joinTable,
1167 std::string_view joinColumnName,
1168 SqlQualifiedTableColumnName onOtherColumn)
1170 static constexpr std::array<std::string_view, 4> JoinTypeStrings = {
1177 if constexpr (std::is_same_v<std::remove_cvref_t<
decltype(joinTable)>, AliasedTableName>)
1179 SearchCondition().tableJoins += std::format(
"\n"
1180 R
"( {0} JOIN "{1}" AS "{2}" ON "{2}"."{3}" = "{4}"."{5}")",
1181 JoinTypeStrings[static_cast<std::size_t
>(joinType)],
1182 joinTable.tableName,
1185 onOtherColumn.tableName,
1186 onOtherColumn.columnName);
1190 SearchCondition().tableJoins += std::format(
"\n"
1191 R
"( {0} JOIN "{1}" ON "{1}"."{2}" = "{3}"."{4}")",
1192 JoinTypeStrings[static_cast<std::size_t
>(joinType)],
1195 onOtherColumn.tableName,
1196 onOtherColumn.columnName);
1198 return static_cast<Derived&
>(*this);
1201template <
typename Derived>
1202inline LIGHTWEIGHT_FORCE_INLINE Derived& SqlWhereClauseBuilder<Derived>::Join(JoinType joinType,
1203 TableName
auto joinTable,
1204 std::string_view joinColumnName,
1205 std::string_view onMainTableColumn)
1207 return Join(joinType,
1210 SqlQualifiedTableColumnName { .tableName = SearchCondition().tableName, .columnName = onMainTableColumn });
1214template <
typename Derived>
1215template <
typename Callable>
1217 TableName
auto joinTable,
1218 Callable
const& onClauseBuilder)
1220 static constexpr std::array<std::string_view, 4> JoinTypeStrings = {
1227 size_t const originalSize = SearchCondition().tableJoins.size();
1228 SearchCondition().tableJoins +=
1229 std::format(
"\n {0} JOIN \"{1}\" ON ", JoinTypeStrings[
static_cast<std::size_t
>(joinType)], joinTable);
1230 size_t const sizeBefore = SearchCondition().tableJoins.size();
1232 size_t const sizeAfter = SearchCondition().tableJoins.size();
1233 if (sizeBefore == sizeAfter)
1234 SearchCondition().tableJoins.resize(originalSize);
1236 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.
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.