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 "SPDbAdapter.h"
25 : #include "SPDbScheme.h"
26 :
27 : namespace STAPPLER_VERSIONIZED stappler::db {
28 :
29 75 : ApplicationInterface::~ApplicationInterface() { }
30 :
31 0 : db::Adapter ApplicationInterface::getAdapterFromContext() const {
32 0 : if (auto p = pool::acquire()) {
33 0 : db::BackendInterface *h = nullptr;
34 0 : pool::userdata_get((void **)&h, db::config::STORAGE_INTERFACE_KEY.data(), p);
35 0 : if (h) {
36 0 : return db::Adapter(h, this);
37 : }
38 : }
39 0 : return db::Adapter(nullptr, nullptr);
40 : }
41 :
42 0 : void ApplicationInterface::scheduleAyncDbTask(const Callback<Function<void(const Transaction &)>(pool_t *)> &setupCb) const {
43 0 : log::error("ApplicationInterface", "scheduleAyncDbTask is not define");
44 0 : ::abort();
45 : }
46 :
47 25 : StringView ApplicationInterface::getDocumentRoot() const {
48 25 : return filesystem::writablePath<Interface>();
49 : }
50 :
51 0 : void ApplicationInterface::pushErrorMessage(Value &&val) const {
52 0 : log::error("ApplicationInterface", data::EncodeFormat::Pretty, val);
53 0 : }
54 :
55 0 : void ApplicationInterface::pushDebugMessage(Value &&val) const {
56 0 : log::debug("ApplicationInterface", data::EncodeFormat::Pretty, val);
57 0 : }
58 :
59 100 : void ApplicationInterface::reportDbUpdate(StringView data, bool successful) {
60 100 : auto dir = filepath::merge<Interface>(getDocumentRoot(), ".reports");
61 100 : filesystem::mkdir(dir);
62 100 : auto path = toString(dir, "/update.", stappler::Time::now().toMilliseconds(), ".sql");
63 100 : stappler::filesystem::write(path, (const uint8_t *)data.data(), data.size());
64 100 : }
65 :
66 0 : Adapter Adapter::FromContext(const ApplicationInterface *app) {
67 0 : return app->getAdapterFromContext();
68 : }
69 :
70 8870 : Adapter::Adapter(BackendInterface *iface, const ApplicationInterface *app)
71 8870 : : _application(app), _interface(iface) { }
72 :
73 5616 : Adapter::Adapter(const Adapter &other) {
74 5616 : _application = other._application;
75 5616 : _interface = other._interface;
76 5616 : }
77 :
78 0 : Adapter& Adapter::operator=(const Adapter &other) {
79 0 : _application = other._application;
80 0 : _interface = other._interface;
81 0 : return *this;
82 : }
83 :
84 17310 : String Adapter::getTransactionKey() const {
85 17310 : if (!_interface) {
86 0 : return String();
87 : }
88 :
89 17310 : auto ret = _interface->getTransactionKey();
90 17317 : if (!ret.empty()) {
91 0 : return ret;
92 : }
93 :
94 17314 : char buf[32] = { 0 };
95 17314 : auto prefix = StringView(config::STORAGE_TRANSACTION_PREFIX);
96 17314 : memcpy(buf, prefix.data(), prefix.size());
97 17315 : stappler::base16::encode(buf + prefix.size(), 32 - prefix.size(),
98 17313 : stappler::CoderSource((const uint8_t *)(_interface), sizeof(void *)));
99 17316 : return String(buf, prefix.size() + sizeof(void *) * 2);
100 17318 : }
101 :
102 125 : bool Adapter::set(const stappler::CoderSource &key, const Value &val, stappler::TimeInterval maxAge) const {
103 125 : return _interface->set(key, val, maxAge);
104 : }
105 :
106 250 : Value Adapter::get(const stappler::CoderSource &key) const {
107 250 : return _interface->get(key);
108 : }
109 :
110 100 : bool Adapter::clear(const stappler::CoderSource &key) const {
111 100 : return _interface->clear(key);
112 : }
113 :
114 775 : Vector<int64_t> Adapter::performQueryListForIds(const QueryList &ql, size_t count) const {
115 775 : return _interface->performQueryListForIds(ql, count);
116 : }
117 1125 : Value Adapter::performQueryList(const QueryList &ql, size_t count, bool forUpdate) const {
118 1125 : auto targetScheme = ql.getScheme();
119 1125 : if (targetScheme) {
120 : // virtual fields should be resolved within interface
121 1125 : return _interface->performQueryList(ql, count, forUpdate);
122 : }
123 0 : return Value();
124 : }
125 :
126 174 : bool Adapter::init(const BackendInterface::Config &cfg, const Map<StringView, const Scheme *> &schemes) const {
127 174 : Scheme::initSchemes(schemes);
128 175 : return _interface->init(cfg, schemes);
129 : }
130 :
131 0 : void Adapter::makeSessionsCleanup() const {
132 0 : _interface->makeSessionsCleanup();
133 0 : }
134 :
135 575 : User * Adapter::authorizeUser(const Auth &auth, const StringView &name, const StringView &password) const {
136 575 : if (_interface) {
137 575 : return _interface->authorizeUser(auth, name, password);
138 : }
139 0 : return nullptr;
140 : }
141 :
142 50 : void Adapter::broadcast(const Bytes &data) const {
143 50 : _interface->broadcast(data);
144 50 : }
145 :
146 50 : void Adapter::broadcast(const Value &val) const {
147 50 : broadcast(data::write<Interface>(val, EncodeFormat::Cbor));
148 50 : }
149 :
150 0 : void Adapter::broadcast(StringView url, Value &&val, bool exclusive) const {
151 0 : broadcast(Value({
152 0 : stappler::pair("url", Value(url)),
153 0 : stappler::pair("exclusive", Value(exclusive)),
154 0 : stappler::pair("data", std::move(val)),
155 0 : }));
156 0 : }
157 :
158 3475 : bool Adapter::performWithTransaction(const Callback<bool(const db::Transaction &)> &cb) const {
159 3475 : if (auto t = db::Transaction::acquire(*this)) {
160 3475 : bool success = true;
161 3475 : if (isInTransaction()) {
162 0 : if (!cb(t)) {
163 0 : cancelTransaction();
164 0 : success = false;
165 : }
166 : } else {
167 3475 : if (beginTransaction()) {
168 3471 : if (!cb(t)) {
169 0 : cancelTransaction();
170 0 : success = false;
171 0 : endTransaction();
172 : } else {
173 3475 : success = endTransaction();
174 : }
175 : } else {
176 0 : success = false;
177 : }
178 : }
179 3473 : t.release();
180 3472 : return success;
181 : }
182 0 : return false;
183 : }
184 :
185 1025 : int64_t Adapter::getDeltaValue(const Scheme &s) {
186 1025 : return _interface->getDeltaValue(s);
187 : }
188 :
189 50 : int64_t Adapter::getDeltaValue(const Scheme &s, const FieldView &v, uint64_t id) {
190 50 : return _interface->getDeltaValue(s, v, id);
191 : }
192 :
193 0 : bool Adapter::foreach(Worker &w, const Query &q, const Callback<bool(Value &)> &cb) const {
194 0 : return _interface->foreach(w, q, cb);
195 : }
196 :
197 6249 : Value Adapter::select(Worker &w, const Query &q) const {
198 6249 : auto targetScheme = &w.scheme();
199 6249 : auto ordField = q.getQueryField();
200 6249 : if (!ordField.empty()) {
201 50 : if (auto f = targetScheme->getField(ordField)) {
202 50 : targetScheme = f->getForeignScheme();
203 : } else {
204 0 : return Value();
205 : }
206 : }
207 :
208 : // virtual fields should be resolved within interface
209 6250 : return _interface->select(w, q);
210 : }
211 :
212 3650 : Value Adapter::create(Worker &w, Value &changeSet) const {
213 3650 : auto &scheme = w.scheme();
214 3650 : auto &fullTextFields = scheme.getFullTextFields();
215 :
216 3650 : Vector<InputField> inputFields;
217 3650 : Vector< InputRow > inputRows;
218 :
219 3650 : bool stop = false;
220 3650 : if (changeSet.isDictionary()) {
221 3625 : auto &targetRow = inputRows.emplace_back();
222 42125 : for (auto &it : scheme.getFields()) {
223 38500 : auto &val = changeSet.getValue(it.first);
224 38500 : if (val) {
225 28325 : if (fullTextFields.find(&it.second) == fullTextFields.end()) {
226 23525 : targetRow.values.emplace_back(move(val));
227 : } else {
228 4800 : targetRow.values.emplace_back(Value(val));
229 : }
230 28325 : inputFields.emplace_back(InputField{&it.second});
231 : } else {
232 10175 : if (it.second.hasFlag(Flags::Required)) {
233 0 : w.getApplicationInterface()->error("Storage", "No value for required field",
234 0 : Value({ std::make_pair("field", Value(it.first)) }));
235 0 : stop = true;
236 : }
237 : }
238 : }
239 25 : } else if (changeSet.isArray()) {
240 75 : for (auto &rowValues : changeSet.asArray()) {
241 700 : for (auto &it : scheme.getFields()) {
242 650 : auto &val = rowValues.getValue(it.first);
243 650 : if (val) {
244 100 : emplace_ordered(inputFields, InputField{&it.second});
245 : } else {
246 550 : if (it.second.hasFlag(Flags::Required)) {
247 0 : w.getApplicationInterface()->error("Storage", "No value for required field",
248 0 : Value({ std::make_pair("field", Value(it.first)) }));
249 0 : stop = true;
250 : }
251 : }
252 : }
253 : }
254 : } else {
255 0 : stop = true;
256 : }
257 :
258 3650 : if (stop) {
259 0 : return Value();
260 : }
261 :
262 3650 : if (changeSet.isArray()) {
263 75 : for (auto &rowValues : changeSet.asArray()) {
264 50 : auto &targetRow = inputRows.emplace_back();
265 150 : for (auto &it : inputFields) {
266 100 : auto &v = rowValues.getValue(it.field->getName());
267 100 : if (v) {
268 100 : if (fullTextFields.find(it.field) == fullTextFields.end()) {
269 50 : targetRow.values.emplace_back(move(v));
270 : } else {
271 50 : targetRow.values.emplace_back(Value(v));
272 : }
273 : } else {
274 0 : targetRow.values.emplace_back(Value(v));
275 : }
276 : }
277 : }
278 : }
279 :
280 3650 : processFullTextFields(scheme, changeSet, inputFields, inputRows);
281 :
282 3650 : auto ret = _interface->create(w, inputFields, inputRows, changeSet.isArray());
283 3675 : auto updateData = [&] (Value &value) -> bool {
284 35775 : for (auto &it : value.asDict()) {
285 32100 : auto f = w.scheme().getField(it.first);
286 32100 : if (f && f->getType() == Type::Virtual) {
287 0 : auto slot = f->getSlot<FieldVirtual>();
288 0 : if (slot->writeFn) {
289 0 : if (!slot->writeFn(w.scheme(), ret, it.second)) {
290 0 : return false;
291 : }
292 : } else {
293 0 : return false;
294 : }
295 : }
296 : }
297 3675 : return true;
298 3650 : };
299 :
300 3650 : if (ret.isArray()) {
301 75 : for (auto &it : ret.asArray()) {
302 50 : if (!updateData(it)) {
303 0 : _interface->cancelTransaction();
304 0 : return Value();
305 : }
306 : }
307 3625 : } else if (ret.isDictionary()) {
308 3625 : if (!updateData(ret)) {
309 0 : _interface->cancelTransaction();
310 0 : return Value();
311 : }
312 : }
313 3650 : return ret;
314 3650 : }
315 :
316 3025 : static void Adapter_mergeValues(const Scheme &scheme, const Field &f, const Value &obj, Value &original, Value &newVal) {
317 3025 : if (f.getType() == Type::Extra) {
318 75 : if (newVal.isDictionary()) {
319 75 : auto &extraFields = static_cast<const FieldExtra *>(f.getSlot())->fields;
320 300 : for (auto &it : newVal.asDict()) {
321 225 : auto f_it = extraFields.find(it.first);
322 225 : if (f_it != extraFields.end()) {
323 225 : auto slot = f_it->second.getSlot();
324 225 : auto &val = original.getValue(it.first);
325 225 : if (!slot->replaceFilterFn || slot->replaceFilterFn(scheme, obj, val, it.second)) {
326 225 : if (!it.second.isNull()) {
327 225 : if (val) {
328 225 : Adapter_mergeValues(scheme, f_it->second, obj, val, it.second);
329 : } else {
330 0 : original.setValue(std::move(it.second), it.first);
331 : }
332 : } else {
333 0 : original.erase(it.first);
334 : }
335 : }
336 : }
337 : }
338 0 : } else if (newVal.isArray() && f.getTransform() == Transform::Array) {
339 0 : original.setValue(std::move(newVal));
340 : }
341 : } else {
342 2950 : original.setValue(std::move(newVal));
343 : }
344 3025 : }
345 :
346 2575 : Value Adapter::save(Worker &w, uint64_t oid, Value &obj, Value &patch, const Set<const Field *> &fields) const {
347 2575 : bool hasNonVirtualUpdates = false;
348 2575 : Map<const FieldVirtual *, Value> virtualWrites;
349 :
350 2575 : Vector<InputField> inputFields;
351 2575 : Vector<InputRow> inputRows;
352 2575 : auto &inputRow = inputRows.emplace_back();
353 2575 : if (!fields.empty()) {
354 6350 : for (auto &it : fields) {
355 4500 : auto &patchValue = patch.getValue(it->getName());
356 4500 : auto &val = obj.getValue(it->getName());
357 :
358 4500 : if (!patchValue.isNull()) {
359 4500 : if (val) {
360 2800 : inputRow.values.emplace_back(Value(val));
361 2800 : Adapter_mergeValues(w.scheme(), *it, obj, inputRow.values.back().value, patchValue);
362 : } else {
363 1700 : inputRow.values.emplace_back(Value(std::move(patchValue)));
364 : }
365 4500 : obj.setValue(inputRow.values.back().value, it->getName());
366 : } else {
367 0 : inputRow.values.emplace_back(Value());
368 0 : obj.erase(it->getName());
369 : }
370 :
371 4500 : inputFields.emplace_back(InputField{it});
372 : }
373 :
374 1850 : processFullTextFields(w.scheme(), obj, inputFields, inputRows);
375 : } else {
376 1775 : for (auto &it : patch.asDict()) {
377 1050 : auto f = w.scheme().getField(it.first);
378 1050 : if (f) {
379 1050 : inputFields.emplace_back(InputField{f});
380 1050 : inputRow.values.emplace_back(Value(std::move(it.second)));
381 : }
382 : }
383 725 : processFullTextFields(w.scheme(), patch, inputFields, inputRows);
384 : }
385 :
386 :
387 2575 : size_t i = 0;
388 8225 : for (auto &it : inputFields) {
389 5650 : if (it.field->getType() != Type::Virtual) {
390 5625 : hasNonVirtualUpdates = true;
391 : } else {
392 25 : if (inputRow.values[i].hasValue()) {
393 25 : virtualWrites.emplace(it.field->getSlot<FieldVirtual>(), move(inputRow.values[i].value));
394 : }
395 : }
396 5650 : ++ i;
397 : }
398 :
399 2575 : Value ret;
400 2575 : if (hasNonVirtualUpdates) {
401 2550 : ret = _interface->save(w, oid, obj, inputFields, inputRow);
402 : } else {
403 25 : ret = obj;
404 : }
405 2575 : if (ret) {
406 2600 : for (auto &it : virtualWrites) {
407 25 : if (it.first->writeFn) {
408 25 : if (it.first->writeFn(w.scheme(), obj, it.second)) {
409 25 : ret.setValue(std::move(it.second), it.first->getName());
410 : } else {
411 0 : _interface->cancelTransaction();
412 0 : return Value();
413 : }
414 : } else {
415 0 : _interface->cancelTransaction();
416 0 : return Value();
417 : }
418 : }
419 : }
420 2575 : return ret;
421 2575 : }
422 :
423 275 : bool Adapter::remove(Worker &w, uint64_t oid) const {
424 275 : return _interface->remove(w, oid);
425 : }
426 :
427 375 : size_t Adapter::count(Worker &w, const Query &q) const {
428 375 : return _interface->count(w, q);
429 : }
430 :
431 2550 : void Adapter::scheduleAutoField(const Scheme &scheme, const Field &field, uint64_t id) {
432 : struct Adapter_TaskData : AllocPool {
433 : const Scheme *scheme = nullptr;
434 : const Field *field = nullptr;
435 : Set<uint64_t> objects;
436 : };
437 :
438 2550 : if (!id) {
439 25 : return;
440 : }
441 :
442 2525 : stappler::memory::pool_t * p = stappler::memory::pool::acquire();
443 2525 : if (Adapter_TaskData *obj = memory::pool::get<Adapter_TaskData>(p, toString(scheme.getName(), "_f_", field.getName()))) {
444 2175 : obj->objects.emplace(id);
445 : } else {
446 350 : auto d = new (p) Adapter_TaskData;
447 350 : d->scheme = &scheme;
448 350 : d->field = &field;
449 350 : d->objects.emplace(id);
450 350 : memory::pool::store(p, d, toString(scheme.getName(), "_f_", field.getName()), [d, this] {
451 350 : _application->scheduleAyncDbTask([this, d] (stappler::memory::pool_t *p) -> Function<void(const Transaction &t)> {
452 350 : auto vec = new (p) Vector<uint64_t>(p);
453 2875 : for (auto &it : d->objects) {
454 2525 : vec->push_back(it);
455 : }
456 :
457 675 : return [this, vec, scheme = d->scheme, field = d->field] (const Transaction &t) {
458 325 : runAutoFields(t, *vec, *scheme, *field);
459 350 : };
460 : });
461 350 : });
462 : }
463 : }
464 :
465 350 : Value Adapter::field(Action a, Worker &w, uint64_t oid, const Field &f, Value &&data) const {
466 350 : return _interface->field(a, w, oid, f, std::move(data));
467 : }
468 :
469 425 : Value Adapter::field(Action a, Worker &w, const Value &obj, const Field &f, Value &&data) const {
470 425 : return _interface->field(a, w, obj, f, std::move(data));
471 : }
472 :
473 125 : bool Adapter::addToView(const FieldView &v, const Scheme *s, uint64_t oid, const Value &data) const {
474 125 : return _interface->addToView(v, s, oid, data);
475 : }
476 200 : bool Adapter::removeFromView(const FieldView &v, const Scheme *s, uint64_t oid) const {
477 200 : return _interface->removeFromView(v, s, oid);
478 : }
479 :
480 0 : Vector<int64_t> Adapter::getReferenceParents(const Scheme &s, uint64_t oid, const Scheme *fs, const Field *f) const {
481 0 : return _interface->getReferenceParents(s, oid, fs, f);
482 : }
483 :
484 6100 : bool Adapter::beginTransaction() const {
485 6100 : return _interface->beginTransaction();
486 : }
487 :
488 6100 : bool Adapter::endTransaction() const {
489 6100 : return _interface->endTransaction();
490 : }
491 :
492 0 : void Adapter::cancelTransaction() const {
493 0 : _interface->cancelTransaction();
494 0 : }
495 :
496 21597 : bool Adapter::isInTransaction() const {
497 21597 : return _interface->isInTransaction();
498 : }
499 :
500 0 : TransactionStatus Adapter::getTransactionStatus() const {
501 0 : return _interface->getTransactionStatus();
502 : }
503 :
504 325 : void Adapter::runAutoFields(const Transaction &t, const Vector<uint64_t> &vec, const Scheme &scheme, const Field &field) {
505 325 : auto &defs = field.getSlot()->autoField;
506 325 : if (defs.defaultFn) {
507 325 : auto includeSelf = (std::find(defs.requireFields.begin(), defs.requireFields.end(), field.getName()) == defs.requireFields.end());
508 2100 : for (auto &id : vec) {
509 1775 : Query q; q.select(id);
510 5325 : for (auto &req : defs.requireFields) {
511 3550 : q.include(req);
512 : }
513 1775 : if (includeSelf) {
514 1775 : q.include(field.getName());
515 : }
516 :
517 1775 : auto objs = scheme.select(t, q);
518 1775 : if (auto obj = objs.getValue(0)) {
519 1700 : auto newValue = defs.defaultFn(obj);
520 1700 : if (newValue != obj.getValue(field.getName())) {
521 1700 : Value patch;
522 1700 : patch.setValue(std::move(newValue), field.getName().str<Interface>());
523 1700 : scheme.update(t, obj, patch, UpdateFlags::Protected | UpdateFlags::NoReturn);
524 1700 : }
525 3475 : }
526 1775 : }
527 : }
528 325 : }
529 :
530 6225 : void Adapter::processFullTextFields(const Scheme &scheme, Value &patch, Vector<InputField> &ifields, Vector<InputRow> &ivalues) const {
531 2525 : auto addFullTextView = [&] (const Field *f, const FieldFullTextView *slot) {
532 2525 : if (slot->viewFn) {
533 2525 : size_t target = 0;
534 2525 : auto iit = std::find(ifields.begin(), ifields.end(), InputField{f});
535 2525 : if (iit == ifields.end()) {
536 2525 : ifields.emplace_back(InputField{f});
537 5075 : for (auto &row : ivalues) {
538 2550 : row.values.emplace_back(Value());
539 : }
540 2525 : target = ifields.size() - 1;
541 : } else {
542 0 : target = iit - ifields.begin();
543 : }
544 :
545 2525 : size_t i = 0;
546 5075 : for (auto &row : ivalues) {
547 2550 : auto result = slot->viewFn(scheme, patch.isArray()? patch.getValue(i):patch);
548 2550 : if (!result.empty()) {
549 2550 : row.values[target] = InputValue(move(result));
550 : }
551 2550 : ++ i;
552 2550 : }
553 : }
554 2525 : };
555 :
556 78425 : for (auto &it : scheme.getFields()) {
557 72200 : if (it.second.getType() == Type::FullTextView) {
558 4275 : auto slot = it.second.getSlot<FieldFullTextView>();
559 17175 : for (auto &p_it : ifields) {
560 15425 : if (std::find(slot->requireFields.begin(), slot->requireFields.end(), p_it.field->getName()) != slot->requireFields.end()) {
561 2525 : addFullTextView(&it.second, slot);
562 2525 : break;
563 : }
564 : }
565 : }
566 : }
567 6225 : }
568 :
569 :
570 17650 : void Binder::setInterface(QueryInterface *iface) {
571 17650 : _iface = iface;
572 17650 : }
573 22850 : QueryInterface * Binder::getInterface() const {
574 22850 : return _iface;
575 : }
576 :
577 7125 : void Binder::writeBind(StringStream &query, int64_t val) {
578 7125 : _iface->bindInt(*this, query, val);
579 7125 : }
580 5575 : void Binder::writeBind(StringStream &query, uint64_t val) {
581 5575 : _iface->bindUInt(*this, query, val);
582 5575 : }
583 0 : void Binder::writeBind(StringStream &query, double val) {
584 0 : _iface->bindDouble(*this, query, val);
585 0 : }
586 50 : void Binder::writeBind(StringStream &query, stappler::Time val) {
587 50 : _iface->bindUInt(*this, query, val.toMicros());
588 50 : }
589 0 : void Binder::writeBind(StringStream &query, stappler::TimeInterval val) {
590 0 : _iface->bindUInt(*this, query, val.toMicros());
591 0 : }
592 0 : void Binder::writeBind(StringStream &query, const String &val) {
593 0 : _iface->bindString(*this, query, val);
594 0 : }
595 1225 : void Binder::writeBind(StringStream &query, String &&val) {
596 1225 : _iface->bindMoveString(*this, query, std::move(val));
597 1225 : }
598 350 : void Binder::writeBind(StringStream &query, const StringView &val) {
599 350 : _iface->bindStringView(*this, query, val);
600 350 : }
601 50 : void Binder::writeBind(StringStream &query, const Bytes &val) {
602 50 : _iface->bindBytes(*this, query, val);
603 50 : }
604 175 : void Binder::writeBind(StringStream &query, Bytes &&val) {
605 175 : _iface->bindMoveBytes(*this, query, std::move(val));
606 175 : }
607 475 : void Binder::writeBind(StringStream &query, const stappler::CoderSource &val) {
608 475 : _iface->bindCoderSource(*this, query, val);
609 475 : }
610 2275 : void Binder::writeBind(StringStream &query, const Value &val) {
611 2275 : _iface->bindValue(*this, query, val);
612 2275 : }
613 34300 : void Binder::writeBind(StringStream &query, const DataField &f) {
614 34300 : _iface->bindDataField(*this, query, f);
615 34300 : }
616 50 : void Binder::writeBind(StringStream &query, const TypeString &type) {
617 50 : _iface->bindTypeString(*this, query, type);
618 50 : }
619 2550 : void Binder::writeBind(StringStream &query, const FullTextField &d) {
620 2550 : _iface->bindFullText(*this, query, d);
621 2550 : }
622 300 : void Binder::writeBind(StringStream &query, const FullTextFrom &d) {
623 300 : _iface->bindFullTextFrom(*this, query, d);
624 300 : }
625 300 : void Binder::writeBind(StringStream &query, const FullTextRank &rank) {
626 300 : _iface->bindFullTextRank(*this, query, rank);
627 300 : }
628 300 : void Binder::writeBind(StringStream &query, const FullTextQueryRef &data) {
629 300 : _iface->bindFullTextQuery(*this, query, data);
630 300 : }
631 0 : void Binder::writeBind(StringStream &query, const stappler::sql::PatternComparator<const Value &> &cmp) {
632 0 : if (cmp.value->isString()) {
633 0 : switch (cmp.cmp) {
634 0 : case Comparation::Prefix: {
635 0 : String str; str.reserve(cmp.value->getString().size() + 1);
636 0 : str.append(cmp.value->getString());
637 0 : str.append("%");
638 0 : _iface->bindMoveString(*this, query, std::move(str));
639 0 : break;
640 0 : }
641 0 : case Comparation::Suffix: {
642 0 : String str; str.reserve(cmp.value->getString().size() + 1);
643 0 : str.append("%");
644 0 : str.append(cmp.value->getString());
645 0 : _iface->bindMoveString(*this, query, std::move(str));
646 0 : break;
647 0 : }
648 0 : case Comparation::WordPart: {
649 0 : String str; str.reserve(cmp.value->getString().size() + 2);
650 0 : str.append("%");
651 0 : str.append(cmp.value->getString());
652 0 : str.append("%");
653 0 : _iface->bindMoveString(*this, query, std::move(str));
654 0 : break;
655 0 : }
656 0 : default:
657 0 : _iface->bindValue(*this, query, Value());
658 0 : break;
659 : }
660 : } else {
661 0 : _iface->bindValue(*this, query, Value());
662 : }
663 0 : }
664 0 : void Binder::writeBind(StringStream &query, const stappler::sql::PatternComparator<const StringView &> &cmp) {
665 0 : switch (cmp.cmp) {
666 0 : case Comparation::Prefix: {
667 0 : String str; str.reserve(cmp.value->size() + 1);
668 0 : str.append(cmp.value->data(), cmp.value->size());
669 0 : str.append("%");
670 0 : _iface->bindMoveString(*this, query, std::move(str));
671 0 : break;
672 0 : }
673 0 : case Comparation::Suffix: {
674 0 : String str; str.reserve(cmp.value->size() + 1);
675 0 : str.append("%");
676 0 : str.append(cmp.value->data(), cmp.value->size());
677 0 : _iface->bindMoveString(*this, query, std::move(str));
678 0 : break;
679 0 : }
680 0 : case Comparation::WordPart: {
681 0 : String str; str.reserve(cmp.value->size() + 2);
682 0 : str.append("%");
683 0 : str.append(cmp.value->data(), cmp.value->size());
684 0 : str.append("%");
685 0 : _iface->bindMoveString(*this, query, std::move(str));
686 0 : break;
687 0 : }
688 0 : default:
689 0 : break;
690 : }
691 0 : _iface->bindMoveString(*this, query, "NULL");
692 0 : }
693 125 : void Binder::writeBind(StringStream &query, const Vector<int64_t> &vec) {
694 125 : _iface->bindIntVector(*this, query, vec);
695 125 : }
696 :
697 0 : void Binder::writeBind(StringStream &query, const Vector<double> &vec) {
698 0 : _iface->bindDoubleVector(*this, query, vec);
699 0 : }
700 :
701 0 : void Binder::writeBind(StringStream &query, const Vector<StringView> &vec) {
702 0 : _iface->bindStringVector(*this, query, vec);
703 0 : }
704 :
705 0 : void Binder::writeBindArray(StringStream &query, const Vector<int64_t> &vec) {
706 0 : _iface->bindIntVector(*this, query, vec);
707 0 : }
708 :
709 0 : void Binder::writeBindArray(StringStream &query, const Vector<double> &vec) {
710 0 : _iface->bindDoubleVector(*this, query, vec);
711 0 : }
712 :
713 0 : void Binder::writeBindArray(StringStream &query, const Vector<StringView> &vec) {
714 0 : _iface->bindStringVector(*this, query, vec);
715 0 : }
716 :
717 25 : void Binder::writeBindArray(StringStream &query, const Value &val) {
718 25 : if (val.isArray()) {
719 25 : if (val.getValue(0).isInteger()) {
720 25 : Vector<int64_t> vec;
721 75 : for (auto &it : val.asArray()) {
722 50 : vec.emplace_back(it.getInteger());
723 : }
724 25 : _iface->bindIntVector(*this, query, vec);
725 25 : } else if (val.getValue(0).isDouble()) {
726 0 : Vector<double> vec;
727 0 : for (auto &it : val.asArray()) {
728 0 : vec.emplace_back(it.getDouble());
729 : }
730 0 : _iface->bindDoubleVector(*this, query, vec);
731 0 : } else if (val.getValue(0).isString()) {
732 0 : Vector<StringView> vec;
733 0 : for (auto &it : val.asArray()) {
734 0 : vec.emplace_back(it.getString());
735 : }
736 0 : _iface->bindStringVector(*this, query, vec);
737 0 : } else {
738 0 : log::error("db::Binder", "Malformed Value for writeBindArray - not an array");
739 : }
740 : } else {
741 0 : log::error("db::Binder", "Malformed Value for writeBindArray - not an array");
742 : }
743 25 : }
744 :
745 7375 : void Binder::clear() {
746 7375 : _iface->clear();
747 7375 : }
748 :
749 28622 : ResultRow::ResultRow(const ResultCursor *res, size_t r) : result(res), row(r) { }
750 :
751 0 : ResultRow::ResultRow(const ResultRow & other) noexcept : result(other.result), row(other.row) { }
752 0 : ResultRow & ResultRow::operator=(const ResultRow &other) noexcept {
753 0 : result = other.result;
754 0 : row = other.row;
755 0 : return *this;
756 : }
757 :
758 625 : size_t ResultRow::size() const {
759 625 : return result->getFieldsCount();
760 : }
761 16950 : Value ResultRow::toData(const db::Scheme &scheme, const Map<String, db::Field> &viewFields,
762 : const Vector<const Field *> &virtuals) {
763 16950 : Value row(Value::Type::DICTIONARY);
764 16950 : row.asDict().reserve(result->getFieldsCount() + virtuals.size());
765 16950 : Value *deltaPtr = nullptr;
766 123550 : for (size_t i = 0; i < result->getFieldsCount(); i++) {
767 106600 : auto n = result->getFieldName(i);
768 106600 : if (n == "__oid") {
769 16950 : if (!isNull(i)) {
770 16925 : row.setInteger(toInteger(i), n.str<Interface>());
771 : }
772 89650 : } else if (n == "__vid") {
773 100 : auto val = isNull(i)?int64_t(0):toInteger(i);
774 100 : row.setInteger(val, n.str<Interface>());
775 100 : if (deltaPtr && val == 0) {
776 0 : deltaPtr->setString("delete", "action");
777 : }
778 89550 : } else if (n == "__d_action") {
779 175 : if (!deltaPtr) {
780 175 : deltaPtr = &row.emplace("__delta");
781 : }
782 175 : switch (DeltaAction(toInteger(i))) {
783 75 : case DeltaAction::Create: deltaPtr->setString("create", "action"); break;
784 75 : case DeltaAction::Update: deltaPtr->setString("update", "action"); break;
785 25 : case DeltaAction::Delete: deltaPtr->setString("delete", "action"); break;
786 0 : case DeltaAction::Append: deltaPtr->setString("append", "action"); break;
787 0 : case DeltaAction::Erase: deltaPtr->setString("erase", "action"); break;
788 0 : default: break;
789 : }
790 89375 : } else if (n == "__d_object") {
791 175 : row.setInteger(toInteger(i), "__oid");
792 89200 : } else if (n == "__d_time") {
793 175 : if (!deltaPtr) {
794 0 : deltaPtr = &row.emplace("__delta");
795 : }
796 175 : deltaPtr->setInteger(toInteger(i), "time");
797 89025 : } else if (n.starts_with("__ts_rank_")) {
798 1000 : auto d = toDouble(i);
799 1000 : row.setDouble(d, n.sub("__ts_rank_"_len).str<Interface>());
800 1000 : row.setDouble(d, n.str<Interface>());
801 88025 : } else if (!isNull(i)) {
802 71675 : if (auto f_it = scheme.getField(n)) {
803 71000 : row.setValue(toData(i, *f_it), n.str<Interface>());
804 : } else {
805 675 : auto ef_it = viewFields.find(n);
806 675 : if (ef_it != viewFields.end()) {
807 0 : row.setValue(toData(i, ef_it->second), n.str<Interface>());
808 : }
809 : }
810 : }
811 : }
812 :
813 16950 : if (!virtuals.empty()) {
814 175 : for (auto &it : virtuals) {
815 100 : auto slot = it->getSlot<FieldVirtual>();
816 100 : if (slot->readFn) {
817 100 : if (auto v = slot->readFn(scheme, row)) {
818 50 : row.setValue(std::move(v), it->getName());
819 100 : }
820 : }
821 : }
822 : }
823 :
824 16950 : return row;
825 0 : }
826 :
827 0 : Value ResultRow::encode() const {
828 0 : Value row(Value::Type::DICTIONARY);
829 0 : row.asDict().reserve(result->getFieldsCount());
830 :
831 0 : for (size_t i = 0; i < result->getFieldsCount(); i++) {
832 0 : auto n = result->getFieldName(i);
833 0 : if (!isNull(i)) {
834 0 : row.setValue(toTypedData(i), n);
835 : }
836 : }
837 0 : return row;
838 0 : }
839 :
840 0 : StringView ResultRow::front() const {
841 0 : return at(0);
842 : }
843 0 : StringView ResultRow::back() const {
844 0 : return at(result->getFieldsCount() - 1);
845 : }
846 :
847 105075 : bool ResultRow::isNull(size_t n) const {
848 105075 : return result->isNull(n);
849 : }
850 :
851 21826 : StringView ResultRow::at(size_t n) const {
852 21826 : return result->toString(n);
853 : }
854 :
855 14325 : StringView ResultRow::toString(size_t n) const {
856 14325 : return result->toString(n);
857 : }
858 13450 : BytesView ResultRow::toBytes(size_t n) const {
859 13450 : return result->toBytes(n);
860 : }
861 :
862 43775 : int64_t ResultRow::toInteger(size_t n) const {
863 43775 : return result->toInteger(n);
864 : }
865 :
866 7600 : double ResultRow::toDouble(size_t n) const {
867 7600 : return result->toDouble(n);
868 : }
869 :
870 11522 : bool ResultRow::toBool(size_t n) const {
871 11522 : return result->toBool(n);
872 : }
873 :
874 0 : Value ResultRow::toTypedData(size_t n) const {
875 0 : return result->toTypedData(n);
876 : }
877 :
878 71100 : Value ResultRow::toData(size_t n, const db::Field &f) {
879 71100 : switch(f.getType()) {
880 20575 : case db::Type::Integer:
881 : case db::Type::Object:
882 : case db::Type::Set:
883 : case db::Type::Array:
884 : case db::Type::File:
885 : case db::Type::Image:
886 20575 : return Value(toInteger(n));
887 : break;
888 6600 : case db::Type::Float:
889 6600 : return Value(toDouble(n));
890 : break;
891 3975 : case db::Type::Boolean:
892 3975 : return Value(toBool(n));
893 : break;
894 13750 : case db::Type::Text:
895 27500 : return Value(toString(n));
896 : break;
897 7350 : case db::Type::Bytes:
898 14700 : return Value(toBytes(n));
899 : break;
900 5850 : case db::Type::Data:
901 : case db::Type::Extra:
902 11700 : return data::read<Interface, BytesView>(toBytes(n));
903 : break;
904 10125 : case db::Type::Custom:
905 10125 : return result->toCustomData(n, f.getSlot<db::FieldCustom>());
906 : break;
907 2875 : default:
908 2875 : break;
909 : }
910 :
911 2875 : return Value();
912 : }
913 :
914 21073 : Result::Result(db::ResultCursor *iface) : _cursor(iface) {
915 21073 : _success = _cursor->isSuccess();
916 21075 : if (_success) {
917 21075 : _nfields = _cursor->getFieldsCount();
918 : }
919 21075 : }
920 21075 : Result::~Result() {
921 21075 : clear();
922 21075 : }
923 :
924 0 : Result::Result(Result &&res) : _cursor(res._cursor), _success(res._success), _nfields(res._nfields) {
925 0 : res._cursor = nullptr;
926 0 : }
927 0 : Result & Result::operator=(Result &&res) {
928 0 : clear();
929 0 : _cursor = res._cursor;
930 0 : _success = res._success;
931 0 : _nfields = res._nfields;
932 0 : res._cursor = nullptr;
933 0 : return *this;
934 : }
935 :
936 10775 : Result::operator bool () const {
937 10775 : return _success;
938 : }
939 1850 : bool Result::success() const {
940 1850 : return _success;
941 : }
942 :
943 0 : Value Result::info() const {
944 0 : return _cursor->getInfo();
945 : }
946 :
947 5225 : bool Result::empty() const {
948 5225 : return _cursor->isEmpty();
949 : }
950 :
951 4200 : int64_t Result::readId() {
952 4200 : return _cursor->toId();
953 : }
954 :
955 1850 : size_t Result::getAffectedRows() const {
956 1850 : return _cursor->getAffectedRows();
957 : }
958 :
959 10925 : size_t Result::getRowsHint() const {
960 10925 : return _cursor->getRowsHint();
961 : }
962 :
963 21200 : void Result::clear() {
964 21200 : if (_cursor) {
965 21200 : _cursor->clear();
966 : }
967 21200 : }
968 :
969 13674 : Result::Iter Result::begin() {
970 13674 : if (_row != 0) {
971 0 : _cursor->reset();
972 0 : _row = 0;
973 : }
974 13674 : if (_cursor->isEmpty()) {
975 700 : return Result::Iter(this, stappler::maxOf<size_t>());
976 : } else {
977 12974 : return Result::Iter(this, _row);
978 : }
979 : }
980 :
981 13675 : Result::Iter Result::end() {
982 13675 : return Result::Iter(this, stappler::maxOf<size_t>());
983 : }
984 :
985 1900 : ResultRow Result::current() const {
986 1900 : return ResultRow(_cursor, _row);
987 : }
988 :
989 25970 : bool Result::next() {
990 25970 : if (_cursor->next()) {
991 13749 : ++ _row;
992 13749 : return true;
993 : }
994 12225 : _row = stappler::maxOf<size_t>();
995 12225 : return false;
996 : }
997 :
998 500 : StringView Result::name(size_t n) const {
999 500 : return _cursor->getFieldName(n);
1000 : }
1001 :
1002 10925 : Value Result::decode(const db::Scheme &scheme, const Vector<const Field *> &virtuals) {
1003 10925 : Value ret(Value::Type::ARRAY);
1004 10925 : ret.asArray().reserve(getRowsHint());
1005 27775 : for (auto it : *this) {
1006 16850 : ret.addValue(it.toData(scheme, Map<String, db::Field>(), virtuals));
1007 : }
1008 10925 : return ret;
1009 0 : }
1010 50 : Value Result::decode(const db::Field &field, const Vector<const Field *> &virtuals) {
1011 50 : Value ret;
1012 50 : if (!empty()) {
1013 50 : if (field.getType() == db::Type::Array) {
1014 50 : auto &arrF = static_cast<const db::FieldArray *>(field.getSlot())->tfield;
1015 150 : for (auto it : *this) {
1016 100 : ret.addValue(it.toData(0, arrF));
1017 : }
1018 0 : } else if (field.getType() == db::Type::View) {
1019 0 : auto v = static_cast<const db::FieldView *>(field.getSlot());
1020 0 : for (auto it : *this) {
1021 0 : ret.addValue(it.toData(*v->scheme, Map<String, db::Field>(), virtuals));
1022 : }
1023 : } else {
1024 0 : for (auto it : *this) {
1025 0 : ret.addValue(it.toData(0, field));
1026 : }
1027 : }
1028 : }
1029 50 : return ret;
1030 0 : }
1031 :
1032 50 : Value Result::decode(const db::FieldView &field) {
1033 50 : Value ret;
1034 150 : for (auto it : *this) {
1035 100 : ret.addValue(it.toData(*field.scheme, Map<String, db::Field>()));
1036 : }
1037 50 : return ret;
1038 0 : }
1039 :
1040 : }
|