LeechCraft  0.6.70-15082-g543737046d
Modular cross-platform feature rich live environment.
oral.h
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2014 Georg Rudoy
4  *
5  * Distributed under the Boost Software License, Version 1.0.
6  * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7  **********************************************************************/
8 
9 #pragma once
10 
11 #include <stdexcept>
12 #include <type_traits>
13 #include <memory>
14 #include <optional>
15 #include <boost/fusion/include/for_each.hpp>
16 #include <boost/fusion/include/fold.hpp>
17 #include <boost/fusion/include/filter_if.hpp>
18 #include <boost/fusion/container/vector.hpp>
19 #include <boost/fusion/include/vector.hpp>
20 #include <boost/fusion/include/transform.hpp>
21 #include <boost/fusion/include/zip.hpp>
22 #include <boost/fusion/container/generation/make_vector.hpp>
23 #include <QStringList>
24 #include <QDateTime>
25 #include <QPair>
26 #include <QSqlQuery>
27 #include <QSqlRecord>
28 #include <QVariant>
29 #include <QDateTime>
30 #include <QtDebug>
31 #include <util/sll/qtutil.h>
32 #include <util/sll/prelude.h>
33 #include <util/sll/typelist.h>
34 #include <util/sll/typelevel.h>
35 #include <util/sll/typegetter.h>
36 #include <util/sll/detector.h>
37 #include <util/sll/unreachable.h>
38 #include <util/sll/void.h>
39 #include <util/db/dblock.h>
40 #include <util/db/util.h>
41 #include "oraltypes.h"
42 #include "oraldetailfwd.h"
43 #include "impldefs.h"
44 #include "sqliteimpl.h"
45 
46 namespace LC
47 {
48 namespace Util
49 {
50 namespace oral
51 {
52  using QSqlQuery_ptr = std::shared_ptr<QSqlQuery>;
53 
54  class QueryException : public std::runtime_error
55  {
56  const QSqlQuery_ptr Query_;
57  public:
58  QueryException (const std::string& str, const QSqlQuery_ptr& q)
59  : std::runtime_error (str)
60  , Query_ (q)
61  {
62  }
63 
64  ~QueryException () noexcept = default;
65 
66  const QSqlQuery_ptr& GetQueryPtr () const
67  {
68  return Query_;
69  }
70 
71  const QSqlQuery& GetQuery () const
72  {
73  return *Query_;
74  }
75  };
76 
77  namespace detail
78  {
79  template<typename U>
80  using MorpherDetector = decltype (std::declval<U> ().FieldNameMorpher (QString {}));
81 
82  template<typename T>
83  QString MorphFieldName (QString str) noexcept
84  {
85  if constexpr (IsDetected_v<MorpherDetector, T>)
86  return T::FieldNameMorpher (str);
87  else
88  {
89  if (str.endsWith ('_'))
90  str.chop (1);
91  return str;
92  }
93  }
94 
95  template<typename Seq, int Idx>
96  QString GetFieldName () noexcept
97  {
98  return MorphFieldName<Seq> (boost::fusion::extension::struct_member_name<Seq, Idx>::call ());
99  }
100 
101  template<typename S>
102  constexpr auto SeqSize = boost::fusion::result_of::size<S>::type::value;
103 
104  template<typename S>
105  constexpr auto SeqIndices = std::make_index_sequence<SeqSize<S>> {};
106 
107  template<typename S>
108  struct GetFieldsNames
109  {
110  QStringList operator() () const noexcept
111  {
112  return Run (SeqIndices<S>);
113  }
114  private:
115  template<size_t... Vals>
116  QStringList Run (std::index_sequence<Vals...>) const noexcept
117  {
118  return { GetFieldName<S, Vals> ()... };
119  }
120  };
121 
122  template<typename S>
123  struct AddressOf
124  {
125  inline static S Obj_ {};
126 
127  template<auto P>
128  static constexpr auto Ptr () noexcept
129  {
130  return &(Obj_.*P);
131  }
132 
133  template<int Idx>
134  static constexpr auto Index () noexcept
135  {
136  return &boost::fusion::at_c<Idx> (Obj_);
137  }
138  };
139 
140  template<auto Ptr, size_t Idx = 0>
141  constexpr size_t FieldIndex () noexcept
142  {
144 
145  if constexpr (Idx == SeqSize<S>)
146  return -1;
147  else
148  {
149  constexpr auto direct = AddressOf<S>::template Ptr<Ptr> ();
150  constexpr auto indexed = AddressOf<S>::template Index<Idx> ();
151  if constexpr (std::is_same_v<decltype (direct), decltype (indexed)>)
152  {
153  if (indexed == direct)
154  return Idx;
155  }
156 
157  return FieldIndex<Ptr, Idx + 1> ();
158  }
159  }
160 
161  template<auto Ptr>
162  QString GetFieldNamePtr () noexcept
163  {
164  using S = MemberPtrStruct_t<Ptr>;
165  return GetFieldName<S, FieldIndex<Ptr> ()> ();
166  }
167 
168  template<auto Ptr>
169  QString GetQualifiedFieldNamePtr () noexcept
170  {
171  using S = MemberPtrStruct_t<Ptr>;
172  return S::ClassName () + "." + GetFieldName<S, FieldIndex<Ptr> ()> ();
173  }
174 
175  template<typename T>
176  using TypeNameDetector = decltype (T::TypeName);
177 
178  template<typename T>
179  constexpr bool TypeNameCustomized = IsDetected_v<TypeNameDetector, T>;
180 
181  template<typename T>
182  using BaseTypeDetector = typename T::BaseType;
183 
184  template<typename T>
185  constexpr bool BaseTypeCustomized = IsDetected_v<BaseTypeDetector, T>;
186  }
187 
188  template<typename ImplFactory, typename T, typename = void>
189  struct Type2Name
190  {
191  QString operator() () const noexcept
192  {
193  if constexpr (HasType<T> (Typelist<int, qlonglong, qulonglong, bool> {}) || std::is_enum_v<T>)
194  return "INTEGER";
195  else if constexpr (std::is_same_v<T, double>)
196  return "REAL";
197  else if constexpr (std::is_same_v<T, QString> || std::is_same_v<T, QDateTime> || std::is_same_v<T, QUrl>)
198  return "TEXT";
199  else if constexpr (std::is_same_v<T, QByteArray>)
200  return ImplFactory::TypeLits::Binary;
201  else if constexpr (detail::TypeNameCustomized<T>)
202  return T::TypeName;
203  else if constexpr (detail::BaseTypeCustomized<T>)
204  return Type2Name<ImplFactory, typename T::BaseType> {} ();
205  else
206  static_assert (std::is_same_v<T, struct Dummy>, "Unsupported type");
207  }
208  };
209 
210  template<typename ImplFactory, typename T>
211  struct Type2Name<ImplFactory, Unique<T>>
212  {
213  QString operator() () const noexcept { return Type2Name<ImplFactory, T> () () + " UNIQUE"; }
214  };
215 
216  template<typename ImplFactory, typename T>
217  struct Type2Name<ImplFactory, NotNull<T>>
218  {
219  QString operator() () const noexcept { return Type2Name<ImplFactory, T> () () + " NOT NULL"; }
220  };
221 
222  template<typename ImplFactory, typename T, typename... Tags>
223  struct Type2Name<ImplFactory, PKey<T, Tags...>>
224  {
225  QString operator() () const noexcept { return Type2Name<ImplFactory, T> () () + " PRIMARY KEY"; }
226  };
227 
228  template<typename ImplFactory, typename... Tags>
229  struct Type2Name<ImplFactory, PKey<int, Tags...>>
230  {
231  QString operator() () const noexcept { return ImplFactory::TypeLits::IntAutoincrement; }
232  };
233 
234  template<typename ImplFactory, auto Ptr>
235  struct Type2Name<ImplFactory, References<Ptr>>
236  {
237  QString operator() () const noexcept
238  {
239  const auto& className = MemberPtrStruct_t<Ptr>::ClassName ();
241  " REFERENCES " + className + " (" + detail::GetFieldNamePtr<Ptr> () + ") ON DELETE CASCADE";
242  }
243  };
244 
245  template<typename T, typename = void>
246  struct ToVariant
247  {
248  QVariant operator() (const T& t) const noexcept
249  {
250  if constexpr (std::is_same_v<T, QDateTime>)
251  return t.toString (Qt::ISODate);
252  else if constexpr (std::is_enum_v<T>)
253  return static_cast<qint64> (t);
254  else if constexpr (IsIndirect<T> {})
256  else if constexpr (detail::TypeNameCustomized<T>)
257  return t.ToVariant ();
258  else if constexpr (detail::BaseTypeCustomized<T>)
259  return ToVariant<typename T::BaseType> {} (t.ToBaseType ());
260  else
261  return t;
262  }
263  };
264 
265  template<typename T, typename = void>
266  struct FromVariant
267  {
268  T operator() (const QVariant& var) const noexcept
269  {
270  if constexpr (std::is_same_v<T, QDateTime>)
271  return QDateTime::fromString (var.toString (), Qt::ISODate);
272  else if constexpr (std::is_enum_v<T>)
273  return static_cast<T> (var.value<qint64> ());
274  else if constexpr (IsIndirect<T> {})
275  return FromVariant<typename T::value_type> {} (var);
276  else if constexpr (detail::TypeNameCustomized<T>)
277  return T::FromVariant (var);
278  else if constexpr (detail::BaseTypeCustomized<T>)
279  return T::FromBaseType (FromVariant<typename T::BaseType> {} (var));
280  else
281  return var.value<T> ();
282  }
283  };
284 
285  namespace detail
286  {
287  template<typename T>
288  struct IsPKey : std::false_type {};
289 
290  template<typename U, typename... Tags>
291  struct IsPKey<PKey<U, Tags...>> : std::true_type {};
292 
293  template<typename T>
294  QVariant ToVariantF (const T& t) noexcept
295  {
296  return ToVariant<T> {} (t);
297  }
298 
299  template<typename T>
300  auto MakeInserter (const CachedFieldsData& data, const QSqlQuery_ptr& insertQuery, bool bindPrimaryKey) noexcept
301  {
302  return [data, insertQuery, bindPrimaryKey] (const T& t)
303  {
304  boost::fusion::fold (t, data.BoundFields_.begin (),
305  [&] (auto pos, const auto& elem)
306  {
307  using Elem = std::decay_t<decltype (elem)>;
308  if (bindPrimaryKey || !IsPKey<Elem>::value)
309  insertQuery->bindValue (*pos++, ToVariantF (elem));
310  return pos;
311  });
312 
313  if (!insertQuery->exec ())
314  {
315  DBLock::DumpError (*insertQuery);
316  throw QueryException ("insert query execution failed", insertQuery);
317  }
318  };
319  }
320 
321  template<typename Seq, int Idx>
322  using ValueAtC_t = typename boost::fusion::result_of::value_at_c<Seq, Idx>::type;
323 
324  template<typename Seq, typename Idx>
325  using ValueAt_t = typename boost::fusion::result_of::value_at<Seq, Idx>::type;
326 
327  template<typename Seq, typename MemberIdx = boost::mpl::int_<0>>
328  struct FindPKey
329  {
330  static_assert ((boost::fusion::result_of::size<Seq>::value) != (MemberIdx::value),
331  "Primary key not found");
332 
333  template<typename T>
334  struct Lazy
335  {
336  using type = T;
337  };
338 
339  using result_type = typename std::conditional_t<
341  Lazy<MemberIdx>,
343  >::type;
344  };
345 
346  template<typename Seq>
347  using FindPKeyDetector = boost::mpl::int_<FindPKey<Seq>::result_type::value>;
348 
349  template<typename Seq>
350  constexpr auto HasPKey = IsDetected_v<FindPKeyDetector, Seq>;
351 
352  template<typename Seq>
353  constexpr auto HasAutogenPKey () noexcept
354  {
355  if constexpr (HasPKey<Seq>)
356  return !HasType<NoAutogen> (AsTypelist_t<ValueAtC_t<Seq, FindPKey<Seq>::result_type::value>> {});
357  else
358  return false;
359  }
360 
361  template<typename T>
362  CachedFieldsData BuildCachedFieldsData (const QString& table) noexcept
363  {
364  const auto& fields = detail::GetFieldsNames<T> {} ();
365  const auto& qualified = Util::Map (fields, [&table] (const QString& field) { return table + "." + field; });
366  const auto& boundFields = Util::Map (fields, [] (const QString& str) { return ':' + str; });
367 
368  return { table, fields, qualified, boundFields };
369  }
370 
371  template<typename T>
373  {
374  static CachedFieldsData result = BuildCachedFieldsData<T> (T::ClassName ());
375  return result;
376  }
377 
378  template<typename Seq>
379  class AdaptInsert
380  {
381  const QSqlDatabase DB_;
382  const CachedFieldsData Data_;
383 
384  constexpr static bool HasAutogen_ = HasAutogenPKey<Seq> ();
385 
386  IInsertQueryBuilder_ptr QueryBuilder_;
387  public:
388  template<typename ImplFactory>
389  AdaptInsert (const QSqlDatabase& db, CachedFieldsData data, ImplFactory&& factory) noexcept
390  : Data_ { RemovePKey (data) }
391  , QueryBuilder_ { factory.MakeInsertQueryBuilder (db, Data_) }
392  {
393  }
394 
395  auto operator() (Seq& t, InsertAction action = InsertAction::Default) const
396  {
397  return Run<true> (t, action);
398  }
399 
400  auto operator() (const Seq& t, InsertAction action = InsertAction::Default) const
401  {
402  return Run<false> (t, action);
403  }
404  private:
405  template<bool UpdatePKey, typename Val>
406  auto Run (Val&& t, InsertAction action) const
407  {
408  const auto query = QueryBuilder_->GetQuery (action);
409 
410  MakeInserter<Seq> (Data_, query, !HasAutogen_) (t);
411 
412  if constexpr (HasAutogen_)
413  {
414  constexpr auto index = FindPKey<Seq>::result_type::value;
415 
416  const auto& lastId = FromVariant<ValueAtC_t<Seq, index>> {} (query->lastInsertId ());
417  if constexpr (UpdatePKey)
418  boost::fusion::at_c<index> (t) = lastId;
419  else
420  return lastId;
421  }
422  }
423 
424  static CachedFieldsData RemovePKey (CachedFieldsData data) noexcept
425  {
426  if constexpr (HasAutogen_)
427  {
428  constexpr auto index = FindPKey<Seq>::result_type::value;
429  data.Fields_.removeAt (index);
430  data.BoundFields_.removeAt (index);
431  }
432  return data;
433  }
434  };
435 
436  template<typename Seq, bool HasPKey = HasPKey<Seq>>
437  struct AdaptDelete
438  {
439  std::function<void (Seq)> Deleter_;
440  public:
441  template<bool B = HasPKey>
442  AdaptDelete (const QSqlDatabase& db, const CachedFieldsData& data, std::enable_if_t<B>* = nullptr) noexcept
443  {
444  const auto index = FindPKey<Seq>::result_type::value;
445 
446  const auto& boundName = data.BoundFields_.at (index);
447  const auto& del = "DELETE FROM " + data.Table_ +
448  " WHERE " + data.Fields_.at (index) + " = " + boundName;
449 
450  const auto deleteQuery = std::make_shared<QSqlQuery> (db);
451  deleteQuery->prepare (del);
452 
453  Deleter_ = [deleteQuery, boundName] (const Seq& t)
454  {
455  constexpr auto index = FindPKey<Seq>::result_type::value;
456  deleteQuery->bindValue (boundName, ToVariantF (boost::fusion::at_c<index> (t)));
457  if (!deleteQuery->exec ())
458  throw QueryException ("delete query execution failed", deleteQuery);
459  };
460  }
461 
462  template<bool B = HasPKey>
463  AdaptDelete (const QSqlDatabase&, const CachedFieldsData&, std::enable_if_t<!B>* = nullptr) noexcept
464  {
465  }
466 
467  template<bool B = HasPKey>
468  std::enable_if_t<B> operator() (const Seq& seq)
469  {
470  Deleter_ (seq);
471  }
472  };
473 
474  template<typename T, typename... Args>
475  using AggregateDetector_t = decltype (new T { std::declval<Args> ()... });
476 
477  template<typename T, size_t... Indices>
478  T InitializeFromQuery (const QSqlQuery& q, std::index_sequence<Indices...>, int startIdx) noexcept
479  {
480  if constexpr (IsDetected_v<AggregateDetector_t, T, ValueAtC_t<T, Indices>...>)
481  return T { FromVariant<ValueAtC_t<T, Indices>> {} (q.value (startIdx + Indices))... };
482  else
483  {
484  T t;
485  const auto dummy = std::initializer_list<int>
486  {
487  (static_cast<void> (boost::fusion::at_c<Indices> (t) = FromVariant<ValueAtC_t<T, Indices>> {} (q.value (startIdx + Indices))), 0)...
488  };
489  Q_UNUSED (dummy);
490  return t;
491  }
492  }
493 
494  enum class ExprType
495  {
497 
499  LeafData,
500 
501  Greater,
502  Less,
503  Equal,
504  Geq,
505  Leq,
506  Neq,
507 
508  Like,
509 
510  And,
511  Or
512  };
513 
514  inline QString TypeToSql (ExprType type) noexcept
515  {
516  switch (type)
517  {
518  case ExprType::Greater:
519  return ">";
520  case ExprType::Less:
521  return "<";
522  case ExprType::Equal:
523  return "=";
524  case ExprType::Geq:
525  return ">=";
526  case ExprType::Leq:
527  return "<=";
528  case ExprType::Neq:
529  return "!=";
530  case ExprType::Like:
531  return "LIKE";
533  return "AND";
534  case ExprType::Or:
535  return "OR";
536 
538  case ExprType::LeafData:
539  case ExprType::ConstTrue:
540  return "invalid type";
541  }
542 
544  }
545 
546  constexpr bool IsRelational (ExprType type) noexcept
547  {
548  return type == ExprType::Greater ||
549  type == ExprType::Less ||
550  type == ExprType::Equal ||
551  type == ExprType::Geq ||
552  type == ExprType::Leq ||
553  type == ExprType::Neq ||
554  type == ExprType::Like;
555  }
556 
557  template<typename T>
558  struct ToSqlState
559  {
560  int LastID_;
561  QVariantMap BoundMembers_;
562  };
563 
564  template<typename T>
565  struct WrapDirect
566  {
567  using value_type = T;
568  };
569 
570  template<typename T>
571  using UnwrapIndirect_t = typename std::conditional_t<IsIndirect<T> {},
572  T,
573  WrapDirect<T>>::value_type;
574 
575  template<typename Seq, typename L, typename R>
576  using ComparableDetector = decltype (std::declval<UnwrapIndirect_t<typename L::template ValueType_t<Seq>>> () ==
577  std::declval<UnwrapIndirect_t<typename R::template ValueType_t<Seq>>> ());
578 
579  template<typename Seq, typename L, typename R>
580  constexpr auto AreComparableTypes = IsDetected_v<ComparableDetector, Seq, L, R> || IsDetected_v<ComparableDetector, Seq, R, L>;
581 
582  template<typename Seq, typename L, typename R, typename = void>
583  struct RelationalTypesCheckerBase : std::false_type {};
584 
585  template<typename Seq, typename L, typename R>
586  struct RelationalTypesCheckerBase<Seq, L, R, std::enable_if_t<AreComparableTypes<Seq, L, R>>> : std::true_type {};
587 
588  template<ExprType Type, typename Seq, typename L, typename R, typename = void>
589  struct RelationalTypesChecker : std::true_type {};
590 
591  template<ExprType Type, typename Seq, typename L, typename R>
592  struct RelationalTypesChecker<Type, Seq, L, R, std::enable_if_t<IsRelational (Type)>> : RelationalTypesCheckerBase<Seq, L, R> {};
593 
594  template<ExprType Type, typename L = void, typename R = void>
595  class ExprTree;
596 
597  template<typename T>
598  struct IsExprTree : std::false_type {};
599 
600  template<ExprType Type, typename L, typename R>
601  struct IsExprTree<ExprTree<Type, L, R>> : std::true_type {};
602 
603  template<typename L, typename R>
605  {
606  L Left_;
607  R Right_;
608  public:
609  AssignList (const L& l, const R& r) noexcept
610  : Left_ { l }
611  , Right_ { r }
612  {
613  }
614 
615  template<typename T>
616  QString ToSql (ToSqlState<T>& state) const noexcept
617  {
618  if constexpr (IsExprTree<L> {})
619  return Left_.GetFieldName () + " = " + Right_.ToSql (state);
620  else
621  return Left_.ToSql (state) + ", " + Right_.ToSql (state);
622  }
623 
624  template<typename OL, typename OR>
625  auto operator, (const AssignList<OL, OR>& tail) noexcept
626  {
628  }
629  };
630 
631  template<ExprType Type, typename L, typename R>
632  class ExprTree
633  {
634  L Left_;
635  R Right_;
636  public:
637  ExprTree (const L& l, const R& r) noexcept
638  : Left_ (l)
639  , Right_ (r)
640  {
641  }
642 
643  template<typename T>
644  QString ToSql (ToSqlState<T>& state) const noexcept
645  {
647  "Incompatible types passed to a relational operator.");
648 
649  return Left_.ToSql (state) + " " + TypeToSql (Type) + " " + Right_.ToSql (state);
650  }
651 
652  template<typename T>
653  QSet<QString> AdditionalTables () const noexcept
654  {
655  return Left_.template AdditionalTables<T> () + Right_.template AdditionalTables<T> ();
656  }
657 
658  template<typename T>
659  constexpr static bool HasAdditionalTables () noexcept
660  {
661  return L::template HasAdditionalTables<T> () || R::template HasAdditionalTables<T> ();
662  }
663  };
664 
665  template<typename T>
666  class ExprTree<ExprType::LeafData, T, void>
667  {
668  T Data_;
669  public:
670  template<typename>
671  using ValueType_t = T;
672 
673  ExprTree (const T& t) noexcept
674  : Data_ (t)
675  {
676  }
677 
678  template<typename ObjT>
679  QString ToSql (ToSqlState<ObjT>& state) const noexcept
680  {
681  const auto& name = ":bound_" + QString::number (++state.LastID_);
682  state.BoundMembers_ [name] = ToVariantF (Data_);
683  return name;
684  }
685 
686  template<typename>
687  QSet<QString> AdditionalTables () const noexcept
688  {
689  return {};
690  }
691 
692  template<typename>
693  constexpr static bool HasAdditionalTables () noexcept
694  {
695  return false;
696  }
697  };
698 
699  template<typename T>
700  constexpr auto AsLeafData (const T& node) noexcept
701  {
702  if constexpr (IsExprTree<T> {})
703  return node;
704  else
706  }
707 
708  template<auto... Ptr>
709  struct MemberPtrs {};
710 
711  template<auto Ptr>
713  {
714  using ExpectedType_t = MemberPtrType_t<Ptr>;
715  public:
716  template<typename>
717  using ValueType_t = ExpectedType_t;
718 
719  template<typename T>
720  QString ToSql (ToSqlState<T>&) const noexcept
721  {
722  return MemberPtrStruct_t<Ptr>::ClassName () + "." + GetFieldName ();
723  }
724 
725  QString GetFieldName () const noexcept
726  {
727  return detail::GetFieldNamePtr<Ptr> ();
728  }
729 
730  template<typename T>
731  QSet<QString> AdditionalTables () const noexcept
732  {
733  using Seq = MemberPtrStruct_t<Ptr>;
734  if constexpr (std::is_same_v<Seq, T>)
735  return {};
736  else
737  return { Seq::ClassName () };
738  }
739 
740  template<typename T>
741  constexpr static bool HasAdditionalTables () noexcept
742  {
743  return !std::is_same_v<MemberPtrStruct_t<Ptr>, T>;
744  }
745 
746  auto operator= (const ExpectedType_t& r) const noexcept
747  {
748  return AssignList { *this, AsLeafData (r) };
749  }
750  };
751 
752  template<>
753  class ExprTree<ExprType::ConstTrue, void, void> {};
754 
755  constexpr auto ConstTrueTree_v = ExprTree<ExprType::ConstTrue> {};
756 
757  template<ExprType Type, typename L, typename R>
758  auto MakeExprTree (const L& left, const R& right) noexcept
759  {
760  using EL = decltype (AsLeafData (left));
761  using ER = decltype (AsLeafData (right));
762  return ExprTree<Type, EL, ER> { AsLeafData (left), AsLeafData (right) };
763  }
764 
765  template<typename L, typename R>
766  constexpr bool EitherIsExprTree () noexcept
767  {
768  if (IsExprTree<L> {})
769  return true;
770  if (IsExprTree<R> {})
771  return true;
772  return false;
773  }
774 
775  template<typename L, typename R>
776  using EnableRelOp_t = std::enable_if_t<EitherIsExprTree<L, R> ()>;
777 
778  template<typename L, typename R, typename = EnableRelOp_t<L, R>>
779  auto operator< (const L& left, const R& right) noexcept
780  {
781  return MakeExprTree<ExprType::Less> (left, right);
782  }
783 
784  template<typename L, typename R, typename = EnableRelOp_t<L, R>>
785  auto operator> (const L& left, const R& right) noexcept
786  {
787  return MakeExprTree<ExprType::Greater> (left, right);
788  }
789 
790  template<typename L, typename R, typename = EnableRelOp_t<L, R>>
791  auto operator== (const L& left, const R& right) noexcept
792  {
793  return MakeExprTree<ExprType::Equal> (left, right);
794  }
795 
796  template<typename L, typename R, typename = EnableRelOp_t<L, R>>
797  auto operator!= (const L& left, const R& right) noexcept
798  {
799  return MakeExprTree<ExprType::Neq> (left, right);
800  }
801 
802  template<ExprType Op>
803  struct InfixBinary {};
804  }
805 
806  namespace infix
807  {
808  constexpr detail::InfixBinary<detail::ExprType::Like> like {};
809  }
810 
811  namespace detail
812  {
813  template<typename L, ExprType Op>
814  struct InfixBinaryProxy
815  {
816  const L& Left_;
817  };
818 
819  template<typename L, ExprType Op>
820  auto operator| (const L& left, InfixBinary<Op>) noexcept
821  {
822  return InfixBinaryProxy<L, Op> { left };
823  }
824 
825  template<typename L, ExprType Op, typename R>
826  auto operator| (const InfixBinaryProxy<L, Op>& left, const R& right) noexcept
827  {
828  return MakeExprTree<Op> (left.Left_, right);
829  }
830 
831  template<typename L, typename R, typename = EnableRelOp_t<L, R>>
832  auto operator&& (const L& left, const R& right) noexcept
833  {
834  return MakeExprTree<ExprType::And> (left, right);
835  }
836 
837  template<typename L, typename R, typename = EnableRelOp_t<L, R>>
838  auto operator|| (const L& left, const R& right) noexcept
839  {
840  return MakeExprTree<ExprType::Or> (left, right);
841  }
842 
843  template<typename F>
845  {
846  QString Sql_;
847  F Binder_;
848  int LastID_;
849 
850  ExprTreeHandler (const QString& sql, F&& binder, int lastId) noexcept
851  : Sql_ { sql }
852  , Binder_ { std::move (binder) }
853  , LastID_ { lastId }
854  {
855  }
856  };
857 
858  template<typename>
859  auto HandleExprTree (const ExprTree<ExprType::ConstTrue>&, int lastId = 0) noexcept
860  {
861  return ExprTreeHandler { "1 = 1", [] (auto&&) {}, lastId };
862  }
863 
864  template<typename Seq, typename Tree,
865  typename = decltype (std::declval<Tree> ().ToSql (std::declval<ToSqlState<Seq>&> ()))>
866  auto HandleExprTree (const Tree& tree, int lastId = 0) noexcept
867  {
868  ToSqlState<Seq> state { lastId, {} };
869 
870  const auto& sql = tree.ToSql (state);
871 
872  return ExprTreeHandler
873  {
874  sql,
875  [state] (QSqlQuery& query)
876  {
877  for (const auto& pair : Stlize (state.BoundMembers_))
878  query.bindValue (pair.first, pair.second);
879  },
880  state.LastID_
881  };
882  }
883 
884  enum class AggregateFunction
885  {
886  Count,
887  Min,
888  Max
889  };
890 
891  template<AggregateFunction, auto Ptr>
892  struct AggregateType {};
893 
894  struct CountAll {};
895 
896  inline constexpr CountAll *CountAllPtr = nullptr;
897 
898  template<typename... MemberDirectionList>
899  struct OrderBy {};
900 
901  template<auto... Ptrs>
902  struct GroupBy {};
903 
904  struct SelectWhole {};
905 
906  template<typename L, typename R>
907  struct SelectorUnion {};
908 
909  template<typename T>
910  struct IsSelector : std::false_type {};
911 
912  template<>
913  struct IsSelector<SelectWhole> : std::true_type {};
914 
915  template<AggregateFunction Fun, auto Ptr>
916  struct IsSelector<AggregateType<Fun, Ptr>> : std::true_type {};
917 
918  template<auto... Ptrs>
919  struct IsSelector<MemberPtrs<Ptrs...>> : std::true_type {};
920 
921  template<typename L, typename R>
922  struct IsSelector<SelectorUnion<L, R>> : std::true_type {};
923 
924  template<typename L, typename R, typename = std::enable_if_t<IsSelector<L> {} && IsSelector<R> {}>>
926  {
927  return {};
928  }
929  }
930 
931  namespace sph
932  {
933  template<auto Ptr>
935 
936  template<auto... Ptrs>
937  constexpr detail::MemberPtrs<Ptrs...> fields {};
938 
939  constexpr detail::SelectWhole all {};
940 
941  template<auto... Ptrs>
942  struct asc {};
943 
944  template<auto... Ptrs>
945  struct desc {};
946 
947  template<auto Ptr = detail::CountAllPtr>
949 
950  template<auto Ptr>
952 
953  template<auto Ptr>
955  };
956 
957  template<typename... Orders>
958  constexpr detail::OrderBy<Orders...> OrderBy {};
959 
960  template<auto... Ptrs>
961  constexpr detail::GroupBy<Ptrs...> GroupBy {};
962 
963  struct Limit
964  {
965  uint64_t Count;
966 
967  Limit (uint64_t count) noexcept
968  : Count { count }
969  {
970  }
971  };
972 
973  struct Offset
974  {
975  uint64_t Count;
976 
977  Offset (uint64_t count) noexcept
978  : Count { count }
979  {
980  }
981  };
982 
983  namespace detail
984  {
985  template<auto... Ptrs, size_t... Idxs>
986  auto MakeIndexedQueryHandler (MemberPtrs<Ptrs...>, std::index_sequence<Idxs...>) noexcept
987  {
988  return [] (const QSqlQuery& q, int startIdx = 0) noexcept
989  {
990  if constexpr (sizeof... (Ptrs) == 1)
991  return FromVariant<UnwrapIndirect_t<Head_t<Typelist<MemberPtrType_t<Ptrs>...>>>> {} (q.value (startIdx));
992  else
993  return std::tuple { FromVariant<UnwrapIndirect_t<MemberPtrType_t<Ptrs>>> {} (q.value (startIdx + Idxs))... };
994  };
995  }
996 
997  template<auto Ptr>
998  auto MakeIndexedQueryHandler () noexcept
999  {
1000  return [] (const QSqlQuery& q, int startIdx = 0) noexcept
1001  {
1002  return FromVariant<UnwrapIndirect_t<MemberPtrType_t<Ptr>>> {} (q.value (startIdx));
1003  };
1004  }
1005 
1006  template<auto... Ptrs>
1007  QStringList BuildFieldNames () noexcept
1008  {
1009  return { BuildCachedFieldsData<MemberPtrStruct_t<Ptrs>> ().QualifiedFields_.value (FieldIndex<Ptrs> ())... };
1010  }
1011 
1012  enum class SelectBehaviour { Some, One };
1013 
1014  struct OrderNone {};
1015  struct GroupNone {};
1016  struct LimitNone {};
1017  struct OffsetNone {};
1018 
1019  template<size_t RepIdx, size_t TupIdx, typename Tuple, typename NewType>
1020  constexpr decltype (auto) GetReplaceTupleElem (Tuple&& tuple, NewType&& arg) noexcept
1021  {
1022  if constexpr (RepIdx == TupIdx)
1023  return std::forward<NewType> (arg);
1024  else
1025  return std::get<TupIdx> (tuple);
1026  }
1027 
1028  template<size_t RepIdx, typename NewType, typename Tuple, size_t... TupIdxs>
1029  constexpr auto ReplaceTupleElemImpl (Tuple&& tuple, NewType&& arg, std::index_sequence<TupIdxs...>) noexcept
1030  {
1031  return std::tuple
1032  {
1033  GetReplaceTupleElem<RepIdx, TupIdxs> (std::forward<Tuple> (tuple), std::forward<NewType> (arg))...
1034  };
1035  }
1036 
1037  template<size_t RepIdx, typename NewType, typename... TupleArgs>
1038  constexpr auto ReplaceTupleElem (std::tuple<TupleArgs...>&& tuple, NewType&& arg) noexcept
1039  {
1040  return ReplaceTupleElemImpl<RepIdx> (std::move (tuple),
1041  std::forward<NewType> (arg),
1042  std::index_sequence_for<TupleArgs...> {});
1043  }
1044 
1045  template<typename Seq, typename T>
1046  struct DetectShift
1047  {
1048  constexpr static int Value = 1;
1049  };
1050 
1051  template<typename Seq, typename... Args>
1052  struct DetectShift<Seq, std::tuple<Args...>>
1053  {
1054  constexpr static int Value = (DetectShift<Seq, Args>::Value + ...);
1055  };
1057  template<typename Seq>
1058  struct DetectShift<Seq, Seq>
1059  {
1060  constexpr static int Value = SeqSize<Seq>;
1061  };
1062 
1063  template<typename... LArgs, typename... RArgs>
1064  auto Combine (std::tuple<LArgs...>&& left, std::tuple<RArgs...>&& right) noexcept
1065  {
1066  return std::tuple_cat (std::move (left), std::move (right));
1067  }
1068 
1069  template<typename... LArgs, typename R>
1070  auto Combine (std::tuple<LArgs...>&& left, const R& right) noexcept
1071  {
1072  return std::tuple_cat (std::move (left), std::tuple { right });
1073  }
1074 
1075  template<typename L, typename... RArgs>
1076  auto Combine (const L& left, std::tuple<RArgs...>&& right) noexcept
1077  {
1078  return std::tuple_cat (std::tuple { left }, std::move (right));
1079  }
1080 
1081  template<typename L, typename R>
1082  auto Combine (const L& left, const R& right) noexcept
1083  {
1084  return std::tuple { left, right };
1085  }
1086 
1087  struct ResultBehaviour
1088  {
1089  struct All {};
1090  struct First {};
1091  };
1092 
1093  template<typename L, typename R>
1094  constexpr auto CombineBehaviour (L, R) noexcept
1095  {
1096  if constexpr (std::is_same_v<L, ResultBehaviour::First> && std::is_same_v<R, ResultBehaviour::First>)
1097  return ResultBehaviour::First {};
1098  else
1099  return ResultBehaviour::All {};
1100  }
1101 
1102  template<typename ResList>
1103  decltype (auto) HandleResultBehaviour (ResultBehaviour::All, ResList&& list) noexcept
1104  {
1105  return std::forward<ResList> (list);
1106  }
1108  template<typename ResList>
1109  auto HandleResultBehaviour (ResultBehaviour::First, ResList&& list) noexcept
1110  {
1111  return list.value (0);
1112  }
1113 
1114  template<typename F, typename R>
1115  struct HandleSelectorResult
1116  {
1117  QString Fields_;
1118  F Initializer_;
1119  R Behaviour_;
1120  };
1122  template<typename F, typename R>
1124 
1125  class SelectWrapperCommon
1126  {
1127  protected:
1128  const QSqlDatabase DB_;
1129  const QString LimitNone_;
1130 
1131  SelectWrapperCommon (const QSqlDatabase& db, const QString& limitNone)
1132  : DB_ { db }
1133  , LimitNone_ { limitNone }
1134  {
1135  }
1137  auto RunQuery (const QString& fields, const QString& from,
1138  QString where, std::function<void (QSqlQuery&)>&& binder,
1139  const QString& orderStr,
1140  const QString& groupStr,
1141  const QString& limitOffsetStr) const
1142  {
1143  if (!where.isEmpty ())
1144  where.prepend (" WHERE ");
1145 
1146  const auto& queryStr = "SELECT " + fields +
1147  " FROM " + from +
1148  where +
1149  orderStr +
1150  groupStr +
1151  limitOffsetStr;
1152 
1153  QSqlQuery query { DB_ };
1154  query.prepare (queryStr);
1155  if (binder)
1156  binder (query);
1157 
1158  if (!query.exec ())
1159  {
1160  DBLock::DumpError (query);
1161  throw QueryException ("fetch query execution failed", std::make_shared<QSqlQuery> (query));
1162  }
1163 
1164  return query;
1165  }
1166 
1167  QString HandleLimitOffset (LimitNone, OffsetNone) const noexcept
1168  {
1169  return {};
1170  }
1171 
1172  QString HandleLimitOffset (Limit limit, OffsetNone) const noexcept
1173  {
1174  return " LIMIT " + QString::number (limit.Count);
1175  }
1176 
1177  template<typename L>
1178  QString HandleLimitOffset (L limit, Offset offset) const noexcept
1179  {
1180  QString limitStr;
1181  if constexpr (std::is_same_v<std::decay_t<L>, LimitNone>)
1182  {
1183  Q_UNUSED (limit)
1184  limitStr = LimitNone_;
1185  }
1186  else if constexpr (std::is_integral_v<L>)
1187  limitStr = QString::number (limit);
1188  else
1189  limitStr = QString::number (limit.Count);
1190  return " LIMIT " + limitStr +
1191  " OFFSET " + QString::number (offset.Count);
1192  }
1193  };
1194 
1195  template<typename T, SelectBehaviour SelectBehaviour>
1197  {
1198  const CachedFieldsData Cached_;
1199 
1200  template<typename ParamsTuple>
1201  struct Builder
1202  {
1203  const SelectWrapper& W_;
1204  ParamsTuple Params_;
1205 
1206  template<typename NewTuple>
1207  constexpr auto RepTuple (NewTuple&& tuple) noexcept
1208  {
1209  return Builder<NewTuple> { W_, tuple };
1210  }
1211 
1212  template<typename U>
1213  constexpr auto Select (U&& selector) && noexcept
1214  {
1215  return RepTuple (ReplaceTupleElem<0> (std::move (Params_), std::forward<U> (selector)));
1216  }
1217 
1218  template<typename U>
1219  constexpr auto Where (U&& tree) && noexcept
1220  {
1221  return RepTuple (ReplaceTupleElem<1> (std::move (Params_), std::forward<U> (tree)));
1222  }
1223 
1224  template<typename U>
1225  constexpr auto Order (U&& order) && noexcept
1226  {
1227  return RepTuple (ReplaceTupleElem<2> (std::move (Params_), std::forward<U> (order)));
1228  }
1229 
1230  template<typename U>
1231  constexpr auto Group (U&& group) && noexcept
1232  {
1233  return RepTuple (ReplaceTupleElem<3> (std::move (Params_), std::forward<U> (group)));
1234  }
1235 
1236  template<typename U = Limit>
1237  constexpr auto Limit (U&& limit) && noexcept
1238  {
1239  return RepTuple (ReplaceTupleElem<4> (std::move (Params_), std::forward<U> (limit)));
1240  }
1241 
1242  template<typename U = Offset>
1243  constexpr auto Offset (U&& offset) && noexcept
1244  {
1245  return RepTuple (ReplaceTupleElem<5> (std::move (Params_), std::forward<U> (offset)));
1246  }
1247 
1248  auto operator() () &&
1249  {
1250  return std::apply (W_, Params_);
1251  }
1252 
1253  template<auto... Ptrs>
1254  constexpr auto Group () && noexcept
1255  {
1256  return std::move (*this).Group (GroupBy<Ptrs...> {});
1257  }
1258  };
1259  public:
1260  template<typename ImplFactory>
1261  SelectWrapper (const QSqlDatabase& db, const CachedFieldsData& data, ImplFactory&& factory) noexcept
1262  : SelectWrapperCommon { db, factory.LimitNone }
1263  , Cached_ { data }
1264  {
1265  }
1266 
1267  auto Build () const noexcept
1268  {
1269  std::tuple defParams
1270  {
1271  SelectWhole {},
1273  OrderNone {},
1274  GroupNone {},
1275  LimitNone {},
1276  OffsetNone {}
1277  };
1278  return Builder<decltype (defParams)> { *this, defParams };
1279  }
1280 
1281  auto operator() () const
1282  {
1283  return (*this) (SelectWhole {}, ConstTrueTree_v);
1284  }
1286  template<typename Single>
1287  auto operator() (Single&& single) const
1288  {
1289  if constexpr (IsExprTree<std::decay_t<Single>> {})
1290  return (*this) (SelectWhole {}, std::forward<Single> (single));
1291  else
1292  return (*this) (std::forward<Single> (single), ConstTrueTree_v);
1293  }
1294 
1295  template<
1296  typename Selector,
1297  ExprType Type, typename L, typename R,
1298  typename Order = OrderNone,
1299  typename Group = GroupNone,
1300  typename Limit = LimitNone,
1301  typename Offset = OffsetNone
1302  >
1303  auto operator() (Selector selector,
1304  const ExprTree<Type, L, R>& tree,
1305  Order order = OrderNone {},
1306  Group group = GroupNone {},
1307  Limit limit = LimitNone {},
1308  Offset offset = OffsetNone {}) const
1309  {
1310  const auto& [where, binder, _] = HandleExprTree<T> (tree);
1311  Q_UNUSED (_);
1312  const auto& [fields, initializer, resultBehaviour] = HandleSelector (std::forward<Selector> (selector));
1313  return HandleResultBehaviour (resultBehaviour,
1314  Select (fields, BuildFromClause (tree),
1315  where, binder,
1316  initializer,
1317  HandleOrder (std::forward<Order> (order)),
1318  HandleGroup (std::forward<Group> (group)),
1319  HandleLimitOffset (std::forward<Limit> (limit), std::forward<Offset> (offset))));
1320  }
1321  private:
1322  template<typename Binder, typename Initializer>
1323  auto Select (const QString& fields, const QString& from,
1324  const QString& where, Binder&& binder,
1325  Initializer&& initializer,
1326  const QString& orderStr,
1327  const QString& groupStr,
1328  const QString& limitOffsetStr) const
1329  {
1330  std::function<void (QSqlQuery&)> binderFunc;
1331  if constexpr (!std::is_same_v<Void, std::decay_t<Binder>>)
1332  binderFunc = binder;
1333  auto query = RunQuery (fields, from, where, std::move (binderFunc), orderStr, groupStr, limitOffsetStr);
1334 
1335  if constexpr (SelectBehaviour == SelectBehaviour::Some)
1336  {
1337  QList<std::result_of_t<Initializer (QSqlQuery)>> result;
1338  while (query.next ())
1339  result << initializer (query);
1340  return result;
1341  }
1342  else
1343  {
1344  using RetType_t = std::optional<std::result_of_t<Initializer (QSqlQuery)>>;
1345  return query.next () ?
1346  RetType_t { initializer (query) } :
1347  RetType_t {};
1348  }
1349  }
1350 
1351  template<ExprType Type, typename L, typename R>
1352  QString BuildFromClause (const ExprTree<Type, L, R>& tree) const noexcept
1353  {
1354  if constexpr (Type != ExprType::ConstTrue)
1355  {
1356  auto result = Cached_.Table_;
1357  for (const auto& item : tree.template AdditionalTables<T> ())
1358  result += ", " + item;
1359  return result;
1360  }
1361  else
1362  return Cached_.Table_;
1363  }
1364 
1365  auto HandleSelector (SelectWhole) const noexcept
1366  {
1367  return HandleSelectorResult
1368  {
1369  Cached_.QualifiedFields_.join (", "),
1370  [] (const QSqlQuery& q, int startIdx = 0)
1371  {
1372  return InitializeFromQuery<T> (q, SeqIndices<T>, startIdx);
1373  },
1374  ResultBehaviour::All {}
1375  };
1376  }
1377 
1378  template<auto... Ptrs>
1379  auto HandleSelector (MemberPtrs<Ptrs...> ptrs) const noexcept
1380  {
1381  return HandleSelectorResult
1382  {
1383  BuildFieldNames<Ptrs...> ().join (", "),
1384  MakeIndexedQueryHandler (ptrs, std::make_index_sequence<sizeof... (Ptrs)> {}),
1385  ResultBehaviour::All {}
1386  };
1387  }
1388 
1389  auto HandleSelector (AggregateType<AggregateFunction::Count, CountAllPtr>) const noexcept
1390  {
1391  return HandleSelectorResult
1392  {
1393  "count(1)",
1394  [] (const QSqlQuery& q, int startIdx = 0) { return q.value (startIdx).toLongLong (); },
1396  };
1397  }
1398 
1399  template<auto Ptr>
1400  auto HandleSelector (AggregateType<AggregateFunction::Count, Ptr>) const noexcept
1401  {
1402  return HandleSelectorResult
1403  {
1404  "count(" + GetQualifiedFieldNamePtr<Ptr> () + ")",
1405  [] (const QSqlQuery& q, int startIdx = 0) { return q.value (startIdx).toLongLong (); },
1407  };
1408  }
1409 
1410  template<auto Ptr>
1411  auto HandleSelector (AggregateType<AggregateFunction::Min, Ptr>) const noexcept
1412  {
1413  return HandleSelectorResult
1414  {
1415  "min(" + GetQualifiedFieldNamePtr<Ptr> () + ")",
1416  MakeIndexedQueryHandler<Ptr> (),
1418  };
1419  }
1420 
1421  template<auto Ptr>
1422  auto HandleSelector (AggregateType<AggregateFunction::Max, Ptr>) const noexcept
1423  {
1424  return HandleSelectorResult
1425  {
1426  "max(" + GetQualifiedFieldNamePtr<Ptr> () + ")",
1427  MakeIndexedQueryHandler<Ptr> (),
1429  };
1430  }
1431 
1432  template<typename L, typename R>
1433  auto HandleSelector (SelectorUnion<L, R>) const noexcept
1434  {
1435  const auto& lSel = HandleSelector (L {});
1436  const auto& rSel = HandleSelector (R {});
1437 
1438  const auto& lHandler = lSel.Initializer_;
1439  const auto& rHandler = rSel.Initializer_;
1440 
1441  return HandleSelectorResult
1442  {
1443  lSel.Fields_ + ", " + rSel.Fields_,
1444  [lHandler, rHandler] (const QSqlQuery& q, int startIdx = 0)
1445  {
1446  constexpr auto shift = DetectShift<T, decltype (lHandler (q))>::Value;
1447  return Combine (lHandler (q, startIdx), rHandler (q, startIdx + shift));
1448  },
1449  CombineBehaviour (lSel.Behaviour_, rSel.Behaviour_)
1450  };
1451  }
1452 
1453  QString HandleOrder (OrderNone) const noexcept
1454  {
1455  return {};
1456  }
1457 
1458  template<auto... Ptrs>
1459  QList<QString> HandleSuborder (sph::asc<Ptrs...>) const noexcept
1460  {
1461  return { (GetQualifiedFieldNamePtr<Ptrs> () + " ASC")... };
1462  }
1463 
1464  template<auto... Ptrs>
1465  QList<QString> HandleSuborder (sph::desc<Ptrs...>) const noexcept
1466  {
1467  return { (GetQualifiedFieldNamePtr<Ptrs> () + " DESC")... };
1468  }
1469 
1470  template<typename... Suborders>
1471  QString HandleOrder (OrderBy<Suborders...>) const noexcept
1472  {
1473  return " ORDER BY " + QStringList { Concat (QList { HandleSuborder (Suborders {})... }) }.join (", ");
1474  }
1475 
1476  QString HandleGroup (GroupNone) const noexcept
1477  {
1478  return {};
1479  }
1480 
1481  template<auto... Ptrs>
1482  QString HandleGroup (GroupBy<Ptrs...>) const noexcept
1483  {
1484  return " GROUP BY " + QStringList { GetQualifiedFieldNamePtr<Ptrs> ()... }.join (", ");
1485  }
1486  };
1487 
1488  template<typename T>
1489  class DeleteByFieldsWrapper
1490  {
1491  const QSqlDatabase DB_;
1492  const QString Table_;
1493  public:
1494  DeleteByFieldsWrapper (const QSqlDatabase& db, const CachedFieldsData& data) noexcept
1495  : DB_ { db }
1496  , Table_ (data.Table_)
1497  {
1498  }
1499 
1500  template<ExprType Type, typename L, typename R>
1501  void operator() (const ExprTree<Type, L, R>& tree) const noexcept
1502  {
1503  const auto& [where, binder, _] = HandleExprTree<T> (tree);
1504  Q_UNUSED (_);
1505 
1506  const auto& selectAll = "DELETE FROM " + Table_ +
1507  " WHERE " + where;
1508 
1509  QSqlQuery query { DB_ };
1510  query.prepare (selectAll);
1511  binder (query);
1512  query.exec ();
1513  }
1514  };
1515 
1516  template<typename T, bool HasPKey = HasPKey<T>>
1517  class AdaptUpdate
1518  {
1519  const QSqlDatabase DB_;
1520  const QString Table_;
1521 
1522  std::function<void (T)> Updater_;
1523  public:
1524  AdaptUpdate (const QSqlDatabase& db, const CachedFieldsData& data) noexcept
1525  : DB_ { db }
1526  , Table_ { data.Table_ }
1527  {
1528  if constexpr (HasPKey)
1529  {
1530  constexpr auto index = FindPKey<T>::result_type::value;
1531 
1532  auto statements = Util::ZipWith<QList> (data.Fields_, data.BoundFields_,
1533  [] (const QString& s1, const QString& s2) { return s1 + " = " + s2; });
1534  auto wherePart = statements.takeAt (index);
1535  const auto& update = "UPDATE " + data.Table_ +
1536  " SET " + statements.join (", ") +
1537  " WHERE " + wherePart;
1538 
1539  const auto updateQuery = std::make_shared<QSqlQuery> (db);
1540  updateQuery->prepare (update);
1541  Updater_ = MakeInserter<T> (data, updateQuery, true);
1542  }
1543  }
1544 
1545  template<bool B = HasPKey>
1546  std::enable_if_t<B> operator() (const T& seq)
1547  {
1548  Updater_ (seq);
1549  }
1550 
1551  template<typename SL, typename SR, ExprType WType, typename WL, typename WR>
1552  int operator() (const AssignList<SL, SR>& set, const ExprTree<WType, WL, WR>& where)
1553  {
1554  static_assert (!ExprTree<WType, WL, WR>::template HasAdditionalTables<T> (),
1555  "joins in update statements are not supported by SQL");
1556 
1557  const auto& [setClause, setBinder, setLast] = HandleExprTree<T> (set);
1558  const auto& [whereClause, whereBinder, _] = HandleExprTree<T> (where, setLast);
1559 
1560  const auto& update = "UPDATE " + Table_ +
1561  " SET " + setClause +
1562  " WHERE " + whereClause;
1563 
1564  QSqlQuery query { DB_ };
1565  query.prepare (update);
1566  setBinder (query);
1567  whereBinder (query);
1568  if (!query.exec ())
1569  {
1571  throw QueryException ("update query execution failed", std::make_shared<QSqlQuery> (query));
1572  }
1573 
1574  return query.numRowsAffected ();
1575  }
1576  };
1577 
1578  template<typename T>
1579  using ConstraintsDetector = typename T::Constraints;
1580 
1581  template<typename T>
1583 
1584  template<typename T>
1585  struct ExtractConstraintFields;
1586 
1587  template<int... Fields>
1588  struct ExtractConstraintFields<UniqueSubset<Fields...>>
1589  {
1590  QString operator() (const CachedFieldsData& data) const noexcept
1591  {
1592  return "UNIQUE (" + QStringList { data.Fields_.value (Fields)... }.join (", ") + ")";
1593  }
1594  };
1595 
1596  template<int... Fields>
1598  {
1599  QString operator() (const CachedFieldsData& data) const noexcept
1600  {
1601  return "PRIMARY KEY (" + QStringList { data.Fields_.value (Fields)... }.join (", ") + ")";
1602  }
1603  };
1604 
1605  template<typename... Args>
1607  {
1608  return { ExtractConstraintFields<Args> {} (data)... };
1609  }
1610 
1611  template<typename ImplFactory, typename T, size_t... Indices>
1612  QList<QString> GetTypes (std::index_sequence<Indices...>) noexcept
1613  {
1614  return { Type2Name<ImplFactory, ValueAtC_t<T, Indices>> {} ()... };
1615  }
1616 
1617  template<typename ImplFactory, typename T>
1618  QString AdaptCreateTable (const CachedFieldsData& data) noexcept
1619  {
1620  const auto& types = GetTypes<ImplFactory, T> (SeqIndices<T>);
1621 
1622  const auto& constraints = GetConstraintsStringList (ConstraintsType<T> {}, data);
1623  const auto& constraintsStr = constraints.isEmpty () ?
1624  QString {} :
1625  (", " + constraints.join (", "));
1626 
1627  const auto& statements = Util::ZipWith<QList> (types, data.Fields_,
1628  [] (const QString& type, const QString& field) { return field + " " + type; });
1629  return "CREATE TABLE " +
1630  data.Table_ +
1631  " (" +
1632  statements.join (", ") +
1633  constraintsStr +
1634  ");";
1635  }
1636  }
1637 
1638  template<auto... Ptrs>
1639  InsertAction::Replace::FieldsType<Ptrs...>::operator InsertAction::Replace () const
1640  {
1641  return { { detail::BuildCachedFieldsData<MemberPtrStruct_t<Ptrs>> ().Fields_.value (detail::FieldIndex<Ptrs> ())... } };
1642  }
1643 
1644  template<typename Seq>
1645  InsertAction::Replace::PKeyType<Seq>::operator InsertAction::Replace () const
1646  {
1647  static_assert (detail::HasPKey<Seq>, "Sequence does not have any primary keys");
1648  return { { detail::GetFieldName<Seq, detail::FindPKey<Seq>::result_type::value> () } };
1649  }
1650 
1651  template<typename T>
1652  struct ObjectInfo
1653  {
1654  detail::AdaptInsert<T> Insert;
1655  detail::AdaptUpdate<T> Update;
1656  detail::AdaptDelete<T> Delete;
1661 
1662  using ObjectType_t = T;
1663  };
1664 
1665  template<typename T, typename ImplFactory = detail::SQLite::ImplFactory>
1666  ObjectInfo<T> Adapt (const QSqlDatabase& db)
1667  {
1668  const auto& cachedData = detail::BuildCachedFieldsData<T> ();
1669 
1670  if (!db.tables ().contains (cachedData.Table_, Qt::CaseInsensitive))
1671  RunTextQuery (db, detail::AdaptCreateTable<ImplFactory, T> (cachedData));
1673  ImplFactory factory;
1675  return
1676  {
1677  { db, cachedData, factory },
1678  { db, cachedData },
1679  { db, cachedData },
1681  { db, cachedData, factory },
1682  { db, cachedData, factory },
1683  { db, cachedData }
1684  };
1685  }
1686 
1687  template<typename T>
1688  using ObjectInfo_ptr = std::shared_ptr<ObjectInfo<T>>;
1689 
1690  template<typename T, typename ImplFactory = SQLiteImplFactory>
1691  ObjectInfo_ptr<T> AdaptPtr (const QSqlDatabase& db)
1692  {
1693  return std::make_shared<ObjectInfo<T>> (Adapt<T, ImplFactory> (db));
1694  }
1695 
1696  namespace detail
1697  {
1698  template<size_t Idx, typename Tuple>
1699  using UnderlyingObject_t = typename std::decay_t<std::tuple_element_t<Idx, Tuple>>::element_type::ObjectType_t;
1700 
1701  template<typename ImplFactory, typename Tuple, size_t... Idxs>
1702  void AdaptPtrs (const QSqlDatabase& db, Tuple& tuple, std::index_sequence<Idxs...>)
1703  {
1704  ((std::get<Idxs> (tuple) = AdaptPtr<UnderlyingObject_t<Idxs, Tuple>, ImplFactory> (db)), ...);
1705  }
1706  }
1707 
1708  template<typename ImplFactory, typename Tuple>
1709  void AdaptPtrs (const QSqlDatabase& db, Tuple& tuple)
1710  {
1711  detail::AdaptPtrs<ImplFactory> (db, tuple, std::make_index_sequence<std::tuple_size_v<Tuple>> {});
1712  }
1713 }
1714 }
1715 }
LC::Util::oral::detail::FieldIndex
constexpr size_t FieldIndex() noexcept
Definition: oral.h:159
LC::Util::oral::detail::ResultBehaviour::All
Definition: oral.h:1107
LC::Util::oral::detail::GetFieldName
QString GetFieldName() noexcept
Definition: oral.h:114
LC::Util::oral::detail::TypeToSql
QString TypeToSql(ExprType type) noexcept
Definition: oral.h:532
LC::Util::oral::detail::ValueAtC_t
typename boost::fusion::result_of::value_at_c< Seq, Idx >::type ValueAtC_t
Definition: oral.h:340
typelist.h
LC::Util::oral::IsIndirect
Definition: oraltypes.h:170
LC::Util::oral::detail::TypeNameCustomized
constexpr bool TypeNameCustomized
Definition: oral.h:197
LC::Util::oral::ObjectInfo_ptr
std::shared_ptr< ObjectInfo< T > > ObjectInfo_ptr
Definition: oral.h:1706
LC::Util::oral::detail::GetReplaceTupleElem
constexpr decltype(auto) GetReplaceTupleElem(Tuple &&tuple, NewType &&arg) noexcept
Definition: oral.h:1038
LC::Util::oral::ToVariant::operator()
QVariant operator()(const T &t) const noexcept
Definition: oral.h:266
LC::Util::oral::detail::TypeNameDetector
decltype(T::TypeName) TypeNameDetector
Definition: oral.h:194
LC::Util::oral::detail::UnderlyingObject_t
typename std::decay_t< std::tuple_element_t< Idx, Tuple > >::element_type::ObjectType_t UnderlyingObject_t
Definition: oral.h:1717
LC::Util::oral::detail::ToVariantF
QVariant ToVariantF(const T &t) noexcept
Definition: oral.h:312
LC::Util::oral::detail::OrderBy
Definition: oral.h:917
LC::Util::oral::detail::IsRelational
constexpr bool IsRelational(ExprType type) noexcept
Definition: oral.h:564
LC::Util::oral::Type2Name
Definition: oral.h:207
LC::Util::oral::detail::ConstTrueTree_v
constexpr auto ConstTrueTree_v
Definition: oral.h:773
LC::Util::Concat
Container< T > Concat(const Container< Container< T >> &containers)
Definition: prelude.h:171
LC::Util::oral::detail::MorphFieldName
QString MorphFieldName(QString str) noexcept
Definition: oral.h:101
LC::Util::oral::detail::IsPKey
Definition: oral.h:306
LC::Util::oral::detail::CachedFieldsData::Table_
QString Table_
Definition: oraldetailfwd.h:27
LC::Util::DBLock::DumpError
static UTIL_DB_API void DumpError(const QSqlError &error)
Dumps the error to the qWarning() stream.
Definition: dblock.cpp:74
LC::Util::oral::detail::FindPKey::Lazy::type
T type
Definition: oral.h:354
LC::Util::oral::detail::RelationalTypesCheckerBase
Definition: oral.h:601
LC::Util::oral::detail::HasAutogenPKey
constexpr auto HasAutogenPKey() noexcept
Definition: oral.h:371
LC::Util::oral::detail::WrapDirect
Definition: oral.h:583
LC::Util::oral::detail::OffsetNone
Definition: oral.h:1035
void.h
LC::Util::oral::detail::FindPKey
Definition: oral.h:346
LC::Util::oral::detail::SelectWrapper
Definition: oral.h:1214
QList
Definition: ianrulesstorage.h:14
LC::Util::oral::detail::ConstraintsDetector
typename T::Constraints ConstraintsDetector
Definition: oral.h:1597
LC::Util::oral::detail::SeqSize
constexpr auto SeqSize
Definition: oral.h:120
LC::Util::oral::detail::AggregateType
Definition: oral.h:910
LC::Util::oral::detail::HandleSelectorResult
Definition: oral.h:1133
LC::Util::oral::InsertAction::Replace::FieldsType
Definition: oraltypes.h:194
LC::Util::oral::detail::ExprType::Or
@ Or
LC::Util::oral::detail::CountAllPtr
constexpr CountAll * CountAllPtr
Definition: oral.h:914
LC::EF::Tags
const Q_DECL_IMPORT QString Tags
Definition: anconstantsdefs.cpp:28
LC::Util::oral::sph::fields
constexpr detail::MemberPtrs< Ptrs... > fields
Definition: oral.h:955
LC::Util::oral::detail::HandleSelectorResult
HandleSelectorResult(QString, F, R) -> HandleSelectorResult< F, R >
LC::Util::oral::AdaptPtr
ObjectInfo_ptr< T > AdaptPtr(const QSqlDatabase &db)
Definition: oral.h:1709
LC::Util::oral::detail::MemberPtrs
Definition: oral.h:727
LC::Util::oral::detail::AddressOf
Definition: oral.h:141
LC::Util::oral::detail::ExprType::Leq
@ Leq
LC::Util::oral::detail::AddressOf::Ptr
static constexpr auto Ptr() noexcept
Definition: oral.h:146
LC::Util::oral::detail::AddressOf::Index
static constexpr auto Index() noexcept
Definition: oral.h:152
LC::Util::oral::detail::AdaptDelete
Definition: oral.h:455
LC::Util::IsDetected_t
typename detail::IsDetected< Type, void, Op, Args... >::type IsDetected_t
Definition: detector.h:50
LC::Util::oral::detail::GetFieldsNames
Definition: oral.h:126
LC::Util::oral::detail::ExprTree< ExprType::LeafData, T, void >::ValueType_t
T ValueType_t
Definition: oral.h:689
LC::Util::oral::detail::ExprType::And
@ And
LC::Util::oral::detail::SelectWhole
Definition: oral.h:922
LC::Util::oral::References
Definition: oraltypes.h:130
LC::Util::oral::detail::ExtractConstraintFields
Definition: oral.h:1603
util.h
LC::Util::oral::detail::InitializeFromQuery
T InitializeFromQuery(const QSqlQuery &q, std::index_sequence< Indices... >, int startIdx) noexcept
Definition: oral.h:496
LC::Util::oral::detail::CachedFieldsData::QualifiedFields_
QStringList QualifiedFields_
Definition: oraldetailfwd.h:30
LC::Util::oral::detail::GroupNone
Definition: oral.h:1033
LC::Util::oral::detail::OrderNone
Definition: oral.h:1032
LC::Util::oral::detail::AreComparableTypes
constexpr auto AreComparableTypes
Definition: oral.h:598
LC::Util::oral::detail::FindPKeyDetector
boost::mpl::int_< FindPKey< Seq >::result_type::value > FindPKeyDetector
Definition: oral.h:365
LC::Util::oral::detail::ExprType::Less
@ Less
LC::Util::MemberPtrType_t
MemberTypeType_t< decltype(Ptr)> MemberPtrType_t
Definition: typegetter.h:67
LC::Util::oral::detail::LimitNone
Definition: oral.h:1034
LC::Util::oral::detail::BaseTypeCustomized
constexpr bool BaseTypeCustomized
Definition: oral.h:203
LC::Util::oral::FromVariant
Definition: oral.h:284
oraltypes.h
boost
Definition: prelude.h:17
LC::Util::oral::detail::operator+
SelectorUnion< L, R > operator+(L, R) noexcept
Definition: oral.h:943
LC::Util::oral::detail::BuildCachedFieldsData
CachedFieldsData BuildCachedFieldsData(const QString &table) noexcept
Definition: oral.h:380
LC::Util::oral::sph::all
constexpr detail::SelectWhole all
Definition: oral.h:957
LC::Util::oral::PrimaryKey
Definition: oraltypes.h:155
oraldetailfwd.h
LC::Util::oral::Index
Definition: oraltypes.h:164
LC::Util::oral::detail::ExprType::Neq
@ Neq
LC::Util::oral::detail::CachedFieldsData::Fields_
QStringList Fields_
Definition: oraldetailfwd.h:29
LC::Util::oral::detail::ExprType::ConstTrue
@ ConstTrue
LC::Util::oral::detail::HandleResultBehaviour
decltype(auto) HandleResultBehaviour(ResultBehaviour::All, ResList &&list) noexcept
Definition: oral.h:1121
LC::Util::oral::detail::HandleExprTree
auto HandleExprTree(const ExprTree< ExprType::ConstTrue > &, int lastId=0) noexcept
Definition: oral.h:877
LC::Util::oral::sph::min
constexpr detail::AggregateType< detail::AggregateFunction::Min, Ptr > min
Definition: oral.h:969
LC::Util::oral::detail::FindPKey::result_type
typename std::conditional_t< IsPKey< ValueAt_t< Seq, MemberIdx > >::value, Lazy< MemberIdx >, Lazy< FindPKey< Seq, typename boost::mpl::next< MemberIdx >::type > > >::type result_type
Definition: oral.h:361
LC::Util::Stlize
auto Stlize(Assoc &&assoc) noexcept
Converts an Qt's associative sequence assoc to an STL-like iteratable range.
Definition: qtutil.h:49
LC::Util::oral::detail::AdaptInsert::AdaptInsert
AdaptInsert(const QSqlDatabase &db, CachedFieldsData data, ImplFactory &&factory) noexcept
Definition: oral.h:407
LC::Util::oral::detail::CachedFieldsData
Definition: oraldetailfwd.h:19
LC::Util::oral::detail::ExprTreeHandler::LastID_
int LastID_
Definition: oral.h:866
LC::Util::oral::detail::GetTypes
QList< QString > GetTypes(std::index_sequence< Indices... >) noexcept
Definition: oral.h:1630
LC::Util::oral::detail::GroupBy
Definition: oral.h:920
LC::Util::oral::Limit
Definition: oral.h:981
LC::Util::oral::detail::AggregateFunction::Max
@ Max
LC::Util::IsDetected_v
constexpr bool IsDetected_v
Definition: detector.h:47
LC::Util::oral::detail::RelationalTypesChecker
Definition: oral.h:607
LC::Util::oral::detail::AdaptPtrs
void AdaptPtrs(const QSqlDatabase &db, Tuple &tuple, std::index_sequence< Idxs... >)
Definition: oral.h:1720
LC::Util::oral::InsertAction::Replace
Definition: oraltypes.h:189
LC::Util::oral::detail::operator<
auto operator<(const L &left, const R &right) noexcept
Definition: oral.h:797
LC::Util::Map
auto Map(Container &&c, F &&f) noexcept(noexcept(std::is_nothrow_invocable_v< F, decltype(*c.begin())>))
Definition: prelude.h:149
LC::Util::oral::detail::ExprTreeHandler
Definition: oral.h:862
typelevel.h
LC::Util::RunQuery
void RunQuery(const QSqlDatabase &db, const QString &pluginName, const QString &filename)
Loads the query from the given resource file and runs it.
Definition: util.cpp:50
LC::Util::oral::ToVariant
Definition: oral.h:264
LC::Util::XDG::Type
Type
Describes the various types of XDG .desktop files.
Definition: itemtypes.h:23
LC::Util::oral::detail::operator!=
auto operator!=(const L &left, const R &right) noexcept
Definition: oral.h:815
LC::Util::oral::detail::SeqIndices
constexpr auto SeqIndices
Definition: oral.h:123
LC::Util::oral::QSqlQuery_ptr
std::shared_ptr< QSqlQuery > QSqlQuery_ptr
Definition: oral.h:70
LC::Util::oral::detail::MakeExprTree
auto MakeExprTree(const L &left, const R &right) noexcept
Definition: oral.h:776
sqliteimpl.h
LC::Util::oral::detail::EitherIsExprTree
constexpr bool EitherIsExprTree() noexcept
Definition: oral.h:784
LC::Util::oral::detail::DeleteByFieldsWrapper
Definition: oral.h:1507
LC::Util::First
auto First(F &&f)
Definition: prelude.h:245
LC::Util::oral::Adapt
ObjectInfo< T > Adapt(const QSqlDatabase &db)
Definition: oral.h:1684
LC::Util::oral::detail::AdaptCreateTable
QString AdaptCreateTable(const CachedFieldsData &data) noexcept
Definition: oral.h:1636
LC::Util::Typelist
Definition: typelist.h:30
LC::Util::oral::detail::BuildFieldNames
QStringList BuildFieldNames() noexcept
Definition: oral.h:1025
LC::Util::oral::detail::SelectBehaviour
SelectBehaviour
Definition: oral.h:1030
LC::Util::oral::detail::ReplaceTupleElemImpl
constexpr auto ReplaceTupleElemImpl(Tuple &&tuple, NewType &&arg, std::index_sequence< TupIdxs... >) noexcept
Definition: oral.h:1047
LC::Util::oral::detail::AssignList
Definition: oral.h:622
LC::Util::oral::OrderBy
constexpr detail::OrderBy< Orders... > OrderBy
Definition: oral.h:976
LC::Util::oral::infix::like
constexpr detail::InfixBinary< detail::ExprType::Like > like
Definition: oral.h:826
LC::Util::oral::detail::HasPKey
constexpr auto HasPKey
Definition: oral.h:368
impldefs.h
dblock.h
LC::Util::oral::detail::IInsertQueryBuilder_ptr
std::unique_ptr< IInsertQueryBuilder > IInsertQueryBuilder_ptr
Definition: impldefs.h:27
LC::Util::Head_t
typename Head< List >::Head_t Head_t
Definition: typelist.h:44
LC::Util::Unreachable
void Unreachable()
Definition: unreachable.h:27
LC::Util::oral::detail::GetQualifiedFieldNamePtr
QString GetQualifiedFieldNamePtr() noexcept
Definition: oral.h:187
LC::Util::oral::detail::GetFieldsNames::operator()
QStringList operator()() const noexcept
Definition: oral.h:128
LC::Util::oral::NotNull
Definition: oraltypes.h:106
LC::Util::oral::detail::InfixBinaryProxy
Definition: oral.h:832
LC::Util::oral::sph::count
constexpr detail::AggregateType< detail::AggregateFunction::Count, Ptr > count
Definition: oral.h:966
LC::Util::oral::detail::ExprType::Geq
@ Geq
LC::Util::oral::sph::max
constexpr detail::AggregateType< detail::AggregateFunction::Max, Ptr > max
Definition: oral.h:972
LC::Util::oral::detail::DetectShift::Value
constexpr static int Value
Definition: oral.h:1066
LC::Util::oral::detail::AssignList::ToSql
QString ToSql(ToSqlState< T > &state) const noexcept
Definition: oral.h:634
LC::Util::oral::detail::MakeInserter
auto MakeInserter(const CachedFieldsData &data, const QSqlQuery_ptr &insertQuery, bool bindPrimaryKey) noexcept
Definition: oral.h:318
LC::Util::oral::detail::operator>
auto operator>(const L &left, const R &right) noexcept
Definition: oral.h:803
LC::Util::oral::detail::ResultBehaviour::First
Definition: oral.h:1108
LC::Util::oral::detail::SelectBehaviour::Some
@ Some
LC::Util::oral::detail::AggregateDetector_t
decltype(new T { std::declval< Args >()... }) AggregateDetector_t
Definition: oral.h:493
typegetter.h
LC::Util::oral::detail::operator==
auto operator==(const L &left, const R &right) noexcept
Definition: oral.h:809
LC::Util::oral::PKey
Definition: oraltypes.h:88
qtutil.h
LC::Util::oral::detail::ExprType::Greater
@ Greater
LC::Util::oral::Constraints
Typelist< Args... > Constraints
Definition: oraltypes.h:161
LC::Util::AsTypelist_t
typename AsTypelist< T >::Result_t AsTypelist_t
Definition: typelist.h:152
LC::Util::oral::detail::GetConstraintsStringList
QStringList GetConstraintsStringList(Constraints< Args... >, const CachedFieldsData &data) noexcept
Definition: oral.h:1624
Fields_
Fields_t Fields_
Definition: desktopparser.cpp:44
LC::Util::oral::detail::Combine
auto Combine(std::tuple< LArgs... > &&left, std::tuple< RArgs... > &&right) noexcept
Definition: oral.h:1082
LC::Util::oral::detail::ExprType::Equal
@ Equal
LC::Util::oral::detail::AggregateFunction
AggregateFunction
Definition: oral.h:902
LC::Util::oral::FromVariant::operator()
T operator()(const QVariant &var) const noexcept
Definition: oral.h:286
LC::Util::oral::detail::ValueAt_t
typename boost::fusion::result_of::value_at< Seq, Idx >::type ValueAt_t
Definition: oral.h:343
LC::Util::oral::QueryException::~QueryException
~QueryException() noexcept=default
LC::Util::oral::detail::BaseTypeDetector
typename T::BaseType BaseTypeDetector
Definition: oral.h:200
LC::Util::oral::detail::DetectShift
Definition: oral.h:1064
LC::Util::oral::ObjectInfo
Definition: oral.h:1670
LC::Util::RunTextQuery
QSqlQuery RunTextQuery(const QSqlDatabase &db, const QString &text)
Runs the given query text on the given db.
Definition: util.cpp:24
prelude.h
LC::Util::oral::detail::ExprTree
Definition: oral.h:613
LC::Util::oral::detail::IsSelector
Definition: oral.h:928
LC::Util::oral::detail::AdaptUpdate
Definition: oral.h:1535
LC
Definition: constants.h:14
LC::Util::oral::detail::ExprType
ExprType
Definition: oral.h:512
LC::Util::oral::detail::ReplaceTupleElem
constexpr auto ReplaceTupleElem(std::tuple< TupleArgs... > &&tuple, NewType &&arg) noexcept
Definition: oral.h:1056
LC::Util::oral::Offset
Definition: oral.h:991
LC::Util::oral::GroupBy
constexpr detail::GroupBy< Ptrs... > GroupBy
Definition: oral.h:979
LC::Util::oral::detail::ConstraintsType
Util::IsDetected_t< Constraints<>, ConstraintsDetector, T > ConstraintsType
Definition: oral.h:1600
LC::Util::Views::detail::ValueType_t
PairType< typename std::iterator_traits< FirstIt >::value_type, typename std::iterator_traits< SecondIt >::value_type > ValueType_t
Definition: views.h:48
detector.h
LC::Util::oral::InsertAction::Default
static struct LC::Util::oral::InsertAction::DefaultTag Default
LC::Util::oral::QueryException
Definition: oral.h:72
LC::Util::oral::QueryException::GetQuery
const QSqlQuery & GetQuery() const
Definition: oral.h:89
LC::Util::oral::sph::f
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptr > > f
Definition: oral.h:952
LC::Util::NewType
A somewhat "strong" typedef.
Definition: newtype.h:44
LC::Util::oral::detail::SelectorUnion
Definition: oral.h:925
LC::Util::oral::detail::AggregateFunction::Min
@ Min
LC::Util::MemberPtrStruct_t
MemberTypeStruct_t< decltype(Ptr)> MemberPtrStruct_t
Definition: typegetter.h:70
LC::Util::oral::detail::CombineBehaviour
constexpr auto CombineBehaviour(L, R) noexcept
Definition: oral.h:1112
LC::Util::oral::Indices
Typelist< Args... > Indices
Definition: oraltypes.h:167
LC::Util::Void
A proper void type, akin to unit (or ()) type in functional languages.
Definition: void.h:32
LC::Util::oral::detail::operator&&
auto operator&&(const L &left, const R &right) noexcept
Definition: oral.h:850
LC::Util::oral::detail::AsLeafData
constexpr auto AsLeafData(const T &node) noexcept
Definition: oral.h:718
LC::Util::oral::detail::UnwrapIndirect_t
typename std::conditional_t< IsIndirect< T > {}, T, WrapDirect< T > >::value_type UnwrapIndirect_t
Definition: oral.h:591
LC::Util::oral::detail::ExprType::LeafData
@ LeafData
LC::Util::oral::detail::AdaptInsert::operator()
auto operator()(Seq &t, InsertAction action=InsertAction::Default) const
Definition: oral.h:413
LC::Util::oral::detail::MakeIndexedQueryHandler
auto MakeIndexedQueryHandler(MemberPtrs< Ptrs... >, std::index_sequence< Idxs... >) noexcept
Definition: oral.h:1004
LC::Util::oral::detail::IsExprTree
Definition: oral.h:616
LC::Util::oral::InsertAction
Definition: oraltypes.h:184
LC::Util::oral::detail::MorpherDetector
decltype(std::declval< U >().FieldNameMorpher(QString {})) MorpherDetector
Definition: oral.h:98
LC::Util::oral::detail::operator||
auto operator||(const L &left, const R &right) noexcept
Definition: oral.h:856
LC::Util::oral::QueryException::QueryException
QueryException(const std::string &str, const QSqlQuery_ptr &q)
Definition: oral.h:76
LC::Util::oral::QueryException::GetQueryPtr
const QSqlQuery_ptr & GetQueryPtr() const
Definition: oral.h:84
LC::Util::oral::detail::ExprType::Like
@ Like
LC::Util::oral::detail::GetFieldNamePtr
QString GetFieldNamePtr() noexcept
Definition: oral.h:180
LC::Util::oral::detail::ExprType::LeafStaticPlaceholder
@ LeafStaticPlaceholder
LC::Util::oral::detail::ComparableDetector
decltype(std::declval< UnwrapIndirect_t< typename L::template ValueType_t< Seq > >>()==std::declval< UnwrapIndirect_t< typename R::template ValueType_t< Seq > >>()) ComparableDetector
Definition: oral.h:595
LC::Util::oral::detail::EnableRelOp_t
std::enable_if_t< EitherIsExprTree< L, R >()> EnableRelOp_t
Definition: oral.h:794
LC::Util::oral::detail::SelectWrapperCommon
Definition: oral.h:1143
unreachable.h
LC::Util::RetType_t
std::tuple_element_t< 0, decltype(detail::TypeGetter(*static_cast< F * >(nullptr)))> RetType_t
Definition: typegetter.h:43
LC::Util::oral::Unique
Definition: oraltypes.h:97
LC::Util::oral::detail::CachedFieldsData::BoundFields_
QStringList BoundFields_
Definition: oraldetailfwd.h:31
LC::Util::oral::Type2Name::operator()
QString operator()() const noexcept
Definition: oral.h:209
LC::Util::oral::detail::AddressOf::Obj_
static S Obj_
Definition: oral.h:143
LC::Util::oral::detail::InfixBinary
Definition: oral.h:821
LC::Util::oral::detail::ToSqlState
Definition: oral.h:576
LC::Util::oral::detail::operator|
auto operator|(const L &left, InfixBinary< Op >) noexcept
Definition: oral.h:838