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