comparison cppdb/cppdb.h @ 0:a4671277546c tip

created the repository for the thymian project
author ferencd
date Tue, 17 Aug 2021 11:19:54 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:a4671277546c
1 #ifndef CPPDB_H
2 #define CPPDB_H
3
4 #include <string>
5 #include <common.h>
6 #include <tuple>
7 #include <functional>
8 #include <type_traits>
9 #include <algorithm>
10
11 #define _O(x) x
12
13 // helper macros
14 #define CONCAT_IMPL( x, y ) x##y
15 #define MACRO_CONCAT( x, y ) CONCAT_IMPL( x, y )
16
17 // basic value retrieval for various column types
18 struct value_renderer
19 {
20 value_renderer() = default;
21 virtual ~value_renderer() = default;
22 virtual std::string render(const std::string& t) const { return t; }
23
24 virtual std::string value() const = 0;
25 virtual std::string crypted(bool) = 0;
26 virtual value_renderer& decrypted(bool) = 0;
27
28 };
29
30 /**
31 * Class representing a column
32 */
33 class Column
34 {
35 public:
36 virtual ~Column() = default;
37 virtual std::string name() const = 0;
38 virtual std::string realname() const = 0;
39 virtual std::string type() const = 0;
40 virtual const value_renderer* get_value_renderer() const = 0;
41 virtual std::string extra_modifiers() const = 0;
42 virtual std::string crypt_value(const std::string&) const = 0;
43 virtual std::string decrypt_value(const std::string&) const = 0;
44 virtual Column* clone() const = 0;
45 };
46
47 class BasicColumn : public Column
48 {
49 public:
50 virtual std::string name() const { return "" ;}
51 virtual std::string type() const { return "" ;}
52 virtual std::string extra_modifiers() const { return "";}
53 };
54
55 class NotAColumn : public Column
56 {
57 public:
58 virtual std::string name() const = 0;
59 virtual std::string realname() const = 0;
60 virtual std::string type() const { return ""; }
61 virtual const value_renderer* get_value_renderer() const { return nullptr; }
62 virtual std::string extra_modifiers() const { return ""; }
63 virtual std::string crypt_value(const std::string&) const { return ""; }
64 virtual std::string decrypt_value(const std::string&) const { return ""; }
65 virtual Column* clone() const { return nullptr; }
66 };
67
68 class DescAsColumn : public NotAColumn
69 {
70 public:
71 typedef DescAsColumn type;
72 virtual std::string name() const { return "DESC"; }
73 virtual std::string realname() const { return "DESC"; }
74 };
75
76 class AscAsColumn : public NotAColumn
77 {
78 public:
79 typedef AscAsColumn type;
80 virtual std::string name() const { return "ASC"; }
81 virtual std::string realname() const { return "ASC"; }
82 };
83
84 #define DESC ,DescAsColumn()
85 #define ASC ,AscAsColumn()
86
87 class BasicTable
88 {
89 public:
90 virtual std::string name() const = 0;
91 virtual bool is_crypted() const = 0;
92 virtual ~BasicTable() = default;
93 };
94
95 struct Functor
96 {
97 Functor(std::string& rstr) : s(rstr) {}
98 std::string& s;
99
100 template<typename T>
101 void operator()(T& t)
102 {
103 std::string g = unafrog::utils::to_string(t);
104 this->s = g;
105 }
106 };
107
108 struct GetNameFunctor
109 {
110 GetNameFunctor(std::string& rstr) : s(rstr) {}
111 std::string& s;
112
113 template<typename T>
114 void operator()(T& t)
115 {
116 std::string g = t.name();
117 this->s = g;
118 }
119 };
120
121
122 static const char* insert_into = "INSERT OR IGNORE INTO ";
123
124 // columnset stuff for insert operations
125 class Columnset
126 {
127 size_t colcount;
128 std::vector<std::string> colnames;
129 std::vector<const Column*> cols;
130 std::vector<const Column*> mcols;
131
132 std::vector<const value_renderer*> valrends;
133 const BasicTable& t;
134 mutable std::string values_s;
135 mutable std::string s;
136
137 public:
138 template<class ...Cs>
139 Columnset(const BasicTable& bt, Cs&... inputs) : colcount(sizeof...(Cs)), cols{&inputs...}, t(bt), values_s(""),
140 s(insert_into + t.name() + "(")
141 {
142 for (auto c : cols)
143 {
144 colnames.push_back(c->name());
145 valrends.push_back(c->get_value_renderer());
146 mcols.push_back(c->clone());
147 }
148 }
149
150 virtual ~Columnset()
151 {
152 for (auto c : mcols)
153 {
154 delete c;
155 }
156 for (auto c : valrends)
157 {
158 delete c;
159 }
160 }
161
162 template <class ...Vals>
163 std::string insert(const char* c, Vals... v)
164 {
165 return std::string(c), + valset(v...);
166 }
167
168 template <class ...Vals>
169 std::string insert(Vals... v) const
170 {
171 auto r = valset(v...);
172 for(size_t i=0; i<colcount; i++)
173 {
174 std::string cn = colnames.at(i);
175 s += cn.substr(cn.find('.') + 1);
176
177 // the value from the template arguments, stored as a tuple.
178 std::string returned;
179 Functor a(returned);
180 for_index(i, r, a);
181 std::string crypted = mcols.at(i)->crypt_value(returned);
182 values_s += valrends.at(i)->render(crypted);
183 if(i < cols.size() - 1)
184 {
185 s+= ", ";
186 values_s += ", ";
187 }
188 }
189 s += ") VALUES (" + values_s + ")";
190 return s;
191 }
192
193 std::string prepare_insert() const
194 {
195 std::string s = std::string(insert_into) + t.name() + "(";
196 std::string values_s = "";
197
198 for(size_t i=0; i<colcount; i++)
199 {
200 std::string cn = mcols[i]->name();
201 s += cn.substr(cn.find('.') + 1);
202 values_s += ":v" + std::to_string(i + 1);
203
204 if(i < cols.size() - 1)
205 {
206 s+= ", ";
207 values_s += ", ";
208 }
209 }
210 s += _O(") VALUES (") + values_s + ")";
211 return s;
212 }
213
214 };
215
216 /**
217 * Class representing a Table
218 */
219 class Table : public BasicTable
220 {
221 mutable std::vector<std::string> foreign_keys;
222 std::vector<std::string> inited_foreign_keys;
223 std::vector<const Column*> columns;
224 std::string resolve_foreign_key(const std::string& s) const;
225
226 protected:
227 bool init_foreign_key(const std::string& s);
228
229 public:
230 virtual std::string verify() const;
231 virtual std::string create() const;
232
233 virtual std::string name() const = 0;
234 virtual std::string realname() const = 0;
235 virtual bool is_crypted() const = 0;
236
237 void addColumn(const Column* c) {columns.push_back(c);}
238 };
239
240 class Condition
241 {
242 public:
243 Condition(const std::string& s);
244 std::string cond() const;
245 private:
246 std::string cstr;
247 };
248
249 std::string operator && (const Condition& c1, const Condition& c2);
250 std::string operator || (const Condition& c1, const Condition& c2);
251 typedef std::string (*PT)(const Condition& c1, const Condition& c2);
252
253 #define AND &&
254 #define OR ||
255
256 template<typename TF>
257 std::string write_debug_output( TF const& f) {
258 std::stringstream ss;
259 ss << f.get_modifier();
260 return ss.str();
261 }
262
263 struct modifier_retriever {
264 template<typename TF, typename ... TR>
265 std::string write( TF const& f, TR const& ... rest ) {
266 std::string full = write_debug_output( f );
267 full += " ";
268 full += write( rest... );
269 return full;
270 }
271 template<typename TF>
272 std::string write( TF const& f ) {
273 return write_debug_output( f );
274 }
275 std::string write() {
276 return "";
277 }
278 };
279
280 namespace cppdb
281 {
282 std::string crypt_db_name(const std::string& in);
283 std::string crypt_db_value(const std::string& in, bool do_crypt);
284 std::string decrypt_db_value(const std::string& in, bool do_decrypt);
285 unsigned long crypt_number(unsigned long in, bool do_crypt);
286 unsigned long decrypt_number(unsigned long in, bool do_crypt);
287 }
288
289 #define TABLE_WRAPPER(Name,Crypt) namespace { \
290 class Table##Name : public Table \
291 { \
292 mutable std::string crypted_name = ""; \
293 public: \
294 static std::string tablename; \
295 Table##Name() {} \
296 bool is_crypted() const {return Crypt;} \
297 template<class ...Cs> \
298 const Columnset operator() (Cs... cols) const \
299 { return Columnset(*this, cols...);} \
300 virtual std::string name() const \
301 { \
302 if(Crypt) \
303 { \
304 if(crypted_name.empty()) \
305 crypted_name = cppdb::crypt_db_name(tablename); \
306 return crypted_name; \
307 } \
308 else return tablename; \
309 } \
310 virtual std::string realname() const {return tablename; }
311
312 #define TABLE(Name) TABLE_WRAPPER(Name,0)
313 #define CRYP_TABLE(Name) TABLE_WRAPPER(Name,1)
314
315 // Will create the actual "Name" object of type Table##Name
316 #define ENDTABLE(Name) }; \
317 std::string Table##Name::tablename = #Name; \
318 const Table##Name& Name = Table##Name(); \
319 bool MACRO_CONCAT(reg_tab_, Name) = cppdb_warehouse::instance().add_table(&Name); \
320 }
321
322 #define DEF_OPERATOR(OP,sqlop,Type) \
323 Condition operator OP (const Type::type& t) const \
324 { return Condition( "(" + name() + #sqlop + unafrog::utils::to_string(t) + ")"); } \
325 Condition operator OP (const Column& t) const \
326 { return Condition( "(" + name() + #sqlop + t.name() + ")"); } \
327
328
329 #define COLUMN_WRAPPER(Name, Type, Crypt, ...) \
330 class Column##Name : public BasicColumn \
331 { \
332 Table& parent; \
333 mutable std::string crypted_name = ""; \
334 std::string extra = modifier_retriever().write(__VA_ARGS__); \
335 public: \
336 Column##Name (Table& p) : parent(p) {p.addColumn(this);} \
337 virtual std::string name() const \
338 { \
339 if (Crypt || parent.is_crypted()) \
340 { \
341 if(crypted_name.empty()) \
342 { \
343 crypted_name = parent.name() + "." + cppdb::crypt_db_name(#Name); \
344 } \
345 return crypted_name; \
346 } \
347 else return parent.name() + "." + #Name; \
348 } \
349 virtual std::string realname() const { return #Name; } \
350 DEF_OPERATOR(==, =, Type) \
351 Condition operator == (const std::string& t) const \
352 { return Condition( "(" + name() + " = '" + t + "')"); } \
353 DEF_OPERATOR(!=, <>, Type) \
354 DEF_OPERATOR(<=, <=, Type) \
355 DEF_OPERATOR(>=, >=, Type) \
356 DEF_OPERATOR(<, <, Type) \
357 DEF_OPERATOR(>, >, Type) \
358 std::string type() const { return Type().get_type(); } \
359 std::string extra_modifiers() const { return extra; } \
360 const value_renderer* get_value_renderer() const { return new Type(); } \
361 std::string crypt_value(const std::string& value) const \
362 { \
363 return Type(value).crypted(Crypt || parent.is_crypted()); \
364 } \
365 std::string crypt_value(const Type::type& value) const \
366 { \
367 return Type(value).crypted(Crypt || parent.is_crypted()); \
368 } \
369 std::string decrypt_value(const std::string& value) const \
370 { \
371 return Type(value).decrypted(Crypt || parent.is_crypted()).value(); \
372 } \
373 Column* clone() const { Column* c = new Column##Name(parent); dynamic_cast<Column##Name*>(c)->crypted_name = crypted_name; dynamic_cast<Column##Name*>(c)->extra = extra; return c;}\
374 }; \
375 Column##Name Name = Column##Name(*this); \
376 bool MACRO_CONCAT(reg_col_, Name) = cppdb_warehouse::instance().add_column(&Name)
377
378
379 #define COLUMN(Name, Type, ...) COLUMN_WRAPPER(Name, Type, 0, __VA_ARGS__)
380 #define CRYP_COLUMN(Name, Type, ...) COLUMN_WRAPPER(Name, Type, 1, __VA_ARGS__)
381
382 // Foreign Key stuff
383 #define FOREIGN_KEY(X) bool MACRO_CONCAT(g, __COUNTER__ ) = init_foreign_key(std::string(#X))
384
385 // Order by
386
387 template<typename T, typename U>
388 struct is_same : std::false_type { };
389
390 template<typename T>
391 struct is_same<T, T> : std::true_type { };
392
393 template<typename T, typename U>
394 constexpr bool eqTypes() { return is_same<T, U>::value; }
395
396 std::string orderby_helper(const Column& c);
397
398 template <class... args>
399 std::string orderby_helper(args... a)
400 {
401
402 std::size_t cnt = sizeof...(args);
403 auto r = std::tuple<args...>(a...);
404 std::vector<std::string> columns;
405
406 for(std::size_t i=0; i<cnt; i++)
407 {
408 std::string returned;
409 GetNameFunctor a(returned);
410 for_index(i, r, a);
411 columns.push_back(returned);
412 }
413 std::string result = "";
414 for(size_t i = 0; i<columns.size(); i++)
415 {
416 result += columns.at(i);
417 if(i < columns.size() - 1)
418 {
419 if(columns.at(i + 1) != "ASC" && columns.at(i + 1) != "DESC")
420 {
421 result += ", ";
422 }
423 else
424 {
425 result += " ";
426 }
427 }
428 }
429 return result;
430 }
431
432 template <class... all>
433 std::string ORDER_BY(all... a)
434 {
435 std::string s = " ORDER BY ";
436 std::string g = orderby_helper(a...);
437 return s + g;
438 }
439
440 // Where
441
442 std::string where_helper(const Condition& c);
443
444 template <class C = Condition, class... args>
445 std::string where_helper(const Condition& c, args... a)
446 {
447 std::string s = c.cond();
448 s += from(a...);
449 return s;
450 }
451
452 template <class... all>
453 std::string WHERE(all... a)
454 {
455 std::string s = "WHERE ";
456 std::string g = where_helper(a...);
457 return s + g;
458 }
459
460 // From
461
462 std::string from_helper(const Table& t);
463
464 template <class T = Table, class... args>
465 std::string from_helper(const Table& t, args... a)
466 {
467 std::string s = t.name() + ", ";
468 s += from_helper(a...);
469 return s;
470 }
471
472 template <class... all>
473 std::string FROM(all... a)
474 {
475 std::string s = "FROM ";
476 std::string g = from_helper(a...);
477 return s + g + " ";
478 }
479
480 // Select
481
482 std::string select_helper(const Column& c);
483
484 template <class C = Column, class... args>
485 std::string select_helper(const Column& c, args... a)
486 {
487 std::string s = c.name() + ", ";
488 s += select_helper(a...);
489 return s;
490 }
491
492
493 template <class... all>
494 std::string SELECT(all... a)
495 {
496 std::string s = "SELECT ";
497 std::string g = select_helper(a...);
498 return s + g + " ";
499 }
500
501 // Delete
502
503 #define DELETE "DELETE "
504
505 // Update
506
507 std::string UPDATE(const Table& tab);
508
509 std::string set_helper(int total_size, const Column& c);
510
511 template <class C = Column, class... args>
512 std::string set_helper(std::size_t total_size, const Column& c, args... a)
513 {
514 std::string s = c.realname() + "=:v";
515 std::stringstream ss;
516 ss << total_size - sizeof...(a);
517 s += ss.str() + ", ";
518 s += set_helper(total_size, a...);
519 return s;
520 }
521
522 template <class... all>
523 std::string SET(all... a)
524 {
525 std::string s = " SET ";
526 std::string g = set_helper(sizeof...(a), a...);
527 return s + g ;
528 }
529
530 // varchar support
531 template<size_t SIZE> class varchar : public value_renderer
532 {
533 public:
534 // this has to be "const char*" otherwise overloading upon const std::string& is not possible in Column classes
535 typedef const char* type;
536
537 varchar() : s(SIZE) {}
538 varchar(const std::string& v) : s(SIZE), mvalue(v) {}
539 operator std::string () const
540 {
541 return _O("VARCHAR(") + std::to_string(s) + ")";
542 }
543
544 std::string get_type() const
545 {
546 return operator std::string();
547 }
548
549 virtual std::string render(const std::string& t) const {return "\"" + t + "\"" ; }
550
551 virtual std::string crypted(bool crypt) {return cppdb::crypt_db_value(mvalue, crypt); }
552 virtual value_renderer& decrypted(bool crypt) { mvalue = cppdb::decrypt_db_value(mvalue, crypt); return *this;}
553 std::string value() const {return mvalue; }
554 private:
555 size_t s;
556 std::string mvalue = "";
557 };
558
559 template <size_t SIZE>
560 std::basic_ostream<char>& operator << (std::basic_ostream<char>& os, varchar<SIZE> vc)
561 {
562 os << vc.operator std::string();
563 return os;
564 }
565
566 #define VARCHAR(S) varchar<S>
567
568 // text support
569 class text: public value_renderer
570 {
571 public:
572 // this has to be "const char*" otherwise overloading upon const std::string& is not possible in Column classes
573 typedef const char* type;
574
575 text() = default;
576 text(const std::string& v) : mvalue(v) {}
577 operator std::string () const
578 {
579 return _O("TEXT");
580 }
581
582 std::string get_type() const
583 {
584 return operator std::string();
585 }
586
587 virtual std::string render(const std::string& t) const {return "\"" + t + "\"" ; }
588
589 virtual std::string crypted(bool crypt) {return cppdb::crypt_db_value(mvalue, crypt); }
590 virtual value_renderer& decrypted(bool crypt) { mvalue = cppdb::decrypt_db_value(mvalue, crypt); return *this;}
591 std::string value() const {return mvalue; }
592 private:
593 std::string mvalue = "";
594 };
595 std::basic_ostream<char>& operator << (std::basic_ostream<char>& os, const text& tx);
596
597 #define TEXT text
598
599 // other types support
600 template <class T> class simple_type : public value_renderer
601 {
602 public:
603 typedef T type;
604 simple_type() = default;
605 simple_type(T t) : mt(t) {}
606 private:
607 T mt;
608 };
609
610 template <> class simple_type<time_t> : public value_renderer
611 {
612 public:
613 typedef int type;
614 simple_type() = default;
615 simple_type(time_t t) : mt(t) {}
616 simple_type(const std::string& sv) : mt(stol(sv)) {}
617 std::string get_type() const {return _O("TIMESTAMP"); }
618 virtual std::string crypted(bool crypt) {return std::to_string(cppdb::crypt_number(mt, crypt));}
619 virtual value_renderer& decrypted(bool crypt) { mt = cppdb::decrypt_number(mt, crypt); return *this; }
620 std::string value() const {return std::to_string(mt); }
621 private:
622 time_t mt = 0;
623 };
624
625 template <> class simple_type<int> : public value_renderer
626 {
627 public:
628 typedef int type;
629 simple_type() = default;
630 simple_type(int t) : mt(t) {}
631 simple_type(const std::string& sv) : mt(stoi(sv)) {}
632 std::string get_type() const {return _O("INTEGER"); }
633 virtual std::string crypted(bool crypt) {return std::to_string(cppdb::crypt_number(mt, crypt));}
634 virtual value_renderer& decrypted(bool crypt) { mt = static_cast<int>(cppdb::decrypt_number(mt, crypt)); return *this; }
635 std::string value() const {return std::to_string(mt); }
636 private:
637 int mt = 0;
638 };
639
640 #define INTEGER simple_type<int>
641 #define TIMESTAMP simple_type<time_t>
642
643 struct primary_key { const std::string modifier() {return _O("PRIMARY KEY"); } };
644 struct not_null { const std::string modifier() {return _O("NOT NULL"); } };
645
646 template<class D>
647 struct defaults
648 {
649 defaults(const D& d) : md(d) {}
650 std::string get_modifier() const
651 {
652 std::string res = _O("DEFAULT ");
653 std::stringstream ss; ss << md ; return res + ss.str();
654 }
655 private:
656 D md;
657 };
658
659 template <class T> class modifier_templ
660 {
661 public:
662 modifier_templ(){}
663 std::string get_modifier() const {return T().modifier();}
664 };
665
666 static const modifier_templ<primary_key> pk;
667 static const modifier_templ<not_null> nn;
668
669 #define PRIMARY_KEY pk
670 #define NOT_NULL nn
671 #define CURRENT_TIMESTAMP _O("CURRENT_TIMESTAMP")
672 #define DEFAULT(X) defaults<decltype(X)>(X)
673
674 /* The actual warehouse keeping all the tables, columns and other elements */
675 class cppdb_warehouse
676 {
677 public:
678 static cppdb_warehouse& instance();
679 bool add_column(const Column* c);
680 bool add_table(const Table* t);
681 const Table* table(const std::string& tabname);
682 const Column* column(const std::string& colname);
683 private:
684 std::vector<const Column*> columns;
685 std::vector<const Table*> tables;
686 };
687
688 #endif // CPPDB