Line data Source code
1 : /**
2 : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023-2024 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 : #include "SPDbQueryList.h"
25 : #include "SPDbFile.h"
26 : #include "SPDbScheme.h"
27 : #include "SPValid.h"
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::db {
30 :
31 4150 : static const Field *getFieldFormMap(const Map<String, Field> &fields, const StringView &name) {
32 4150 : auto it = fields.find(name);
33 4150 : if (it != fields.end()) {
34 3125 : return &it->second;
35 : }
36 1025 : return nullptr;
37 : }
38 :
39 8800 : static const Query::FieldsVec *getFieldsVec(const Query::FieldsVec *vec, const StringView &name) {
40 8800 : if (vec) {
41 9525 : for (auto &it : *vec) {
42 1350 : if (it.name == name) {
43 225 : return it.fields.empty() ? nullptr : &it.fields;
44 : }
45 : }
46 : }
47 8575 : return nullptr;
48 : }
49 :
50 4225 : static void QueryFieldResolver_resolveByName(Set<const Field *> &ret, const Map<String, Field> &fields, const StringView &name) {
51 4225 : if (!name.empty() && name.front() == '$') {
52 75 : auto res = Query::decodeResolve(name);
53 75 : switch (res) {
54 25 : case Resolve::Files:
55 475 : for (auto &it : fields) {
56 450 : if (it.second.isFile()) {
57 175 : ret.emplace(&it.second);
58 : }
59 : }
60 25 : break;
61 0 : case Resolve::Sets:
62 0 : for (auto &it : fields) {
63 0 : if (it.second.getType() == Type::Set) {
64 0 : ret.emplace(&it.second);
65 : }
66 : }
67 0 : break;
68 0 : case Resolve::Objects:
69 0 : for (auto &it : fields) {
70 0 : if (it.second.getType() == Type::Object) {
71 0 : ret.emplace(&it.second);
72 : }
73 : }
74 0 : break;
75 0 : case Resolve::Arrays:
76 0 : for (auto &it : fields) {
77 0 : if (it.second.getType() == Type::Array) {
78 0 : ret.emplace(&it.second);
79 : }
80 : }
81 0 : break;
82 25 : case Resolve::Basics:
83 475 : for (auto &it : fields) {
84 450 : if (it.second.isSimpleLayout() && !it.second.isDataLayout() && !it.second.hasFlag(db::Flags::ForceExclude)) {
85 100 : ret.emplace(&it.second);
86 : }
87 : }
88 25 : break;
89 0 : case Resolve::Defaults:
90 0 : for (auto &it : fields) {
91 0 : if (it.second.isSimpleLayout() && !it.second.hasFlag(db::Flags::ForceExclude)) {
92 0 : ret.emplace(&it.second);
93 : }
94 : }
95 0 : break;
96 0 : case Resolve::All:
97 0 : for (auto &it : fields) {
98 0 : if (!it.second.hasFlag(db::Flags::ForceExclude)) {
99 0 : ret.emplace(&it.second);
100 : }
101 : }
102 0 : break;
103 25 : case Resolve::Ids:
104 325 : for (auto &it : fields) {
105 300 : if (it.second.isFile() || it.second.getType() == Type::Object) {
106 25 : ret.emplace(&it.second);
107 : }
108 : }
109 25 : break;
110 0 : default: break;
111 : }
112 : } else {
113 4150 : if (auto field = getFieldFormMap(fields, name)) {
114 3125 : ret.emplace(field);
115 : }
116 : }
117 4225 : }
118 :
119 3200 : QueryFieldResolver::QueryFieldResolver() : root(nullptr) { }
120 :
121 2575 : QueryFieldResolver::QueryFieldResolver(const ApplicationInterface * app, const Scheme &scheme, const Query &query, const Vector<StringView> &extraFields) {
122 2575 : root = new Data{&scheme, &scheme.getFields(), &query.getIncludeFields(), &query.getExcludeFields()};
123 2575 : doResolve(app, root, extraFields, 0, query.getResolveDepth());
124 2575 : }
125 :
126 37650 : const Field *QueryFieldResolver::getField(const String &name) const {
127 37650 : if (root && root->fields) {
128 37600 : auto it = root->fields->find(name);
129 37600 : if (it != root->fields->end()) {
130 37375 : return &it->second;
131 : }
132 : }
133 275 : return nullptr;
134 : }
135 :
136 325 : const Scheme *QueryFieldResolver::getScheme() const {
137 325 : if (root) {
138 325 : return root->scheme;
139 : }
140 0 : return nullptr;
141 : }
142 6025 : const Map<String, Field> *QueryFieldResolver::getFields() const {
143 6025 : if (root) {
144 6025 : return root->fields;
145 : }
146 0 : return nullptr;
147 : }
148 :
149 100 : QueryFieldResolver::Meta QueryFieldResolver::getMeta() const {
150 100 : return root ? root->meta : Meta::None;
151 : }
152 :
153 8800 : const Set<const Field *> &QueryFieldResolver::getResolves() const {
154 8800 : return root->resolved;
155 : }
156 :
157 1100 : const Set<StringView> &QueryFieldResolver::getResolvesData() const {
158 1100 : return root->resolvedData;
159 : }
160 :
161 0 : const Query::FieldsVec *QueryFieldResolver::getIncludeVec() const {
162 0 : if (root) {
163 0 : return root->include;
164 : }
165 0 : return nullptr;
166 : }
167 :
168 0 : const Query::FieldsVec *QueryFieldResolver::getExcludeVec() const {
169 0 : if (root) {
170 0 : return root->exclude;
171 : }
172 0 : return nullptr;
173 : }
174 :
175 2625 : QueryFieldResolver QueryFieldResolver::next(const StringView &f) const {
176 2625 : if (root) {
177 2625 : auto it = root->next.find(f);
178 2625 : if (it != root->next.end()) {
179 2475 : return QueryFieldResolver(&it->second);
180 : }
181 : }
182 150 : return QueryFieldResolver();
183 : }
184 :
185 8525 : QueryFieldResolver::operator bool () const {
186 8525 : return root && root->scheme != nullptr && (root->fields != nullptr || !root->resolvedData.empty());
187 : }
188 :
189 2475 : QueryFieldResolver::QueryFieldResolver(Data *data) : root(data) { }
190 :
191 5750 : void QueryFieldResolver::doResolve(const ApplicationInterface *app, Data *data, const Vector<StringView> &extra, uint16_t depth, uint16_t max) {
192 5750 : if (!data->fields) {
193 0 : return;
194 : }
195 :
196 5750 : if (data->include && !data->include->empty()) {
197 3200 : for (const Query::Field &it : *data->include) {
198 2400 : if (it.name == "$meta") {
199 0 : for (auto &f_it : it.fields) {
200 0 : if (f_it.name == "time") {
201 0 : data->meta |= Meta::Time;
202 0 : } else if (f_it.name == "action") {
203 0 : data->meta |= Meta::Action;
204 0 : } else if (f_it.name == "view") {
205 0 : data->meta |= Meta::View;
206 : }
207 : }
208 : } else {
209 2400 : QueryFieldResolver_resolveByName(data->resolved, *data->fields, it.name);
210 : }
211 : }
212 : }
213 :
214 5750 : if (!data->include || data->include->empty() || (data->include->size() == 1 && data->include->front().name == "$meta")) {
215 35325 : for (auto &it : *data->fields) {
216 30375 : if (it.second.isSimpleLayout()) {
217 22950 : if (!it.second.hasFlag(Flags::ForceExclude)) {
218 22950 : data->resolved.emplace(&it.second);
219 : }
220 : }
221 : }
222 : }
223 :
224 5750 : if (!extra.empty()) {
225 2400 : for (auto &it : extra) {
226 1825 : QueryFieldResolver_resolveByName(data->resolved, *data->fields, it);
227 : }
228 : }
229 :
230 5750 : if (data->exclude) {
231 2575 : for (const Query::Field &it : *data->exclude) {
232 0 : if (it.fields.empty()) {
233 0 : if (auto field = getFieldFormMap(*data->fields, it.name)) {
234 0 : data->resolved.erase(field);
235 : }
236 : }
237 : }
238 : }
239 :
240 31500 : for (const Field *it : data->resolved) {
241 25750 : const Scheme *scheme = nullptr;
242 25750 : const Map<String, Field> *fields = nullptr;
243 :
244 25750 : if (auto s = it->getForeignScheme()) {
245 125 : scheme = s;
246 125 : fields = &s->getFields();
247 25625 : } else if (it->getType() == Type::Extra) {
248 3100 : scheme = data->scheme;
249 3100 : fields = &static_cast<const FieldExtra *>(it->getSlot())->fields;
250 22525 : } else if (it->getType() == Type::Data || it->getType() == Type::Virtual) {
251 1875 : scheme = data->scheme;
252 1875 : if (depth < max) {
253 1200 : auto n_it = data->next.emplace(it->getName().str<Interface>(), Data{scheme, nullptr, getFieldsVec(data->include, it->getName()), getFieldsVec(data->exclude, it->getName())}).first;
254 1200 : doResolveData(&n_it->second, depth + 1, max);
255 : }
256 20650 : } else if (it->isFile()) {
257 350 : scheme = app->getFileScheme();
258 350 : fields = &scheme->getFields();
259 : }
260 25750 : if (scheme && fields && depth < max) {
261 3175 : auto n_it = data->next.emplace(it->getName().str<Interface>(), Data{scheme, fields, getFieldsVec(data->include, it->getName()), getFieldsVec(data->exclude, it->getName())}).first;
262 3175 : doResolve(app, &n_it->second, extra, depth + 1, max);
263 : }
264 : }
265 : }
266 :
267 1225 : void QueryFieldResolver::doResolveData(Data *data, uint16_t depth, uint16_t max) {
268 1225 : if (data->include && !data->include->empty()) {
269 50 : for (const Query::Field &it : *data->include) {
270 25 : data->resolvedData.emplace(StringView(it.name));
271 : }
272 : }
273 :
274 1225 : if (data->exclude) {
275 0 : for (const Query::Field &it : *data->exclude) {
276 0 : data->resolvedData.erase(it.name);
277 : }
278 : }
279 :
280 1250 : for (const StringView &it : data->resolvedData) {
281 25 : auto scheme = data->scheme;
282 25 : if (depth < max) {
283 25 : auto n_it = data->next.emplace(it.str<Interface>(), Data{scheme, nullptr, getFieldsVec(data->include, it), getFieldsVec(data->exclude, it)}).first;
284 25 : doResolveData(&n_it->second, depth + 1, max);
285 : }
286 : }
287 1225 : }
288 :
289 1125 : const Set<const Field *> &QueryList::Item::getQueryFields() const {
290 1125 : return fields.getResolves();
291 : }
292 :
293 : /*void QueryList::readFields(const Scheme &scheme, const Set<const Field *> &fields, const FieldCallback &cb, bool isSimpleGet) {
294 : if (!fields.empty()) {
295 : cb("__oid", nullptr);
296 : for (auto &it : fields) {
297 : if (it != nullptr) {
298 : auto type = it->getType();
299 : if (type == Type::Virtual) {
300 : auto slot = it->getSlot<FieldVirtual>();
301 : for (auto &it : slot->requires) {
302 : if (auto f = scheme.getField(it)) {
303 : if (!f->hasFlag(db::Flags::ForceInclude) && fields.find(f) == fields.end()) {
304 : cb(f->getName(), f);
305 : }
306 : }
307 : }
308 : } else if (type != Type::Set && type != Type::Array && type != Type::View) {
309 : cb(it->getName(), it);
310 : }
311 : }
312 : }
313 : auto &forced = scheme.getForceInclude();
314 : for (auto &it : scheme.getFields()) {
315 : if (it.second.getType() != Type::Virtual) {
316 : if ((it.second.hasFlag(db::Flags::ForceInclude) || (!isSimpleGet && forced.find(&it.second) != forced.end()))
317 : && fields.find(&it.second) == fields.end()) {
318 : cb(it.first, &it.second);
319 : }
320 : }
321 : }
322 : } else {
323 : cb("*", nullptr);
324 : }
325 : }
326 :
327 : void QueryList::Item::readFields(const FieldCallback &cb, bool isSimpleGet) const {
328 : QueryList::readFields(*scheme, getQueryFields(), cb, isSimpleGet);
329 : }*/
330 :
331 2500 : QueryList::QueryList(const ApplicationInterface *app, const Scheme *scheme)
332 2500 : : _application(app) {
333 2500 : queries.reserve(config::RESOURCE_RESOLVE_MAX_DEPTH);
334 2500 : queries.emplace_back(Item{scheme});
335 2500 : }
336 :
337 1025 : bool QueryList::selectById(const Scheme *scheme, uint64_t id) {
338 1025 : Item &b = queries.back();
339 1025 : if (b.scheme == scheme && b.query.getSelectIds().empty() && b.query.getSelectAlias().empty()) {
340 1025 : b.query.select(id);
341 1025 : return true;
342 : }
343 0 : return false;
344 : }
345 :
346 50 : bool QueryList::selectByName(const Scheme *scheme, const StringView &f) {
347 50 : Item &b = queries.back();
348 50 : if (b.scheme == scheme && b.query.getSelectIds().empty() && b.query.getSelectAlias().empty()) {
349 50 : b.query.select(f);
350 50 : return true;
351 : }
352 0 : return false;
353 : }
354 :
355 400 : bool QueryList::selectByQuery(const Scheme *scheme, Query::Select &&f) {
356 400 : Item &b = queries.back();
357 400 : if (b.scheme == scheme && (b.query.empty() || !b.query.getSelectList().empty())) {
358 400 : b.query.select(std::move(f));
359 400 : return true;
360 : }
361 0 : return false;
362 : }
363 :
364 100 : bool QueryList::order(const Scheme *scheme, const StringView &f, Ordering o) {
365 100 : Item &b = queries.back();
366 100 : if (b.scheme == scheme && b.query.getOrderField().empty()) {
367 100 : b.query.order(f, o);
368 100 : return true;
369 : }
370 :
371 0 : return false;
372 : }
373 75 : bool QueryList::first(const Scheme *scheme, const StringView &f, size_t v) {
374 75 : Item &b = queries.back();
375 75 : if (b.scheme == scheme && b.query.getOrderField().empty() && b.query.getLimitValue() > v && b.query.getOffsetValue() == 0) {
376 75 : b.query.order(f, Ordering::Ascending);
377 75 : b.query.limit(v, 0);
378 75 : return true;
379 : }
380 :
381 0 : return false;
382 : }
383 50 : bool QueryList::last(const Scheme *scheme, const StringView &f, size_t v) {
384 50 : Item &b = queries.back();
385 50 : if (b.scheme == scheme && b.query.getOrderField().empty() && b.query.getLimitValue() > v && b.query.getOffsetValue() == 0) {
386 50 : b.query.order(f, Ordering::Descending);
387 50 : b.query.limit(v, 0);
388 50 : return true;
389 : }
390 :
391 0 : return false;
392 : }
393 275 : bool QueryList::limit(const Scheme *scheme, size_t limit) {
394 275 : Item &b = queries.back();
395 275 : if (b.scheme == scheme && b.query.getLimitValue() > limit) {
396 275 : b.query.limit(limit);
397 275 : return true;
398 : }
399 :
400 0 : return false;
401 : }
402 50 : bool QueryList::offset(const Scheme *scheme, size_t offset) {
403 50 : Item &b = queries.back();
404 50 : if (b.scheme == scheme && b.query.getOffsetValue() == 0) {
405 50 : b.query.offset(offset);
406 50 : return true;
407 : }
408 :
409 0 : return false;
410 : }
411 :
412 225 : bool QueryList::setFullTextQuery(const Field *field, FullTextQuery &&data) {
413 225 : if (queries.size() > 0 && field->getType() == Type::FullTextView) {
414 225 : Item &b = queries.back();
415 225 : b.query.select(field->getName(), std::move(data));
416 225 : b.field = field;
417 225 : return true;
418 : }
419 0 : return false;
420 : }
421 :
422 150 : bool QueryList::setAll() {
423 150 : Item &b = queries.back();
424 150 : if (!b.all) {
425 150 : b.all = true;
426 150 : return true;
427 : }
428 0 : return false;
429 : }
430 :
431 550 : bool QueryList::setField(const Scheme *scheme, const Field *field) {
432 550 : if (queries.size() < config::RESOURCE_RESOLVE_MAX_DEPTH) {
433 550 : Item &prev = queries.back();
434 550 : prev.field = field;
435 550 : queries.emplace_back(Item{scheme, prev.scheme->getForeignLink(*prev.field)});
436 550 : return true;
437 : }
438 0 : return false;
439 : }
440 :
441 350 : bool QueryList::setProperty(const Field *field) {
442 350 : queries.back().query.include(Query::Field(field->getName().str<Interface>()));
443 350 : return true;
444 : }
445 :
446 25 : StringView QueryList::setQueryAsMtime() {
447 25 : if (auto scheme = getScheme()) {
448 200 : for (auto &it : scheme->getFields()) {
449 200 : if (it.second.hasFlag(db::Flags::AutoMTime)) {
450 25 : auto &q = queries.back();
451 25 : q.query.clearFields().include(it.first);
452 25 : q.fields = QueryFieldResolver(_application, *q.scheme, q.query, Vector<StringView>());
453 25 : return it.first;
454 : }
455 : }
456 : }
457 0 : return StringView();
458 : }
459 :
460 25 : void QueryList::clearFlags() {
461 25 : _flags = None;
462 25 : }
463 :
464 2375 : void QueryList::addFlag(Flags flags) {
465 2375 : _flags |= flags;
466 2375 : }
467 :
468 1975 : bool QueryList::hasFlag(Flags flags) const {
469 1975 : return (_flags & flags) != Flags::None;
470 : }
471 :
472 0 : bool QueryList::isAll() const {
473 0 : return queries.back().all;
474 : }
475 :
476 1050 : bool QueryList::isRefSet() const {
477 1050 : return (queries.size() > 1 && !queries.back().ref && !queries.back().all);
478 : }
479 :
480 725 : bool QueryList::isObject() const {
481 725 : const Query &b = queries.back().query;
482 725 : return b.getSelectIds().size() == 1 || !b.getSelectAlias().empty() || b.getLimitValue() == 1;
483 : }
484 1900 : bool QueryList::isView() const {
485 1900 : if (queries.size() > 1 && queries.at(queries.size() - 2).field) {
486 1200 : return queries.at(queries.size() - 2).field->getType() == Type::View;
487 700 : } else if (!queries.empty() && queries.back().field) {
488 0 : return queries.back().field->getType() == Type::View;
489 : }
490 700 : return false;
491 : }
492 1850 : bool QueryList::empty() const {
493 1850 : return queries.size() == 1 && queries.front().query.empty();
494 : }
495 :
496 2675 : bool QueryList::isDeltaApplicable() const {
497 2675 : const QueryList::Item &item = getItems().back();
498 3325 : if ((queries.size() == 1 || (isView() && queries.size() == 2
499 225 : && (queries.front().query.getSelectIds().size() == 1 || queries.front().query.getLimitValue() == 1)))
500 3325 : && !item.query.hasSelectName() && !item.query.hasSelectList()) {
501 1250 : return true;
502 : }
503 1425 : return false;
504 : }
505 :
506 2050 : size_t QueryList::size() const {
507 2050 : return queries.size();
508 : }
509 :
510 0 : const Scheme *QueryList::getPrimaryScheme() const {
511 0 : return queries.front().scheme;
512 : }
513 375 : const Scheme *QueryList::getSourceScheme() const {
514 375 : if (queries.size() >= 2) {
515 375 : return queries.at(queries.size() - 2).scheme;
516 : }
517 0 : return getPrimaryScheme();
518 : }
519 16200 : const Scheme *QueryList::getScheme() const {
520 16200 : return queries.back().scheme;
521 : }
522 :
523 725 : const Field *QueryList::getField() const {
524 725 : if (queries.size() >= 2) {
525 725 : return queries.at(queries.size() - 2).field;
526 : }
527 0 : return nullptr;
528 : }
529 :
530 1125 : const Query &QueryList::getTopQuery() const {
531 1125 : return queries.back().query;
532 : }
533 :
534 12300 : const Vector<QueryList::Item> &QueryList::getItems() const {
535 12300 : return queries;
536 : }
537 :
538 0 : void QueryList::decodeSelect(const Scheme &scheme, Query &q, const Value &val) {
539 0 : if (val.isInteger()) {
540 0 : q.select(val.asInteger());
541 0 : } else if (val.isString()) {
542 0 : q.select(val.getString());
543 0 : } else if (val.isArray() && val.size() > 0) {
544 0 : auto cb = [&, this] (const Value &iit) {
545 0 : if (iit.isArray() && iit.size() >= 3) {
546 0 : auto field = iit.getValue(0).asString();
547 0 : if (auto f = scheme.getField(field)) {
548 0 : auto cmp = iit.getValue(1).asString();
549 0 : auto d = decodeComparation(cmp);
550 0 : if (f->isIndexed() || d.first == Comparation::IsNotNull || d.first == Comparation::IsNull) {
551 0 : auto &val = iit.getValue(2);
552 0 : if (d.second && iit.size() >= 4) {
553 0 : auto &val2 = iit.getValue(4);
554 0 : q.select(field, d.first, Value(val), val2);
555 : } else {
556 0 : q.select(field, d.first, Value(val), Value());
557 : }
558 : } else {
559 0 : _application->error("QueryList", "Invalid field for select", Value(field));
560 : }
561 0 : } else {
562 0 : _application->error("QueryList", "Invalid field for select", Value(field));
563 : }
564 0 : }
565 0 : };
566 :
567 0 : if (val.getValue(0).isString()) {
568 0 : cb(val);
569 0 : } else if (val.getValue(0).isArray()) {
570 0 : for (auto &iit : val.asArray()) {
571 0 : cb(iit);
572 : }
573 : }
574 : }
575 0 : }
576 :
577 0 : void QueryList::decodeOrder(const Scheme &scheme, Query &q, const String &str, const Value &val) {
578 0 : String field;
579 0 : Ordering ord = Ordering::Ascending;
580 0 : size_t limit = stappler::maxOf<size_t>();
581 0 : size_t offset = 0;
582 0 : if (val.isArray() && val.size() > 0) {
583 0 : size_t target = 1;
584 0 : auto size = val.size();
585 0 : field = val.getValue(0).asString();
586 0 : if (str == "order") {
587 0 : if (size > target) {
588 0 : auto dir = val.getValue(target).asString();
589 0 : if (dir == "desc") {
590 0 : ord = Ordering::Descending;
591 : }
592 0 : ++ target;
593 0 : }
594 0 : } else if (str == "last") {
595 0 : ord = Ordering::Descending;
596 0 : limit = 1;
597 0 : } else if (str == "first") {
598 0 : ord = Ordering::Ascending;
599 0 : limit = 1;
600 : }
601 :
602 0 : if (size > target) {
603 0 : limit = val.getInteger(target);
604 0 : ++ target;
605 0 : if (size > target) {
606 0 : offset = val.getInteger(target);
607 0 : ++ target;
608 : }
609 : }
610 0 : } else if (val.isString()) {
611 0 : field = val.asString();
612 0 : if (str == "last") {
613 0 : ord = Ordering::Descending;
614 0 : limit = 1;
615 0 : } else if (str == "first") {
616 0 : ord = Ordering::Ascending;
617 0 : limit = 1;
618 : }
619 : }
620 0 : if (!field.empty()) {
621 0 : if (auto f = scheme.getField(field)) {
622 0 : if (f->isIndexed()) {
623 0 : q.order(field, ord);
624 0 : if (limit != stappler::maxOf<size_t>() && !q.hasLimit()) {
625 0 : q.limit(limit);
626 : }
627 0 : if (offset != 0 && !q.hasOffset()) {
628 0 : q.offset(offset);
629 : }
630 0 : return;
631 : }
632 : }
633 : }
634 0 : _application->error("QueryList", "Invalid field for ordering", Value(field));
635 0 : }
636 :
637 75 : const Field *QueryList_getField(const Scheme &scheme, const Field *f, const String &name) {
638 75 : if (!f) {
639 75 : return scheme.getField(name);
640 0 : } else if (f->getType() == Type::Extra) {
641 0 : auto slot = static_cast<const FieldExtra *>(f->getSlot());
642 0 : auto it = slot->fields.find(name);
643 0 : if (it != slot->fields.end()) {
644 0 : return &it->second;
645 : }
646 : }
647 0 : return nullptr;
648 : }
649 :
650 2000 : static uint16_t QueryList_emplaceItem(const ApplicationInterface *app, const Scheme &scheme, const Field *f, Vector<Query::Field> &dec, const String &name) {
651 2000 : if (!name.empty() && name.front() == '$') {
652 75 : dec.emplace_back(String(name));
653 75 : return 1;
654 : }
655 1925 : if (!f) {
656 1900 : if (auto field = scheme.getField(name)) {
657 1900 : dec.emplace_back(String(name));
658 1900 : return (field->isFile() || field->getForeignScheme()) ? 1 : 0;
659 : }
660 25 : } else if (f->getType() == Type::Extra) {
661 0 : auto slot = static_cast<const FieldExtra *>(f->getSlot());
662 0 : if (slot->fields.find(name) != slot->fields.end()) {
663 0 : dec.emplace_back(String(name));
664 0 : return 0;
665 : }
666 25 : } else if (f->getType() == Type::Data || f->getType() == Type::Virtual) {
667 25 : dec.emplace_back(String(name));
668 25 : return 0;
669 : }
670 0 : if (!f) {
671 0 : app->error("QueryList", toString("Invalid field name in 'include' for scheme ", scheme.getName()), Value(name));
672 : } else {
673 0 : app->error("QueryList",
674 0 : toString("Invalid field name in 'include' for scheme ", scheme.getName(), " and field ", f->getName()), Value(name));
675 : }
676 0 : return 0;
677 : }
678 :
679 450 : static uint16_t QueryList_decodeIncludeItem(const ApplicationInterface *app, const Scheme &scheme, const Field *f, Vector<Query::Field> &dec, const Value &val) {
680 450 : uint16_t depth = 0;
681 450 : if (val.isString()) {
682 75 : return QueryList_emplaceItem(app, scheme, f, dec, val.getString());
683 375 : } else if (val.isArray()) {
684 2250 : for (auto &iit : val.asArray()) {
685 1875 : if (iit.isString()) {
686 1875 : depth = std::max(depth, QueryList_emplaceItem(app, scheme, f, dec, iit.getString()));
687 : }
688 : }
689 : }
690 375 : return depth;
691 : }
692 :
693 0 : static void QueryList_decodeMeta(Vector<Query::Field> &dec, const Value &val) {
694 0 : if (val.isArray()) {
695 0 : for (auto &it : val.asArray()) {
696 0 : auto str = it.asString();
697 0 : if (!str.empty()) {
698 0 : dec.emplace_back(std::move(str));
699 : }
700 0 : }
701 0 : } else if (val.isDictionary()) {
702 0 : for (auto &it : val.asDict()) {
703 0 : dec.emplace_back(String(it.first));
704 0 : QueryList_decodeMeta(dec.back().fields, it.second);
705 : }
706 0 : } else if (val.isString()) {
707 0 : dec.emplace_back(val.asString());
708 : }
709 0 : }
710 :
711 475 : static uint16_t QueryList_decodeInclude(const ApplicationInterface *app, const Scheme &scheme, const Field *f, Vector<Query::Field> &dec, const Value &val) {
712 475 : uint16_t depth = 0;
713 475 : if (val.isDictionary()) {
714 150 : for (auto &it : val.asDict()) {
715 125 : if (!it.first.empty()) {
716 125 : if (it.second.isBool() && it.second.asBool()) {
717 50 : QueryList_emplaceItem(app, scheme, f, dec, it.first);
718 75 : } else if (it.second.isArray() || it.second.isDictionary() || it.second.isString()) {
719 75 : if (it.first.front() == '$') {
720 0 : dec.emplace_back(String(it.first));
721 0 : QueryList_decodeMeta(dec.back().fields, it.second);
722 75 : } else if (auto target = QueryList_getField(scheme, f, it.first)) {
723 75 : if (auto ts = target->getForeignScheme()) {
724 50 : dec.emplace_back(String(it.first));
725 50 : depth = std::max(depth, QueryList_decodeInclude(app, *ts, nullptr, dec.back().fields, it.second));
726 25 : } else if (target->isFile()) {
727 0 : dec.emplace_back(String(it.first));
728 0 : depth = std::max(depth, QueryList_decodeInclude(app, *app->getFileScheme(), nullptr, dec.back().fields, it.second));
729 : } else {
730 25 : dec.emplace_back(String(it.first));
731 25 : depth = std::max(depth, QueryList_decodeInclude(app, scheme, target, dec.back().fields, it.second));
732 : }
733 : }
734 : }
735 : }
736 : }
737 25 : depth = (depth + 1);
738 : } else {
739 450 : depth = std::max(depth, QueryList_decodeIncludeItem(app, scheme, f, dec, val));
740 : }
741 475 : return depth;
742 : }
743 :
744 50 : static Ordering QueryList_getTokenOrdering(const Value &v) {
745 50 : return ((v.isInteger() && v.getInteger() == 1) || (v.isString() && v.getString() == "desc")) ? Ordering::Descending : Ordering::Ascending;
746 : }
747 :
748 125 : static ContinueToken QueryList_decodeToken(const ApplicationInterface *app, const Scheme &scheme, const Value &val) {
749 125 : StringView fStr = StringView("__oid");
750 125 : int64_t count = QueryList::DefaultSoftLimit;
751 125 : Ordering ord = Ordering::Ascending;
752 :
753 125 : if (val.isArray() && val.size() == 3) {
754 25 : fStr = StringView(val.getString(0));
755 25 : count = val.getInteger(1);
756 25 : ord = QueryList_getTokenOrdering(val.getValue(2));
757 100 : } else if (val.isArray() && val.size() == 2) {
758 25 : if (val.getValue(0).isString()) {
759 0 : fStr = StringView(val.getValue(0).getString());
760 0 : count = val.getInteger(1);
761 25 : } else if (val.getValue(0).isInteger()) {
762 25 : count = val.getInteger(0);
763 25 : ord = QueryList_getTokenOrdering(val.getValue(1));
764 : }
765 : } else {
766 75 : auto &v = (val.isArray() && val.size() == 1) ? val.getValue(0) : val;
767 75 : if (v.isInteger()) {
768 25 : count = v.getInteger();
769 50 : } else if (v.isString()) {
770 50 : auto &vStr = v.getString();
771 50 : if (stappler::valid::validateNumber(vStr)) {
772 0 : count = v.getInteger();
773 50 : } else if (vStr == "asc") {
774 0 : ord = Ordering::Ascending;
775 50 : } else if (vStr == "desc") {
776 0 : ord = Ordering::Descending;
777 50 : } else if (scheme.getField(vStr)) {
778 50 : fStr = vStr;
779 : } else {
780 0 : app->error("QueryList", "Invalid token field", Value(val));
781 : }
782 : }
783 : }
784 :
785 125 : count = stappler::math::clamp(count, QueryList::MinSoftLimit, QueryList::MaxSoftLimit);
786 125 : if (scheme.getField(fStr) == nullptr) {
787 0 : app->error("QueryList", "Invalid token field", Value(val));
788 : }
789 :
790 250 : return ContinueToken(fStr, count, ord == Ordering::Descending);
791 : }
792 :
793 725 : bool QueryList::apply(const Value &val) {
794 725 : Item &item = queries.back();
795 725 : Query &q = item.query;
796 725 : const Scheme &scheme = *item.scheme;
797 :
798 2000 : for (auto &it : val.asDict()) {
799 1275 : if (it.first == "select") {
800 0 : decodeSelect(scheme, q, it.second);
801 1275 : } else if (it.first == "order" || it.first == "last" || it.first == "first") {
802 0 : decodeOrder(scheme, q, it.first, it.second);
803 1275 : } else if (it.first == "limit") {
804 100 : if (it.second.isInteger()) {
805 100 : q.limit(it.second.asInteger());
806 : }
807 1175 : } else if (it.first == "offset") {
808 0 : if (it.second.isInteger()) {
809 0 : q.offset(it.second.asInteger());
810 : }
811 1175 : } else if (it.first == "fields") {
812 400 : Vector<Query::Field> dec;
813 400 : q.depth(std::min(QueryList_decodeInclude(_application, scheme, nullptr, dec, it.second), config::RESOURCE_RESOLVE_MAX_DEPTH));
814 2400 : for (auto &it : dec) {
815 2000 : q.include(std::move(it));
816 : }
817 1175 : } else if (it.first == "include") {
818 0 : Vector<Query::Field> dec;
819 0 : q.depth(std::min(QueryList_decodeInclude(_application, scheme, nullptr, dec, it.second), config::RESOURCE_RESOLVE_MAX_DEPTH));
820 0 : for (auto &it : dec) {
821 0 : q.include(std::move(it));
822 : }
823 775 : } else if (it.first == "exclude") {
824 0 : Vector<Query::Field> dec;
825 0 : q.depth(std::min(QueryList_decodeInclude(_application, scheme, nullptr, dec, it.second), config::RESOURCE_RESOLVE_MAX_DEPTH));
826 0 : for (auto &it : dec) {
827 0 : q.exclude(std::move(it));
828 : }
829 775 : } else if (it.first == "delta") {
830 0 : if (it.second.isString()) {
831 0 : q.delta(it.second.asString());
832 0 : } else if (it.second.isInteger()) {
833 0 : q.delta(it.second.asInteger());
834 : }
835 775 : } else if (it.first == "forUpdate") {
836 0 : q.forUpdate();
837 775 : } else if (it.first == "continue") {
838 250 : if (auto t = ContinueToken(it.second.asString())) {
839 250 : token = t;
840 : } else {
841 0 : _application->error("QueryList", "Invalid token", Value(it.second));
842 0 : failed = true;
843 250 : }
844 525 : } else if (it.first == "begin") {
845 125 : if (auto t = QueryList_decodeToken(_application, scheme, it.second)) {
846 125 : token = t;
847 : } else {
848 0 : failed = true;
849 125 : }
850 : } else {
851 400 : extraData.setValue(it.second, it.first);
852 : }
853 : }
854 :
855 725 : return true;
856 : }
857 :
858 2550 : void QueryList::resolve(const Vector<StringView> &vec) {
859 2550 : Item &b = queries.back();
860 2550 : b.fields = QueryFieldResolver(_application, *b.scheme, b.query, vec);
861 2550 : }
862 :
863 5825 : uint16_t QueryList::getResolveDepth() const {
864 5825 : return queries.back().query.getResolveDepth();
865 : }
866 :
867 0 : void QueryList::setResolveDepth(uint16_t d) {
868 0 : queries.back().query.depth(d);
869 0 : }
870 :
871 75 : void QueryList::setDelta(stappler::Time d) {
872 75 : queries.back().query.delta(d.toMicroseconds());
873 75 : }
874 :
875 50 : stappler::Time QueryList::getDelta() const {
876 50 : return stappler::Time::microseconds(queries.back().query.getDeltaToken());
877 : }
878 :
879 0 : const Query::FieldsVec &QueryList::getIncludeFields() const {
880 0 : return queries.back().query.getIncludeFields();
881 : }
882 0 : const Query::FieldsVec &QueryList::getExcludeFields() const {
883 0 : return queries.back().query.getExcludeFields();
884 : }
885 :
886 5950 : QueryFieldResolver QueryList::getFields() const {
887 5950 : return QueryFieldResolver(queries.back().fields);
888 : }
889 :
890 450 : const Value &QueryList::getExtraData() const {
891 450 : return extraData;
892 : }
893 :
894 3400 : ContinueToken &QueryList::getContinueToken() const {
895 3400 : return token;
896 : }
897 :
898 : }
|