Lightweight 0.20251201.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 /// This is the default behavior since compilation times significantly increase otherwise.
24 bool loadRelations { false };
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
39 friend class SqlWhereClauseBuilder<Derived>;
40
41 LIGHTWEIGHT_FORCE_INLINE SqlSearchCondition& SearchCondition() noexcept
42 {
43 return this->_query.searchCondition;
44 }
45
46 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE SqlQueryFormatter const& Formatter() const noexcept
47 {
48 return _formatter;
49 }
50
51 protected:
52 LIGHTWEIGHT_FORCE_INLINE explicit SqlCoreDataMapperQueryBuilder(DataMapper& dm, std::string fields) noexcept;
53
54 public:
55 /// Executes a SELECT 1 ... query and returns true if a record exists
56 /// We do not provide db specific syntax to check this but reuse the First() implementation
57 [[nodiscard]] bool Exist();
58
59 /// Executes a SELECT COUNT query and returns the number of records found.
60 [[nodiscard]] size_t Count();
61
62 /// Executes a SELECT query and returns all records found.
63 [[nodiscard]] std::vector<Record> All();
64
65 /// Executes a DELETE query.
66 void Delete();
67
68 /// @brief Executes a SELECT query and returns all records found for the specified field.
69 ///
70 /// @tparam Field The field to select from the record, in the form of &Record::FieldName.
71 ///
72 /// @returns A vector of values of the type of the specified field.
73 ///
74 /// @code
75 /// auto dm = DataMapper {};
76 /// auto const ages = dm.Query<Person>()
77 /// .OrderBy(FieldNameOf<&Person::age>, SqlResultOrdering::ASCENDING)
78 /// .All<&Person::age>();
79 /// @endcode
80 template <auto Field>
81#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
82 requires(is_aggregate_type(parent_of(Field)))
83#else
84 requires std::is_member_object_pointer_v<decltype(Field)>
85#endif
86 [[nodiscard]] auto All() -> std::vector<ReferencedFieldTypeOf<Field>>;
87
88 /// @brief Executes a SELECT query and returns all records found for the specified field,
89 /// only having the specified fields queried and populated.
90 ///
91 /// @tparam ReferencedFields The fields to select from the record, in the form of &Record::FieldName.
92 ///
93 /// @returns A vector of records with the given fields populated.
94 ///
95 /// @code
96 /// auto dm = DataMapper {};
97 /// auto const ages = dm.Query<Person>()
98 /// .OrderBy(FieldNameOf<&Person::age>, SqlResultOrdering::ASCENDING)
99 /// .All<&Person::name, &Person::age>();
100 /// @endcode
101 template <auto... ReferencedFields>
102 requires(sizeof...(ReferencedFields) >= 2)
103 [[nodiscard]] auto All() -> std::vector<Record>;
104
105 /// Executes a SELECT query for the first record found and returns it.
106 [[nodiscard]] std::optional<Record> First();
107
108 /// @brief Executes the query to get a single scalar value from the first record found.
109 ///
110 /// @tparam Field The field to select from the record, in the form of &Record::FieldName.
111 ///
112 /// @returns an optional value of the type of the field, or an empty optional if no record was found.
113 template <auto Field>
114#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
115 requires(is_aggregate_type(parent_of(Field)))
116#else
117 requires std::is_member_object_pointer_v<decltype(Field)>
118#endif
119 auto First() -> std::optional<ReferencedFieldTypeOf<Field>>;
120
121 /// @brief Executes a SELECT query for the first record found and returns it with only the specified fields populated.
122 ///
123 /// @tparam ReferencedFields The fields to select from the record, in the form of &Record::FieldName.
124 ///
125 /// @returns an optional record with only the specified fields populated, or an empty optional if no record was found.
126 template <auto... ReferencedFields>
127 requires(sizeof...(ReferencedFields) >= 2)
128 [[nodiscard]] auto First() -> std::optional<Record>;
129
130 /// Executes a SELECT query for the first n records found and returns them.
131 [[nodiscard]] std::vector<Record> First(size_t n);
132
133 template <auto... ReferencedFields>
134 [[nodiscard]] std::vector<Record> First(size_t n);
135
136 /// Executes a SELECT query for a range of records and returns them.
137 [[nodiscard]] std::vector<Record> Range(size_t offset, size_t limit);
138
139 template <auto... ReferencedFields>
140 [[nodiscard]] std::vector<Record> Range(size_t offset, size_t limit);
141};
142
143/// @brief Represents a query builder that retrieves all fields of a record.
144///
145/// @ingroup DataMapper
146template <typename Record, DataMapperOptions QueryOptions>
147class [[nodiscard]] SqlAllFieldsQueryBuilder final:
148 public SqlCoreDataMapperQueryBuilder<Record, SqlAllFieldsQueryBuilder<Record, QueryOptions>, QueryOptions>
149{
150 private:
151 friend class DataMapper;
152 friend class SqlCoreDataMapperQueryBuilder<Record, SqlAllFieldsQueryBuilder<Record, QueryOptions>, QueryOptions>;
153
154 LIGHTWEIGHT_FORCE_INLINE explicit SqlAllFieldsQueryBuilder(DataMapper& dm, std::string fields) noexcept:
156 dm, std::move(fields)
157 }
158 {
159 }
160
161 static void ReadResults(SqlServerType sqlServerType, SqlResultCursor reader, std::vector<Record>* records);
162 static void ReadResult(SqlServerType sqlServerType, SqlResultCursor reader, std::optional<Record>* optionalRecord);
163};
164
165/// @brief Specialization of SqlAllFieldsQueryBuilder for the case when we return std::tuple
166/// of two records
167///
168/// @ingroup DataMapper
169/// @todo deprecate this in favor of a more generic tuple support
170template <typename FirstRecord, typename SecondRecord, DataMapperOptions QueryOptions>
171class [[nodiscard]] SqlAllFieldsQueryBuilder<std::tuple<FirstRecord, SecondRecord>, QueryOptions> final:
172 public SqlCoreDataMapperQueryBuilder<std::tuple<FirstRecord, SecondRecord>,
173 SqlAllFieldsQueryBuilder<std::tuple<FirstRecord, SecondRecord>, QueryOptions>,
174 QueryOptions>
175{
176 private:
177 using RecordType = std::tuple<FirstRecord, SecondRecord>;
178 friend class DataMapper;
179 friend class SqlCoreDataMapperQueryBuilder<RecordType, SqlAllFieldsQueryBuilder<RecordType, QueryOptions>>;
180
181 LIGHTWEIGHT_FORCE_INLINE explicit SqlAllFieldsQueryBuilder(DataMapper& dm, std::string fields) noexcept:
183 dm, std::move(fields)
184 }
185 {
186 }
187
188 static void ReadResults(SqlServerType sqlServerType, SqlResultCursor reader, std::vector<RecordType>* records);
189};
190
191} // 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
This is the default behavior since compilation times significantly increase otherwise.
Represents a single column in a table.
Definition Field.hpp:84