LCOV - code coverage report
Current view: top level - core/db/sql - SPSqlHandleProp.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 213 512 41.6 %
Date: 2024-05-12 00:16:13 Functions: 17 50 34.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             : SPUNUSED static void Handle_writeSelectViewDataQuery(SqlQuery &q, const db::Scheme &s, uint64_t oid, const db::FieldView &f, const Value &data);
      31             : 
      32         200 : Value SqlHandle::getFileField(Worker &w, SqlQuery &query, uint64_t oid, uint64_t targetId, const Field &f) {
      33         200 :         if (auto fs = w.getApplicationInterface()->getFileScheme()) {
      34         200 :                 auto sel = targetId ? query.select() : query.with("s", [&] (SqlQuery::GenericQuery &q) {
      35           0 :                         q.select(f.getName()).from(w.scheme().getName()).where("__oid", Comparation::Equal, oid);
      36         200 :                 }).select();
      37         200 :                 String alias("t"); // do not touch;
      38             : 
      39         200 :                 FieldResolver resv(*fs, w);
      40             : 
      41         200 :                 resv.readFields([&] (const StringView &name, const Field *) {
      42           0 :                         sel = sel.field(SqlQuery::Field("t", name));
      43           0 :                 });
      44             : 
      45         200 :                 if (targetId) {
      46         200 :                         sel.from(SqlQuery::Field("__files").as(alias))
      47         200 :                                 .where(SqlQuery::Field(alias, "__oid"), Comparation::Equal, targetId).finalize();
      48             :                 } else {
      49           0 :                         sel.from(SqlQuery::Field("__files").as(alias)).innerJoinOn("s", [&] (SqlQuery::WhereBegin &q) {
      50           0 :                                 q.where(SqlQuery::Field(alias,"__oid"), Comparation::Equal, SqlQuery::Field("s", f.getName()));
      51           0 :                         }).finalize();
      52             :                 }
      53             : 
      54         200 :                 auto ret = selectValueQuery(*fs, query, resv.getVirtuals());
      55         200 :                 if (ret.isArray()) {
      56         200 :                         ret = std::move(ret.getValue(0));
      57             :                 }
      58         200 :                 return ret;
      59         200 :         }
      60           0 :         return Value();
      61             : }
      62             : 
      63           0 : size_t SqlHandle::getFileCount(Worker &w, SqlQuery &query, uint64_t oid, uint64_t targetId, const Field &f) {
      64           0 :         size_t ret = 0;
      65           0 :         auto sel = (targetId ? query.select() : query.with("s", [&] (SqlQuery::GenericQuery &q) {
      66           0 :                 q.select(f.getName()).from(w.scheme().getName()).where("__oid", Comparation::Equal, oid);
      67           0 :         }).select()).aggregate("COUNT", "*");
      68           0 :         String alias("t"); // do not touch;
      69             : 
      70           0 :         if (targetId) {
      71           0 :                 sel.from(SqlQuery::Field("__files").as(alias))
      72           0 :                         .where(SqlQuery::Field(alias, "__oid"), Comparation::Equal, targetId).finalize();
      73             :         } else {
      74           0 :                 sel.from(SqlQuery::Field("__files").as(alias)).innerJoinOn("s", [&] (SqlQuery::WhereBegin &q) {
      75           0 :                         q.where(SqlQuery::Field(alias,"__oid"), Comparation::Equal, SqlQuery::Field("s", f.getName()));
      76           0 :                 }).finalize();
      77             :         }
      78             : 
      79           0 :         selectQuery(query, [&] (Result &result) {
      80           0 :                 if (!result.empty()) {
      81           0 :                         ret = size_t(result.current().toInteger(0));
      82           0 :                         return true;
      83             :                 }
      84           0 :                 return false;
      85             :         });
      86           0 :         return ret;
      87           0 : }
      88             : 
      89          50 : Value SqlHandle::getArrayField(Worker &w, SqlQuery &query, uint64_t oid, const Field &f) {
      90          50 :         query.select("data").from(toString(w.scheme().getName(), "_f_", f.getName()))
      91          50 :                 .where(toString(w.scheme().getName(), "_id"), Comparation::Equal, oid).finalize();
      92         100 :         return selectValueQuery(f, query, Vector<const Field *>());
      93             : }
      94             : 
      95           0 : size_t SqlHandle::getArrayCount(Worker &w, SqlQuery &query, uint64_t oid, const Field &f) {
      96           0 :         size_t ret = 0;
      97           0 :         query.select().aggregate("COUNT", "*").from(toString(w.scheme().getName(), "_f_", f.getName()))
      98           0 :                 .where(toString(w.scheme().getName(), "_id"), Comparation::Equal, oid).finalize();
      99             : 
     100           0 :         selectQuery(query, [&] (Result &result) {
     101           0 :                 if (!result.empty()) {
     102           0 :                         ret = size_t(result.current().toInteger(0));
     103           0 :                         return true;
     104             :                 }
     105           0 :                 return false;
     106             :         });
     107           0 :         return ret;
     108             : }
     109             : 
     110          75 : Value SqlHandle::getObjectField(Worker &w, SqlQuery &query, uint64_t oid, uint64_t targetId, const Field &f) {
     111          75 :         if (auto fs = f.getForeignScheme()) {
     112          75 :                 auto sel = targetId ? query.select() : query.with("s", [&] (SqlQuery::GenericQuery &q) {
     113           0 :                         q.select(f.getName()).from(w.scheme().getName()).where("__oid", Comparation::Equal, oid);
     114          75 :                 }).select();
     115          75 :                 String alias("t"); // do not touch;
     116             : 
     117          75 :                 FieldResolver resv(*fs, w);
     118          75 :                 resv.readFields([&] (const StringView &name, const Field *) {
     119         600 :                         sel = sel.field(SqlQuery::Field("t", name));
     120         600 :                 });
     121             : 
     122          75 :                 if (targetId) {
     123          75 :                         sel.from(SqlQuery::Field(fs->getName()).as(alias))
     124          75 :                                 .where(SqlQuery::Field(alias, "__oid"), Comparation::Equal, targetId).finalize();
     125             :                 } else {
     126           0 :                         sel.from(SqlQuery::Field(fs->getName()).as(alias)).innerJoinOn("s", [&] (SqlQuery::WhereBegin &q) {
     127           0 :                                 q.where(SqlQuery::Field("t", "__oid"), Comparation::Equal, SqlQuery::Field("s", f.getName()));
     128           0 :                         }).finalize();
     129             :                 }
     130             : 
     131          75 :                 UpdateFlags flags = UpdateFlags::None;
     132          75 :                 if (w.shouldIncludeAll()) { flags |= UpdateFlags::GetAll; }
     133             : 
     134          75 :                 auto ret = selectValueQuery(*fs, query, resv.getVirtuals());
     135          75 :                 if (ret.isArray()) {
     136          75 :                         ret = std::move(ret.getValue(0));
     137             :                 }
     138          75 :                 return ret;
     139          75 :         }
     140           0 :         return Value();
     141             : }
     142             : 
     143           0 : size_t SqlHandle::getObjectCount(Worker &w, SqlQuery &query, uint64_t oid, uint64_t targetId, const Field &f) {
     144           0 :         size_t ret = 0;
     145           0 :         if (auto fs = f.getForeignScheme()) {
     146           0 :                 auto sel = (targetId ? query.select() : query.with("s", [&] (SqlQuery::GenericQuery &q) {
     147           0 :                         q.select(f.getName()).from(w.scheme().getName()).where("__oid", Comparation::Equal, oid);
     148           0 :                 }).select()).aggregate("COUNT", "*");
     149           0 :                 String alias("t"); // do not touch;
     150             : 
     151           0 :                 if (targetId) {
     152           0 :                         sel.from(SqlQuery::Field(fs->getName()).as(alias))
     153           0 :                                 .where(SqlQuery::Field(alias, "__oid"), Comparation::Equal, targetId).finalize();
     154             :                 } else {
     155           0 :                         sel.from(SqlQuery::Field(fs->getName()).as(alias)).innerJoinOn("s", [&] (SqlQuery::WhereBegin &q) {
     156           0 :                                 q.where(SqlQuery::Field("t", "__oid"), Comparation::Equal, SqlQuery::Field("s", f.getName()));
     157           0 :                         }).finalize();
     158             :                 }
     159             : 
     160           0 :                 selectQuery(query, [&] (Result &result) {
     161           0 :                         if (!result.empty()) {
     162           0 :                                 ret = size_t(result.current().toInteger(0));
     163           0 :                                 return true;
     164             :                         }
     165           0 :                         return false;
     166             :                 });
     167           0 :         }
     168           0 :         return ret;
     169             : }
     170             : 
     171          75 : Value SqlHandle::getSetField(Worker &w, SqlQuery &query, uint64_t oid, const Field &f, const db::Query &q) {
     172          75 :         auto fs = f.getForeignScheme();
     173          75 :         if (!fs) {
     174           0 :                 return Value();
     175             :         }
     176             : 
     177          75 :         SqlQuery::Context ctx(query, *fs, w, q);
     178          75 :         if (query.writeQuery(ctx, w.scheme(), oid, f)) {
     179         150 :                 return selectValueQuery(*f.getForeignScheme(), query, ctx.getVirtuals());
     180             :         }
     181           0 :         return Value();
     182          75 : }
     183             : 
     184           0 : size_t SqlHandle::getSetCount(Worker &w, SqlQuery &query, uint64_t oid, const Field &f, const db::Query &q) {
     185           0 :         size_t ret = 0;
     186           0 :         if (auto fs = f.getForeignScheme()) {
     187           0 :                 if (f.isReference()) {
     188           0 :                         auto sel = query.with("s", [&] (SqlQuery::GenericQuery &q) {
     189           0 :                                 q.select(SqlQuery::Field(toString(fs->getName(), "_id")).as("id"))
     190           0 :                                                 .from(toString(w.scheme().getName(), "_f_", f.getName()))
     191           0 :                                                 .where(toString(w.scheme().getName(), "_id"), Comparation::Equal, oid);
     192           0 :                         }).select();
     193           0 :                         query.writeFullTextRank(sel, *fs, q);
     194           0 :                         sel.aggregate("COUNT", "*");
     195             : 
     196           0 :                         auto tmp = sel.from(fs->getName())
     197           0 :                                         .innerJoinOn("s", [&] (SqlQuery::WhereBegin &q) {
     198           0 :                                 q.where(SqlQuery::Field(fs->getName(), "__oid"), Comparation::Equal, SqlQuery::Field("s", "id"));
     199           0 :                         });
     200             : 
     201           0 :                         if (q.hasSelect()) {
     202           0 :                                 auto whi = tmp.where();
     203           0 :                                 query.writeWhere(whi, db::Operator::And, *fs, q);
     204             :                         }
     205           0 :                         query.finalize();
     206           0 :                 } else if (auto l = w.scheme().getForeignLink(f)) {
     207           0 :                         auto sel = query.select();
     208           0 :                         query.writeFullTextRank(sel, *fs, q);
     209           0 :                         sel.aggregate("COUNT", "*");
     210             : 
     211           0 :                         auto whi = sel.from(fs->getName())
     212           0 :                                 .where(l->getName(), Comparation::Equal, oid);
     213           0 :                         query.writeWhere(whi, db::Operator::And, *fs, q);
     214           0 :                         query.finalize();
     215             :                 } else {
     216           0 :                         return 0;
     217             :                 }
     218           0 :                 selectQuery(query, [&] (Result &result) {
     219           0 :                         if (!result.empty()) {
     220           0 :                                 ret = size_t(result.current().toInteger(0));
     221           0 :                                 return true;
     222             :                         }
     223           0 :                         return false;
     224             :                 });
     225             :         }
     226           0 :         return ret;
     227             : }
     228             : 
     229          75 : Value SqlHandle::getViewField(Worker &w, SqlQuery &query, uint64_t oid, const Field &f, const db::Query &q) {
     230          75 :         auto fs = f.getForeignScheme();
     231          75 :         if (!fs) {
     232           0 :                 return Value();
     233             :         }
     234             : 
     235          75 :         SqlQuery::Context ctx(query, *fs, w, q);
     236          75 :         if (query.writeQuery(ctx, w.scheme(), oid, f)) {
     237          75 :                 auto ret = selectValueQuery(*ctx.scheme, query, ctx.getVirtuals());
     238          75 :                 if (ret.isArray() && ret.size() > 0) {
     239          50 :                         query.clear();
     240             : 
     241          50 :                         auto v = f.getSlot<FieldView>();
     242             : 
     243          50 :                         Handle_writeSelectViewDataQuery(query, w.scheme(), oid, *v, ret);
     244          50 :                         selectValueQuery(ret, *v, query);
     245          50 :                         return ret;
     246             :                 }
     247          75 :         }
     248          25 :         return Value();
     249          75 : }
     250             : 
     251           0 : size_t SqlHandle::getViewCount(Worker &w, SqlQuery &query, uint64_t oid, const Field &f, const db::Query &q) {
     252           0 :         size_t ret = 0;
     253           0 :         if (auto fs = f.getForeignScheme()) {
     254           0 :                 auto sel = query.with("s", [&] (SqlQuery::GenericQuery &q) {
     255           0 :                         q.select(SqlQuery::Distinct::Distinct, SqlQuery::Field(toString(fs->getName(), "_id")).as("__id"))
     256           0 :                                         .from(toString(w.scheme().getName(), "_f_", f.getName(), "_view"))
     257           0 :                                         .where(toString(w.scheme().getName(), "_id"), Comparation::Equal, oid);
     258           0 :                 }).select();
     259           0 :                 query.writeFullTextRank(sel, *fs, q);
     260           0 :                 sel.aggregate("COUNT", "*");
     261             : 
     262           0 :                 auto tmp = sel.from(fs->getName())
     263           0 :                                 .innerJoinOn("s", [&] (SqlQuery::WhereBegin &q) {
     264           0 :                         q.where(SqlQuery::Field(fs->getName(), "__oid"), Comparation::Equal, SqlQuery::Field("s", "__id"));
     265           0 :                 });
     266             : 
     267           0 :                 if (q.hasSelect()) {
     268           0 :                         auto whi = tmp.where();
     269           0 :                         query.writeWhere(whi, db::Operator::And, *fs, q);
     270             :                 }
     271           0 :                 query.finalize();
     272             : 
     273           0 :                 selectQuery(query, [&] (Result &result) {
     274           0 :                         if (!result.empty()) {
     275           0 :                                 ret = size_t(result.current().toInteger(0));
     276           0 :                                 return true;
     277             :                         }
     278           0 :                         return false;
     279             :                 });
     280             :         }
     281           0 :         return ret;
     282             : }
     283             : 
     284           0 : Value SqlHandle::getSimpleField(Worker &w, SqlQuery &query, uint64_t oid, const Field &f) {
     285           0 :         if (f.getType() == Type::Virtual) {
     286           0 :                 auto v = f.getSlot<FieldVirtual>();
     287           0 :                 auto sel = query.select("__oid");
     288           0 :                 for (auto &it : v->requireFields) {
     289           0 :                         sel.field(it);
     290             :                 }
     291           0 :                 sel.from(w.scheme().getName()).where("__oid", Comparation::Equal, oid).finalize();
     292           0 :                 auto ret = selectValueQuery(w.scheme(), query, Vector<const Field *>({&f}));
     293           0 :                 if (ret.isArray()) {
     294           0 :                         ret = std::move(ret.getValue(0));
     295             :                 }
     296           0 :                 if (ret.isDictionary()) {
     297           0 :                         ret = ret.getValue(f.getName());
     298             :                 }
     299           0 :                 return ret;
     300           0 :         } else {
     301           0 :                 query.select(f.getName()).from(w.scheme().getName()).where("__oid", Comparation::Equal, oid).finalize();
     302           0 :                 auto ret = selectValueQuery(w.scheme(), query, Vector<const Field *>());
     303           0 :                 if (ret.isArray()) {
     304           0 :                         ret = std::move(ret.getValue(0));
     305             :                 }
     306           0 :                 if (ret.isDictionary()) {
     307           0 :                         ret = ret.getValue(f.getName());
     308             :                 }
     309           0 :                 return ret;
     310           0 :         }
     311             : }
     312             : 
     313           0 : size_t SqlHandle::getSimpleCount(Worker &w, SqlQuery &query, uint64_t oid, const Field &f) {
     314           0 :         size_t ret = 0;
     315           0 :         query.select().aggregate("COUNT", f.getName()).from(w.scheme().getName()).where("__oid", Comparation::Equal, oid).finalize();
     316           0 :         selectQuery(query, [&] (Result &result) {
     317           0 :                 if (!result.empty()) {
     318           0 :                         ret = size_t(result.current().toInteger(0));
     319           0 :                         return true;
     320             :                 }
     321           0 :                 return false;
     322             :         });
     323           0 :         return ret;
     324             : }
     325             : 
     326           0 : bool SqlHandle::insertIntoSet(SqlQuery &query, const Scheme &s, int64_t id, const db::FieldObject &field, const Field &ref, const Value &d) {
     327           0 :         if (field.type == db::Type::Object) {
     328           0 :                 if (ref.getType() == db::Type::Object) {
     329             :                         // object to object is not implemented
     330             :                 } else {
     331             :                         // object to set is maintained by trigger
     332             :                 }
     333           0 :         } else if (field.type == db::Type::Set) {
     334           0 :                 if (ref.getType() == db::Type::Object) {
     335           0 :                         if (d.isArray() && d.getValue(0).isInteger()) {
     336           0 :                                 auto w = query.update(field.scheme->getName()).set(ref.getName(), id).where();
     337           0 :                                 for (auto & it : d.asArray()) {
     338           0 :                                         if (it.isInteger()) {
     339           0 :                                                 w.where(Operator::Or, "__oid", Comparation::Equal, it.getInteger());
     340             :                                         }
     341             :                                 }
     342           0 :                                 w.finalize();
     343           0 :                                 return performQuery(query) != stappler::maxOf<size_t>();
     344             :                         }
     345             :                 } else {
     346             :                         // set to set is not implemented
     347             :                 }
     348             :         }
     349           0 :         return false;
     350             : }
     351             : 
     352         200 : bool SqlHandle::insertIntoArray(SqlQuery &query, const Scheme &scheme, int64_t id, const Field &field, Value &d) {
     353         200 :         if (d.isNull()) {
     354           0 :                 query.remove(toString(scheme.getName(), "_f_", field.getName()))
     355           0 :                                 .where(toString(scheme.getName(), "_id"), Comparation::Equal, id).finalize();
     356           0 :                 return performQuery(query) != stappler::maxOf<size_t>();
     357             :         } else {
     358         200 :                 if (field.transform(scheme, id, const_cast<Value &>(d))) {
     359         200 :                         auto &arrf = static_cast<const db::FieldArray *>(field.getSlot())->tfield;
     360         200 :                         if (!d.empty()) {
     361         200 :                                 auto vals = query.insert(toString(scheme.getName(), "_f_", field.getName()))
     362         200 :                                                 .fields(toString(scheme.getName(), "_id"), "data").values();
     363         500 :                                 for (auto &it : d.asArray()) {
     364         300 :                                         vals.values(id, db::Binder::DataField {&arrf, it, arrf.isDataLayout(), arrf.hasFlag(db::Flags::Compressed)});
     365             :                                 }
     366         200 :                                 if (field.hasFlag(Flags::Unique)) {
     367           0 :                                         vals.finalize();
     368             :                                 } else {
     369         200 :                                         vals.onConflictDoNothing().finalize();
     370             :                                 }
     371         200 :                                 return performQuery(query) != stappler::maxOf<size_t>();
     372             :                         }
     373             :                 }
     374             :         }
     375           0 :         return false;
     376             : }
     377             : 
     378         125 : bool SqlHandle::insertIntoRefSet(SqlQuery &query, const Scheme &scheme, int64_t id, const Field &field, const Vector<int64_t> &ids) {
     379         125 :         auto fScheme = field.getForeignScheme();
     380         125 :         if (!ids.empty() && fScheme) {
     381         125 :                 auto vals = query.insert(toString(scheme.getName(), "_f_", field.getName()))
     382         125 :                                 .fields(toString(scheme.getName(), "_id"), toString(fScheme->getName(), "_id")).values();
     383         350 :                 for (auto &it : ids) {
     384         225 :                         vals.values(id, it);
     385             :                 }
     386         125 :                 vals.onConflictDoNothing().finalize();
     387         125 :                 performQuery(query);
     388         125 :                 return true;
     389             :         }
     390           0 :         return false;
     391             : }
     392             : 
     393           0 : bool SqlHandle::cleanupRefSet(SqlQuery &query, const Scheme &scheme, uint64_t oid, const Field &field, const Vector<int64_t> &ids) {
     394           0 :         auto objField = static_cast<const db::FieldObject *>(field.getSlot());
     395           0 :         auto fScheme = objField->scheme;
     396           0 :         if (!ids.empty() && fScheme) {
     397           0 :                 if (objField->onRemove == db::RemovePolicy::Reference) {
     398           0 :                         auto w = query.remove(toString(scheme.getName(), "_f_", field.getName()))
     399           0 :                                         .where(toString(scheme.getName(), "_id"), Comparation::Equal, oid);
     400           0 :                         w.parenthesis(Operator::And, [&] (SqlQuery::WhereBegin &wh) {
     401           0 :                                 auto whi = wh.where();
     402           0 :                                 for (auto &it : ids) {
     403           0 :                                         whi.where(Operator::Or, toString(fScheme->getName(), "_id"), Comparation::Equal, it);
     404             :                                 }
     405           0 :                         }).finalize();
     406           0 :                         performQuery(query);
     407           0 :                         return true;
     408           0 :                 } else if (objField->onRemove == db::RemovePolicy::StrongReference) {
     409           0 :                         auto w = query.remove(fScheme->getName()).where();
     410           0 :                         for (auto &it : ids) {
     411           0 :                                 w.where(Operator::Or, "__oid", Comparation::Equal, it);
     412             :                         }
     413           0 :                         w.finalize();
     414           0 :                         performQuery(query);
     415           0 :                         return true;
     416             :                 }
     417             :         }
     418           0 :         return false;
     419             : }
     420             : 
     421         425 : Value SqlHandle::field(db::Action a, Worker &w, uint64_t oid, const Field &f, Value &&val) {
     422         425 :         auto queryStorage = _driver->makeQueryStorage(w.scheme().getName());
     423             : 
     424         425 :         Value ret;
     425         425 :         switch (a) {
     426           0 :         case db::Action::Get:
     427           0 :                 makeQuery([&, this] (SqlQuery &query) {
     428           0 :                         switch (f.getType()) {
     429           0 :                         case db::Type::File:
     430           0 :                         case db::Type::Image: ret = getFileField(w, query, oid, 0, f); break;
     431           0 :                         case db::Type::Array: ret = getArrayField(w, query, oid, f); break;
     432           0 :                         case db::Type::Object: ret = getObjectField(w, query, oid, 0, f); break;
     433           0 :                         case db::Type::Set: {
     434           0 :                                 db::Query db;
     435           0 :                                 auto &fields = w.getRequiredFields();
     436           0 :                                 for (auto &it : fields.includeFields) {
     437           0 :                                         if (it) { db.include(it->getName()); }
     438             :                                 }
     439           0 :                                 for (auto &it : fields.excludeFields) {
     440           0 :                                         if (it) { db.exclude(it->getName()); }
     441             :                                 }
     442           0 :                                 ret = getSetField(w, query, oid, f, db);
     443           0 :                                 break;
     444           0 :                         }
     445           0 :                         case db::Type::View: {
     446           0 :                                 db::Query db;
     447           0 :                                 auto &fields = w.getRequiredFields();
     448           0 :                                 for (auto &it : fields.includeFields) {
     449           0 :                                         if (it) { db.include(it->getName()); }
     450             :                                 }
     451           0 :                                 for (auto &it : fields.excludeFields) {
     452           0 :                                         if (it) { db.exclude(it->getName()); }
     453             :                                 }
     454           0 :                                 ret = getViewField(w, query, oid, f, db);
     455           0 :                                 break;
     456           0 :                         }
     457           0 :                         default: ret = getSimpleField(w, query, oid, f); break;
     458             :                         }
     459           0 :                 }, &queryStorage);
     460           0 :                 break;
     461           0 :         case db::Action::Count:
     462           0 :                 makeQuery([&, this] (SqlQuery &query) {
     463           0 :                         switch (f.getType()) {
     464           0 :                         case db::Type::File:
     465           0 :                         case db::Type::Image: ret = Value(getFileCount(w, query, oid, 0, f)); break;
     466           0 :                         case db::Type::Array: ret = Value(getArrayCount(w, query, oid, f)); break;
     467           0 :                         case db::Type::Object: ret = Value(getObjectCount(w, query, oid, 0, f)); break;
     468           0 :                         case db::Type::Set: ret = Value(getSetCount(w, query, oid, f, db::Query())); break;
     469           0 :                         case db::Type::View: ret = Value(getViewCount(w, query, oid, f, db::Query())); break;
     470           0 :                         default: ret = Value(getSimpleCount(w, query, oid, f)); break;
     471             :                         }
     472           0 :                 }, &queryStorage);
     473           0 :                 break;
     474          75 :         case db::Action::Set:
     475          75 :                 switch (f.getType()) {
     476           0 :                 case db::Type::File:
     477             :                 case db::Type::Image:
     478             :                 case db::Type::View:
     479           0 :                 case db::Type::FullTextView: return Value(); break; // file update should be done by scheme itself
     480          50 :                 case db::Type::Array:
     481          50 :                         if (val.isArray()) {
     482          50 :                                 field(db::Action::Remove, w, oid, f, Value());
     483          50 :                                 bool success = false;
     484          50 :                                 makeQuery([&, this] (SqlQuery &query) {
     485          50 :                                         success = insertIntoArray(query, w.scheme(), oid, f, val);
     486          50 :                                 }, &queryStorage);
     487          50 :                                 if (success) {
     488          50 :                                         ret = std::move(val);
     489             :                                 }
     490             :                         }
     491          50 :                         break;
     492          25 :                 case db::Type::Set:
     493          25 :                         if (f.isReference()) {
     494          25 :                                 auto objField = static_cast<const db::FieldObject *>(f.getSlot());
     495          25 :                                 if (objField->onRemove == db::RemovePolicy::Reference) {
     496           0 :                                         field(db::Action::Remove, w, oid, f, Value());
     497             :                                 } else {
     498          25 :                                         makeQuery([&, this] (SqlQuery &query) {
     499          25 :                                                 auto obj = static_cast<const db::FieldObject *>(f.getSlot());
     500             : 
     501          25 :                                                 auto source = w.scheme().getName();
     502          25 :                                                 auto target = obj->scheme->getName();
     503             : 
     504             :                                                 query << "DELETE FROM " << target << " WHERE __oid IN (SELECT " << target << "_id FROM "
     505          25 :                                                                 << w.scheme().getName() << "_f_" << f.getName() << " WHERE "<< source << "_id=" << oid << ")";
     506             : 
     507          75 :                                                 for (auto &it : val.asArray()) {
     508          50 :                                                         if (it.isInteger()) {
     509          50 :                                                                 query << " AND __oid != " << it.asInteger();
     510             :                                                         }
     511             :                                                 }
     512          25 :                                                 query << ";";
     513          25 :                                                 performQuery(query);
     514          25 :                                         }, &queryStorage);
     515             :                                 }
     516          25 :                                 ret = field(db::Action::Append, w, oid, f, std::move(val));
     517             :                         }
     518             :                         // not implemented
     519          25 :                         break;
     520           0 :                 default: {
     521           0 :                         Value patch;
     522           0 :                         patch.setValue(val, f.getName().str<Interface>());
     523           0 :                         Worker(w.scheme(), w.transaction()).update(oid, patch);
     524           0 :                         return val;
     525             :                         break;
     526           0 :                 }
     527             :                 }
     528          75 :                 break;
     529         225 :         case db::Action::Append:
     530         225 :                 switch (f.getType()) {
     531         100 :                 case db::Type::Array:
     532         100 :                         if (!val.isNull()) {
     533         100 :                                 Worker(w).touch(oid);
     534         100 :                                 bool success = false;
     535         100 :                                 makeQuery([&, this] (SqlQuery &query) {
     536         100 :                                         success = insertIntoArray(query, w.scheme(), oid, f, val);
     537         100 :                                 }, &queryStorage);
     538         100 :                                 if (success) {
     539         100 :                                         ret = std::move(val);
     540             :                                 }
     541             :                         }
     542         100 :                         break;
     543         125 :                 case db::Type::Set:
     544         125 :                         if (f.isReference()) {
     545         125 :                                 Worker(w).touch(oid);
     546         125 :                                 Vector<int64_t> toAdd;
     547         125 :                                 if (val.isArray()) {
     548         350 :                                         for (auto &it : val.asArray()) {
     549         225 :                                                 if (auto id = it.asInteger()) {
     550         225 :                                                         toAdd.push_back(id);
     551             :                                                 }
     552             :                                         }
     553           0 :                                 } else if (val.isInteger()) {
     554           0 :                                         toAdd.push_back(val.asInteger());
     555             :                                 }
     556         125 :                                 bool success = false;
     557         125 :                                 makeQuery([&, this] (SqlQuery &query) {
     558         125 :                                         success = insertIntoRefSet(query, w.scheme(), oid, f, toAdd);
     559         125 :                                 }, &queryStorage);
     560         125 :                                 if (success) {
     561         125 :                                         ret = std::move(val);
     562             :                                 }
     563         125 :                         }
     564         125 :                         break;
     565           0 :                 default:
     566           0 :                         break;
     567             :                 }
     568         225 :                 break;
     569         125 :         case db::Action::Remove:
     570         125 :                 switch (f.getType()) {
     571           0 :                 case db::Type::File:
     572             :                 case db::Type::Image:
     573             :                 case db::Type::View:
     574           0 :                 case db::Type::FullTextView: return Value(); break; // file update should be done by scheme itself
     575          50 :                 case db::Type::Array:
     576          50 :                         Worker(w).touch(oid);
     577          50 :                         makeQuery([&, this] (SqlQuery &query) {
     578          50 :                                 query << "DELETE FROM " << w.scheme().getName() << "_f_" << f.getName() << " WHERE " << w.scheme().getName() << "_id=" << oid << ";";
     579          50 :                                 if (performQuery(query) != stappler::maxOf<size_t>()) {
     580          50 :                                         ret = Value(true);
     581             :                                 }
     582          50 :                         }, &queryStorage);
     583          50 :                         break;
     584          25 :                 case db::Type::Set:
     585          25 :                         if (f.isReference()) {
     586          25 :                                 Worker(w).touch(oid);
     587          25 :                                 auto objField = static_cast<const db::FieldObject *>(f.getSlot());
     588          25 :                                 if (!val.isArray()) {
     589          25 :                                         makeQuery([&, this] (SqlQuery &query) {
     590          25 :                                                 if (objField->onRemove == db::RemovePolicy::Reference) {
     591           0 :                                                         query.remove(toString(w.scheme().getName(), "_f_", f.getName()))
     592           0 :                                                                         .where(toString(w.scheme().getName(), "_id"), Comparation::Equal, oid)
     593           0 :                                                                         .finalize();
     594           0 :                                                         ret = Value(performQuery(query) != stappler::maxOf<size_t>());
     595             :                                                 } else {
     596             :                                                         // for strong refs
     597          25 :                                                         auto obj = static_cast<const db::FieldObject *>(f.getSlot());
     598             : 
     599          25 :                                                         auto source = w.scheme().getName();
     600          25 :                                                         auto target = obj->scheme->getName();
     601             : 
     602             :                                                         query << "DELETE FROM " << target << " WHERE __oid IN (SELECT " << target << "_id FROM "
     603          25 :                                                                         << w.scheme().getName() << "_f_" << f.getName() << " WHERE "<< source << "_id=" << oid << ");";
     604          25 :                                                         ret = Value(performQuery(query) != stappler::maxOf<size_t>());
     605             :                                                 }
     606          25 :                                         }, &queryStorage);
     607             :                                 } else {
     608           0 :                                         Vector<int64_t> toRemove;
     609           0 :                                         for (auto &it : val.asArray()) {
     610           0 :                                                 if (auto id = it.asInteger()) {
     611           0 :                                                         toRemove.push_back(id);
     612             :                                                 }
     613             :                                         }
     614             : 
     615           0 :                                         makeQuery([&, this] (SqlQuery &query) {
     616           0 :                                                 ret = Value(cleanupRefSet(query, w.scheme(), oid, f, toRemove));
     617           0 :                                         }, &queryStorage);
     618           0 :                                 }
     619             :                         }
     620          25 :                         break;
     621          50 :                 case db::Type::Object: {
     622          50 :                         if (f.isReference()) {
     623           0 :                                 auto ref = static_cast<const FieldObject *>(f.getSlot());
     624           0 :                                 if (ref->onRemove == RemovePolicy::StrongReference) {
     625           0 :                                         if (auto obj = Worker(w).get(oid, { f.getName() })) {
     626           0 :                                                 Worker(*ref->scheme, w.transaction()).remove(obj.getInteger("__oid"));
     627           0 :                                         }
     628             :                                 }
     629             :                         }
     630          50 :                         Value patch;
     631          50 :                         patch.setValue(Value(), f.getName().str<Interface>());
     632          50 :                         ret = Worker(w).update(oid, patch);
     633          50 :                         break;
     634          50 :                 }
     635           0 :                 default:
     636           0 :                         break;
     637             :                 }
     638         125 :                 break;
     639             :         }
     640         425 :         return ret;
     641         425 : }
     642             : 
     643         425 : Value SqlHandle::field(db::Action a, Worker &w, const Value &obj, const Field &f, Value &&val) {
     644         425 :         auto queryStorage = _driver->makeQueryStorage(w.scheme().getName());
     645             : 
     646         425 :         Value ret;
     647         425 :         auto oid = obj.isInteger() ? obj.asInteger() : obj.getInteger("__oid");
     648         425 :         auto targetId = obj.isInteger() ? obj.asInteger() : obj.getInteger(f.getName());
     649         425 :         switch (a) {
     650         425 :         case db::Action::Get:
     651         425 :                 makeQuery([&, this] (SqlQuery &query) {
     652         425 :                         switch (f.getType()) {
     653         200 :                         case db::Type::File:
     654         200 :                         case db::Type::Image: ret = getFileField(w, query, oid, targetId, f); break;
     655          50 :                         case db::Type::Array: ret = getArrayField(w, query, oid, f); break;
     656          75 :                         case db::Type::Object: ret = getObjectField(w, query, oid, targetId, f); break;
     657          75 :                         case db::Type::Set: {
     658          75 :                                 db::Query db;
     659          75 :                                 auto &fields = w.getRequiredFields();
     660         125 :                                 for (auto &it : fields.includeFields) {
     661          50 :                                         if (it) { db.include(it->getName()); }
     662             :                                 }
     663          75 :                                 for (auto &it : fields.excludeFields) {
     664           0 :                                         if (it) { db.exclude(it->getName()); }
     665             :                                 }
     666          75 :                                 ret = getSetField(w, query, oid, f, db);
     667          75 :                                 break;
     668          75 :                         }
     669          25 :                         case db::Type::View: {
     670          25 :                                 db::Query db;
     671          25 :                                 auto &fields = w.getRequiredFields();
     672          25 :                                 for (auto &it : fields.includeFields) {
     673           0 :                                         if (it) { db.include(it->getName()); }
     674             :                                 }
     675          25 :                                 for (auto &it : fields.excludeFields) {
     676           0 :                                         if (it) { db.exclude(it->getName()); }
     677             :                                 }
     678          25 :                                 ret = getViewField(w, query, oid, f, db);
     679          25 :                                 break;
     680          25 :                         }
     681           0 :                         default:
     682           0 :                                 if (auto val = obj.getValue(f.getName())) {
     683           0 :                                         ret = std::move(val);
     684             :                                 } else {
     685           0 :                                         ret = getSimpleField(w, query, oid, f);
     686           0 :                                 }
     687           0 :                                 break;
     688             :                         }
     689         425 :                 }, &queryStorage);
     690         425 :                 break;
     691           0 :         case db::Action::Count:
     692           0 :                 makeQuery([&, this] (SqlQuery &query) {
     693           0 :                         switch (f.getType()) {
     694           0 :                         case db::Type::File:
     695           0 :                         case db::Type::Image: ret = Value(getFileCount(w, query, oid, 0, f)); break;
     696           0 :                         case db::Type::Array: ret = Value(getArrayCount(w, query, oid, f)); break;
     697           0 :                         case db::Type::Object: ret = Value(getObjectCount(w, query, oid, 0, f)); break;
     698           0 :                         case db::Type::Set: ret = Value(getSetCount(w, query, oid, f, db::Query())); break;
     699           0 :                         case db::Type::View: ret = Value(getViewCount(w, query, oid, f, db::Query())); break;
     700           0 :                         default:
     701           0 :                                 if (auto val = obj.getValue(f.getName())) {
     702           0 :                                         ret = Value(1);
     703             :                                 } else {
     704           0 :                                         ret = Value(getSimpleCount(w, query, oid, f));
     705           0 :                                 }
     706           0 :                                 break;
     707             :                         }
     708           0 :                 }, &queryStorage);
     709           0 :                 break;
     710           0 :         case db::Action::Set:
     711             :         case db::Action::Remove:
     712             :         case db::Action::Append:
     713           0 :                 ret = field(a, w, oid, f, std::move(val));
     714           0 :                 break;
     715             :         }
     716         850 :         return ret;
     717         425 : }
     718             : 
     719             : }

Generated by: LCOV version 1.14