Lightweight 0.20260303.0
Loading...
Searching...
No Matches
QueryBuilders.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "../SqlConnection.hpp"
6#include "../SqlQueryFormatter.hpp"
7#include "../SqlStatement.hpp"
8#include "../Utils.hpp"
9#include "BelongsTo.hpp"
10#include "Field.hpp"
11#include "Record.hpp"
12
13namespace Lightweight
14{
15
16class DataMapper;
17
18/// Structural type for options for DataMapper queries.
19/// This allows to configure behavior of the queries at compile time
20/// when using query builder directly from the DataMapper
22{
23 /// Whether to automatically load relations when querying records.
24 bool loadRelations { true };
25};
26
27/// Main API for mapping records to C++ from the database using high level C++ syntax.
28///
29/// @ingroup DataMapper
30template <typename Record, typename Derived, DataMapperOptions QueryOptions = {}>
31class [[nodiscard]] SqlCoreDataMapperQueryBuilder: public SqlBasicSelectQueryBuilder<Derived>
32{
33 private:
34 DataMapper& _dm;
35 SqlQueryFormatter const& _formatter;
36
37 std::string _fields;
38 std::vector<SqlVariant> _boundInputs;
39
40 friend class SqlWhereClauseBuilder<Derived>;
41
42 LIGHTWEIGHT_FORCE_INLINE SqlSearchCondition& SearchCondition() noexcept
43 {
44 return this->_query.searchCondition;
45 }
46
47 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE SqlQueryFormatter const& Formatter() const noexcept
48 {
49 return _formatter;
50 }
51
52 protected:
53 /// Constructs a query builder with the given data mapper and field list.
54 LIGHTWEIGHT_FORCE_INLINE explicit SqlCoreDataMapperQueryBuilder(DataMapper& dm, std::string fields) noexcept;
55
56 public:
57 /// Executes a SELECT 1 ... query and returns true if a record exists
58 /// We do not provide db specific syntax to check this but reuse the First() implementation
59 [[nodiscard]] bool Exist();
60
61 /// Executes a SELECT COUNT query and returns the number of records found.
62 [[nodiscard]] size_t Count();
63
64 /// Executes a SELECT query and returns all records found.
65 [[nodiscard]] std::vector<Record> All();
66
67 /// Executes a DELETE query.
68 void Delete();
69
70 /// @brief Executes a SELECT query and returns all records found for the specified field.
71 ///
72 /// @tparam Field The field to select from the record, in the form of &Record::FieldName.
73 ///
74 /// @returns A vector of values of the type of the specified field.
75 ///
76 /// @code
77 /// auto dm = DataMapper {};
78 /// auto const ages = dm.Query<Person>()
79 /// .OrderBy(FieldNameOf<&Person::age>, SqlResultOrdering::ASCENDING)
80 /// .All<&Person::age>();
81 /// @endcode
82 template <auto Field>
83#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
84 requires(is_aggregate_type(parent_of(Field)))
85#else
86 requires std::is_member_object_pointer_v<decltype(Field)>
87#endif
88 [[nodiscard]] auto All() -> std::vector<ReferencedFieldTypeOf<Field>>;
89
90 /// @brief Executes a SELECT query and returns all records found for the specified field,
91 /// only having the specified fields queried and populated.
92 ///
93 /// @tparam ReferencedFields The fields to select from the record, in the form of &Record::FieldName.
94 ///
95 /// @returns A vector of records with the given fields populated.
96 ///
97 /// @code
98 /// auto dm = DataMapper {};
99 /// auto const ages = dm.Query<Person>()
100 /// .OrderBy(FieldNameOf<&Person::age>, SqlResultOrdering::ASCENDING)
101 /// .All<&Person::name, &Person::age>();
102 /// @endcode
103 template <auto... ReferencedFields>
104 requires(sizeof...(ReferencedFields) >= 2)
105 [[nodiscard]] auto All() -> std::vector<Record>;
106
107 /// Executes a SELECT query for the first record found and returns it.
108 [[nodiscard]] std::optional<Record> First();
109
110 /// @brief Executes the query to get a single scalar value from the first record found.
111 ///
112 /// @tparam Field The field to select from the record, in the form of &Record::FieldName.
113 ///
114 /// @returns an optional value of the type of the field, or an empty optional if no record was found.
115 template <auto Field>
116#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
117 requires(is_aggregate_type(parent_of(Field)))
118#else
119 requires std::is_member_object_pointer_v<decltype(Field)>
120#endif
121 auto First() -> std::optional<ReferencedFieldTypeOf<Field>>;
122
123 /// @brief Executes a SELECT query for the first record found and returns it with only the specified fields populated.
124 ///
125 /// @tparam ReferencedFields The fields to select from the record, in the form of &Record::FieldName.
126 ///
127 /// @returns an optional record with only the specified fields populated, or an empty optional if no record was found.
128 template <auto... ReferencedFields>
129 requires(sizeof...(ReferencedFields) >= 2)
130 [[nodiscard]] auto First() -> std::optional<Record>;
131
132 /// Executes a SELECT query for the first n records found and returns them.
133 [[nodiscard]] std::vector<Record> First(size_t n);
134
135 /// Executes a SELECT query for the first n records with only the specified fields populated.
136 template <auto... ReferencedFields>
137 [[nodiscard]] std::vector<Record> First(size_t n);
138
139 /// Executes a SELECT query for a range of records and returns them.
140 [[nodiscard]] std::vector<Record> Range(size_t offset, size_t limit);
141
142 /// Executes a SELECT query for a range of records with only the specified fields populated.
143 template <auto... ReferencedFields>
144 [[nodiscard]] std::vector<Record> Range(size_t offset, size_t limit);
145};
146
147/// @brief Represents a query builder that retrieves all fields of a record.
148///
149/// @ingroup DataMapper
150template <typename Record, DataMapperOptions QueryOptions>
151class [[nodiscard]] SqlAllFieldsQueryBuilder final:
152 public SqlCoreDataMapperQueryBuilder<Record, SqlAllFieldsQueryBuilder<Record, QueryOptions>, QueryOptions>
153{
154 private:
155 friend class DataMapper;
156 friend class SqlCoreDataMapperQueryBuilder<Record, SqlAllFieldsQueryBuilder<Record, QueryOptions>, QueryOptions>;
157
158 LIGHTWEIGHT_FORCE_INLINE explicit SqlAllFieldsQueryBuilder(DataMapper& dm, std::string fields) noexcept:
160 dm, std::move(fields)
161 }
162 {
163 }
164
165 static void ReadResults(SqlServerType sqlServerType, SqlResultCursor reader, std::vector<Record>* records);
166 static void ReadResult(SqlServerType sqlServerType, SqlResultCursor reader, std::optional<Record>* optionalRecord);
167};
168
169/// @brief Specialization of SqlAllFieldsQueryBuilder for the case when we return std::tuple
170/// of two records
171///
172/// @ingroup DataMapper
173/// @todo deprecate this in favor of a more generic tuple support
174template <typename FirstRecord, typename SecondRecord, DataMapperOptions QueryOptions>
175class [[nodiscard]] SqlAllFieldsQueryBuilder<std::tuple<FirstRecord, SecondRecord>, QueryOptions> final:
176 public SqlCoreDataMapperQueryBuilder<std::tuple<FirstRecord, SecondRecord>,
177 SqlAllFieldsQueryBuilder<std::tuple<FirstRecord, SecondRecord>, QueryOptions>,
178 QueryOptions>
179{
180 private:
181 using RecordType = std::tuple<FirstRecord, SecondRecord>;
182 friend class DataMapper;
183 friend class SqlCoreDataMapperQueryBuilder<RecordType, SqlAllFieldsQueryBuilder<RecordType, QueryOptions>>;
184
185 LIGHTWEIGHT_FORCE_INLINE explicit SqlAllFieldsQueryBuilder(DataMapper& dm, std::string fields) noexcept:
187 dm, std::move(fields)
188 }
189 {
190 }
191
192 static void ReadResults(SqlServerType sqlServerType, SqlResultCursor reader, std::vector<RecordType>* records);
193};
194
195} // namespace Lightweight
Main API for mapping records to and from the database using high level C++ syntax.
Represents a query builder that retrieves all fields of a record.
auto First() -> std::optional< Record >
Executes a SELECT query for the first record found and returns it with only the specified fields popu...
auto All() -> std::vector< Record >
Executes a SELECT query and returns all records found for the specified field, only having the specif...
API to format SQL queries for different SQL dialects.
API for reading an SQL query result set.
bool loadRelations
Whether to automatically load relations when querying records.
Represents a single column in a table.
Definition Field.hpp:84