LCOV - code coverage report
Current view: top level - core/db/sql - SPSqlHandleObject.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 301 484 62.2 %
Date: 2024-05-12 00:16:13 Functions: 28 40 70.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2018-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 "SPSqlHandle.h"
      25             : #include "SPSqlDriver.h"
      26             : #include "SPDbScheme.h"
      27             : 
      28             : namespace STAPPLER_VERSIONIZED stappler::db::sql {
      29             : 
      30             : template <typename Clause>
      31             : static void SqlQuery_makeCustomFrom(const Driver *driver, SqlQuery &q, Clause &tmp, const Query &query, const Scheme &scheme);
      32             : 
      33        3650 : static bool Handle_hasPostUpdate(const SpanView<InputField> &idata, const SpanView<InputRow> &inputRows) {
      34        3650 :         size_t i = 0;
      35       33775 :         for (auto &it : idata) {
      36       30425 :                 auto t = it.field->getType();
      37       30425 :                 switch (t) {
      38          50 :                 case db::Type::Array:
      39             :                 case db::Type::Set:
      40          50 :                         for (auto &row : inputRows) {
      41          50 :                                 if (row.values[i].hasValue()) {
      42          50 :                                         return true;
      43             :                                 }
      44             :                         }
      45           0 :                         return true;
      46             :                         break;
      47         250 :                 case db::Type::Object:
      48         500 :                         for (auto &row : inputRows) {
      49         250 :                                 if (row.values[i].hasValue() && !row.values[i].value.isBasicType()) {
      50           0 :                                         return true;
      51             :                                 }
      52             :                         }
      53         250 :                         break;
      54       30125 :                 default:
      55       30125 :                         break;
      56             :                 }
      57       30375 :                 if (t == db::Type::Array || t == db::Type::Set || t == db::Type::Object) {
      58         250 :                         return true;
      59             :                 }
      60       30125 :                 ++ i;
      61             :         }
      62        3350 :         return false;
      63             : }
      64             : 
      65        6175 : static Value Handle_preparePostUpdate(const Vector<InputField> &inputFields, InputRow &row) {
      66        6175 :         Value postUpdate(Value::Type::DICTIONARY);
      67        6175 :         size_t i = 0;
      68       42525 :         for (auto &field : inputFields) {
      69       36350 :                 switch (field.field->getType()) {
      70          75 :                 case db::Type::Array:
      71             :                 case db::Type::Set:
      72          75 :                         if (row.values[i].hasValue()) {
      73          50 :                                 postUpdate.setValue(std::move(row.values[i].value), field.field->getName());
      74             :                         }
      75          75 :                         break;
      76         375 :                 case db::Type::Object:
      77         375 :                         if (row.values[i].hasValue() && !row.values[i].value.isBasicType()) {
      78           0 :                                 postUpdate.setValue(std::move(row.values[i].value), field.field->getName());
      79             :                         }
      80         375 :                         break;
      81       35900 :                 default:
      82       35900 :                         break;
      83             :                 }
      84       36350 :                 ++ i;
      85             :         }
      86             : 
      87        6175 :         return postUpdate;
      88           0 : }
      89             : 
      90           0 : bool SqlHandle::foreach(Worker &worker, const Query &q, const Callback<bool(Value &)> &cb) {
      91           0 :         auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
      92           0 :         bool ret = false;
      93           0 :         auto &scheme = worker.scheme();
      94           0 :         makeQuery([&, this] (SqlQuery &query) {
      95           0 :                 auto ordField = q.getQueryField();
      96           0 :                 if (ordField.empty()) {
      97           0 :                         SqlQuery::Context ctx(query, scheme, worker, q);
      98           0 :                         query.writeQuery(ctx);
      99           0 :                         ret = selectQuery(query, [&] (Result &res) -> bool {
     100           0 :                                 auto virtuals = ctx.getVirtuals();
     101           0 :                                 for (auto it : res) {
     102           0 :                                         auto d = it.toData(scheme, Map<String, db::Field>(), virtuals);
     103           0 :                                         if (!cb(d)) {
     104           0 :                                                 return false;
     105             :                                         }
     106           0 :                                 }
     107           0 :                                 return true;
     108           0 :                         });
     109           0 :                 } else if (auto f = scheme.getField(ordField)) {
     110           0 :                         switch (f->getType()) {
     111           0 :                         case Type::Set: {
     112           0 :                                 SqlQuery::Context ctx(query, *f->getForeignScheme(), worker, q);
     113           0 :                                 if (query.writeQuery(ctx, scheme, q.getQueryId(), *f)) {
     114           0 :                                         ret = selectQuery(query, [&] (Result &res) -> bool {
     115           0 :                                                 auto virtuals = ctx.getVirtuals();
     116           0 :                                                 for (auto it : res) {
     117           0 :                                                         auto d = it.toData(*f->getForeignScheme(), Map<String, db::Field>(), virtuals);
     118           0 :                                                         if (!cb(d)) {
     119           0 :                                                                 return false;
     120             :                                                         }
     121           0 :                                                 }
     122           0 :                                                 return true;
     123           0 :                                         });
     124             :                                 }
     125           0 :                                 break;
     126           0 :                         }
     127           0 :                         default:
     128           0 :                                 break;
     129             :                         }
     130             :                 }
     131           0 :         }, &queryStorage);
     132           0 :         return ret;
     133           0 : }
     134             : 
     135        6249 : Value SqlHandle::select(Worker &worker, const db::Query &q) {
     136        6249 :         auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
     137             : 
     138        6250 :         Value ret;
     139        6250 :         auto &scheme = worker.scheme();
     140        6250 :         makeQuery([&, this] (SqlQuery &query) {
     141        6250 :                 auto ordField = q.getQueryField();
     142        6250 :                 if (ordField.empty()) {
     143        6200 :                         SqlQuery::Context ctx(query, scheme, worker, q);
     144        6200 :                         query.writeQuery(ctx);
     145        6200 :                         ret = selectValueQuery(scheme, query, ctx.getVirtuals());
     146        6250 :                 } else if (auto f = scheme.getField(ordField)) {
     147          50 :                         switch (f->getType()) {
     148           0 :                         case Type::Set:
     149           0 :                                 ret = getSetField(worker, query, q.getQueryId(), *f, q);
     150           0 :                                 break;
     151          50 :                         case Type::View:
     152          50 :                                 ret = getViewField(worker, query, q.getQueryId(), *f, q);
     153          50 :                                 break;
     154           0 :                         default:
     155           0 :                                 break;
     156             :                         }
     157             :                 }
     158        6250 :         }, &queryStorage);
     159       12500 :         return ret;
     160        6250 : }
     161             : 
     162        3650 : Value SqlHandle::create(Worker &worker, const Vector<InputField> &inputFields, Vector<InputRow> &inputRows, bool multiCreate) {
     163        3650 :         if (inputRows.empty() || inputFields.empty()) {
     164           0 :                 return Value();
     165             :         }
     166             : 
     167        3650 :         auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
     168             : 
     169        3650 :         auto &scheme = worker.scheme();
     170             : 
     171        3675 :         auto bindRow = [&] (Value &ret, stappler::sql::Query<Binder,Interface>::InsertValues &val, InputRow &input) {
     172       34550 :                 for (size_t idx = 0; idx < inputFields.size(); ++ idx) {
     173       30875 :                         auto f = inputFields[idx].field;
     174       30875 :                         switch (f->getType()) {
     175          50 :                         case Type::Set:
     176             :                         case Type::Array:
     177             :                         case Type::Virtual:
     178          50 :                                 break;
     179       30825 :                         default:
     180       30825 :                                 switch (input.values[idx].type) {
     181       28375 :                                 case InputValue::Type::Value: {
     182       28375 :                                         auto &v = ret.setValue(input.values[idx].value, f->getName());
     183       28375 :                                         val.value(db::Binder::DataField{f, v, f->isDataLayout(), f->hasFlag(db::Flags::Compressed)});
     184       28375 :                                         break;
     185             :                                 }
     186           0 :                                 case InputValue::Type::File:
     187             :                                 case InputValue::Type::None:
     188           0 :                                         val.def();
     189           0 :                                         break;
     190        2450 :                                 case InputValue::Type::TSV:
     191        2450 :                                         val.value(db::Binder::FullTextField{f, input.values[idx].tsv});
     192        2450 :                                         break;
     193             :                                 }
     194       30825 :                                 break;
     195             :                         }
     196             :                 }
     197        3675 :         };
     198             : 
     199        7250 :         auto perform = [&, this] (InputRow &row) {
     200        3625 :                 int64_t id = 0;
     201        3625 :                 Value ret;
     202        3625 :                 Value postUpdate(Handle_preparePostUpdate(inputFields, row));
     203             : 
     204        3625 :                 makeQuery([&, this] (SqlQuery &query) {
     205        3625 :                         auto ins = query.insert(scheme.getName());
     206       34350 :                         for (auto &it : inputFields) {
     207       30725 :                                 switch (it.field->getType()) {
     208          50 :                                 case Type::Set:
     209             :                                 case Type::Array:
     210             :                                 case Type::Virtual:
     211          50 :                                         break;
     212       30675 :                                 default:
     213       30675 :                                         ins.field(it.field->getName());
     214       30675 :                                         break;
     215             :                                 }
     216             :                         }
     217             : 
     218        3625 :                         auto val = ins.values();
     219        3625 :                         bindRow(ret, val, row);
     220             : 
     221        3625 :                         auto &conflicts = worker.getConflicts();
     222        3725 :                         for (auto &it : conflicts) {
     223         100 :                                 if (it.second.isDoNothing()) {
     224          50 :                                         val.onConflict(it.first->getName()).doNothing();
     225             :                                 } else {
     226          50 :                                         auto c = val.onConflict(it.first->getName()).doUpdate();
     227         550 :                                         for (auto &iit : ret.asDict()) {
     228         500 :                                                 auto f = scheme.getField(iit.first);
     229         500 :                                                 if (f && (it.second.mask.empty() || std::find(it.second.mask.begin(), it.second.mask.end(), f) != it.second.mask.end())) {
     230         500 :                                                         c.excluded(iit.first);
     231             :                                                 }
     232             :                                         }
     233             : 
     234          50 :                                         if (it.second.hasCondition()) {
     235           0 :                                                 c.where().parenthesis(db::Operator::And, [&] (SqlQuery::WhereBegin &wh) {
     236           0 :                                                         SqlQuery::WhereContinue iw(wh.query, wh.state);
     237           0 :                                                         query.writeWhereCond(iw, db::Operator::And, worker.scheme(), it.second.condition);
     238           0 :                                                 });
     239             :                                         }
     240             :                                 }
     241             :                         }
     242             : 
     243        3625 :                         if (id == 0) {
     244        3625 :                                 val.returning().field(SqlQuery::Field("__oid").as("id")).finalize();
     245        3625 :                                 id = selectQueryId(query);
     246        3625 :                                 if (id) {
     247        3625 :                                         if (worker.shouldIncludeNone() && worker.scheme().hasForceExclude()) {
     248           0 :                                                 for (auto &it : worker.scheme().getFields()) {
     249           0 :                                                         if (it.second.hasFlag(db::Flags::ForceExclude)) {
     250           0 :                                                                 ret.erase(it.second.getName());
     251             :                                                         }
     252             :                                                 }
     253             :                                         }
     254        3625 :                                         ret.setInteger(id, "__oid");
     255             :                                 } else {
     256           0 :                                         ret = Value();
     257           0 :                                         return;
     258             :                                 }
     259             :                         } else {
     260           0 :                                 val.finalize();
     261           0 :                                 if (performQuery(query) != 1) {
     262           0 :                                         ret = Value();
     263           0 :                                         return;
     264             :                                 }
     265             :                         }
     266             : 
     267        3625 :                         if (id > 0) {
     268        3625 :                                 performPostUpdate(worker.transaction(), query, scheme, ret, id, postUpdate, false);
     269             :                         }
     270        3625 :                 }, &queryStorage);
     271        3625 :                 queryStorage.clear();
     272             : 
     273        7250 :                 return ret;
     274        3625 :         };
     275             : 
     276        3650 :         if (Handle_hasPostUpdate(inputFields, inputRows)) {
     277             :                 // process one-by-one
     278         300 :                 Value ret;
     279         300 :                 for (auto &it : inputRows) {
     280         300 :                         if (!multiCreate) {
     281         300 :                                 ret = perform(it);
     282             :                         } else {
     283           0 :                                 ret.addValue(perform(it));
     284             :                         }
     285         300 :                         return ret;
     286             :                 }
     287         300 :         } else {
     288        3350 :                 if (!multiCreate) {
     289        3325 :                         return perform(inputRows.front());
     290             :                 }
     291             : 
     292          25 :                 Value ret;
     293          25 :                 makeQuery([&, this] (SqlQuery &query) {
     294          25 :                         auto ins = query.insert(scheme.getName());
     295         100 :                         for (auto &it : inputFields) {
     296          75 :                                 ins.field(it.field->getName());
     297             :                         }
     298             : 
     299          25 :                         auto val = ins.values();
     300          75 :                         for (auto &row : inputRows) {
     301          50 :                                 auto &r = ret.emplace();
     302          50 :                                 bindRow(r, val, row);
     303          50 :                                 val = val.next();
     304             :                         }
     305             : 
     306          25 :                         auto &conflicts = worker.getConflicts();
     307          25 :                         for (auto &it : conflicts) {
     308           0 :                                 if (it.second.isDoNothing()) {
     309           0 :                                         val.onConflict(it.first->getName()).doNothing();
     310             :                                 } else {
     311           0 :                                         auto c = val.onConflict(it.first->getName()).doUpdate();
     312           0 :                                         for (auto &iit : inputFields) {
     313           0 :                                                 if ((it.second.mask.empty() || std::find(it.second.mask.begin(), it.second.mask.end(), iit.field) != it.second.mask.end())) {
     314           0 :                                                         c.excluded(iit.field->getName());
     315             :                                                 }
     316             :                                         }
     317             : 
     318           0 :                                         if (it.second.hasCondition()) {
     319           0 :                                                 c.where().parenthesis(db::Operator::And, [&] (SqlQuery::WhereBegin &wh) {
     320           0 :                                                         SqlQuery::WhereContinue iw(wh.query, wh.state);
     321           0 :                                                         query.writeWhereCond(iw, db::Operator::And, worker.scheme(), it.second.condition);
     322           0 :                                                 });
     323             :                                         }
     324             :                                 }
     325             :                         }
     326             : 
     327          25 :                         val.returning().field(SqlQuery::Field("__oid").as("id")).finalize();
     328          25 :                         selectQuery(query, [&, this] (Result &res) {
     329          25 :                                 size_t i = 0;
     330          75 :                                 for (auto it : res) {
     331          50 :                                         ret.getValue(i).setInteger(it.toInteger(0), "__oid");
     332          50 :                                         ++ i;
     333             :                                 }
     334             : 
     335          75 :                                 for (auto &iit : ret.asArray()) {
     336          50 :                                         if (worker.shouldIncludeNone() && worker.scheme().hasForceExclude()) {
     337           0 :                                                 for (auto &it : worker.scheme().getFields()) {
     338           0 :                                                         if (it.second.hasFlag(db::Flags::ForceExclude)) {
     339           0 :                                                                 iit.erase(it.second.getName());
     340             :                                                         }
     341             :                                                 }
     342             :                                         }
     343             :                                 }
     344          25 :                                 return true;
     345             :                         });
     346          25 :                 }, &queryStorage);
     347             : 
     348          25 :                 return ret;
     349          25 :         }
     350           0 :         return Value();
     351        3650 : }
     352             : 
     353        2550 : Value SqlHandle::save(Worker &worker, uint64_t oid, const Value &data, const Vector<InputField> &inputFields, InputRow &inputRow) {
     354        2550 :         if ((!data.isDictionary() && !data.empty()) || inputFields.empty() || inputRow.values.empty()) {
     355           0 :                 return Value();
     356             :         }
     357             : 
     358        2550 :         auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
     359             : 
     360        2550 :         Value ret(data);
     361        2550 :         auto &scheme = worker.scheme();
     362             : 
     363        2550 :         Value postUpdate(Handle_preparePostUpdate(inputFields, inputRow));
     364             : 
     365        2550 :         makeQuery([&, this] (SqlQuery &query) {
     366        2550 :                 auto upd = query.update(scheme.getName());
     367             : 
     368        8175 :                 for (size_t idx = 0; idx < inputFields.size(); ++ idx) {
     369        5625 :                         auto &f = inputFields[idx];
     370        5625 :                         auto &v = inputRow.values[idx];
     371             : 
     372        5625 :                         switch (f.field->getType()) {
     373          25 :                         case Type::View:
     374             :                         case Type::Set:
     375             :                         case Type::Array:
     376             :                         case Type::Virtual:
     377          25 :                                 break;
     378         125 :                         case Type::Object:
     379         125 :                                 if (v.hasValue() && v.value.isDictionary() && v.value.isInteger("__oid")) {
     380           0 :                                         upd.set(f.field->getName(), v.value.getInteger("__oid"));
     381         125 :                                 } else if (v.value.isInteger()) {
     382          75 :                                         upd.set(f.field->getName(), v.value.getInteger());
     383             :                                 }
     384         125 :                                 break;
     385        5475 :                         default:
     386        5475 :                                 switch (v.type) {
     387        5375 :                                 case InputValue::Type::Value: {
     388        5375 :                                         ret.setValue(v.value, f.field->getName());
     389        5375 :                                         upd.set(f.field->getName(), db::Binder::DataField{f.field, v.value, f.field->isDataLayout(), f.field->hasFlag(db::Flags::Compressed)});
     390        5375 :                                         break;
     391             :                                 }
     392         100 :                                 case InputValue::Type::TSV:
     393         100 :                                         upd.set(f.field->getName(), db::Binder::FullTextField{f.field, v.tsv});
     394         100 :                                         break;
     395           0 :                                 case InputValue::Type::File:
     396             :                                 case InputValue::Type::None:
     397           0 :                                         break;
     398             :                                 }
     399        5475 :                                 break;
     400             :                         }
     401             :                 }
     402             : 
     403        2550 :                 auto q = upd.where("__oid", Comparation::Equal, oid);
     404        2550 :                 auto &cond = worker.getConditions();
     405        2550 :                 if (!cond.empty()) {
     406           0 :                         q.parenthesis(db::Operator::And, [&] (SqlQuery::WhereBegin &wh) {
     407           0 :                                 SqlQuery::WhereContinue iw(wh.query, wh.state);
     408           0 :                                 for (auto &it : cond) {
     409           0 :                                         query.writeWhereCond(iw, db::Operator::And, worker.scheme(), it);
     410             :                                 }
     411           0 :                         });
     412             :                 }
     413             : 
     414        5100 :                 FieldResolver resv(worker.scheme(), worker);
     415        2550 :                 if (!worker.shouldIncludeNone()) {
     416         450 :                         auto returning = q.returning();
     417        1100 :                         for (auto &it : data.asDict()) {
     418         650 :                                 resv.include(it.first);
     419             :                         }
     420         450 :                         resv.readFields([&] (const StringView &name, const Field *) {
     421         450 :                                 returning.field(name);
     422         450 :                         });
     423         450 :                         q.finalize();
     424             :                 } else {
     425        2100 :                         q.returning().field("__oid").finalize();
     426             :                 }
     427             : 
     428        5100 :                 auto retVal = selectValueQuery(worker.scheme(), query, resv.getVirtuals());
     429        2550 :                 if (retVal.isArray() && retVal.size() == 1) {
     430        2550 :                         Value obj = std::move(retVal.getValue(0));
     431        2550 :                         int64_t id = obj.getInteger("__oid");
     432        2550 :                         if (id > 0) {
     433        2550 :                                 performPostUpdate(worker.transaction(), query, scheme, obj, id, postUpdate, false);
     434             :                         }
     435        2550 :                         ret = std::move(obj);
     436        2550 :                 } else if (!cond.empty() && isSuccess()) {
     437           0 :                         ret = Value({ stappler::pair("__oid", Value(oid)) });
     438             :                 } else {
     439           0 :                         _driver->getApplicationInterface()->debug("Storage", "Fail to update object", Value({
     440           0 :                                 std::make_pair("id", Value(oid)),
     441           0 :                                 std::make_pair("query", Value(query.getStream().weak())),
     442           0 :                                 std::make_pair("data", Value(data)),
     443           0 :                                 std::make_pair("ret", Value(ret)),
     444           0 :                         }));
     445             :                 }
     446        2550 :         }, &queryStorage);
     447        2550 :         return ret;
     448        2550 : }
     449             : 
     450         275 : bool SqlHandle::remove(Worker &worker, uint64_t oid) {
     451         275 :         auto &scheme = worker.scheme();
     452             : 
     453         275 :         auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
     454             : 
     455         275 :         bool ret = false;
     456         275 :         makeQuery([&, this] (SqlQuery &query) {
     457         275 :                 auto q = query.remove(scheme.getName())
     458         275 :                                 .where("__oid", Comparation::Equal, oid);
     459         275 :                 q.finalize();
     460         275 :                 if (performQuery(query) == 1) { // one row affected
     461         275 :                         ret = true;
     462             :                 }
     463         275 :         }, &queryStorage);
     464         275 :         return ret;
     465         275 : }
     466             : 
     467         375 : size_t SqlHandle::count(Worker &worker, const db::Query &q) {
     468         375 :         auto &scheme = worker.scheme();
     469             : 
     470         375 :         auto queryStorage = _driver->makeQueryStorage(worker.scheme().getName());
     471             : 
     472         375 :         size_t ret = 0;
     473         375 :         makeQuery([&, this] (SqlQuery &query) {
     474         375 :                 auto ordField = q.getQueryField();
     475         375 :                 if (ordField.empty()) {
     476         375 :                         auto f = query.select().count().from(scheme.getName());
     477             : 
     478         375 :                         SqlQuery_makeCustomFrom(_driver, query, f, q, scheme);
     479             : 
     480         375 :                         if (!q.empty()) {
     481         200 :                                 auto w = f.where();
     482         200 :                                 query.writeWhere(w, Operator::And, scheme, q);
     483             :                         }
     484             : 
     485         375 :                         query.finalize();
     486         750 :                         selectQuery(query, [&] (Result &res) {
     487         375 :                                 if (!res.empty()) {
     488         750 :                                         ret = res.current().toInteger(0);
     489         375 :                                         return true;
     490             :                                 }
     491           0 :                                 return false;
     492             :                         });
     493           0 :                 } else if (auto f = scheme.getField(ordField)) {
     494           0 :                         switch (f->getType()) {
     495           0 :                         case Type::Set:
     496           0 :                                 ret = getSetCount(worker, query, q.getQueryId(), *f, q);
     497           0 :                                 break;
     498           0 :                         case Type::View:
     499           0 :                                 ret = getViewCount(worker, query, q.getQueryId(), *f, q);
     500           0 :                                 break;
     501           0 :                         default:
     502           0 :                                 break;
     503             :                         }
     504             :                 }
     505         375 :         }, &queryStorage);
     506         375 :         return ret;
     507         375 : }
     508             : 
     509        6175 : void SqlHandle::performPostUpdate(const db::Transaction &t, SqlQuery &query, const Scheme &s, Value &data, int64_t id, const Value &upd, bool clear) {
     510        6175 :         query.clear();
     511             : 
     512           0 :         auto makeObject = [&] (const Field &field, const Value &obj) {
     513           0 :                 int64_t targetId = 0;
     514           0 :                 if (obj.isDictionary()) {
     515           0 :                         Value val(std::move(obj));
     516           0 :                         if (auto scheme = field.getForeignScheme()) {
     517           0 :                                 if (auto link = s.getForeignLink(field)) {
     518           0 :                                         val.setInteger(id, link->getName().str<Interface>());
     519             :                                 }
     520           0 :                                 val = Worker(*scheme, t).create(val);
     521           0 :                                 if (val.isInteger("__oid")) {
     522           0 :                                         targetId = val.getInteger("__oid");
     523             :                                 }
     524             :                         }
     525           0 :                 }
     526             : 
     527           0 :                 if (targetId) {
     528           0 :                         Worker w(s, t);
     529           0 :                         w.includeNone();
     530           0 :                         Value patch{ stappler::pair(field.getName().str<Interface>(), Value(targetId)) };
     531           0 :                         t.patch(w, id, patch);
     532           0 :                         data.setInteger(targetId, field.getName().str<Interface>());
     533           0 :                 }
     534           0 :         };
     535             : 
     536           0 :         auto makeSet = [&, this] (const Field &field, const Value &obj) {
     537           0 :                 auto f = field.getSlot<db::FieldObject>();
     538           0 :                 auto scheme = field.getForeignScheme();
     539             : 
     540           0 :                 if (f && scheme && obj.isArray()) {
     541           0 :                         Value ret;
     542           0 :                         Vector<int64_t> toAdd;
     543             : 
     544           0 :                         if (clear && obj) {
     545           0 :                                 Worker(s, t).clearField(id, field);
     546             :                         }
     547             : 
     548           0 :                         for (auto &arr_it : obj.asArray()) {
     549           0 :                                 if (arr_it.isDictionary()) {
     550           0 :                                         Value val(std::move(arr_it));
     551           0 :                                         if (auto link = s.getForeignLink(field)) {
     552           0 :                                                 val.setInteger(id, link->getName().str<Interface>());
     553             :                                         }
     554           0 :                                         val = Worker(*scheme, t).create(val);
     555           0 :                                         if (val) {
     556           0 :                                                 ret.addValue(std::move(val));
     557             :                                         }
     558           0 :                                 } else {
     559           0 :                                         if (auto tmp = arr_it.asInteger()) {
     560           0 :                                                 if (field.isReference()) {
     561           0 :                                                         toAdd.emplace_back(tmp);
     562           0 :                                                 } else if (auto link = s.getForeignLink(field)) {
     563           0 :                                                         if (auto val = Worker(*scheme, t).update(tmp, Value{stappler::pair(link->getName().str<Interface>(), Value(id))})) {
     564           0 :                                                                 ret.addValue(std::move(val));
     565           0 :                                                         }
     566             :                                                 }
     567             :                                         }
     568             :                                 }
     569             :                         }
     570             : 
     571           0 :                         if (!toAdd.empty()) {
     572           0 :                                 if (field.isReference()) {
     573           0 :                                         query.clear();
     574           0 :                                         if (insertIntoRefSet(query, s, id, field, toAdd)) {
     575           0 :                                                 for (auto &add_it : toAdd) {
     576           0 :                                                         ret.addInteger(add_it);
     577             :                                                 }
     578             :                                         }
     579             :                                 }
     580             :                         }
     581           0 :                         data.setValue(std::move(ret), field.getName().str<Interface>());
     582           0 :                 }
     583           0 :         };
     584             : 
     585        6175 :         const Map<String, Field> &fields = s.getFields();
     586        6225 :         for (auto &it : upd.asDict()) {
     587          50 :                 auto f_it = fields.find(it.first);
     588          50 :                 if (f_it != fields.end()) {
     589          50 :                         if (f_it->second.getType() == db::Type::Object) {
     590           0 :                                 makeObject(f_it->second, it.second);
     591          50 :                         } else if (f_it->second.getType() == db::Type::Set) {
     592           0 :                                 makeSet(f_it->second, it.second);
     593          50 :                         } else if (f_it->second.getType() == db::Type::Array) {
     594          50 :                                 if (clear && it.second) {
     595           0 :                                         Worker(s, t).clearField(id, f_it->second);
     596             :                                 }
     597          50 :                                 query.clear();
     598          50 :                                 auto tmp = it.second;
     599          50 :                                 if (insertIntoArray(query, s, id, f_it->second, tmp)) {
     600          50 :                                         data.setValue(tmp, f_it->second.getName());
     601             :                                 }
     602          50 :                         }
     603             :                 }
     604             :         }
     605        6175 : }
     606             : 
     607         775 : Vector<int64_t> SqlHandle::performQueryListForIds(const QueryList &list, size_t count) {
     608         775 :         Vector<int64_t> ret;
     609             : 
     610         775 :         auto queryStorage = _driver->makeQueryStorage(list.getScheme()->getName());
     611             : 
     612         775 :         makeQuery([&, this] (SqlQuery &query) {
     613         775 :                 query.writeQueryList(list, true, count);
     614         775 :                 query.finalize();
     615             : 
     616        1550 :                 selectQuery(query, [&] (Result &res) {
     617         775 :                         for (auto it : res) {
     618        1525 :                                 ret.push_back(it.toInteger(0));
     619         750 :                                 return true;
     620             :                         }
     621          25 :                         return false;
     622             :                 });
     623         775 :         }, &queryStorage);
     624             : 
     625        1550 :         return ret;
     626         775 : }
     627             : 
     628        1125 : Value SqlHandle::performQueryList(const QueryList &list, size_t count, bool forUpdate) {
     629        1125 :         Value ret;
     630             : 
     631        1125 :         auto queryStorage = _driver->makeQueryStorage(list.getScheme()->getName());
     632             : 
     633        1125 :         makeQuery([&, this] (SqlQuery &query) {
     634        1125 :                 FieldResolver resv(*list.getScheme(), list.getTopQuery());
     635        1125 :                 query.writeQueryList(list, false, count);
     636        1125 :                 if (forUpdate) {
     637           0 :                         query << "FOR UPDATE";
     638             :                 }
     639        1125 :                 query.finalize();
     640             : 
     641        1125 :                 ret = selectValueQuery(*list.getScheme(), query, resv.getVirtuals());
     642        1125 :         }, &queryStorage);
     643        2250 :         return ret;
     644        1125 : }
     645             : 
     646         200 : bool SqlHandle::removeFromView(const db::FieldView &view, const Scheme *scheme, uint64_t oid) {
     647         200 :         bool ret = false;
     648         200 :         if (scheme) {
     649         200 :                 String name = toString(scheme->getName(), "_f_", view.name, "_view");
     650             : 
     651         200 :                 auto queryStorage = _driver->makeQueryStorage(view.owner->getName());
     652             : 
     653         200 :                 makeQuery([&, this] (SqlQuery &query) {
     654         200 :                         query << "DELETE FROM " << name << " WHERE \"" << view.scheme->getName() << "_id\"=" << oid << ";";
     655         200 :                         ret = performQuery(query) != stappler::maxOf<size_t>();
     656         200 :                 }, &queryStorage);
     657         200 :         }
     658         200 :         return ret;
     659             : }
     660             : 
     661         125 : bool SqlHandle::addToView(const db::FieldView &view, const Scheme *scheme, uint64_t tag, const Value &data) {
     662         125 :         bool ret = false;
     663         125 :         if (scheme) {
     664         125 :                 String name = toString(scheme->getName(), "_f_", view.name, "_view");
     665             : 
     666         125 :                 auto queryStorage = _driver->makeQueryStorage(view.owner->getName());
     667             : 
     668         125 :                 makeQuery([&, this] (SqlQuery &query) {
     669         125 :                         auto ins = query.insert(name);
     670         375 :                         for (auto &it : data.asDict()) {
     671         250 :                                 ins.field(it.first);
     672             :                         }
     673             : 
     674         125 :                         auto val = ins.values();
     675         375 :                         for (auto &it : data.asDict()) {
     676         250 :                                 val.value(db::Binder::DataField{nullptr, it.second, false});
     677             :                         }
     678             : 
     679         125 :                         val.finalize();
     680         125 :                         ret = performQuery(query) != stappler::maxOf<size_t>();
     681         125 :                 }, &queryStorage);
     682         125 :         }
     683         125 :         return ret;
     684             : }
     685             : 
     686           0 : Vector<int64_t> SqlHandle::getReferenceParents(const Scheme &objectScheme, uint64_t oid, const Scheme *parentScheme, const Field *parentField) {
     687           0 :         Vector<int64_t> vec;
     688           0 :         if (parentField->isReference() && parentField->getType() == db::Type::Set) {
     689           0 :                 auto schemeName = toString(parentScheme->getName(), "_f_", parentField->getName());
     690           0 :                 auto queryStorage = _driver->makeQueryStorage(schemeName);
     691           0 :                 makeQuery([&, this] (SqlQuery &q) {
     692           0 :                         q.select(toString(parentScheme->getName(), "_id"))
     693           0 :                                 .from(schemeName)
     694           0 :                                 .where(toString(objectScheme.getName(), "_id"), Comparation::Equal, oid);
     695             : 
     696           0 :                         selectQuery(q, [&] (Result &res) {
     697           0 :                                 vec.reserve(res.getRowsHint());
     698           0 :                                 for (auto it : res) {
     699           0 :                                         if (auto id = it.toInteger(0)) {
     700           0 :                                                 vec.emplace_back(id);
     701             :                                         }
     702             :                                 }
     703           0 :                                 return true;
     704             :                         });
     705           0 :                 }, &queryStorage);
     706           0 :         }
     707             : 
     708           0 :         return vec;
     709           0 : }
     710             : 
     711             : }

Generated by: LCOV version 1.14