LCOV - code coverage report
Current view: top level - core/db - SPDbAdapter.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 462 689 67.1 %
Date: 2024-05-12 00:16:13 Functions: 87 119 73.1 %

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

Generated by: LCOV version 1.14