Lightweight 0.20260303.0
Loading...
Searching...
No Matches
Select.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "../SqlQueryFormatter.hpp"
6#include "../Utils.hpp"
7#include "Core.hpp"
8
9#include <reflection-cpp/reflection.hpp>
10
11#include <span>
12
13namespace Lightweight
14{
15
16enum class SqlQueryBuilderMode : uint8_t
17{
18 Fluent,
19 Varying
20};
21
22struct [[nodiscard]] SqlFieldExpression final
23{
24 std::string expression;
25};
26
27namespace Aggregate
28{
29
30 inline SqlFieldExpression Count(std::string const& field = "*") noexcept
31 {
32 return SqlFieldExpression { .expression = std::format("COUNT(\"{}\")", field) };
33 }
34
35 inline SqlFieldExpression Count(SqlQualifiedTableColumnName const& field) noexcept
36 {
37 return SqlFieldExpression { .expression = std::format(R"(COUNT("{}"."{}"))", field.tableName, field.columnName) };
38 }
39
40 inline SqlFieldExpression Sum(std::string const& field) noexcept
41 {
42 return SqlFieldExpression { .expression = std::format("SUM(\"{}\")", field) };
43 }
44
45 inline SqlFieldExpression Sum(SqlQualifiedTableColumnName const& field) noexcept
46 {
47 return SqlFieldExpression { .expression = std::format(R"(SUM("{}"."{}"))", field.tableName, field.columnName) };
48 }
49
50 inline SqlFieldExpression Avg(std::string const& field) noexcept
51 {
52 return SqlFieldExpression { .expression = std::format("AVG(\"{}\")", field) };
53 }
54
55 inline SqlFieldExpression Avg(SqlQualifiedTableColumnName const& field) noexcept
56 {
57 return SqlFieldExpression { .expression = std::format(R"(AVG("{}"."{}"))", field.tableName, field.columnName) };
58 }
59
60 inline SqlFieldExpression Min(std::string const& field) noexcept
61 {
62 return SqlFieldExpression { .expression = std::format("MIN(\"{}\")", field) };
63 }
64
65 inline SqlFieldExpression Min(SqlQualifiedTableColumnName const& field) noexcept
66 {
67 return SqlFieldExpression { .expression = std::format(R"(MIN("{}"."{}"))", field.tableName, field.columnName) };
68 }
69
70 inline SqlFieldExpression Max(std::string const& field) noexcept
71 {
72 return SqlFieldExpression { .expression = std::format("MAX(\"{}\")", field) };
73 }
74
75 inline SqlFieldExpression Max(SqlQualifiedTableColumnName const& field) noexcept
76 {
77 return SqlFieldExpression { .expression = std::format(R"(MAX("{}"."{}"))", field.tableName, field.columnName) };
78 }
79
80} // namespace Aggregate
81
82/// @brief Query builder for building SELECT ... queries.
83///
84/// @see SqlQueryBuilder
85class [[nodiscard]] SqlSelectQueryBuilder final: public SqlBasicSelectQueryBuilder<SqlSelectQueryBuilder>
86{
87 public:
88 /// The select query type alias.
89 using SelectType = detail::SelectType;
90
91 /// Constructs a SELECT query builder.
92 explicit SqlSelectQueryBuilder(SqlQueryFormatter const& formatter, std::string table, std::string tableAlias) noexcept:
93 SqlBasicSelectQueryBuilder<SqlSelectQueryBuilder> {},
94 _formatter { formatter }
95 {
96 _query.formatter = &formatter;
97 _query.searchCondition.tableName = std::move(table);
98 _query.searchCondition.tableAlias = std::move(tableAlias);
99 _query.fields.reserve(256);
100 }
101
102 /// Sets the builder mode to Varying, allowing varying final query types.
103 constexpr LIGHTWEIGHT_FORCE_INLINE SqlSelectQueryBuilder& Varying() noexcept
104 {
105 _mode = SqlQueryBuilderMode::Varying;
106 return *this;
107 }
108
109 /// Adds a sequence of columns to the SELECT clause.
110 template <typename... MoreFields>
111 SqlSelectQueryBuilder& Fields(std::string_view const& firstField, MoreFields&&... moreFields);
112
113 /// Adds a single column to the SELECT clause.
114 LIGHTWEIGHT_API SqlSelectQueryBuilder& Field(std::string_view const& fieldName);
115
116 /// Adds a single column to the SELECT clause.
117 LIGHTWEIGHT_API SqlSelectQueryBuilder& Field(SqlQualifiedTableColumnName const& fieldName);
118
119 /// Adds an aggregate function call to the SELECT clause.
120 LIGHTWEIGHT_API SqlSelectQueryBuilder& Field(SqlFieldExpression const& fieldExpression);
121
122 /// Aliases the last added field (a column or an aggregate call) in the SELECT clause.
123 LIGHTWEIGHT_API SqlSelectQueryBuilder& As(std::string_view alias);
124
125 /// Adds a sequence of columns to the SELECT clause.
126 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::vector<std::string_view> const& fieldNames);
127
128 /// Adds a sequence of columns from the given table to the SELECT clause.
129 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::vector<std::string_view> const& fieldNames,
130 std::string_view tableName);
131
132 /// Adds a sequence of columns from the given table to the SELECT clause.
133 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::initializer_list<std::string_view> const& fieldNames,
134 std::string_view tableName);
135
136 /// Adds a sequence of qualified table column names to the SELECT clause.
137 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::span<SqlQualifiedTableColumnName const> fieldNames);
138
139 /// Adds a sequence of qualified table column names to the SELECT clause.
140 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::initializer_list<SqlQualifiedTableColumnName const> fieldNames);
141
142 /// Adds a sequence of columns from the given tables to the SELECT clause.
143 template <typename FirstRecord, typename... MoreRecords>
145
146 /// Adds a single column with an alias to the SELECT clause.
147 [[deprecated("Use Field(...).As(\"alias\") instead.")]]
148 LIGHTWEIGHT_API SqlSelectQueryBuilder& FieldAs(std::string_view const& fieldName, std::string_view const& alias);
149
150 /// Adds a single column with an alias to the SELECT clause.
151 [[deprecated("Use Field(...).As(\"alias\") instead.")]]
153 std::string_view const& alias);
154
155 /// Builds the query using a callable.
156 template <typename Callable>
157 SqlSelectQueryBuilder& Build(Callable const& callable);
158
159 /// Finalizes building the query as SELECT COUNT(*) ... query.
160 LIGHTWEIGHT_API ComposedQuery Count();
161
162 /// Finalizes building the query as SELECT field names FROM ... query.
163 LIGHTWEIGHT_API ComposedQuery All();
164
165 /// Finalizes building the query as SELECT TOP n field names FROM ... query.
166 LIGHTWEIGHT_API ComposedQuery First(size_t count = 1);
167
168 /// Finalizes building the query as SELECT field names FROM ... query with a range.
169 LIGHTWEIGHT_API ComposedQuery Range(std::size_t offset, std::size_t limit);
170
171 // clang-format off
172 /// Returns the search condition for the query.
173 LIGHTWEIGHT_FORCE_INLINE SqlSearchCondition& SearchCondition() noexcept // NOLINT(bugprone-derived-method-shadowing-base-method)
174 {
175 // clang-format on
176 return _query.searchCondition;
177 }
178
179 // clang-format off
180 /// Returns the SQL query formatter.
181 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE SqlQueryFormatter const& Formatter() const noexcept // NOLINT(bugprone-derived-method-shadowing-base-method)
182 {
183 // clang-format on
184 return _formatter;
185 }
186
187 private:
188 SqlQueryFormatter const& _formatter;
189 SqlQueryBuilderMode _mode = SqlQueryBuilderMode::Fluent;
190 bool _aliasAllowed = false;
191};
192
193template <typename... MoreFields>
194SqlSelectQueryBuilder& SqlSelectQueryBuilder::Fields(std::string_view const& firstField, MoreFields&&... moreFields)
195{
196 using namespace std::string_view_literals;
197
198 std::ostringstream fragment;
199
200 if (!_query.fields.empty())
201 fragment << ", "sv;
202
203 fragment << '"' << firstField << '"';
204
205 if constexpr (sizeof...(MoreFields) > 0)
206 ((fragment << R"(, ")"sv << std::forward<MoreFields>(moreFields) << '"') << ...);
207
208 _query.fields += fragment.str();
209 return *this;
210}
211
212/// Builds the query using a callable.
213template <typename Callable>
214inline LIGHTWEIGHT_FORCE_INLINE SqlSelectQueryBuilder& SqlSelectQueryBuilder::Build(Callable const& callable)
215{
216 callable(*this);
217 return *this;
218}
219
220/// Adds fields from one or more record types to the SELECT clause.
221template <typename FirstRecord, typename... MoreRecords>
222inline LIGHTWEIGHT_FORCE_INLINE SqlSelectQueryBuilder& SqlSelectQueryBuilder::Fields()
223{
224 if constexpr (sizeof...(MoreRecords) == 0)
225 {
226 Reflection::EnumerateMembers<FirstRecord>(
227 [&]<size_t FieldIndex, typename FieldType>() { Field(FieldNameAt<FieldIndex, FirstRecord>); });
228 }
229 else
230 {
231 Reflection::EnumerateMembers<FirstRecord>([&]<size_t FieldIndex, typename FieldType>() {
233 .tableName = RecordTableName<FirstRecord>,
234 .columnName = FieldNameAt<FieldIndex, FirstRecord>,
235 });
236 });
237
238 (Reflection::EnumerateMembers<MoreRecords>([&]<size_t FieldIndex, typename FieldType>() {
240 .tableName = RecordTableName<MoreRecords>,
241 .columnName = FieldNameAt<FieldIndex, MoreRecords>,
242 });
243 }),
244 ...);
245 }
246 return *this;
247}
248
249} // namespace Lightweight
API to format SQL queries for different SQL dialects.
Query builder for building SELECT ... queries.
Definition Select.hpp:86
LIGHTWEIGHT_API SqlSelectQueryBuilder & FieldAs(std::string_view const &fieldName, std::string_view const &alias)
Adds a single column with an alias to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder & Fields(std::vector< std::string_view > const &fieldNames, std::string_view tableName)
Adds a sequence of columns from the given table to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder & Field(SqlQualifiedTableColumnName const &fieldName)
Adds a single column to the SELECT clause.
SqlSelectQueryBuilder(SqlQueryFormatter const &formatter, std::string table, std::string tableAlias) noexcept
Constructs a SELECT query builder.
Definition Select.hpp:92
SqlSelectQueryBuilder & Fields()
Adds a sequence of columns from the given tables to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder & Fields(std::vector< std::string_view > const &fieldNames)
Adds a sequence of columns to the SELECT clause.
SqlSelectQueryBuilder & Build(Callable const &callable)
Builds the query using a callable.
LIGHTWEIGHT_API SqlSelectQueryBuilder & Fields(std::initializer_list< SqlQualifiedTableColumnName const > fieldNames)
Adds a sequence of qualified table column names to the SELECT clause.
LIGHTWEIGHT_API ComposedQuery First(size_t count=1)
Finalizes building the query as SELECT TOP n field names FROM ... query.
LIGHTWEIGHT_API ComposedQuery All()
Finalizes building the query as SELECT field names FROM ... query.
LIGHTWEIGHT_API SqlSelectQueryBuilder & Field(SqlFieldExpression const &fieldExpression)
Adds an aggregate function call to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder & FieldAs(SqlQualifiedTableColumnName const &fieldName, std::string_view const &alias)
Adds a single column with an alias to the SELECT clause.
LIGHTWEIGHT_FORCE_INLINE SqlQueryFormatter const & Formatter() const noexcept
Returns the SQL query formatter.
Definition Select.hpp:181
LIGHTWEIGHT_API ComposedQuery Count()
Finalizes building the query as SELECT COUNT(*) ... query.
LIGHTWEIGHT_FORCE_INLINE SqlSearchCondition & SearchCondition() noexcept
Returns the search condition for the query.
Definition Select.hpp:173
LIGHTWEIGHT_API SqlSelectQueryBuilder & Fields(std::span< SqlQualifiedTableColumnName const > fieldNames)
Adds a sequence of qualified table column names to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder & As(std::string_view alias)
Aliases the last added field (a column or an aggregate call) in the SELECT clause.
constexpr LIGHTWEIGHT_FORCE_INLINE SqlSelectQueryBuilder & Varying() noexcept
Sets the builder mode to Varying, allowing varying final query types.
Definition Select.hpp:103
LIGHTWEIGHT_API SqlSelectQueryBuilder & Field(std::string_view const &fieldName)
Adds a single column to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder & Fields(std::initializer_list< std::string_view > const &fieldNames, std::string_view tableName)
Adds a sequence of columns from the given table to the SELECT clause.
LIGHTWEIGHT_API ComposedQuery Range(std::size_t offset, std::size_t limit)
Finalizes building the query as SELECT field names FROM ... query with a range.
Represents a single column in a table.
Definition Field.hpp:84
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