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