Lightweight 0.20260921.0
Loading...
Searching...
No Matches
Insert.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "Core.hpp"
6
7#include <cassert>
8#include <string>
9#include <string_view>
10#include <vector>
11
12namespace Lightweight
13{
14
15/// @brief Query builder for building INSERT INTO ... queries.
16///
17/// @see SqlQueryBuilder
18/// @ingroup QueryBuilder
19class [[nodiscard]] SqlInsertQueryBuilder final
20{
21 public:
22 /// Constructs an INSERT query builder.
23 explicit SqlInsertQueryBuilder(SqlQueryFormatter const& formatter,
24 std::string tableName,
25 std::vector<SqlVariant>* inputBindings) noexcept;
26
27 /// Adds a single column to the INSERT query.
28 template <typename ColumnValue>
29 SqlInsertQueryBuilder& Set(std::string_view columnName, ColumnValue const& value);
30
31 /// Adds a single column to the INSERT query with the value being a string literal.
32 template <std::size_t N>
33 inline SqlInsertQueryBuilder& Set(std::string_view columnName, char const (&value)[N]);
34
35 /// Finalizes building the query as INSERT INTO ... query.
36 [[nodiscard]] inline std::string ToSql() const;
37
38 private:
39 SqlQueryFormatter const& m_formatter;
40 std::string m_tableName;
41 std::string m_fields;
42 std::string m_values;
43 std::vector<SqlVariant>* m_inputBindings;
44};
45
46inline LIGHTWEIGHT_FORCE_INLINE SqlInsertQueryBuilder::SqlInsertQueryBuilder(SqlQueryFormatter const& formatter,
47 std::string tableName,
48 std::vector<SqlVariant>* inputBindings) noexcept
49 :
50 m_formatter { formatter },
51 m_tableName { std::move(tableName) },
52 m_inputBindings { inputBindings }
53{
54}
55
56template <typename ColumnValue>
57SqlInsertQueryBuilder& SqlInsertQueryBuilder::Set(std::string_view columnName, ColumnValue const& value)
58{
59 using namespace std::string_view_literals;
60
61 if (!m_fields.empty())
62 m_fields += ", "sv;
63
64 m_fields += '"';
65 m_fields += columnName;
66 m_fields += '"';
67
68 if (!m_values.empty())
69 m_values += ", "sv;
70
71 if constexpr (std::is_same_v<ColumnValue, SqlNullType>)
72 m_values += "NULL"sv;
73 else if constexpr (std::is_same_v<ColumnValue, SqlWildcardType>)
74 m_values += '?';
75 else if constexpr (std::is_same_v<ColumnValue, SqlVariant>)
76 {
77 // A NULL variant becomes the SQL literal NULL rather than a bound parameter. A bound NULL has
78 // no type of its own, so the driver must be told one; the SqlNullType binder discovers it
79 // lazily with SQLDescribeParam while binding. But parameters are bound in order, and by the
80 // time a NULL is reached earlier parameters are already bound -- and the MS SQL Server driver
81 // rejects SQLDescribeParam once any parameter has been bound, with SQLSTATE 07009 ("Invalid
82 // Descriptor Index"). The NULL then falls back to a char-typed parameter, which the server
83 // refuses to assign to a binary column. A literal carries no type to resolve, so it needs no
84 // describe at all.
85 if (value.IsNull())
86 m_values += "NULL"sv;
87 else if (m_inputBindings)
88 {
89 m_values += '?';
90 m_inputBindings->emplace_back(value);
91 }
92 else
93 m_values += m_formatter.StringLiteral(std::format("{}", value));
94 }
95 else if (m_inputBindings)
96 {
97 m_values += '?';
98 m_inputBindings->emplace_back(value);
99 }
100 else if constexpr (std::is_same_v<ColumnValue, char>)
101 m_values += m_formatter.StringLiteral(value);
102 else if constexpr (std::is_arithmetic_v<ColumnValue>)
103 m_values += std::format("{}", value);
104 else if constexpr (std::is_convertible_v<ColumnValue, std::string>
105 || std::is_convertible_v<ColumnValue, std::string_view>
106 || std::is_convertible_v<ColumnValue, char const*>)
107 {
108 m_values += m_formatter.StringLiteral(value);
109 }
110 else
111 {
112 m_values += m_formatter.StringLiteral(std::format("{}", value));
113 }
114
115 return *this;
116}
117
118template <std::size_t N>
119inline SqlInsertQueryBuilder& SqlInsertQueryBuilder::Set(std::string_view columnName, char const (&value)[N])
120{
121 return Set(columnName, std::string_view { value, N - 1 });
122}
123
124inline std::string SqlInsertQueryBuilder::ToSql() const
125{
126 return m_formatter.Insert(m_tableName, m_fields, m_values);
127}
128
129} // namespace Lightweight
Query builder for building INSERT INTO ... queries.
Definition Insert.hpp:20
SqlInsertQueryBuilder(SqlQueryFormatter const &formatter, std::string tableName, std::vector< SqlVariant > *inputBindings) noexcept
Constructs an INSERT query builder.
Definition Insert.hpp:46
std::string ToSql() const
Finalizes building the query as INSERT INTO ... query.
Definition Insert.hpp:124
SqlInsertQueryBuilder & Set(std::string_view columnName, ColumnValue const &value)
Adds a single column to the INSERT query.
Definition Insert.hpp:57
API to format SQL queries for different SQL dialects.
virtual std::string StringLiteral(std::string_view value) const noexcept=0
Converts a string value to a string literal.
virtual std::string Insert(std::string_view intoTable, std::string_view fields, std::string_view values) const =0
LIGHTWEIGHT_API std::vector< std::string > ToSql(SqlQueryFormatter const &formatter, SqlMigrationPlanElement const &element)