Line data Source code
1 : /**
2 : Copyright (c) 2018-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 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_SPDBINTERFACE_H_
25 : #define STAPPLER_DB_SPDBINTERFACE_H_
26 :
27 : #include "SPDbAuth.h"
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::db {
30 :
31 : class Result;
32 : class ApplicationInterface;
33 :
34 : enum class DeltaAction {
35 : Create = 1,
36 : Update,
37 : Delete,
38 : Append,
39 : Erase
40 : };
41 :
42 : /* Common storage/database interface, used for schemes and some other operations,
43 : * that requires persistent storage
44 : */
45 : class BackendInterface : public AllocBase {
46 : public:
47 : enum class StorageType {
48 : Unknown,
49 : Bool,
50 : Char,
51 : Float4,
52 : Float8,
53 : Int2,
54 : Int4,
55 : Int8,
56 : Text,
57 : VarChar,
58 : Numeric,
59 : Bytes,
60 : TsVector,
61 : };
62 :
63 : struct Config {
64 : StringView name;
65 : const Scheme *fileScheme = nullptr;
66 : };
67 :
68 2850 : virtual ~BackendInterface() { }
69 :
70 : public: // key-value storage
71 : // set or replace value for specific key for specified time interval (no values stored forever)
72 : // if value is replaced, it's expiration time also updated
73 : virtual bool set(const stappler::CoderSource &, const Value &, stappler::TimeInterval) = 0;
74 :
75 : // get value for specific key
76 : virtual Value get(const stappler::CoderSource &) = 0;
77 :
78 : // remove value for specific key
79 : virtual bool clear(const stappler::CoderSource &) = 0;
80 :
81 : // get list of ids ('__oid's) for hierarchical query list
82 : // performs only first `count` queries in list
83 : virtual Vector<int64_t> performQueryListForIds(const QueryList &, size_t count) = 0;
84 :
85 : // get objects for specific hierarchical query list
86 : // performs only first `count` queries in list
87 : // optionally, mark objects as selected for update (lock them in DB)
88 : virtual Value performQueryList(const QueryList &, size_t count, bool forUpdate) = 0;
89 :
90 : public:
91 : // initialize schemes in database
92 : // all fields, indexes, constraints and triggers updated to match schemes definition
93 : virtual bool init(const Config &serv, const Map<StringView, const Scheme *> &) = 0;
94 :
95 : // force temporary data cleanup
96 0 : virtual void makeSessionsCleanup() { }
97 :
98 : // force broadcast data processing
99 0 : virtual int64_t processBroadcasts(const Callback<void(BytesView)> &, int64_t value) { return 0; }
100 :
101 : // perform select operation with result cursor callback
102 : // fields will not be resolved in this case, you should call `decode` or `toData` from result manually
103 : virtual bool foreach(Worker &, const Query &, const Callback<bool(Value &)> &) = 0;
104 :
105 : // perform select operation, returns resolved data
106 : virtual Value select(Worker &, const Query &) = 0;
107 :
108 : // create new object or objects, returns new values
109 : virtual Value create(Worker &, const Vector<InputField> &inputField, Vector<InputRow> &inputRows, bool multiCreate) = 0;
110 : // virtual Value create(Worker &, Map<StringView, InputValue> &) = 0;
111 :
112 : // perform update operation (read-modify-write), update only specified fields in new object
113 : virtual Value save(Worker &, uint64_t oid, const Value &obj, const Vector<InputField> &, InputRow &) = 0;
114 :
115 : // delete object by id
116 : virtual bool remove(Worker &, uint64_t oid) = 0;
117 :
118 : // count objects for specified query
119 : virtual size_t count(Worker &, const Query &) = 0;
120 :
121 : public:
122 : // perform generic operation on object's field (Array or Set)
123 : virtual Value field(Action, Worker &, uint64_t oid, const Field &, Value &&) = 0;
124 :
125 : // perform generic operation on object's field (Array or Set)
126 : virtual Value field(Action, Worker &, const Value &, const Field &, Value &&) = 0;
127 :
128 : // add object (last parameter) info View field of scheme
129 : virtual bool addToView(const FieldView &, const Scheme *, uint64_t oid, const Value &) = 0;
130 :
131 : // remove object with specific id from View field
132 : virtual bool removeFromView(const FieldView &, const Scheme *, uint64_t oid) = 0;
133 :
134 : // find in which sets object with id can be found
135 : virtual Vector<int64_t> getReferenceParents(const Scheme &, uint64_t oid, const Scheme *, const Field *) = 0;
136 :
137 : public: // others
138 : virtual bool beginTransaction() = 0;
139 : virtual bool endTransaction() = 0;
140 :
141 : // try to authorize user with name and password, using fields and scheme from Auth object
142 : // authorization is protected with internal '__login" scheme to prevent bruteforce attacks
143 : virtual User * authorizeUser(const Auth &, const StringView &name, const StringView &password) = 0;
144 :
145 : // send broadcast with data
146 : virtual void broadcast(const Bytes &) = 0;
147 :
148 : // get scheme delta value (like, last modification time) for scheme
149 : // Scheme should have Delta flag
150 : virtual int64_t getDeltaValue(const Scheme &) = 0;
151 :
152 : // get delta value for View field in specific object
153 : // View should have Delta flag
154 : virtual int64_t getDeltaValue(const Scheme &, const FieldView &, uint64_t) = 0;
155 :
156 : public:
157 : // prevent transaction from successfully competition
158 0 : void cancelTransaction() { transactionStatus = TransactionStatus::Rollback; }
159 :
160 : // check if there is active transaction
161 21600 : bool isInTransaction() const { return transactionStatus != TransactionStatus::None; }
162 :
163 : // get active transaction status
164 40071 : TransactionStatus getTransactionStatus() const { return transactionStatus; }
165 :
166 : // get current database name (driver-specific)
167 350 : StringView getDatabaseName() const { return dbName; }
168 :
169 17312 : virtual String getTransactionKey() const { return String(); }
170 :
171 : protected:
172 : StringView dbName;
173 : TransactionStatus transactionStatus = TransactionStatus::None;
174 : };
175 :
176 : class Binder {
177 : public:
178 : struct DataField {
179 : const Field *field;
180 : const Value &data;
181 : bool force = false;
182 : bool compress = false;
183 : };
184 :
185 : struct FullTextField {
186 : const Field *field;
187 : const FullTextVector &data;
188 : };
189 :
190 : struct FullTextFrom {
191 : StringView scheme;
192 : const Field *field;
193 : StringView query;
194 : };
195 :
196 : struct FullTextRank {
197 : StringView scheme;
198 : const Field *field;
199 : StringView query;
200 : };
201 :
202 : struct FullTextQueryRef {
203 : StringView scheme;
204 : const Field *field;
205 : const FullTextQuery &query;
206 : };
207 :
208 : struct TypeString {
209 : StringView str;
210 : StringView type;
211 :
212 : template <typename Str, typename Type>
213 50 : TypeString(Str && str, Type && type)
214 50 : : str(str), type(type) { }
215 : };
216 :
217 : void setInterface(QueryInterface *);
218 : QueryInterface * getInterface() const;
219 :
220 : void writeBind(StringStream &, int64_t);
221 : void writeBind(StringStream &, uint64_t);
222 : void writeBind(StringStream &, double);
223 : void writeBind(StringStream &query, Time val);
224 : void writeBind(StringStream &query, TimeInterval val);
225 : void writeBind(StringStream &, const String &);
226 : void writeBind(StringStream &, String &&);
227 : void writeBind(StringStream &, const StringView &);
228 : void writeBind(StringStream &, const Bytes &);
229 : void writeBind(StringStream &, Bytes &&);
230 : void writeBind(StringStream &, const CoderSource &);
231 : void writeBind(StringStream &, const Value &);
232 : void writeBind(StringStream &, const DataField &);
233 : void writeBind(StringStream &, const TypeString &);
234 : void writeBind(StringStream &, const FullTextField &);
235 : void writeBind(StringStream &, const FullTextFrom &);
236 : void writeBind(StringStream &, const FullTextRank &);
237 : void writeBind(StringStream &, const FullTextQueryRef &);
238 : void writeBind(StringStream &, const stappler::sql::PatternComparator<const Value &> &);
239 : void writeBind(StringStream &, const stappler::sql::PatternComparator<const StringView &> &);
240 : void writeBind(StringStream &, const Vector<int64_t> &);
241 : void writeBind(StringStream &, const Vector<double> &);
242 : void writeBind(StringStream &, const Vector<StringView> &);
243 :
244 : void writeBindArray(StringStream &, const Vector<int64_t> &);
245 : void writeBindArray(StringStream &, const Vector<double> &);
246 : void writeBindArray(StringStream &, const Vector<StringView> &);
247 : void writeBindArray(StringStream &, const Value &);
248 :
249 : void clear();
250 :
251 : protected:
252 : QueryInterface *_iface = nullptr;
253 : };
254 :
255 : class QueryInterface {
256 : public:
257 17650 : virtual ~QueryInterface() = default;
258 :
259 : virtual void bindInt(Binder &, StringStream &, int64_t) = 0;
260 : virtual void bindUInt(Binder &, StringStream &, uint64_t) = 0;
261 : virtual void bindDouble(Binder &, StringStream &, double) = 0;
262 : virtual void bindString(Binder &, StringStream &, const String &) = 0;
263 : virtual void bindMoveString(Binder &, StringStream &, String &&) = 0;
264 : virtual void bindStringView(Binder &, StringStream &, const StringView &) = 0;
265 : virtual void bindBytes(Binder &, StringStream &, const Bytes &) = 0;
266 : virtual void bindMoveBytes(Binder &, StringStream &, Bytes &&) = 0;
267 : virtual void bindCoderSource(Binder &, StringStream &, const stappler::CoderSource &) = 0;
268 : virtual void bindValue(Binder &, StringStream &, const Value &) = 0;
269 : virtual void bindDataField(Binder &, StringStream &, const Binder::DataField &) = 0;
270 : virtual void bindTypeString(Binder &, StringStream &, const Binder::TypeString &) = 0;
271 : virtual void bindFullText(Binder &, StringStream &, const Binder::FullTextField &) = 0;
272 : virtual void bindFullTextFrom(Binder &, StringStream &, const Binder::FullTextFrom &) = 0;
273 : virtual void bindFullTextRank(Binder &, StringStream &, const Binder::FullTextRank &) = 0;
274 : virtual void bindFullTextQuery(Binder &, StringStream &, const Binder::FullTextQueryRef &d) = 0;
275 : virtual void bindIntVector(Binder &, StringStream &, const Vector<int64_t> &) = 0;
276 : virtual void bindDoubleVector(Binder &, StringStream &, const Vector<double> &) = 0;
277 : virtual void bindStringVector(Binder &, StringStream &, const Vector<StringView> &) = 0;
278 :
279 : virtual void clear() = 0;
280 : };
281 :
282 : class ResultCursor {
283 : public:
284 22375 : virtual ~ResultCursor() = default;
285 :
286 : virtual bool isBinaryFormat(size_t field) const = 0;
287 :
288 : virtual bool isNull(size_t field) const = 0;
289 :
290 : virtual StringView toString(size_t field) const = 0;
291 : virtual stappler::BytesView toBytes(size_t field) const = 0;
292 :
293 : virtual int64_t toInteger(size_t field) const = 0;
294 : virtual double toDouble(size_t field) const = 0;
295 : virtual bool toBool(size_t field) const = 0;
296 :
297 : virtual Value toTypedData(size_t field) const = 0;
298 :
299 : virtual Value toCustomData(size_t field, const FieldCustom *) const = 0;
300 :
301 : virtual int64_t toId() const = 0;
302 :
303 : virtual StringView getFieldName(size_t field) const = 0;
304 :
305 : virtual bool isSuccess() const = 0;
306 : virtual bool isEmpty() const = 0;
307 : virtual bool isEnded() const = 0;
308 : virtual size_t getFieldsCount() const = 0;
309 : virtual size_t getAffectedRows() const = 0;
310 : virtual size_t getRowsHint() const = 0;
311 :
312 : virtual Value getInfo() const = 0;
313 : virtual bool next() = 0;
314 : virtual void reset() = 0;
315 : virtual void clear() = 0;
316 : };
317 :
318 : struct ResultRow {
319 : ResultRow(const db::ResultCursor *, size_t);
320 : ResultRow(const ResultRow & other) noexcept;
321 : ResultRow & operator=(const ResultRow &other) noexcept;
322 :
323 : size_t size() const;
324 : Value toData(const db::Scheme &, const Map<String, db::Field> & = Map<String, db::Field>(),
325 : const Vector<const Field *> &virtuals = Vector<const Field *>());
326 :
327 : Value encode() const;
328 :
329 : StringView front() const;
330 : StringView back() const;
331 :
332 : bool isNull(size_t) const;
333 : StringView at(size_t) const;
334 :
335 : StringView toString(size_t) const;
336 : BytesView toBytes(size_t) const;
337 : int64_t toInteger(size_t) const;
338 : double toDouble(size_t) const;
339 : bool toBool(size_t) const;
340 :
341 : Value toTypedData(size_t n) const;
342 :
343 : Value toData(size_t n, const db::Field &);
344 :
345 : const db::ResultCursor *result = nullptr;
346 : size_t row = 0;
347 : };
348 :
349 : class Result {
350 : public:
351 : struct Iter {
352 : Iter() noexcept {}
353 27348 : Iter(Result *res, size_t n) noexcept : result(res), row(n) { }
354 :
355 : Iter& operator=(const Iter &other) { result = other.result; row = other.row; return *this; }
356 : bool operator==(const Iter &other) const { return row == other.row; }
357 33304 : bool operator!=(const Iter &other) const { return row != other.row; }
358 : bool operator<(const Iter &other) const { return row < other.row; }
359 : bool operator>(const Iter &other) const { return row > other.row; }
360 : bool operator<=(const Iter &other) const { return row <= other.row; }
361 : bool operator>=(const Iter &other) const { return row >= other.row; }
362 :
363 21817 : Iter& operator++() { if (!result->next()) { row = stappler::maxOf<size_t>(); } return *this; }
364 :
365 22448 : ResultRow operator*() const { return ResultRow(result->_cursor, row); }
366 :
367 : Result *result = nullptr;
368 : size_t row = 0;
369 : };
370 :
371 : Result() = default;
372 : Result(db::ResultCursor *);
373 : ~Result();
374 :
375 : Result(const Result &) = delete;
376 : Result & operator=(const Result &) = delete;
377 :
378 : Result(Result &&);
379 : Result & operator=(Result &&);
380 :
381 : explicit operator bool () const;
382 : bool success() const;
383 :
384 : Value info() const;
385 :
386 : bool empty() const;
387 : size_t nrows() const { return getRowsHint(); }
388 : size_t nfields() const { return _nfields; }
389 : size_t getRowsHint() const;
390 : size_t getAffectedRows() const;
391 :
392 : int64_t readId();
393 :
394 : void clear();
395 :
396 : Iter begin();
397 : Iter end();
398 :
399 : ResultRow current() const;
400 : bool next();
401 :
402 : StringView name(size_t) const;
403 :
404 : Value decode(const db::Scheme &, const Vector<const Field *> &virtuals);
405 : Value decode(const db::Field &, const Vector<const Field *> &virtuals);
406 : Value decode(const db::FieldView &);
407 :
408 : protected:
409 : friend struct ResultRow;
410 :
411 : db::ResultCursor *_cursor = nullptr;
412 : size_t _row = 0;
413 :
414 : bool _success = false;
415 :
416 : size_t _nfields = 0;
417 : };
418 :
419 : }
420 :
421 : #endif /* STAPPLER_DB_SPDBINTERFACE_H_ */
|