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