LCOV - code coverage report
Current view: top level - core/db - SPDbQueryList.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 348 559 62.3 %
Date: 2024-05-12 00:16:13 Functions: 59 70 84.3 %

          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             : }

Generated by: LCOV version 1.14