Line data Source code
1 : /**
2 : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef STAPPLER_DB_SPDBSCHEME_H_
25 : #define STAPPLER_DB_SPDBSCHEME_H_
26 :
27 : #include "SPDbWorker.h"
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::db {
30 :
31 : class Scheme : public AllocBase {
32 : public:
33 : enum Options {
34 : None = 0,
35 : WithDelta = 1 << 0,
36 : Detouched = 1 << 1,
37 : Compressed = 1 << 2,
38 : };
39 :
40 : struct ViewScheme : AllocBase {
41 : const Scheme *scheme = nullptr;
42 : const Field *viewField = nullptr;
43 : Set<const Field *> fields;
44 : const Field *autoLink = nullptr;
45 : const AutoFieldScheme *autoField = nullptr;
46 :
47 100 : ViewScheme(const Scheme *s, const Field *v, const FieldView &) : scheme(s), viewField(v) { }
48 75 : ViewScheme(const Scheme *s, const Field *v, const AutoFieldScheme &af) : scheme(s), viewField(v), autoField(&af) { }
49 : };
50 :
51 : struct ParentScheme : AllocPool {
52 : const Scheme *scheme = nullptr;
53 : const Field *pointerField = nullptr;
54 : const Field *backReference = nullptr;
55 :
56 50 : ParentScheme(const Scheme *s, const Field *v) : scheme(s), pointerField(v) { }
57 : };
58 :
59 : struct UniqueConstraint {
60 : StringView name;
61 : Vector<const Field *> fields;
62 :
63 0 : UniqueConstraint(StringView n, Vector<const Field *> &&f) : name(n), fields(std::move(f)) { }
64 : };
65 :
66 : enum class TransformAction {
67 : Create,
68 : Update,
69 : Compare,
70 : ProtectedCreate,
71 : ProtectedUpdate,
72 : Touch
73 : };
74 :
75 : using FieldVec = Vector<const Field *>;
76 : using AccessTable = std::array<AccessRole *, stappler::toInt(AccessRoleId::Max)>;
77 :
78 : // field list to send, when no field is required to return
79 : static FieldVec EmptyFieldList() { return FieldVec{nullptr}; }
80 :
81 : static bool initSchemes(const Map<StringView, const Scheme *> &);
82 :
83 : public:
84 : Scheme(const StringView &name, bool delta = false);
85 : Scheme(const StringView &name, Options);
86 : Scheme(const StringView &name, std::initializer_list<Field> il, bool delta = false);
87 : Scheme(const StringView &name, std::initializer_list<Field> il, Options);
88 :
89 : Scheme(const Scheme &) = delete;
90 : Scheme& operator=(const Scheme &) = delete;
91 :
92 150 : Scheme(Scheme &&) = default;
93 75 : Scheme& operator=(Scheme &&) = default;
94 :
95 : bool hasDelta() const;
96 : bool isDetouched() const;
97 : bool isCompressed() const;
98 : bool hasFullText() const;
99 :
100 : const Scheme & define(std::initializer_list<Field> il);
101 : const Scheme & define(Vector<Field> &&il);
102 : const Scheme & define(AccessRole &&role);
103 : const Scheme & define(UniqueConstraintDef &&);
104 : const Scheme & define(Bytes &&);
105 :
106 : template <typename T, typename ... Args>
107 : const Scheme & define(T &&il, Args && ... args);
108 :
109 : bool init();
110 :
111 : void addFlags(Options);
112 :
113 : void cloneFrom(Scheme *);
114 :
115 : StringView getName() const;
116 : bool hasAliases() const;
117 :
118 : bool isProtected(const StringView &) const;
119 : bool save(const Transaction &, Object *) const;
120 :
121 : bool hasFiles() const;
122 : bool hasForceExclude() const;
123 : bool hasAccessControl() const;
124 : bool hasVirtuals() const;
125 :
126 : const Set<const Field *> & getForceInclude() const;
127 : const Map<String, Field> & getFields() const;
128 : const Field *getField(const StringView &str) const;
129 : const Vector<UniqueConstraint> &getUnique() const;
130 : BytesView getCompressDict() const;
131 :
132 3650 : const Set<const Field *> &getFullTextFields() const { return fullTextFields; }
133 :
134 : const Field *getForeignLink(const FieldObject *f) const;
135 : const Field *getForeignLink(const Field &f) const;
136 : const Field *getForeignLink(const StringView &f) const;
137 :
138 75 : void setConfig(InputConfig cfg) { config = cfg; }
139 100 : const InputConfig &getConfig() const { return config; }
140 :
141 525 : size_t getMaxRequestSize() const { return config.maxRequestSize; }
142 525 : size_t getMaxVarSize() const { return config.maxVarSize; }
143 525 : size_t getMaxFileSize() const { return std::max(config.maxFileSize, config.maxVarSize); }
144 :
145 : bool isAtomicPatch(const Value &) const;
146 :
147 : uint64_t hash(ValidationLevel l = ValidationLevel::NamesAndTypes) const;
148 :
149 : const Vector<ViewScheme *> &getViews() const;
150 : Vector<const Field *> getPatchFields(const Value &patch) const;
151 :
152 : const AccessTable &getAccessTable() const;
153 : const AccessRole *getAccessRole(AccessRoleId) const;
154 : void setAccessRole(AccessRoleId, AccessRole &&);
155 :
156 : Value &transform(Value &, TransformAction = TransformAction::Create) const;
157 :
158 : public: // worker interface
159 : template <typename Storage, typename _Value> auto get(Storage &&, _Value &&, UpdateFlags = UpdateFlags::None) const -> Value;
160 : template <typename Storage, typename _Value> auto get(Storage &&, _Value &&, StringView, UpdateFlags = UpdateFlags::None) const -> Value;
161 : template <typename Storage, typename _Value> auto get(Storage &&, _Value &&, std::initializer_list<StringView> &&fields, UpdateFlags = UpdateFlags::None) const -> Value;
162 : template <typename Storage, typename _Value> auto get(Storage &&, _Value &&, std::initializer_list<const char *> &&fields, UpdateFlags = UpdateFlags::None) const -> Value;
163 : template <typename Storage, typename _Value> auto get(Storage &&, _Value &&, std::initializer_list<const Field *> &&fields, UpdateFlags = UpdateFlags::None) const -> Value;
164 : template <typename Storage, typename _Value> auto get(Storage &&, _Value &&, SpanView<const Field *> fields, UpdateFlags = UpdateFlags::None) const -> Value;
165 :
166 : // Select objects via callback iterator
167 : template <typename T> auto foreach(T &&t, const Query &,
168 : const Callback<bool(Value &)> &, UpdateFlags = UpdateFlags::None) const -> bool;
169 :
170 : // Select objects by query
171 : // - db::Transaction, db::Query
172 : template <typename T, typename ... Args> auto select(T &&t, Args && ... args) const -> Value;
173 :
174 : // Create new object (single for dict or multi for array)
175 : // - db::Transaction, Value[, UpdateFlags][, Conflict]
176 : template <typename T, typename ... Args> auto create(T &&t, Args && ... args) const -> Value;
177 :
178 : // Update object
179 : // - db::Transaction, Value obj, Value patch[, UpdateFlags]
180 : // - db::Transaction, int64_t id, Value patch[, UpdateFlags]
181 : template <typename T, typename ... Args> auto update(T &&t, Args && ... args) const -> Value;
182 :
183 : // Remove object
184 : // - db::Transaction, Value obj
185 : // - db::Transaction, int64_t id
186 : template <typename T, typename ... Args> auto remove(T &&t, Args && ... args) const -> bool;
187 :
188 : // Count resulting objects by query
189 : // - db::Transaction, db::Query
190 : template <typename T, typename ... Args> auto count(T &&t, Args && ... args) const -> size_t;
191 :
192 : // Touch object (update autofields)
193 : // - db::Transaction, Value obj
194 : // - db::Transaction, int64_t id
195 : template <typename T, typename ... Args> auto touch(T &&t, Args && ... args) const -> void;
196 :
197 : template <typename _Storage, typename _Value, typename _Field>
198 : auto getProperty(_Storage &&, _Value &&, _Field &&, std::initializer_list<StringView> fields) const -> Value;
199 :
200 : template <typename _Storage, typename _Value, typename _Field>
201 : auto getProperty(_Storage &&, _Value &&, _Field &&, const Set<const Field *> & = Set<const Field *>()) const -> Value;
202 :
203 : template <typename T, typename ... Args> auto setProperty(T &&t, Args && ... args) const -> Value;
204 : template <typename T, typename ... Args> auto appendProperty(T &&t, Args && ... args) const -> Value;
205 : template <typename T, typename ... Args> auto clearProperty(T &&t, Args && ... args) const -> bool;
206 : template <typename T, typename ... Args> auto countProperty(T &&t, Args && ... args) const -> size_t;
207 :
208 : protected:// CRUD functions
209 : friend class Worker;
210 :
211 : bool foreachWithWorker(Worker &, const Query &, const Callback<bool(Value &)> &) const;
212 :
213 : // returns Array with zero or more Dictionaries with object data or Null value
214 : Value selectWithWorker(Worker &, const Query &) const;
215 :
216 : // returns Dictionary with single object data or Null value
217 : Value createWithWorker(Worker &, const Value &data, bool isProtected = false) const;
218 :
219 : Value updateWithWorker(Worker &, uint64_t oid, const Value &data, bool isProtected = false) const;
220 : Value updateWithWorker(Worker &, const Value & obj, const Value &data, bool isProtected = false) const;
221 :
222 : bool removeWithWorker(Worker &, uint64_t oid) const;
223 :
224 : size_t countWithWorker(Worker &, const Query &) const;
225 :
226 : void touchWithWorker(Worker &, uint64_t id) const;
227 : void touchWithWorker(Worker &, const Value & obj) const;
228 :
229 : Value fieldWithWorker(Action, Worker &, uint64_t oid, const Field &, Value && = Value()) const;
230 : Value fieldWithWorker(Action, Worker &, const Value &, const Field &, Value && = Value()) const;
231 :
232 : Value setFileWithWorker(Worker &w, uint64_t oid, const Field &, InputFile &) const;
233 :
234 : void initScheme();
235 :
236 : void addView(const Scheme *, const Field *);
237 : void addAutoField(const Scheme *, const Field *f, const AutoFieldScheme &);
238 : void addParent(const Scheme *, const Field *);
239 :
240 : Value createFilePatch(const Transaction &, const Value &val, Value &changeSet) const;
241 : void purgeFilePatch(const Transaction &t, const Value &) const;
242 : void mergeValues(const Field &f, const Value &obj, Value &original, Value &newVal) const;
243 :
244 : stappler::Pair<bool, Value> prepareUpdate(const Value &data, bool isProtected) const;
245 : Value updateObject(Worker &, Value & obj, Value &data) const;
246 :
247 : Value doPatch(Worker &w, const Transaction &t, uint64_t obj, Value & patch) const;
248 :
249 : Value patchOrUpdate(Worker &, uint64_t id, Value & patch) const;
250 : Value patchOrUpdate(Worker &, Value & obj, Value & patch) const;
251 :
252 : void touchParents(const Transaction &, const Value &obj) const;
253 : void extractParents(Map<int64_t, const Scheme *> &, const Transaction &, const Value &obj, bool isChangeSet = false) const;
254 :
255 : // returns:
256 : // - true if field was successfully removed
257 : // - null or false if field was not removed, we should abort transaction
258 : // - value, that will be sent to finalizeField if all fields will be removed
259 : Value removeField(const Transaction &, Value &, const Field &, const Value &old);
260 : void finalizeField(const Transaction &, const Field &, const Value &old);
261 :
262 : // call before object is created, used for additional checking or default values
263 : Value createFile(const Transaction &, const Field &, InputFile &) const;
264 :
265 : // call before object is created, when file is embedded into patch
266 : Value createFile(const Transaction &, const Field &, const BytesView &, const StringView &type, int64_t = 0) const;
267 :
268 : Value makeObjectForPatch(const Transaction &, uint64_t id, const Value &, const Value &patch) const;
269 :
270 : void updateLimits();
271 :
272 : bool validateHint(uint64_t, const Value &);
273 : bool validateHint(const String &alias, const Value &);
274 : bool validateHint(const Value &);
275 :
276 : Vector<uint64_t> getLinkageForView(const Value &, const ViewScheme &) const;
277 :
278 : void updateView(const Transaction &, const Value &, const ViewScheme *, const Vector<uint64_t> &) const;
279 :
280 : Map<String, Field> fields;
281 : String name;
282 :
283 : Options flags = Options::None;
284 :
285 : InputConfig config;
286 :
287 : Vector<ViewScheme *> views;
288 : Vector<ParentScheme *> parents;
289 : Set<const Field *> forceInclude;
290 : Set<const Field *> fullTextFields;
291 : Set<const Field *> autoFieldReq;
292 :
293 : bool _init = false;
294 : bool _hasFiles = false;
295 : bool _hasForceExclude = false;
296 : bool _hasAccessControl = false;
297 : bool _hasVirtuals = false;
298 :
299 : AccessTable roles;
300 : Field oidField;
301 : Vector<UniqueConstraint> unique;
302 : Bytes _compressDict;
303 : };
304 :
305 : SP_DEFINE_ENUM_AS_MASK(Scheme::Options)
306 :
307 : template <typename Storage, typename _Value>
308 176 : inline auto Scheme::get(Storage &&s, _Value &&v, UpdateFlags flags) const -> Value {
309 310 : return Worker(*this, std::forward<Storage>(s)).get(std::forward<_Value>(v), flags);
310 : }
311 :
312 : template <typename Storage, typename _Value>
313 126 : inline auto Scheme::get(Storage &&s, _Value &&v, StringView it, UpdateFlags flags) const -> Value {
314 210 : return Worker(*this, std::forward<Storage>(s)).get(std::forward<_Value>(v), it, flags);
315 : }
316 :
317 : template <typename Storage, typename _Value>
318 : inline auto Scheme::get(Storage &&s, _Value &&v, std::initializer_list<StringView> &&fields, UpdateFlags flags) const -> Value {
319 : return Worker(*this, std::forward<Storage>(s)).get(std::forward<_Value>(v), std::move(fields), flags);
320 : }
321 :
322 : template <typename Storage, typename _Value>
323 25 : inline auto Scheme::get(Storage &&s, _Value &&v, std::initializer_list<const char *> &&fields, UpdateFlags flags) const -> Value {
324 50 : return Worker(*this, std::forward<Storage>(s)).get(std::forward<_Value>(v), std::move(fields), flags);
325 : }
326 :
327 : template <typename Storage, typename _Value>
328 : inline auto Scheme::get(Storage &&s, _Value &&v, std::initializer_list<const Field *> &&fields, UpdateFlags flags) const -> Value {
329 : return Worker(*this, std::forward<Storage>(s)).get(std::forward<_Value>(v), std::move(fields), flags);
330 : }
331 :
332 : template <typename Storage, typename _Value>
333 378 : inline auto Scheme::get(Storage &&s, _Value &&v, SpanView<const Field *> fields, UpdateFlags flags) const -> Value {
334 378 : return Worker(*this, std::forward<Storage>(s)).get(std::forward<_Value>(v), fields, flags);
335 : }
336 :
337 : template <typename T>
338 : inline auto Scheme::foreach(T &&s, const Query &q, const Callback<bool(Value &)> &cb, UpdateFlags flags) const -> bool {
339 : return Worker(*this, std::forward<T>(s)).foreach(q, cb, flags);
340 : }
341 :
342 : template <typename T, typename ... Args>
343 2667 : inline auto Scheme::select(T &&t, Args && ... args) const -> Value {
344 5334 : return Worker(*this, std::forward<T>(t)).select(std::forward<Args>(args)...);
345 : }
346 :
347 : template <typename T, typename ... Args>
348 3034 : inline auto Scheme::create(T &&t, Args && ... args) const -> Value {
349 5984 : return Worker(*this, std::forward<T>(t)).create(std::forward<Args>(args)...);
350 : }
351 :
352 : template <typename T, typename ... Args>
353 1600 : inline auto Scheme::update(T &&t, Args && ... args) const -> Value {
354 3200 : return Worker(*this, std::forward<T>(t)).update(std::forward<Args>(args)...);
355 : }
356 :
357 : template <typename T, typename ... Args>
358 188 : inline auto Scheme::remove(T &&t, Args && ... args) const -> bool {
359 188 : return Worker(*this, std::forward<T>(t)).remove(std::forward<Args>(args)...);
360 : }
361 :
362 : template <typename T, typename ... Args>
363 285 : inline auto Scheme::count(T &&t, Args && ... args) const -> size_t {
364 285 : return Worker(*this, std::forward<T>(t)).count(std::forward<Args>(args)...);
365 : }
366 :
367 : template <typename T, typename ... Args>
368 42 : inline auto Scheme::touch(T &&t, Args && ... args) const -> void {
369 42 : Worker(*this, std::forward<T>(t)).touch(std::forward<Args>(args)...);
370 42 : }
371 :
372 :
373 : template <typename _Storage, typename _Value, typename _Field>
374 : inline auto Scheme::getProperty(_Storage &&s, _Value &&v, _Field &&f, std::initializer_list<StringView> fields) const -> Value {
375 : return Worker(*this, std::forward<_Storage>(s)).getField(std::forward<_Value>(v), std::forward<_Field>(f), fields);
376 : }
377 :
378 : template <typename _Storage, typename _Value, typename _Field>
379 100 : auto Scheme::getProperty(_Storage &&s, _Value &&v, _Field &&f, const Set<const Field *> &fields) const -> Value {
380 150 : return Worker(*this, std::forward<_Storage>(s)).getField(std::forward<_Value>(v), std::forward<_Field>(f), fields);
381 : }
382 :
383 : template <typename T, typename ... Args>
384 : inline auto Scheme::setProperty(T &&t, Args && ... args) const -> Value {
385 : return Worker(*this, std::forward<T>(t)).setField(std::forward<Args>(args)...);
386 : }
387 :
388 : template <typename T, typename ... Args>
389 : inline auto Scheme::appendProperty(T &&t, Args && ... args) const -> Value {
390 : return Worker(*this, std::forward<T>(t)).appendField(std::forward<Args>(args)...);
391 : }
392 :
393 : template <typename T, typename ... Args>
394 : inline auto Scheme::clearProperty(T &&t, Args && ... args) const -> bool {
395 : return Worker(*this, std::forward<T>(t)).clearField(std::forward<Args>(args)...);
396 : }
397 :
398 : template <typename T, typename ... Args>
399 : inline auto Scheme::countProperty(T &&t, Args && ... args) const -> size_t {
400 : return Worker(*this, std::forward<T>(t)).countField(std::forward<Args>(args)...);
401 : }
402 :
403 : template <typename T, typename ... Args>
404 175 : const Scheme & Scheme::define(T &&il, Args && ... args) {
405 175 : define(std::forward<T>(il));
406 175 : define(std::forward<Args>(args)...);
407 175 : return *this;
408 : }
409 :
410 : }
411 :
412 : #endif /* STAPPLER_DB_SPDBSCHEME_H_ */
|