Lightweight 0.20261105.1
Loading...
Searching...
No Matches
Select.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "../DataMapper/Record.hpp"
6#include "../SqlQueryFormatter.hpp"
7#include "../Utils.hpp"
8#include "Core.hpp"
9
10#include <reflection-cpp/reflection.hpp>
11
12#include <span>
13#include <utility>
14
15namespace Lightweight
16{
17
18namespace Aggregate
19{
20
21 inline SqlFieldExpression Count(std::string_view field = "*") noexcept
22 {
23 if (field == "*")
24 return SqlFieldExpression { .expression = "COUNT(*)" };
25 return SqlFieldExpression { .expression = std::format("COUNT(\"{}\")", field) };
26 }
27
28 inline SqlFieldExpression Count(SqlQualifiedTableColumnName const& field) noexcept
29 {
30 if (field.columnName == "*")
31 return SqlFieldExpression { .expression = std::format(R"(COUNT("{}".*))", field.tableName) };
32 return SqlFieldExpression { .expression = std::format(R"(COUNT("{}"."{}"))", field.tableName, field.columnName) };
33 }
34
35 inline SqlFieldExpression Sum(std::string_view field) noexcept
36 {
37 return SqlFieldExpression { .expression = std::format("SUM(\"{}\")", field) };
38 }
39
40 inline SqlFieldExpression Sum(SqlQualifiedTableColumnName const& field) noexcept
41 {
42 return SqlFieldExpression { .expression = std::format(R"(SUM("{}"."{}"))", field.tableName, field.columnName) };
43 }
44
45 inline SqlFieldExpression Avg(std::string_view field) noexcept
46 {
47 return SqlFieldExpression { .expression = std::format("AVG(\"{}\")", field) };
48 }
49
50 inline SqlFieldExpression Avg(SqlQualifiedTableColumnName const& field) noexcept
51 {
52 return SqlFieldExpression { .expression = std::format(R"(AVG("{}"."{}"))", field.tableName, field.columnName) };
53 }
54
55 inline SqlFieldExpression Min(std::string_view field) noexcept
56 {
57 return SqlFieldExpression { .expression = std::format("MIN(\"{}\")", field) };
58 }
59
60 inline SqlFieldExpression Min(SqlQualifiedTableColumnName const& field) noexcept
61 {
62 return SqlFieldExpression { .expression = std::format(R"(MIN("{}"."{}"))", field.tableName, field.columnName) };
63 }
64
65 inline SqlFieldExpression Max(std::string_view field) noexcept
66 {
67 return SqlFieldExpression { .expression = std::format("MAX(\"{}\")", field) };
68 }
69
70 inline 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/// Not constructed directly by user code; obtained by adding a projection
80/// (`Field` / `Fields` / `FieldAs` / `Build`) to a @ref SqlSelectQueryStarter — the
81/// type returned by `SqlQueryBuilder::Select()`. The starter intentionally hides
82/// the finalizers @ref All, @ref First, and @ref Range so that an empty
83/// `Select().All()` (which would emit malformed `SELECT FROM "T"` SQL) fails at
84/// compile time; the gate is in the starter, not here.
85///
86/// @see SqlQueryBuilder
87/// @see SqlSelectQueryStarter
88class [[nodiscard]] SqlSelectQueryBuilder: public SqlBasicSelectQueryBuilder<SqlSelectQueryBuilder>
89{
90 public:
91 /// The select query type alias.
92 using SelectType = detail::SelectType;
93
94 /// Constructs a SELECT query builder.
95 ///
96 /// @param formatter Dialect the query is written in.
97 /// @param table Table to select from.
98 /// @param tableAlias Alias for that table, empty for none.
99 /// @param inputBindings Receives the WHERE values as bound parameters instead of having them
100 /// written into the query text; null keeps them inline. Values are
101 /// appended, never cleared. Execute the result with
102 /// SqlStatement::ExecuteWithVariants(), not ExecuteDirect(), which would
103 /// leave the markers unbound. Both the vector and anything a stored
104 /// std::string_view / std::u16string_view points at must outlive the
105 /// execution, because the binder hands the driver that pointer directly.
106 /// @note An explicit SqlWildcard emits its marker without recording a value here, and a
107 /// WhereIn() set larger than SqlMaxBoundSetSize falls back to inline literals; either
108 /// makes the marker count differ from the vector size. A finalizer (All(), First(),
109 /// Count(), Range()) moves the query out of the builder, so keep building only until the
110 /// first one: a Where() issued afterwards still appends here while its marker is gone.
111 explicit SqlSelectQueryBuilder(SqlQueryFormatter const& formatter,
112 std::string table,
113 std::string tableAlias,
114 std::vector<SqlVariant>* inputBindings = nullptr) noexcept:
115 SqlBasicSelectQueryBuilder<SqlSelectQueryBuilder> {},
116 _formatter { formatter }
117 {
118 _query.formatter = &formatter;
119 _query.searchCondition.tableName = std::move(table);
120 _query.searchCondition.tableAlias = std::move(tableAlias);
121 _query.searchCondition.inputBindings = inputBindings;
122 _query.fields.reserve(256);
123 }
124
125 /// Adds a sequence of columns to the SELECT clause.
126 template <typename... MoreFields>
127 SqlSelectQueryBuilder& Fields(std::string_view const& firstField, MoreFields const&... moreFields);
128
129 /// Adds a single column to the SELECT clause.
130 LIGHTWEIGHT_API SqlSelectQueryBuilder& Field(std::string_view const& fieldName);
131
132 /// @copydoc Field(std::string_view const&)
133 /// Const overload: delegates via const_cast — see @ref Count() const.
134 [[nodiscard]] LIGHTWEIGHT_API SqlSelectQueryBuilder const& Field(std::string_view const& fieldName) const;
135
136 /// Adds a single column to the SELECT clause.
137 LIGHTWEIGHT_API SqlSelectQueryBuilder& Field(SqlQualifiedTableColumnName const& fieldName);
138
139 /// @copydoc Field(SqlQualifiedTableColumnName const&)
140 /// Const overload: delegates via const_cast — see @ref Count() const.
141 [[nodiscard]] LIGHTWEIGHT_API SqlSelectQueryBuilder const& Field(SqlQualifiedTableColumnName const& fieldName) const;
142
143 /// Adds an aggregate function call to the SELECT clause.
144 LIGHTWEIGHT_API SqlSelectQueryBuilder& Field(SqlFieldExpression const& fieldExpression);
145
146 /// @copydoc Field(SqlFieldExpression const&)
147 /// Const overload: delegates via const_cast — see @ref Count() const.
148 [[nodiscard]] LIGHTWEIGHT_API SqlSelectQueryBuilder const& Field(SqlFieldExpression const& fieldExpression) const;
149
150 /// Aliases the last added field (a column or an aggregate call) in the SELECT clause.
151 LIGHTWEIGHT_API SqlSelectQueryBuilder& As(std::string_view alias);
152
153 /// @copydoc As
154 /// Const overload: delegates via const_cast — see @ref Count() const.
155 [[nodiscard]] LIGHTWEIGHT_API SqlSelectQueryBuilder const& As(std::string_view alias) const;
156
157 /// Adds a sequence of columns to the SELECT clause.
158 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::vector<std::string_view> const& fieldNames);
159
160 /// @copydoc Fields(std::vector<std::string_view> const&)
161 /// Const overload: delegates via const_cast — see @ref Count() const.
162 [[nodiscard]] LIGHTWEIGHT_API SqlSelectQueryBuilder const& Fields(std::vector<std::string_view> const& fieldNames) const;
163
164 /// Adds a sequence of columns from the given table to the SELECT clause.
165 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::vector<std::string_view> const& fieldNames,
166 std::string_view tableName);
167
168 /// @copydoc Fields(std::vector<std::string_view> const&, std::string_view)
169 /// Const overload: delegates via const_cast — see @ref Count() const.
170 [[nodiscard]] LIGHTWEIGHT_API SqlSelectQueryBuilder const& Fields(std::vector<std::string_view> const& fieldNames,
171 std::string_view tableName) const;
172
173 /// Adds a sequence of columns from the given table to the SELECT clause.
174 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::initializer_list<std::string_view> const& fieldNames,
175 std::string_view tableName);
176
177 /// @copydoc Fields(std::initializer_list<std::string_view> const&, std::string_view)
178 /// Const overload: delegates via const_cast — see @ref Count() const.
179 [[nodiscard]] LIGHTWEIGHT_API SqlSelectQueryBuilder const& Fields(
180 std::initializer_list<std::string_view> const& fieldNames, std::string_view tableName) const;
181
182 /// Adds a sequence of qualified table column names to the SELECT clause.
183 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::span<SqlQualifiedTableColumnName const> fieldNames);
184
185 /// @copydoc Fields(std::span<SqlQualifiedTableColumnName const>)
186 /// Const overload: delegates via const_cast — see @ref Count() const.
187 [[nodiscard]] LIGHTWEIGHT_API SqlSelectQueryBuilder const& Fields(
188 std::span<SqlQualifiedTableColumnName const> fieldNames) const;
189
190 /// Adds a sequence of qualified table column names to the SELECT clause.
191 LIGHTWEIGHT_API SqlSelectQueryBuilder& Fields(std::initializer_list<SqlQualifiedTableColumnName const> fieldNames);
192
193 /// @copydoc Fields(std::initializer_list<SqlQualifiedTableColumnName const>)
194 /// Const overload: delegates via const_cast — see @ref Count() const.
195 [[nodiscard]] LIGHTWEIGHT_API SqlSelectQueryBuilder const& Fields(
196 std::initializer_list<SqlQualifiedTableColumnName const> fieldNames) const;
197
198 /// Adds a sequence of columns from the given tables to the SELECT clause.
199 template <typename FirstRecord, typename... MoreRecords>
201
202 /// Adds a single column with an alias to the SELECT clause.
203 [[deprecated("Use Field(...).As(\"alias\") instead.")]]
204 LIGHTWEIGHT_API SqlSelectQueryBuilder& FieldAs(std::string_view const& fieldName, std::string_view const& alias);
205
206 /// Adds a single column with an alias to the SELECT clause.
207 [[deprecated("Use Field(...).As(\"alias\") instead.")]]
209 std::string_view const& alias);
210
211 /// Builds the query using a callable.
212 template <typename Callable>
213 SqlSelectQueryBuilder& Build(Callable const& callable);
214
215 /// Asks for a dirty read of every table the statement reads, where the dialect has a per-table hint
216 /// for it (SQL Server: `WITH (READUNCOMMITTED)`); other dialects render the statement unchanged.
217 ///
218 /// The hint follows the FROM table (and its alias) and each joined table (and its alias), in every
219 /// finalizer (All(), First(), Range(), Count()). Only this statement is affected: the connection's
220 /// transaction isolation level is left alone, so it also works inside an open transaction.
221 ///
222 /// @note Call it before any join. A join renders its table reference as it is attached, so a join
223 /// added earlier is read without the hint.
224 /// @note A sub-select is a builder of its own and opts in separately.
225 /// @return This builder, for chaining.
226 LIGHTWEIGHT_API SqlSelectQueryBuilder& ReadUncommitted() noexcept;
227
228 /// Finalizes building the query as SELECT COUNT(*) ... query.
229 ///
230 /// A preceding @c GroupBy is honored: the query then counts the rows of each group and
231 /// yields one row per group, rather than a single total over the whole result set.
232 LIGHTWEIGHT_API ComposedQuery Count();
233
234 /// @copydoc Count
235 /// Const overload: doesn't mutate @c *this — returns a snapshot ComposedQuery
236 /// so the finalizer can be reached through a `const SqlSelectQueryBuilder`.
237 [[nodiscard]] LIGHTWEIGHT_API ComposedQuery Count() const;
238
239 /// Finalizes building the query as SELECT field names FROM ... query.
240 LIGHTWEIGHT_API ComposedQuery All();
241
242 /// @copydoc All
243 /// Const overload: doesn't mutate @c *this — see @ref Count() const.
244 [[nodiscard]] LIGHTWEIGHT_API ComposedQuery All() const;
245
246 /// Finalizes building the query as SELECT TOP n field names FROM ... query.
247 LIGHTWEIGHT_API ComposedQuery First(size_t count = 1);
248
249 /// @copydoc First
250 /// Const overload: doesn't mutate @c *this — see @ref Count() const.
251 [[nodiscard]] LIGHTWEIGHT_API ComposedQuery First(size_t count = 1) const;
252
253 /// Finalizes building the query as SELECT field names FROM ... query with a range.
254 LIGHTWEIGHT_API ComposedQuery Range(std::size_t offset, std::size_t limit);
255
256 /// @copydoc Range
257 /// Const overload: doesn't mutate @c *this — see @ref Count() const.
258 [[nodiscard]] LIGHTWEIGHT_API ComposedQuery Range(std::size_t offset, std::size_t limit) const;
259
260 /// Returns the search condition for the query.
261 LIGHTWEIGHT_FORCE_INLINE SqlSearchCondition& SearchCondition() noexcept
262 {
263 return _query.searchCondition;
264 }
265
266 /// Returns the SQL query formatter.
267 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE SqlQueryFormatter const& Formatter() const noexcept
268 {
269 return _formatter;
270 }
271
272 private:
273 /// @brief Records @p name as the caller-given name of the projection just appended.
274 ///
275 /// Pass an empty @p name for a projection the caller did not name (an un-aliased aggregate); the
276 /// slot still holds its position so later entries stay aligned with their result columns.
277 /// @param name The column name exactly as the caller spelled it, or empty for an unnamed projection.
278 LIGHTWEIGHT_API void RecordProjectedFieldName(std::string name) const;
279
280 /// @brief Replaces the name of the most recently recorded projection, backing @c As().
281 /// @param alias The alias the caller gave the projection.
282 LIGHTWEIGHT_API void RenameLastProjectedFieldName(std::string_view alias) const;
283
284 /// @brief Marks the projection as containing a wildcard, disabling named column access.
285 LIGHTWEIGHT_API void RecordProjectionWildcard() const;
286
287 SqlQueryFormatter const& _formatter;
288 // mutable: see the note on _query in SqlBasicSelectQueryBuilder — the alias
289 // flag is part of the projection accumulator, so it follows _query's policy.
290 // Marked mutable so the const-qualified Field/Fields/As overloads above can
291 // delegate to their non-const counterparts via const_cast.
292 mutable bool _aliasAllowed = false;
293};
294
295template <typename... MoreFields>
296SqlSelectQueryBuilder& SqlSelectQueryBuilder::Fields(std::string_view const& firstField, MoreFields const&... moreFields)
297{
298 using namespace std::string_view_literals;
299
300 std::ostringstream fragment;
301
302 if (!_query.fields.empty())
303 fragment << ", "sv;
304
305 fragment << '"' << firstField << '"';
306 RecordProjectedFieldName(std::string(firstField));
307
308 if constexpr (sizeof...(MoreFields) > 0)
309 (((fragment << R"(, ")"sv << moreFields << '"'),
310 RecordProjectedFieldName(std::string(std::string_view(moreFields)))),
311 ...);
312
313 _query.fields += fragment.str();
314 return *this;
315}
316
317/// Builds the query using a callable.
318template <typename Callable>
319inline LIGHTWEIGHT_FORCE_INLINE SqlSelectQueryBuilder& SqlSelectQueryBuilder::Build(Callable const& callable)
320{
321 callable(*this);
322 return *this;
323}
324
325/// Adds fields from one or more record types to the SELECT clause.
326template <typename FirstRecord, typename... MoreRecords>
327inline LIGHTWEIGHT_FORCE_INLINE SqlSelectQueryBuilder& SqlSelectQueryBuilder::Fields()
328{
329 // Relations (HasMany, HasManyThrough, HasOneThrough, ...) have no column of their own and
330 // must not be projected into the SELECT clause.
331 if constexpr (sizeof...(MoreRecords) == 0)
332 {
333 EnumerateRecordMembers<FirstRecord>([&]<size_t FieldIndex, typename FieldType>() {
334 if constexpr (RecordColumnMember<FieldType>)
335 Field(FieldNameAt<FieldIndex, FirstRecord>);
336 });
337 }
338 else
339 {
340 EnumerateRecordMembers<FirstRecord>([&]<size_t FieldIndex, typename FieldType>() {
341 if constexpr (RecordColumnMember<FieldType>)
343 .tableName = RecordTableName<FirstRecord>,
344 .columnName = FieldNameAt<FieldIndex, FirstRecord>,
345 });
346 });
347
348 (EnumerateRecordMembers<MoreRecords>([&]<size_t FieldIndex, typename FieldType>() {
349 if constexpr (RecordColumnMember<FieldType>)
351 .tableName = RecordTableName<MoreRecords>,
352 .columnName = FieldNameAt<FieldIndex, MoreRecords>,
353 });
354 }),
355 ...);
356 }
357 return *this;
358}
359
360namespace detail
361{
362 /// Always-false helper that depends on a template parameter so that a
363 /// @c static_assert in a function-template body only fires on instantiation
364 /// (and stays portable across compilers that have not implemented P2593).
365 template <typename...>
366 inline constexpr bool dependent_false = false;
367} // namespace detail
368
369/// @brief Compile-time gate for SELECT query construction.
370///
371/// Returned by `SqlQueryBuilder::Select()`. The starter inherits @em publicly
372/// from `SqlSelectQueryBuilder` (so every projection / WHERE / JOIN method
373/// resolves directly through inheritance), but defines its own @c All,
374/// @c First, and @c Range as deducing-this member templates whose bodies are
375/// ill-formed via @c static_assert. Those locals shadow the corresponding base
376/// methods at name lookup, so:
377///
378/// - `Select().All()`, `Select().First()`, `Select().Range(...)` — and the
379/// two-step variant `auto q = Select(); q.All();` — fail at compile time
380/// with a diagnostic asking the user to add a projection first. Without a
381/// projection these would emit malformed `SELECT FROM "T"` SQL.
382/// - `Select().Field(...).All()` compiles: `Field(...)` is inherited and
383/// returns `SqlSelectQueryBuilder&`, so the subsequent `All()` resolves
384/// against the base type (no shadowing) and reaches the real finalizer.
385/// - @c Count is intentionally not overridden — `SELECT COUNT(*) FROM ...`
386/// is well-formed without an explicit column list, so the inherited
387/// @c Count remains directly callable.
388/// - @c Distinct is overridden via deducing this so it returns @c Self&& and
389/// the starter identity survives it. That keeps the gate intact for
390/// `Select().Distinct().All()` while still allowing
391/// `Select().Distinct().Fields(...).All()`.
392///
393/// Methods that conceptually follow the column list (@c Where, @c OrderBy,
394/// @c GroupBy, @c InnerJoin, @c LeftOuterJoin, etc.) are reachable on the
395/// starter through public inheritance and return `SqlSelectQueryBuilder&`,
396/// which technically lets `Select().WhereNotNull("x").All()` compile (a known
397/// gate leak the type primarily defends against the empty-`Select().All()`
398/// typo, which is far more common).
399///
400/// For the imperative loop pattern, capture the first projection as a builder
401/// reference and continue from there:
402///
403/// @code
404/// auto starter = qb.Select();
405/// auto& query = starter.Field(columns[0].name);
406/// for (size_t i = 1; i < columns.size(); ++i)
407/// query.Field(columns[i].name);
408/// return query.All();
409/// @endcode
410class [[nodiscard]] SqlSelectQueryStarter final: public SqlSelectQueryBuilder
411{
412 public:
413 /// Constructs a SELECT query starter.
414 ///
415 /// Intentionally not @c explicit so the factory in @ref SqlQueryBuilder::Select
416 /// can return via braced init.
417 ///
418 /// @copydetails SqlSelectQueryBuilder::SqlSelectQueryBuilder
420 std::string table,
421 std::string tableAlias,
422 std::vector<SqlVariant>* inputBindings = nullptr) noexcept:
423 SqlSelectQueryBuilder { formatter, std::move(table), std::move(tableAlias), inputBindings }
424 {
425 }
426
427 /// Empty-projection guard for the @c All finalizer.
428 ///
429 /// Instantiating this template emits a @c static_assert telling the caller
430 /// to add a projection first. Calling `All()` on a `SqlSelectQueryBuilder&`
431 /// returned by `Field(...)` / `Fields(...)` bypasses the shadow and reaches
432 /// the real `SqlSelectQueryBuilder::All()`.
433 template <typename Self>
434 auto All(this Self const& self) -> ComposedQuery
435 {
436 (void) self;
437 static_assert(detail::dependent_false<Self>,
438 "SELECT requires a projection. Call .Field(...) or .Fields(...) "
439 "before .All() — an empty projection produces malformed "
440 "`SELECT FROM \"T\"` SQL.");
441 std::unreachable();
442 }
443
444 /// Empty-projection guard for the @c First finalizer — see @ref All.
445 template <typename Self>
446 auto First(this Self const& self, size_t count = 1) -> ComposedQuery
447 {
448 (void) self;
449 (void) count;
450 static_assert(detail::dependent_false<Self>,
451 "SELECT requires a projection. Call .Field(...) or .Fields(...) "
452 "before .First().");
453 std::unreachable();
454 }
455
456 /// Empty-projection guard for the @c Range finalizer — see @ref All.
457 template <typename Self>
458 auto Range(this Self const& self, std::size_t offset, std::size_t limit) -> ComposedQuery
459 {
460 (void) self;
461 (void) offset;
462 (void) limit;
463 static_assert(detail::dependent_false<Self>,
464 "SELECT requires a projection. Call .Field(...) or .Fields(...) "
465 "before .Range().");
466 std::unreachable();
467 }
468
469 /// State-preserving override: returns @c Self&&, so the starter identity
470 /// survives the call and the @c All / @c First / @c Range guards above
471 /// keep their gate against `Select().Distinct().All()`.
472 template <typename Self>
473 LIGHTWEIGHT_FORCE_INLINE auto&& Distinct(this Self&& self) noexcept
474 {
475 self.SqlSelectQueryBuilder::Distinct();
476 return std::forward<Self>(self);
477 }
478
479 /// State-preserving override of @ref SqlSelectQueryBuilder::ReadUncommitted(); returns @c Self&&
480 /// so `Select().ReadUncommitted().All()` stays rejected like `Select().All()`.
481 template <typename Self>
482 LIGHTWEIGHT_FORCE_INLINE auto&& ReadUncommitted(this Self&& self) noexcept
483 {
484 self.SqlSelectQueryBuilder::ReadUncommitted();
485 return std::forward<Self>(self);
486 }
487};
488
489} // namespace Lightweight
API to format SQL queries for different SQL dialects.
Query builder for building SELECT ... queries.
Definition Select.hpp:89
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 const & Field(SqlQualifiedTableColumnName const &fieldName) const
Adds a single column to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder & Field(SqlQualifiedTableColumnName const &fieldName)
Adds a single column to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder const & Fields(std::vector< std::string_view > const &fieldNames) const
Adds a sequence of columns to the SELECT clause.
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.
LIGHTWEIGHT_API SqlSelectQueryBuilder const & Fields(std::initializer_list< std::string_view > const &fieldNames, std::string_view tableName) const
Adds a sequence of columns from the given table 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 SqlSelectQueryBuilder const & Field(std::string_view const &fieldName) const
Adds a single column to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder const & As(std::string_view alias) const
Aliases the last added field (a column or an aggregate call) in the SELECT clause.
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_API SqlSelectQueryBuilder const & Fields(std::vector< std::string_view > const &fieldNames, std::string_view tableName) const
Adds a sequence of columns from the given table to the SELECT clause.
LIGHTWEIGHT_FORCE_INLINE SqlQueryFormatter const & Formatter() const noexcept
Returns the SQL query formatter.
Definition Select.hpp:267
LIGHTWEIGHT_API SqlSelectQueryBuilder const & Field(SqlFieldExpression const &fieldExpression) const
Adds an aggregate function call to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder const & Fields(std::initializer_list< SqlQualifiedTableColumnName const > fieldNames) const
Adds a sequence of qualified table column names to the SELECT clause.
SqlSelectQueryBuilder(SqlQueryFormatter const &formatter, std::string table, std::string tableAlias, std::vector< SqlVariant > *inputBindings=nullptr) noexcept
Definition Select.hpp:111
LIGHTWEIGHT_API SqlSelectQueryBuilder & Fields(std::span< SqlQualifiedTableColumnName const > fieldNames)
Adds a sequence of qualified table column names to the SELECT clause.
LIGHTWEIGHT_API SqlSelectQueryBuilder & ReadUncommitted() noexcept
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 const & Fields(std::span< SqlQualifiedTableColumnName const > fieldNames) const
Adds a sequence of qualified table column names to the SELECT clause.
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.
Compile-time gate for SELECT query construction.
Definition Select.hpp:411
LIGHTWEIGHT_FORCE_INLINE auto && ReadUncommitted(this Self &&self) noexcept
State-preserving override of SqlSelectQueryBuilder::ReadUncommitted(); returns Self&& so Select()....
Definition Select.hpp:482
auto All(this Self const &self) -> ComposedQuery
Empty-projection guard for the All finalizer.
Definition Select.hpp:434
SqlSelectQueryStarter(SqlQueryFormatter const &formatter, std::string table, std::string tableAlias, std::vector< SqlVariant > *inputBindings=nullptr) noexcept
Constructs a SELECT query starter.
Definition Select.hpp:419
LIGHTWEIGHT_FORCE_INLINE auto && Distinct(this Self &&self) noexcept
State-preserving override: returns Self&&, so the starter identity survives the call and the All / Fi...
Definition Select.hpp:473
auto Range(this Self const &self, std::size_t offset, std::size_t limit) -> ComposedQuery
Empty-projection guard for the Range finalizer — see All.
Definition Select.hpp:458
auto First(this Self const &self, size_t count=1) -> ComposedQuery
Empty-projection guard for the First finalizer — see All.
Definition Select.hpp:446
Requires that T maps onto a column of its record's table.
Definition Record.hpp:419
@ Count
Number of enumerators; not an operation itself.
Represents a single column in a table.
Definition Field.hpp:154
A SQL expression usable as a projection or as the left side of a HAVING term.
Definition Core.hpp:811
std::string expression
The SQL text of the expression.
Definition Core.hpp:813
SqlQualifiedTableColumnName represents a column name qualified with a table name.
Definition Utils.hpp:342
std::string_view tableName
The table name.
Definition Utils.hpp:344