Line data Source code
1 : /**
2 : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : // Excluded from documentation/codegen tool
25 : ///@ SP_EXCLUDE
26 :
27 : #ifndef STAPPLER_SQL_SPSQLSELECT_HPP_
28 : #define STAPPLER_SQL_SPSQLSELECT_HPP_
29 :
30 : #include "SPSql.h"
31 :
32 : namespace STAPPLER_VERSIONIZED stappler::sql {
33 :
34 : template <typename Binder, typename Interface>
35 50 : auto Query<Binder, Interface>::Select::all() -> Select & {
36 50 : if (this->state == State::None) { this->state = State::Some; } else { this->query->stream << ","; }
37 50 : this->query->stream << " *";
38 50 : return *this;
39 : }
40 :
41 : template <typename Binder, typename Interface>
42 375 : auto Query<Binder, Interface>::Select::count() -> Select & {
43 375 : if (this->state == State::None) { this->state = State::Some; } else { this->query->stream << ","; }
44 375 : this->query->stream << " COUNT(*)";
45 375 : return *this;
46 : }
47 :
48 : template <typename Binder, typename Interface>
49 575 : auto Query<Binder, Interface>::Select::count(const String &alias) -> Select & {
50 575 : if (this->state == State::None) { this->state = State::Some; } else { this->query->stream << ","; }
51 575 : this->query->stream << " COUNT(*) AS \"" << alias << "\"";
52 575 : return *this;
53 : }
54 :
55 : template <typename Binder, typename Interface>
56 : template <typename Clause>
57 : template <typename ...Args>
58 1275 : auto Query<Binder, Interface>::FieldsClause<Clause>::fields(const Field &f, Args && ... args) -> Clause & {
59 1275 : Expand<Clause>::fields((Clause &)*this, f, std::forward<Args>(args)...);
60 1275 : return (Clause &)*this;
61 : }
62 :
63 : template <typename Binder, typename Interface>
64 : template <typename Clause>
65 62275 : auto Query<Binder, Interface>::FieldsClause<Clause>::field(const Field &f) -> Clause & {
66 62275 : switch (this->state) {
67 14975 : case State::None:
68 14975 : this->query->stream << " ";
69 14975 : this->state = State::Some;
70 14975 : break;
71 4400 : case State::Init:
72 4400 : this->query->stream << "(";
73 4400 : this->state = State::Some;
74 4400 : break;
75 42900 : case State::Some:
76 42900 : this->query->stream << ", ";
77 42900 : break;
78 : }
79 62275 : this->query->writeBind(f);
80 62275 : return (Clause &)*this;
81 : }
82 :
83 : template <typename Binder, typename Interface>
84 : template <typename Clause>
85 1075 : auto Query<Binder, Interface>::FieldsClause<Clause>::aggregate(const StringView &func, const Field &f) -> Clause & {
86 1075 : switch (this->state) {
87 1000 : case State::None:
88 1000 : this->query->stream << " ";
89 1000 : this->state = State::Some;
90 1000 : break;
91 0 : case State::Init:
92 0 : this->query->stream << "(";
93 0 : this->state = State::Some;
94 0 : break;
95 75 : case State::Some:
96 75 : this->query->stream << ", ";
97 75 : break;
98 : }
99 1075 : this->query->writeBind(func, f);
100 1075 : return (Clause &)*this;
101 : }
102 :
103 : template <typename Binder, typename Interface>
104 1125 : auto Query<Binder, Interface>::Select::from() -> Query<Binder, Interface>::SelectFrom {
105 1125 : if (this->state == State::None) {
106 1125 : this->query->stream << " *";
107 : }
108 1125 : this->query->stream << " FROM";
109 1125 : return SelectFrom{this->query};
110 : }
111 :
112 : template <typename Binder, typename Interface>
113 12500 : auto Query<Binder, Interface>::Select::from(const Field &field) -> SelectFrom {
114 12500 : if (this->state == State::None) {
115 1425 : this->query->stream << " *";
116 : }
117 12500 : this->query->stream << " FROM " << field.name;
118 12500 : this->query->target = field.name;
119 12500 : if (!field.alias.empty()) {
120 725 : this->query->stream << " " << field.alias;
121 : }
122 12500 : return SelectFrom(this->query, State::Some);
123 : }
124 :
125 : template <typename Binder, typename Interface>
126 : template <typename ... Args>
127 1125 : auto Query<Binder, Interface>::Select::from(const Field &field, Args && ... args) -> SelectFrom {
128 1125 : auto f = from();
129 1125 : Expand<SelectFrom>::from(f, field, forward<Args>(args)...);
130 1125 : return f;
131 : }
132 :
133 : template <typename Binder, typename Interface>
134 2375 : auto Query<Binder, Interface>::SelectFrom::from(const Field &field) -> SelectFrom & {
135 2375 : if (this->state == State::None) { this->state = State::Some; } else { this->query->stream << ","; }
136 2375 : this->query->stream << " " << field.name;
137 2375 : if (this->query->target.empty()) {
138 0 : this->query->target = field.name;
139 : }
140 2375 : if (!field.alias.empty()) {
141 100 : this->query->stream << " \"" << field.alias << "\"";
142 : }
143 2375 : return *this;
144 : }
145 :
146 : template <typename Binder, typename Interface>
147 : template <typename ... Args>
148 : auto Query<Binder, Interface>::SelectFrom::from(const Field &field, Args && ... args) -> SelectFrom & {
149 : Expand<SelectFrom>::from(*this, forward<Args>(args)...);
150 : return *this;
151 : }
152 :
153 : template <typename Binder, typename Interface>
154 : template <typename Callback>
155 1425 : auto Query<Binder, Interface>::SelectFrom::innerJoinOn(const StringView &s, const Callback &cb) -> SelectFrom & {
156 1425 : if (this->state == State::Some) {
157 1425 : this->query->stream << " INNER JOIN " << s << " ON(";
158 1425 : WhereBegin tmp(this->query);
159 1425 : cb(tmp);
160 1425 : this->query->stream << ")";
161 : }
162 1425 : return *this;
163 : }
164 :
165 : template <typename Binder, typename Interface>
166 : template <typename Callback>
167 : auto Query<Binder, Interface>::SelectFrom::leftJoinOn(const StringView &s, const Callback &cb) -> SelectFrom & {
168 : if (this->state == State::Some) {
169 : this->query->stream << " LEFT OUTER JOIN " << s << " ON(";
170 : WhereBegin tmp(this->query);
171 : cb(tmp);
172 : this->query->stream << ")";
173 : }
174 : return *this;
175 : }
176 :
177 : template <typename Binder, typename Interface>
178 : template <typename Callback>
179 175 : auto Query<Binder, Interface>::SelectFrom::rightJoinOn(const StringView &s, const Callback &cb) -> SelectFrom & {
180 175 : if (this->state == State::Some) {
181 175 : this->query->stream << " RIGHT OUTER JOIN " << s << " ON(";
182 175 : WhereBegin tmp(this->query);
183 175 : cb(tmp);
184 175 : this->query->stream << ")";
185 : }
186 175 : return *this;
187 : }
188 :
189 : template <typename Binder, typename Interface>
190 : template <typename Callback>
191 : auto Query<Binder, Interface>::SelectFrom::fullJoinOn(const StringView &s, const Callback &cb) -> SelectFrom & {
192 : if (this->state == State::Some) {
193 : this->query->stream << " FULL OUTER JOIN " << s << " ON(";
194 : WhereBegin tmp(this->query);
195 : cb(tmp);
196 : this->query->stream << ")";
197 : }
198 : return *this;
199 : }
200 :
201 : template <typename Binder, typename Interface>
202 : template <typename ... Args>
203 2425 : auto Query<Binder, Interface>::SelectFrom::where(Args && ... args) -> SelectWhere {
204 2425 : this->query->stream << " WHERE";
205 2425 : SelectWhere q(this->query);
206 2425 : q.where(sql::Operator::And, std::forward<Args>(args)...);
207 2425 : return q;
208 : }
209 :
210 : template <typename Binder, typename Interface>
211 7500 : auto Query<Binder, Interface>::SelectFrom::where() -> SelectWhere {
212 7500 : this->query->stream << " WHERE";
213 7500 : return SelectWhere(this->query);
214 : }
215 :
216 : template <typename Binder, typename Interface>
217 : auto Query<Binder, Interface>::SelectFrom::group(const Field &f) -> SelectGroup {
218 : this->query->stream << " GROUP BY ";
219 : auto g = SelectGroup(this->query);
220 : g.field(f);
221 : return g;
222 : }
223 :
224 : template <typename Binder, typename Interface>
225 1375 : inline auto Query_writeOrderSt(typename Interface::StringStreamType &stream, Query<Binder, Interface> &query, Ordering ord, const typename Query<Binder, Interface>::Field &field, Nulls n) {
226 1375 : stream << " ORDER BY ";
227 1375 : query.writeBind(field, false);
228 1375 : switch (ord) {
229 625 : case Ordering::Ascending: stream << " ASC"; break;
230 750 : case Ordering::Descending: stream << " DESC"; break;
231 : }
232 :
233 1375 : switch (n) {
234 775 : case Nulls::None: break;
235 0 : case Nulls::First: stream << " NULLS FIRST"; break;
236 600 : case Nulls::Last: stream << " NULLS LAST"; break;
237 : }
238 1375 : }
239 :
240 : template <typename Binder, typename Interface>
241 1175 : auto Query<Binder, Interface>::SelectFrom::order(Ordering ord, const Field &field, Nulls n) -> SelectOrder {
242 1175 : Query_writeOrderSt<Binder>(this->query->stream, *this->query, ord, field, n);
243 1175 : return SelectOrder(this->query);
244 : }
245 :
246 : template <typename Binder, typename Interface>
247 1925 : void Query<Binder, Interface>::SelectFrom::forUpdate() {
248 1925 : switch (this->query->profile) {
249 775 : case Profile::Postgres: this->query->stream << " FOR UPDATE"; break;
250 1150 : case Profile::Sqlite: break;
251 : }
252 1925 : }
253 :
254 : template <typename Binder, typename Interface>
255 : template <typename ...Args>
256 : auto Query<Binder, Interface>::SelectGroup::fields(const Field &f, Args && ... args) -> SelectGroup & {
257 : Expand<SelectGroup>::fields(*this, f, std::forward<Args>(args)...);
258 : return *this;
259 : }
260 :
261 : template <typename Binder, typename Interface>
262 175 : auto Query<Binder, Interface>::SelectGroup::field(const Field &f) -> SelectGroup & {
263 175 : switch (this->state) {
264 125 : case State::None:
265 125 : this->query->stream << " ";
266 125 : this->state = State::Some;
267 125 : break;
268 50 : case State::Some:
269 50 : this->query->stream << ", ";
270 50 : break;
271 0 : default:
272 0 : break;
273 : }
274 175 : this->query->writeBind(f, false);
275 175 : return *this;
276 : }
277 :
278 : template <typename Binder, typename Interface>
279 75 : auto Query<Binder, Interface>::SelectGroup::order(Ordering ord, const Field &field, Nulls n) -> SelectOrder {
280 75 : Query_writeOrderSt<Binder>(this->query->stream, *this->query, ord, field, n);
281 75 : return SelectOrder(this->query);
282 : }
283 :
284 : template <typename Binder, typename Interface>
285 125 : auto Query<Binder, Interface>::SelectWhere::group(const Field &f) -> SelectGroup {
286 125 : this->query->stream << " GROUP BY ";
287 125 : auto g = SelectGroup(this->query);
288 125 : g.field(f);
289 125 : return g;
290 : }
291 :
292 : template <typename Binder, typename Interface>
293 125 : auto Query<Binder, Interface>::SelectWhere::order(Ordering ord, const Field &field, Nulls n) -> SelectOrder {
294 125 : Query_writeOrderSt<Binder>(this->query->stream, *this->query, ord, field, n);
295 125 : return SelectOrder(this->query);
296 : }
297 :
298 : template <typename Binder, typename Interface>
299 : void Query<Binder, Interface>::SelectWhere::forUpdate() {
300 : switch (this->query->profile) {
301 : case Profile::Postgres: this->query->stream << " FOR UPDATE"; break;
302 : case Profile::Sqlite: break;
303 : }
304 : }
305 :
306 : template <typename Binder, typename Interface>
307 75 : auto Query<Binder, Interface>::SelectOrder::limit(size_t limit, size_t offset) -> SelectPost {
308 75 : this->query->stream << " LIMIT " << limit << " OFFSET " << offset;
309 75 : return SelectPost(this->query);
310 : }
311 :
312 : template <typename Binder, typename Interface>
313 825 : auto Query<Binder, Interface>::SelectOrder::limit(size_t limit) -> SelectPost {
314 825 : this->query->stream << " LIMIT " << limit;
315 825 : return SelectPost(this->query);
316 : }
317 :
318 : template <typename Binder, typename Interface>
319 0 : auto Query<Binder, Interface>::SelectOrder::offset(size_t offset) -> SelectPost {
320 0 : this->query->stream << " OFFSET " << offset;
321 0 : return SelectPost(this->query);
322 : }
323 :
324 : template <typename Binder, typename Interface>
325 : void Query<Binder, Interface>::SelectOrder::forUpdate() {
326 : switch (this->query->profile) {
327 : case Profile::Postgres: this->query->stream << " FOR UPDATE"; break;
328 : case Profile::Sqlite: break;
329 : }
330 : }
331 :
332 : template <typename Binder, typename Interface>
333 : void Query<Binder, Interface>::SelectPost::forUpdate() {
334 : switch (this->query->profile) {
335 : case Profile::Postgres: this->query->stream << " FOR UPDATE"; break;
336 : case Profile::Sqlite: break;
337 : }
338 : }
339 :
340 : template <typename Binder, typename Interface>
341 : template <typename ... Args>
342 375 : auto Query<Binder, Interface>::select(const Field &f, Args && ... args) -> Select {
343 375 : auto s = select();
344 375 : s.fields(f, forward<Args>(args)...);
345 375 : return s;
346 : }
347 :
348 : template <typename Binder, typename Interface>
349 : template <typename ... Args>
350 125 : auto Query<Binder, Interface>::select(Distinct d, const Field &f, Args && ... args) -> Select {
351 125 : auto s = select(d);
352 125 : s.fields(f, forward<Args>(args)...);
353 125 : return s;
354 : }
355 :
356 : template <typename Binder, typename Interface>
357 13625 : auto Query<Binder, Interface>::select(Distinct d) -> Select {
358 13625 : stream << "SELECT";
359 13625 : switch (d) {
360 125 : case Distinct::Distinct:
361 125 : stream << " DISTINCT";
362 125 : break;
363 13500 : default:
364 13500 : break;
365 : }
366 13625 : return Select(this);
367 : }
368 :
369 : }
370 :
371 : #endif /* STAPPLER_SQL_SPSQLSELECT_HPP_ */
|