5#include "../DataMapper/Record.hpp"
6#include "../SqlQueryFormatter.hpp"
10#include <reflection-cpp/reflection.hpp>
18struct [[nodiscard]] SqlFieldExpression final
20 std::string expression;
26 inline SqlFieldExpression
Count(std::string_view field =
"*") noexcept
29 return SqlFieldExpression { .expression =
"COUNT(*)" };
30 return SqlFieldExpression { .expression = std::format(
"COUNT(\"{}\")", field) };
33 inline SqlFieldExpression
Count(SqlQualifiedTableColumnName
const& field)
noexcept
35 if (field.columnName ==
"*")
36 return SqlFieldExpression { .expression = std::format(R
"(COUNT("{}".*))", field.tableName) };
37 return SqlFieldExpression { .expression = std::format(R
"(COUNT("{}"."{}"))", field.tableName, field.columnName) };
40 inline SqlFieldExpression Sum(std::string_view field)
noexcept
42 return SqlFieldExpression { .expression = std::format(
"SUM(\"{}\")", field) };
45 inline SqlFieldExpression Sum(SqlQualifiedTableColumnName
const& field)
noexcept
47 return SqlFieldExpression { .expression = std::format(R
"(SUM("{}"."{}"))", field.tableName, field.columnName) };
50 inline SqlFieldExpression Avg(std::string_view field)
noexcept
52 return SqlFieldExpression { .expression = std::format(
"AVG(\"{}\")", field) };
55 inline SqlFieldExpression Avg(SqlQualifiedTableColumnName
const& field)
noexcept
57 return SqlFieldExpression { .expression = std::format(R
"(AVG("{}"."{}"))", field.tableName, field.columnName) };
60 inline SqlFieldExpression Min(std::string_view field)
noexcept
62 return SqlFieldExpression { .expression = std::format(
"MIN(\"{}\")", field) };
65 inline SqlFieldExpression Min(SqlQualifiedTableColumnName
const& field)
noexcept
67 return SqlFieldExpression { .expression = std::format(R
"(MIN("{}"."{}"))", field.tableName, field.columnName) };
70 inline SqlFieldExpression Max(std::string_view field)
noexcept
72 return SqlFieldExpression { .expression = std::format(
"MAX(\"{}\")", field) };
75 inline SqlFieldExpression Max(SqlQualifiedTableColumnName
const& field)
noexcept
77 return SqlFieldExpression { .expression = std::format(R
"(MAX("{}"."{}"))", field.tableName, field.columnName) };
97 using SelectType = detail::SelectType;
118 std::string tableAlias,
119 std::vector<SqlVariant>* inputBindings =
nullptr) noexcept:
121 _formatter { formatter }
123 _query.formatter = &formatter;
124 _query.searchCondition.tableName = std::move(table);
125 _query.searchCondition.tableAlias = std::move(tableAlias);
126 _query.searchCondition.inputBindings = inputBindings;
127 _query.fields.reserve(256);
131 template <
typename... MoreFields>
132 SqlSelectQueryBuilder& Fields(std::string_view
const& firstField, MoreFields&&... moreFields);
171 std::string_view tableName);
176 std::string_view tableName)
const;
180 std::string_view tableName);
185 std::initializer_list<std::string_view>
const& fieldNames, std::string_view tableName)
const;
193 std::span<SqlQualifiedTableColumnName const> fieldNames)
const;
201 std::initializer_list<SqlQualifiedTableColumnName const> fieldNames)
const;
204 template <
typename FirstRecord,
typename... MoreRecords>
208 [[deprecated(
"Use Field(...).As(\"alias\") instead.")]]
212 [[deprecated(
"Use Field(...).As(\"alias\") instead.")]]
214 std::string_view
const& alias);
217 template <
typename Callable>
224 LIGHTWEIGHT_API ComposedQuery
Count();
229 [[nodiscard]] LIGHTWEIGHT_API ComposedQuery
Count()
const;
232 LIGHTWEIGHT_API ComposedQuery
All();
236 [[nodiscard]] LIGHTWEIGHT_API ComposedQuery
All()
const;
239 LIGHTWEIGHT_API ComposedQuery
First(
size_t count = 1);
243 [[nodiscard]] LIGHTWEIGHT_API ComposedQuery
First(
size_t count = 1)
const;
246 LIGHTWEIGHT_API ComposedQuery
Range(std::size_t offset, std::size_t limit);
250 [[nodiscard]] LIGHTWEIGHT_API ComposedQuery
Range(std::size_t offset, std::size_t limit)
const;
257 return _query.searchCondition;
274 LIGHTWEIGHT_API
void RecordProjectedFieldName(std::string name)
const;
278 LIGHTWEIGHT_API
void RenameLastProjectedFieldName(std::string_view alias)
const;
281 LIGHTWEIGHT_API
void RecordProjectionWildcard()
const;
288 mutable bool _aliasAllowed =
false;
291template <
typename... MoreFields>
294 using namespace std::string_view_literals;
296 std::ostringstream fragment;
298 if (!_query.fields.empty())
301 fragment <<
'"' << firstField <<
'"';
302 RecordProjectedFieldName(std::string(firstField));
304 if constexpr (
sizeof...(MoreFields) > 0)
305 (((fragment << R
"(, ")"sv << std::forward<MoreFields>(moreFields) << '"'),
306 RecordProjectedFieldName(std::string(std::string_view(moreFields)))),
309 _query.fields += fragment.str();
314template <
typename Callable>
322template <
typename FirstRecord,
typename... MoreRecords>
327 if constexpr (
sizeof...(MoreRecords) == 0)
329 EnumerateRecordMembers<FirstRecord>([&]<
size_t FieldIndex,
typename FieldType>() {
331 Field(FieldNameAt<FieldIndex, FirstRecord>);
336 EnumerateRecordMembers<FirstRecord>([&]<
size_t FieldIndex,
typename FieldType>() {
339 .
tableName = RecordTableName<FirstRecord>,
340 .columnName = FieldNameAt<FieldIndex, FirstRecord>,
344 (EnumerateRecordMembers<MoreRecords>([&]<
size_t FieldIndex,
typename FieldType>() {
347 .
tableName = RecordTableName<MoreRecords>,
348 .columnName = FieldNameAt<FieldIndex, MoreRecords>,
361 template <
typename...>
362 inline constexpr bool dependent_false =
false;
417 std::string tableAlias,
418 std::vector<SqlVariant>* inputBindings =
nullptr) noexcept:
429 template <
typename Self>
430 auto All(
this Self
const& self) -> ComposedQuery
433 static_assert(detail::dependent_false<Self>,
434 "SELECT requires a projection. Call .Field(...) or .Fields(...) "
435 "before .All() — an empty projection produces malformed "
436 "`SELECT FROM \"T\"` SQL.");
441 template <
typename Self>
442 auto First(
this Self
const& self,
size_t count = 1) -> ComposedQuery
446 static_assert(detail::dependent_false<Self>,
447 "SELECT requires a projection. Call .Field(...) or .Fields(...) "
453 template <
typename Self>
454 auto Range(
this Self
const& self, std::size_t offset, std::size_t limit) -> ComposedQuery
459 static_assert(detail::dependent_false<Self>,
460 "SELECT requires a projection. Call .Field(...) or .Fields(...) "
468 template <
typename Self>
469 LIGHTWEIGHT_FORCE_INLINE
auto&&
Distinct(
this Self&& self)
noexcept
471 self.SqlSelectQueryBuilder::Distinct();
472 return std::forward<Self>(self);
Query builder for building SELECT ... queries.
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 ComposedQuery First(size_t count=1) const
Finalizes building the query as SELECT TOP n field names FROM ... query.
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 ComposedQuery First(size_t count=1)
Finalizes building the query as SELECT TOP n field names FROM ... query.
LIGHTWEIGHT_API ComposedQuery All() const
Finalizes building the query as SELECT field names FROM ... query.
LIGHTWEIGHT_API SqlSelectQueryBuilder const & Field(std::string_view const &fieldName) const
Adds a single column to the SELECT clause.
LIGHTWEIGHT_API ComposedQuery All()
Finalizes building the query as SELECT field names FROM ... query.
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 ComposedQuery Range(std::size_t offset, std::size_t limit) const
Finalizes building the query as SELECT field names FROM ... query with a range.
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.
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
LIGHTWEIGHT_API ComposedQuery Count()
LIGHTWEIGHT_FORCE_INLINE SqlSearchCondition & SearchCondition() noexcept
Returns the search condition for the query.
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.
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 ComposedQuery Count() const
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.
Compile-time gate for SELECT query construction.
auto All(this Self const &self) -> ComposedQuery
Empty-projection guard for the All finalizer.
SqlSelectQueryStarter(SqlQueryFormatter const &formatter, std::string table, std::string tableAlias, std::vector< SqlVariant > *inputBindings=nullptr) noexcept
Constructs a SELECT query starter.
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...
auto Range(this Self const &self, std::size_t offset, std::size_t limit) -> ComposedQuery
Empty-projection guard for the Range finalizer — see All.
auto First(this Self const &self, size_t count=1) -> ComposedQuery
Empty-projection guard for the First finalizer — see All.
Requires that T maps onto a column of its record's table.
@ Count
Number of enumerators; not an operation itself.
Represents a single column in a table.
SqlQualifiedTableColumnName represents a column name qualified with a table name.
std::string_view tableName
The table name.