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 : #ifndef STAPPLER_DB_SPDBTRANSACTION_H_
25 : #define STAPPLER_DB_SPDBTRANSACTION_H_
26 :
27 : #include "SPDbAdapter.h"
28 : #include "SPDbField.h"
29 : #include "SPDbQueryList.h"
30 :
31 : namespace STAPPLER_VERSIONIZED stappler::db {
32 :
33 : enum class AccessRoleId {
34 : Nobody = 0,
35 : Authorized = 1,
36 : UserDefined1,
37 : UserDefined2,
38 : UserDefined3,
39 : UserDefined4,
40 : UserDefined5,
41 : UserDefined6,
42 : UserDefined7,
43 : UserDefined8,
44 : UserDefined9,
45 : UserDefined10,
46 : UserDefined11,
47 : Admin,
48 : System,
49 : Default,
50 : Max = 16,
51 : };
52 :
53 : class Transaction : public AllocBase {
54 : public:
55 : enum Op {
56 : None = 0,
57 : Id,
58 : Select,
59 : Count,
60 : Remove,
61 : Create,
62 : Save,
63 : Patch,
64 : FieldGet,
65 : FieldSet,
66 : FieldAppend,
67 : FieldClear,
68 : FieldCount,
69 : Delta,
70 : DeltaView,
71 : RemoveFromView,
72 : AddToView,
73 : Max,
74 : };
75 :
76 : struct Data : AllocPool {
77 : Adapter adapter;
78 : pool_t * pool;
79 : Map<String, Value> data;
80 : int status = 0;
81 :
82 : mutable Map<int64_t, Value> objects;
83 : mutable AccessRoleId role = AccessRoleId::Nobody;
84 :
85 : Data(const Adapter &, memory::pool_t * = nullptr);
86 : };
87 :
88 : struct Stack : AllocPool {
89 : Vector<Data *> stack;
90 : };
91 :
92 : static Op getTransactionOp(Action);
93 :
94 : static Transaction acquire(const Adapter &);
95 :
96 : static Transaction acquireIfExists();
97 : static Transaction acquireIfExists(memory::pool_t *);
98 :
99 : Transaction(nullptr_t);
100 :
101 : void setRole(AccessRoleId) const;
102 : AccessRoleId getRole() const;
103 :
104 : void setStatus(int);
105 : int getStatus() const;
106 :
107 : const Value &setValue(const StringView &, Value &&);
108 : const Value &getValue(const StringView &) const;
109 :
110 : Value setObject(int64_t, Value &&) const;
111 : Value getObject(int64_t) const;
112 :
113 : void setAdapter(const Adapter &);
114 : const Adapter &getAdapter() const;
115 :
116 21822 : explicit operator bool () const { return _data != nullptr && _data->adapter; }
117 :
118 : Value acquireObject(const Scheme &, uint64_t oid) const;
119 :
120 : bool perform(const Callback<bool()> & cb) const;
121 : bool performAsSystem(const Callback<bool()> & cb) const;
122 :
123 : bool isInTransaction() const;
124 : TransactionStatus getTransactionStatus() const;
125 :
126 : bool foreach(Worker &, const Query &, const Callback<bool(Value &)> &) const;
127 :
128 : // returns Array with zero or more Dictionaries with object data or Null value
129 : Value select(Worker &, const Query &) const;
130 :
131 : size_t count(Worker &, const Query &) const;
132 :
133 : bool remove(Worker &t, uint64_t oid) const;
134 :
135 : Value create(Worker &, Value &data) const;
136 : Value save(Worker &, uint64_t oid, Value &obj, Value &patch, Set<const Field *> &fields) const;
137 : Value patch(Worker &, uint64_t oid, Value &data) const;
138 :
139 : Value field(Action, Worker &, uint64_t oid, const Field &, Value && = Value()) const;
140 : Value field(Action, Worker &, const Value &, const Field &, Value && = Value()) const;
141 :
142 : bool removeFromView(const Scheme &, const FieldView &, uint64_t oid, const Value &obj) const;
143 : bool addToView(const Scheme &, const FieldView &, uint64_t oid, const Value &obj, const Value &viewObj) const;
144 :
145 : int64_t getDeltaValue(const Scheme &); // scheme-based delta
146 : int64_t getDeltaValue(const Scheme &, const FieldView &, uint64_t); // view-based delta
147 :
148 : Vector<int64_t> performQueryListForIds(const QueryList &, size_t count = stappler::maxOf<size_t>()) const;
149 : Value performQueryList(const QueryList &, size_t count = stappler::maxOf<size_t>(), bool forUpdate = false) const;
150 : Value performQueryListField(const QueryList &, const Field &) const;
151 :
152 : void scheduleAutoField(const Scheme &, const Field &, uint64_t id) const;
153 :
154 : void retain() const;
155 : void release() const;
156 :
157 : protected:
158 : struct TransactionGuard {
159 15500 : TransactionGuard(const Transaction &t) : _t(&t) { _t->retain(); }
160 15500 : ~TransactionGuard() { _t->release(); }
161 :
162 : const Transaction *_t;
163 : };
164 :
165 : friend struct TransactionGuard;
166 : friend class Worker; // for transaction start|stop and role redefinition
167 :
168 : bool beginTransaction() const;
169 : bool endTransaction() const;
170 : void cancelTransaction() const;
171 :
172 : void clearObjectStorage() const;
173 :
174 : bool processReturnObject(const Scheme &, Value &) const;
175 : bool processReturnField(const Scheme &, const Value &obj, const Field &, Value &) const;
176 :
177 : bool isOpAllowed(const Scheme &, Op, const Field * = nullptr) const;
178 :
179 : Transaction(Data *);
180 :
181 : Data *_data = nullptr;
182 : };
183 :
184 15500 : inline bool Transaction::perform(const Callback<bool()> &cb) const {
185 15500 : TransactionGuard g(*this);
186 :
187 15500 : if (isInTransaction()) {
188 12875 : if (!cb()) {
189 0 : cancelTransaction();
190 : } else {
191 12875 : return true;
192 : }
193 : } else {
194 2625 : if (beginTransaction()) {
195 2625 : if (!cb()) {
196 0 : cancelTransaction();
197 : }
198 2625 : return endTransaction();
199 : }
200 : }
201 0 : return false;
202 15500 : }
203 :
204 4975 : inline bool Transaction::performAsSystem(const Callback<bool()> &cb) const {
205 4975 : auto tmpRole = getRole();
206 4975 : setRole(AccessRoleId::System);
207 4975 : auto ret = perform(cb);
208 4975 : setRole(tmpRole);
209 4975 : return ret;
210 : }
211 :
212 : struct AccessRole : public AllocBase {
213 : using OnSelect = stappler::ValueWrapper<Function<bool(Worker &, const Query &)>, class OnSelectTag>;
214 : using OnCount = stappler::ValueWrapper<Function<bool(Worker &, const Query &)>, class OnCountTag>;
215 : using OnCreate = stappler::ValueWrapper<Function<bool(Worker &, Value &obj)>, class OnCreateTag>;
216 : using OnPatch = stappler::ValueWrapper<Function<bool(Worker &, int64_t id, Value &obj)>, class OnPatchTag>;
217 : using OnSave = stappler::ValueWrapper<Function<bool(Worker &, const Value &obj, Value &patch, Set<const Field *> &fields)>, class OnSaveTag>;
218 : using OnRemove = stappler::ValueWrapper<Function<bool(Worker &, const Value &)>, class OnRemoveTag>;
219 : using OnField = stappler::ValueWrapper<Function<bool(Action, Worker &, const Value &, const Field &, Value &)>, class OnFieldTag>;
220 : using OnReturn = stappler::ValueWrapper<Function<bool(const Scheme &, Value &)>, class OnReturnTag>;
221 : using OnReturnField = stappler::ValueWrapper<Function<bool(const Scheme &, const Field &, Value &)>, class OnReturnFieldTag>;
222 :
223 : template <typename ... Args>
224 : static AccessRole Empty(Args && ... args);
225 :
226 : template <typename ... Args>
227 : static AccessRole Default(Args && ... args);
228 :
229 : template <typename ... Args>
230 : static AccessRole Admin(Args && ... args);
231 :
232 : template <typename T, typename ... Args>
233 : AccessRole &define(T &&, Args && ... args);
234 :
235 : AccessRole &define();
236 : AccessRole &define(AccessRoleId);
237 : AccessRole &define(Transaction::Op);
238 : AccessRole &define(OnSelect &&);
239 : AccessRole &define(OnCount &&);
240 : AccessRole &define(OnCreate &&);
241 : AccessRole &define(OnPatch &&);
242 : AccessRole &define(OnSave &&);
243 : AccessRole &define(OnRemove &&);
244 : AccessRole &define(OnField &&);
245 : AccessRole &define(OnReturn &&);
246 : AccessRole &define(OnReturnField &&);
247 :
248 : std::bitset<stappler::toInt(AccessRoleId::Max)> users;
249 : std::bitset<stappler::toInt(Transaction::Op::Max)> operations;
250 :
251 : Function<bool(Worker &, const Query &)> onSelect;
252 : Function<bool(Worker &, const Query &)> onCount;
253 :
254 : Function<bool(Worker &, Value &obj)> onCreate;
255 : Function<bool(Worker &, int64_t id, Value &obj)> onPatch;
256 : Function<bool(Worker &, const Value &obj, Value &patch, Set<const Field *> &fields)> onSave;
257 : Function<bool(Worker &, const Value &)> onRemove;
258 :
259 : Function<bool(Action, Worker &, const Value &, const Field &, Value &)> onField;
260 :
261 : Function<bool(const Scheme &, Value &)> onReturn;
262 : Function<bool(const Scheme &, const Field &, Value &)> onReturnField;
263 : };
264 :
265 : template <typename T, typename ... Args>
266 150 : inline AccessRole &AccessRole::define(T &&v, Args && ... args) {
267 150 : define(std::forward<T>(v));
268 150 : define(std::forward<Args>(args)...);
269 150 : return *this;
270 : }
271 :
272 : template <typename ... Args>
273 50 : AccessRole AccessRole::Empty(Args && ... args) {
274 50 : AccessRole ret;
275 50 : ret.define(std::forward<Args>(args)...);
276 50 : return ret;
277 0 : }
278 :
279 : template <typename ... Args>
280 : AccessRole AccessRole::Default(Args && ... args) {
281 : AccessRole ret;
282 :
283 : ret.operations.set(Transaction::Op::Id);
284 : ret.operations.set(Transaction::Op::Select);
285 : ret.operations.set(Transaction::Op::Count);
286 : ret.operations.set(Transaction::Op::Delta);
287 : ret.operations.set(Transaction::Op::DeltaView);
288 : ret.operations.set(Transaction::Op::FieldGet);
289 : ret.operations.set(Transaction::Op::FieldCount);
290 :
291 : ret.define(std::forward<Args>(args)...);
292 :
293 : return ret;
294 : }
295 :
296 : template <typename ... Args>
297 125 : AccessRole AccessRole::Admin(Args && ... args) {
298 125 : AccessRole ret;
299 :
300 125 : ret.operations.set(Transaction::Op::Id);
301 125 : ret.operations.set(Transaction::Op::Select);
302 125 : ret.operations.set(Transaction::Op::Count);
303 125 : ret.operations.set(Transaction::Op::Delta);
304 125 : ret.operations.set(Transaction::Op::DeltaView);
305 125 : ret.operations.set(Transaction::Op::FieldGet);
306 :
307 125 : ret.operations.set(Transaction::Op::Remove);
308 125 : ret.operations.set(Transaction::Op::Create);
309 125 : ret.operations.set(Transaction::Op::Save);
310 125 : ret.operations.set(Transaction::Op::Patch);
311 125 : ret.operations.set(Transaction::Op::FieldSet);
312 125 : ret.operations.set(Transaction::Op::FieldAppend);
313 125 : ret.operations.set(Transaction::Op::FieldClear);
314 125 : ret.operations.set(Transaction::Op::FieldCount);
315 125 : ret.operations.set(Transaction::Op::RemoveFromView);
316 125 : ret.operations.set(Transaction::Op::AddToView);
317 :
318 125 : ret.define(std::forward<Args>(args)...);
319 :
320 125 : return ret;
321 0 : }
322 :
323 : }
324 :
325 : #endif /* STAPPLER_DB_SPDBTRANSACTION_H_ */
|