Lightweight 0.20261105.1
Loading...
Searching...
No Matches
Update.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "Core.hpp"
6
7#include <string>
8#include <string_view>
9#include <vector>
10
11namespace Lightweight
12{
13
14/// @brief Query builder for building UPDATE ... queries.
15///
16/// @ingroup QueryBuilder
17class [[nodiscard]] SqlUpdateQueryBuilder final: public SqlWhereClauseBuilder<SqlUpdateQueryBuilder>
18{
19 public:
20 /// Constructs a new SqlUpdateQueryBuilder object.
21 ///
22 /// @param formatter The SQL query formatter to use. One of SqlServerQueryFormatter, PostgreSqlFormatter
23 /// @param table The name of the table to update.
24 /// @param tableAlias The alias of the table to update.
25 /// @param inputBindings The input bindings to use for the query.
26 SqlUpdateQueryBuilder(SqlQueryFormatter const& formatter,
27 std::string table,
28 std::string tableAlias,
29 std::vector<SqlVariant>* inputBindings) noexcept:
30 SqlWhereClauseBuilder<SqlUpdateQueryBuilder> {},
31 m_formatter { formatter }
32 {
33 m_searchCondition.tableName = std::move(table);
34 m_searchCondition.tableAlias = std::move(tableAlias);
35 m_searchCondition.inputBindings = inputBindings;
36 }
37
38 /// Returns the search condition for the query.
39 SqlSearchCondition& SearchCondition() noexcept
40 {
41 return m_searchCondition;
42 }
43
44 /// Returns the SQL query formatter.
45 [[nodiscard]] SqlQueryFormatter const& Formatter() const noexcept
46 {
47 return m_formatter;
48 }
49
50 /// Adds a single column to the SET clause.
51 template <typename ColumnValue>
52 SqlUpdateQueryBuilder& Set(std::string_view columnName, ColumnValue const& value);
53
54 /// Adds a single column to the SET clause with the value being a string literal.
55 template <std::size_t N>
56 SqlUpdateQueryBuilder& Set(std::string_view columnName, char const (&value)[N]);
57
58 /// Finalizes building the query as UPDATE ... query.
59 [[nodiscard]] std::string ToSql() const;
60
61 private:
62 SqlQueryFormatter const& m_formatter;
63 std::string m_values;
64 SqlSearchCondition m_searchCondition;
65};
66
67template <typename ColumnValue>
68SqlUpdateQueryBuilder& SqlUpdateQueryBuilder::Set(std::string_view columnName, ColumnValue const& value)
69{
70 using namespace std::string_view_literals;
71
72 if (!m_values.empty())
73 m_values += ", "sv;
74
75 m_values += '"';
76 m_values += columnName;
77 m_values += R"(" = )"sv;
78
79 if constexpr (std::is_same_v<ColumnValue, SqlNullType>)
80 m_values += "NULL"sv;
81 else if constexpr (std::is_same_v<ColumnValue, SqlWildcardType>)
82 m_values += '?';
83 else if constexpr (std::is_same_v<ColumnValue, SqlVariant>)
84 {
85 // A NULL variant becomes the SQL literal NULL rather than a bound parameter -- see the same
86 // branch in SqlInsertQueryBuilder::Set (Insert.hpp) for why a bound NULL cannot be typed
87 // reliably on MS SQL Server (SQLDescribeParam is rejected with 07009 once a parameter has been
88 // bound). A literal needs no type resolution.
89 if (value.IsNull())
90 m_values += "NULL"sv;
91 else if (m_searchCondition.inputBindings)
92 {
93 m_values += '?';
94 m_searchCondition.inputBindings->emplace_back(value);
95 }
96 else
97 m_values += m_formatter.StringLiteral(std::format("{}", value));
98 }
99 else if (m_searchCondition.inputBindings)
100 {
101 m_values += '?';
102 m_searchCondition.inputBindings->emplace_back(value);
103 }
104 else if constexpr (std::is_same_v<ColumnValue, char>)
105 m_values += m_formatter.StringLiteral(value);
106 else if constexpr (std::is_arithmetic_v<ColumnValue>)
107 m_values += std::format("{}", value);
108 else if constexpr (!WhereConditionLiteralType<ColumnValue>::needsQuotes)
109 m_values += std::format("{}", value);
110 else
111 {
112 // Route through the formatter rather than quoting by hand: it escapes embedded quotes and
113 // applies the dialect's literal rules (e.g. SQL Server's N'…' + NCHAR() encoding).
114 // SqlInsertQueryBuilder::Set does the same — see Insert.hpp.
115 m_values += m_formatter.StringLiteral(std::format("{}", value));
116 }
117
118 return *this;
119}
120
121template <std::size_t N>
122SqlUpdateQueryBuilder& SqlUpdateQueryBuilder::Set(std::string_view columnName, char const (&value)[N])
123{
124 return Set(columnName, std::string_view { value, N - 1 });
125}
126
127inline LIGHTWEIGHT_FORCE_INLINE std::string SqlUpdateQueryBuilder::ToSql() const
128{
129 return m_formatter.Update(
130 m_searchCondition.tableName, m_searchCondition.tableAlias, m_values, m_searchCondition.condition);
131}
132
133} // namespace Lightweight
LIGHTWEIGHT_API std::vector< std::string > ToSql(SqlQueryFormatter const &formatter, SqlMigrationPlanElement const &element)