Line data Source code
1 : /**
2 : Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "SPWebResourceResolver.h"
24 : #include "SPWebResource.h"
25 : #include "SPWebRoot.h"
26 : #include "SPValid.h"
27 :
28 : namespace STAPPLER_VERSIONIZED stappler::web {
29 :
30 : template <typename Result = bool>
31 : SP_COVERAGE_TRIVIAL
32 : static auto exitWithResolverError(StringView text, Value &&data = Value()) -> Result {
33 : Root::getCurrent()->error("ResourceResolver", text, move(data));
34 : return Result(0);
35 : }
36 :
37 2450 : static Vector<StringView> parsePath(StringView path) {
38 2450 : Vector<StringView> pathVec;
39 2450 : if (!path.empty() && (path.front() == ':' || path.starts_with("/:"))) {
40 25 : path.split<StringView::Chars<':'>>([&] (const StringView &v) {
41 100 : pathVec.emplace_back(v);
42 100 : });
43 : } else {
44 2425 : path.split<StringView::Chars<'/'>>([&] (const StringView &v) {
45 4650 : pathVec.emplace_back(v);
46 4650 : });
47 : }
48 :
49 2450 : while (!pathVec.empty() && pathVec.back().empty()) {
50 0 : pathVec.pop_back();
51 : }
52 :
53 2450 : if (!pathVec.empty()) {
54 1875 : std::reverse(pathVec.begin(), pathVec.end());
55 1900 : while (pathVec.back().empty() || pathVec.back().equals("/")) {
56 25 : pathVec.pop_back();
57 : }
58 : }
59 :
60 2450 : return pathVec;
61 0 : }
62 :
63 350 : static bool getSelectResource(ResourceResolver *resv, Vector<StringView> &path, bool &isSingleObject) {
64 350 : if (path.size() < 2) {
65 0 : return exitWithResolverError("invalid 'select' query");
66 : }
67 :
68 350 : auto field = resv->getScheme()->getField(path.back());
69 350 : if (!field || !field->isIndexed()) {
70 0 : return exitWithResolverError("invalid 'select' query");
71 : }
72 350 : path.pop_back();
73 :
74 350 : StringView cmpStr(path.back()); path.pop_back();
75 :
76 350 : auto decComp = stappler::sql::decodeComparation(cmpStr);
77 350 : db::Comparation cmp = decComp.first;
78 350 : size_t valuesRequired = (decComp.second ? 2 : 1);
79 :
80 350 : if (cmp == db::Comparation::Invalid) {
81 250 : cmp = db::Comparation::Equal;
82 250 : if (field->hasFlag(db::Flags::Unique) || field->getTransform() == db::Transform::Alias) {
83 175 : isSingleObject = true;
84 : }
85 250 : if (field->getType() == db::Type::Text) {
86 50 : return resv->selectByQuery(db::Query::Select(field->getName(), cmp, cmpStr));
87 200 : } else if (field->getType() == db::Type::Boolean) {
88 75 : if (valid::validateNumber(cmpStr)) {
89 25 : return resv->selectByQuery(db::Query::Select(field->getName(), cmp, cmpStr.readInteger().get(), 0));
90 50 : } else if (cmpStr == "t" || cmpStr == "true") {
91 25 : return resv->selectByQuery(db::Query::Select(field->getName(), cmp, Value(true), Value(false)));
92 25 : } else if (cmpStr == "f" || cmpStr == "false") {
93 25 : return resv->selectByQuery(db::Query::Select(field->getName(), cmp, Value(false), Value(false)));
94 : }
95 125 : } else if (valid::validateNumber(cmpStr) && db::checkIfComparationIsValid(field->getType(), cmp, field->getFlags())) {
96 125 : return resv->selectByQuery(db::Query::Select(field->getName(), cmp, cmpStr.readInteger().get(), 0));
97 : } else {
98 0 : return exitWithResolverError("invalid 'select' query");
99 : }
100 : }
101 :
102 100 : if (path.size() < valuesRequired || !db::checkIfComparationIsValid(field->getType(), cmp, field->getFlags())) {
103 0 : return exitWithResolverError("invalid 'select' query");
104 : }
105 :
106 100 : if (valuesRequired == 1) {
107 75 : StringView value(std::move(path.back())); path.pop_back();
108 75 : if (field->getType() == db::Type::Text) {
109 25 : return resv->selectByQuery(db::Query::Select(field->getName(), cmp, value));
110 50 : } else if (valid::validateNumber(value)) {
111 50 : return resv->selectByQuery(db::Query::Select(field->getName(), cmp, value.readInteger().get(), 0));
112 : } else {
113 0 : return exitWithResolverError("invalid 'select' query");
114 : }
115 : }
116 :
117 25 : if (valuesRequired == 2) {
118 25 : StringView value1(std::move(path.back())); path.pop_back();
119 25 : StringView value2(std::move(path.back())); path.pop_back();
120 25 : if (valid::validateNumber(value1) && valid::validateNumber(value2)) {
121 25 : return resv->selectByQuery(db::Query::Select(field->getName(), cmp, value1.readInteger().get(), value2.readInteger().get()));
122 : }
123 : }
124 :
125 0 : return false;
126 : }
127 :
128 225 : static bool getSearchResource(ResourceResolver *resv, Vector<StringView> &path, bool &isSingleObject) {
129 225 : if (path.size() < 1) {
130 0 : return exitWithResolverError("invalid 'search' query");
131 : }
132 :
133 225 : auto field = resv->getScheme()->getField(path.back());
134 225 : if (!field || field->getType() != db::Type::FullTextView) {
135 0 : return exitWithResolverError("invalid 'search' query");
136 : }
137 225 : path.pop_back();
138 :
139 225 : return resv->searchByField(field);
140 : }
141 :
142 50 : static bool getOrderResource(ResourceResolver *resv, Vector<StringView> &path) {
143 50 : if (path.size() < 1) {
144 0 : return exitWithResolverError("invalid 'order' query");
145 : }
146 :
147 50 : auto field = resv->getScheme()->getField(path.back());
148 50 : if (!field || !field->isIndexed()) {
149 0 : return exitWithResolverError("invalid 'order' query");
150 : }
151 50 : path.pop_back();
152 :
153 50 : db::Ordering ord = db::Ordering::Ascending;
154 50 : if (!path.empty()) {
155 50 : if (path.back() == "asc" ) {
156 25 : ord = db::Ordering::Ascending;
157 25 : path.pop_back();
158 25 : } else if (path.back() == "desc") {
159 25 : ord = db::Ordering::Descending;
160 25 : path.pop_back();
161 : }
162 : }
163 :
164 50 : if (!path.empty()) {
165 25 : auto &n = path.back();
166 25 : if (valid::validateNumber(n)) {
167 25 : if (resv->order(field->getName(), ord)) {
168 25 : auto ret = resv->limit(n.readInteger().get());
169 25 : path.pop_back();
170 25 : return ret;
171 : } else {
172 0 : return false;
173 : }
174 : }
175 : }
176 :
177 25 : return resv->order(field->getName(), ord);
178 : }
179 :
180 50 : static bool getOrderResource(ResourceResolver *resv, Vector<StringView> &path, const StringView &fieldName, db::Ordering ord) {
181 50 : auto field = resv->getScheme()->getField(fieldName);
182 50 : if (!field || !field->isIndexed()) {
183 0 : return exitWithResolverError("invalid 'order' query");
184 : }
185 :
186 50 : if (!path.empty()) {
187 50 : auto &n = path.back();
188 50 : if (valid::validateNumber(n)) {
189 50 : if (resv->order(field->getName(), ord)) {
190 50 : auto ret = resv->limit(n.readInteger().get());
191 50 : path.pop_back();
192 50 : return ret;
193 : } else {
194 0 : return false;
195 : }
196 : }
197 : }
198 :
199 0 : return resv->order(field->getName(), ord);
200 : }
201 :
202 200 : static bool getLimitResource(ResourceResolver *resv, Vector<StringView> &path, bool &isSingleObject) {
203 200 : if (path.size() < 1) {
204 0 : return exitWithResolverError("invalid 'limit' query");
205 : }
206 :
207 200 : StringView value(path.back()); path.pop_back();
208 200 : if (valid::validateNumber(value)) {
209 200 : auto val = value.readInteger().get();
210 200 : if (val == 1) {
211 150 : isSingleObject = true;
212 : }
213 200 : return resv->limit(val);
214 : } else {
215 0 : return exitWithResolverError("invalid 'limit' query");
216 : }
217 : }
218 :
219 50 : static bool getOffsetResource(ResourceResolver *resv, Vector<StringView> &path) {
220 50 : if (path.size() < 1) {
221 0 : return exitWithResolverError("invalid 'offset' query");
222 : }
223 :
224 50 : StringView value(std::move(path.back())); path.pop_back();
225 50 : if (valid::validateNumber(value)) {
226 50 : return resv->offset(value.readInteger().get());
227 : } else {
228 0 : return exitWithResolverError("invalid 'offset' query");
229 : }
230 : }
231 :
232 75 : static bool getFirstResource(ResourceResolver *resv, Vector<StringView> &path, bool &isSingleObject) {
233 75 : if (path.size() < 1) {
234 0 : return exitWithResolverError("invalid 'first' query");
235 : }
236 :
237 75 : auto field = resv->getScheme()->getField(path.back());
238 75 : if (!field || !field->isIndexed()) {
239 0 : return exitWithResolverError("invalid 'first' query");
240 : }
241 75 : path.pop_back();
242 :
243 75 : if (!path.empty()) {
244 25 : if (valid::validateNumber(path.back())) {
245 25 : size_t val = path.back().readInteger().get();
246 25 : path.pop_back();
247 :
248 25 : if (val == 1) {
249 0 : isSingleObject = true;
250 : }
251 25 : return resv->first(field->getName(), val);
252 : }
253 : }
254 :
255 50 : isSingleObject = true;
256 50 : return resv->first(field->getName(), 1);
257 : }
258 :
259 50 : static bool getLastResource(ResourceResolver *resv, Vector<StringView> &path, bool &isSingleObject) {
260 50 : if (path.size() < 1) {
261 0 : return exitWithResolverError("invalid 'last' query");
262 : }
263 :
264 50 : auto field = resv->getScheme()->getField(path.back());
265 50 : if (!field || !field->isIndexed()) {
266 0 : return exitWithResolverError("invalid 'last' query");
267 : }
268 50 : path.pop_back();
269 :
270 50 : if (!path.empty()) {
271 25 : if (valid::validateNumber(path.back())) {
272 25 : size_t val = path.back().readInteger().get();
273 25 : path.pop_back();
274 :
275 25 : if (val == 1) {
276 0 : isSingleObject = true;
277 : }
278 25 : return resv->last(field->getName(), val);
279 : }
280 : }
281 :
282 25 : isSingleObject = true;
283 25 : return resv->last(field->getName(), 1);
284 : }
285 :
286 1875 : static Resource *parseResource(ResourceResolver *resv, Vector<StringView> &path) {
287 1875 : bool isSingleObject = false;
288 4575 : while (!path.empty()) {
289 3075 : StringView filter(std::move(path.back()));
290 3075 : path.pop_back();
291 :
292 3075 : if (!isSingleObject) {
293 2200 : if (filter.starts_with("id")) {
294 1000 : filter += "id"_len;
295 1000 : if (uint64_t id = filter.readInteger().get()) {
296 975 : if (!resv->selectById(id)) {
297 375 : return nullptr;
298 : }
299 975 : isSingleObject = true;
300 : } else {
301 25 : return nullptr;
302 : }
303 1200 : } else if (filter.starts_with("named-")) {
304 25 : filter += "named-"_len;
305 25 : if (valid::validateIdentifier(filter)) {
306 25 : if (!resv->selectByAlias(filter)) {
307 0 : return nullptr;
308 : }
309 25 : isSingleObject = true;
310 : } else {
311 0 : return nullptr;
312 : }
313 1175 : } else if (filter == "all") {
314 125 : if (!resv->getAll()) {
315 0 : return nullptr;
316 : }
317 : // do nothing
318 1050 : } else if (filter == "select") {
319 350 : if (!getSelectResource(resv, path, isSingleObject)) {
320 0 : return nullptr;
321 : }
322 700 : } else if (filter == "search") {
323 225 : if (!getSearchResource(resv, path, isSingleObject)) {
324 0 : return nullptr;
325 : }
326 475 : } else if (filter == "order") {
327 50 : if (!getOrderResource(resv, path)) {
328 0 : return nullptr;
329 : }
330 425 : } else if (filter.size() > 2 && filter.front() == '+') {
331 25 : if (!getOrderResource(resv, path, filter.sub(1), db::Ordering::Ascending)) {
332 0 : return nullptr;
333 : }
334 400 : } else if (filter.size() > 2 && filter.front() == '-') {
335 25 : if (!getOrderResource(resv, path, filter.sub(1), db::Ordering::Descending)) {
336 0 : return nullptr;
337 : }
338 375 : } else if (filter == "limit") {
339 200 : if (!getLimitResource(resv, path, isSingleObject)) {
340 0 : return nullptr;
341 : }
342 175 : } else if (filter == "offset") {
343 50 : if (!getOffsetResource(resv, path)) {
344 0 : return nullptr;
345 : }
346 125 : } else if (filter == "first") {
347 75 : if (!getFirstResource(resv, path, isSingleObject)) {
348 0 : return nullptr;
349 : }
350 50 : } else if (filter == "last") {
351 50 : if (!getLastResource(resv, path, isSingleObject)) {
352 0 : return nullptr;
353 : }
354 : } else {
355 0 : return exitWithResolverError<Resource *>("Invalid query", Value(filter));
356 : }
357 : } else {
358 875 : if (filter == "offset" && !path.empty() && valid::validateNumber(path.back())) {
359 0 : if (resv->offset(path.back().readInteger().get())) {
360 0 : path.pop_back();
361 0 : continue;
362 : }
363 : }
364 :
365 875 : auto f = resv->getScheme()->getField(filter);
366 875 : if (!f) {
367 0 : return exitWithResolverError<Resource *>("No such field", Value(filter));
368 : }
369 :
370 875 : auto type = f->getType();
371 875 : if (type == db::Type::File || type == db::Type::Image || type == db::Type::Array) {
372 350 : isSingleObject = true;
373 350 : if (!resv->getField(filter, f)) {
374 0 : return nullptr;
375 : } else {
376 350 : return resv->getResult();
377 : }
378 525 : } else if (type == db::Type::Object) {
379 175 : isSingleObject = true;
380 175 : if (!resv->getObject(f)) {
381 0 : return nullptr;
382 : }
383 350 : } else if (type == db::Type::Set) {
384 275 : isSingleObject = false;
385 275 : if (!resv->getSet(f)) {
386 0 : return nullptr;
387 : }
388 75 : } else if (type == db::Type::View) {
389 75 : isSingleObject = false;
390 75 : if (!resv->getView(f)) {
391 0 : return nullptr;
392 : }
393 : } else {
394 0 : return exitWithResolverError<Resource *>("Invalid query", Value(filter));
395 : }
396 : }
397 : }
398 :
399 1500 : return resv->getResult();
400 : }
401 :
402 2450 : static Resource *getResolvedResource(ResourceResolver *resv, Vector<StringView> &path) {
403 2450 : if (path.empty()) {
404 575 : return resv->getResult();
405 : }
406 1875 : return parseResource(resv, path);
407 : }
408 :
409 325 : Resource *Resource::resolve(const db::Transaction &a, const db::Scheme &scheme, const StringView &path) {
410 325 : Value tmp;
411 650 : return resolve(a, scheme, path, tmp);
412 325 : }
413 :
414 2450 : Resource *Resource::resolve(const Transaction &a, const Scheme &scheme, const StringView &path, Value & sub) {
415 2450 : auto pathVec = parsePath(path);
416 :
417 2450 : ResourceResolver resolver(a, scheme);
418 2450 : if (sub.isDictionary() && !sub.empty()) {
419 100 : for (auto &it : sub.asDict()) {
420 50 : if (auto f = resolver.getScheme()->getField(it.first)) {
421 50 : if (f->isIndexed()) {
422 50 : switch (f->getType()) {
423 25 : case db::Type::Integer:
424 : case db::Type::Boolean:
425 : case db::Type::Object:
426 25 : resolver.selectByQuery(
427 50 : db::Query::Select(it.first, db::Comparation::Equal, it.second.getInteger(), 0));
428 25 : break;
429 25 : case db::Type::Text:
430 25 : resolver.selectByQuery(
431 50 : db::Query::Select(it.first, db::Comparation::Equal, it.second.getString()));
432 25 : break;
433 0 : default:
434 0 : break;
435 : }
436 : }
437 : }
438 : }
439 2400 : } else if (sub.isInteger()) {
440 25 : auto id = sub.getInteger();
441 25 : if (id) {
442 25 : resolver.selectById(id);
443 : }
444 2375 : } else if (sub.isString()) {
445 25 : auto & str = sub.getString();
446 25 : if (!str.empty()) {
447 25 : resolver.selectByAlias(str);
448 : }
449 : }
450 :
451 4900 : return getResolvedResource(&resolver, pathVec);
452 2450 : }
453 :
454 0 : Resource *Resource::resolve(const db::Transaction &a, const db::Scheme &scheme, Vector<StringView> &pathVec) {
455 0 : ResourceResolver resolver(a, scheme);
456 0 : return getResolvedResource(&resolver, pathVec);
457 0 : }
458 :
459 2450 : ResourceResolver::ResourceResolver(const db::Transaction &a, const db::Scheme &scheme)
460 2450 : : _storage(a), _scheme(&scheme), _queries(a.getAdapter().getApplicationInterface(), &scheme) {
461 2450 : _type = Objects;
462 2450 : }
463 :
464 1000 : bool ResourceResolver::selectById(uint64_t oid) {
465 1000 : if (_type == Objects) {
466 1000 : if (_queries.selectById(_scheme, oid)) {
467 1000 : return true;
468 : }
469 : }
470 0 : return exitWithResolverError("Invalid 'select by id', invalid resource type");
471 : }
472 :
473 50 : bool ResourceResolver::selectByAlias(const StringView &str) {
474 50 : if (_type == Objects) {
475 50 : if (_queries.selectByName(_scheme, str)) {
476 50 : return true;
477 : }
478 : }
479 0 : return exitWithResolverError("Invalid 'select by alias', invalid resource type");
480 : }
481 :
482 400 : bool ResourceResolver::selectByQuery(db::Query::Select &&q) {
483 400 : if (_type == Objects) {
484 400 : if (_queries.selectByQuery(_scheme, move(q))) {
485 400 : return true;
486 : }
487 : }
488 0 : return exitWithResolverError("Invalid 'select by query', invalid resource type");
489 : }
490 :
491 225 : bool ResourceResolver::searchByField(const db::Field *field) {
492 225 : if (_type == Objects) {
493 225 : _resource = makeResource(ResourceType::Search, move(_queries), field);
494 225 : _type = Search;
495 225 : return true;
496 : }
497 0 : return exitWithResolverError("Invalid 'search', invalid resource type");
498 : }
499 :
500 100 : bool ResourceResolver::order(const StringView &f, db::Ordering o) {
501 100 : if (_type == Objects) {
502 100 : if (_queries.order(_scheme, f, o)) {
503 100 : return true;
504 : }
505 : }
506 0 : return exitWithResolverError("Invalid 'order', invalid resource type");
507 : }
508 :
509 75 : bool ResourceResolver::first(const StringView &f, size_t v) {
510 75 : if (_type == Objects) {
511 75 : if (_queries.first(_scheme, f, v)) {
512 75 : return true;
513 : }
514 : }
515 0 : return exitWithResolverError("Invalid 'first', invalid resource type");
516 : }
517 :
518 50 : bool ResourceResolver::last(const StringView &f, size_t v) {
519 50 : if (_type == Objects) {
520 50 : if (_queries.last(_scheme, f, v)) {
521 50 : return true;
522 : }
523 : }
524 0 : return exitWithResolverError("Invalid 'last', invalid resource type");
525 : }
526 :
527 275 : bool ResourceResolver::limit(size_t limit) {
528 275 : if (_type == Objects) {
529 275 : if (_queries.limit(_scheme, limit)) {
530 275 : return true;
531 : }
532 : }
533 0 : return exitWithResolverError("Invalid 'limit', invalid resource type");
534 : }
535 :
536 50 : bool ResourceResolver::offset(size_t offset) {
537 50 : if (_type == Objects) {
538 50 : if (_queries.offset(_scheme, offset)) {
539 50 : return true;
540 : }
541 : }
542 0 : return exitWithResolverError("Invalid 'offset', invalid resource type");
543 : }
544 :
545 175 : bool ResourceResolver::getObject(const db::Field *f) {
546 175 : if (_type == Objects) {
547 175 : if (auto fo = static_cast<const db::FieldObject *>(f->getSlot())) {
548 175 : if (_queries.setField(fo->scheme, f)) {
549 175 : _scheme = fo->scheme;
550 175 : return true;
551 : }
552 : }
553 : }
554 0 : return exitWithResolverError("Invalid 'getObject', invalid resource type");
555 : }
556 :
557 275 : bool ResourceResolver::getSet(const db::Field *f) {
558 275 : if (_type == Objects) {
559 275 : if (auto fo = static_cast<const db::FieldObject *>(f->getSlot())) {
560 275 : if (_queries.setField(fo->scheme, f)) {
561 275 : _scheme = fo->scheme;
562 275 : return true;
563 : }
564 : }
565 : }
566 0 : return exitWithResolverError("Invalid 'getSet', invalid resource type");
567 : }
568 :
569 75 : bool ResourceResolver::getView(const db::Field *f) {
570 75 : if (_type == Objects) {
571 75 : if (auto fo = static_cast<const db::FieldView *>(f->getSlot())) {
572 75 : if (_queries.setField(fo->scheme, f)) {
573 75 : _scheme = fo->scheme;
574 75 : return true;
575 : }
576 : }
577 : }
578 0 : return exitWithResolverError("Invalid 'getView', invalid resource type");
579 : }
580 :
581 350 : bool ResourceResolver::getField(const StringView &str, const db::Field *f) {
582 350 : if ((_type == Objects) && f->getType() == db::Type::Array) {
583 200 : _resource = makeResource(ResourceType::Array, move(_queries), f);
584 200 : _type = Array;
585 200 : return true;
586 : }
587 :
588 150 : if (_type == Objects && (f->getType() == db::Type::File || f->getType() == db::Type::Image)) {
589 150 : _resource = makeResource(ResourceType::File, move(_queries), f);
590 150 : _type = File;
591 150 : return true;
592 : }
593 0 : return exitWithResolverError("Invalid 'getField', invalid resource type");
594 : }
595 :
596 125 : bool ResourceResolver::getAll() {
597 125 : if (_type == Objects) {
598 125 : if (_queries.setAll()) {
599 125 : return true;
600 : }
601 : }
602 0 : return exitWithResolverError("Invalid 'getAll', invalid resource type or already enabled");
603 : }
604 :
605 2425 : Resource *ResourceResolver::getResult() {
606 2425 : if (_type == Objects) {
607 1850 : if (_queries.empty()) {
608 725 : return makeResource(ResourceType::ResourceList, move(_queries), nullptr);
609 1125 : } else if (_queries.isView()) {
610 75 : return makeResource(ResourceType::View, move(_queries), nullptr);
611 1050 : } else if (_queries.isRefSet()) {
612 325 : if (auto f = _queries.getField()) {
613 325 : if (f->getType() == db::Type::Object) {
614 150 : return makeResource(ResourceType::ObjectField, move(_queries), nullptr);
615 : }
616 : }
617 175 : return makeResource(ResourceType::ReferenceSet, move(_queries), nullptr);
618 725 : } else if (_queries.isObject()) {
619 375 : return makeResource(ResourceType::Object, move(_queries), nullptr);
620 : } else {
621 350 : return makeResource(ResourceType::Set, move(_queries), nullptr);
622 : }
623 : }
624 575 : return _resource;
625 : }
626 :
627 1725 : const db::Scheme *ResourceResolver::getScheme() const {
628 1725 : return _scheme;
629 : }
630 :
631 2425 : Resource *ResourceResolver::makeResource(ResourceType type, db::QueryList &&list, const db::Field *f) {
632 2425 : switch (type) {
633 725 : case ResourceType::ResourceList: return new ResourceReslist(_storage, std::move(list)); break;
634 175 : case ResourceType::ReferenceSet: return new ResourceRefSet(_storage, std::move(list)); break;
635 150 : case ResourceType::ObjectField: return new ResourceFieldObject(_storage, std::move(list)); break;
636 375 : case ResourceType::Object: return new ResourceObject(_storage, std::move(list)); break;
637 350 : case ResourceType::Set: return new ResourceSet(_storage, std::move(list)); break;
638 75 : case ResourceType::View: return new ResourceView(_storage, std::move(list)); break;
639 150 : case ResourceType::File: return new ResourceFile(_storage, std::move(list), f); break;
640 200 : case ResourceType::Array: return new ResourceArray(_storage, std::move(list), f); break;
641 225 : case ResourceType::Search: return new ResourceSearch(_storage, std::move(list), f); break;
642 : }
643 0 : return nullptr;
644 : }
645 :
646 : }
|