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