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>
59 :
std::runtime_error (str)
80 using MorpherDetector =
decltype (std::declval<U> ().FieldNameMorpher (QString {}));
85 if constexpr (IsDetected_v<MorpherDetector, T>)
86 return T::FieldNameMorpher (str);
89 if (str.endsWith (
'_'))
95 template<
typename Seq,
int Idx>
98 return MorphFieldName<Seq> (boost::fusion::extension::struct_member_name<Seq, Idx>::call ());
102 constexpr auto SeqSize = boost::fusion::result_of::size<S>::type::value;
105 constexpr auto SeqIndices = std::make_index_sequence<SeqSize<S>> {};
112 return Run (SeqIndices<S>);
115 template<
size_t... Vals>
116 QStringList Run (std::index_sequence<Vals...>)
const noexcept
118 return { GetFieldName<S, Vals> ()... };
128 static constexpr auto Ptr () noexcept
134 static constexpr auto Index () noexcept
136 return &boost::fusion::at_c<Idx> (
Obj_);
140 template<auto Ptr,
size_t Idx = 0>
145 if constexpr (Idx == SeqSize<S>)
151 if constexpr (std::is_same_v<
decltype (direct),
decltype (indexed)>)
153 if (indexed == direct)
157 return FieldIndex<Ptr, Idx + 1> ();
165 return GetFieldName<S, FieldIndex<Ptr> ()> ();
172 return S::ClassName () +
"." + GetFieldName<S, FieldIndex<Ptr> ()> ();
188 template<
typename ImplFactory,
typename T,
typename =
void>
195 else if constexpr (std::is_same_v<T, double>)
197 else if constexpr (std::is_same_v<T, QString> || std::is_same_v<T, QDateTime> || std::is_same_v<T, QUrl>)
199 else if constexpr (std::is_same_v<T, QByteArray>)
200 return ImplFactory::TypeLits::Binary;
201 else if constexpr (detail::TypeNameCustomized<T>)
203 else if constexpr (detail::BaseTypeCustomized<T>)
206 static_assert (std::is_same_v<T, struct Dummy>,
"Unsupported type");
210 template<
typename ImplFactory,
typename T>
216 template<
typename ImplFactory,
typename T>
222 template<
typename ImplFactory,
typename T,
typename... Tags>
228 template<
typename ImplFactory,
typename... Tags>
231 QString
operator() () const noexcept {
return ImplFactory::TypeLits::IntAutoincrement; }
234 template<
typename ImplFactory, auto Ptr>
241 " REFERENCES " + className +
" (" + detail::GetFieldNamePtr<Ptr> () +
") ON DELETE CASCADE";
245 template<
typename T,
typename =
void>
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);
256 else if constexpr (detail::TypeNameCustomized<T>)
257 return t.ToVariant ();
258 else if constexpr (detail::BaseTypeCustomized<T>)
265 template<
typename T,
typename =
void>
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> ());
276 else if constexpr (detail::TypeNameCustomized<T>)
277 return T::FromVariant (var);
278 else if constexpr (detail::BaseTypeCustomized<T>)
281 return var.value<T> ();
290 template<
typename U,
typename... Tags>
302 return [data, insertQuery, bindPrimaryKey] (
const T& t)
304 boost::fusion::fold (t, data.BoundFields_.begin (),
305 [&] (
auto pos,
const auto& elem)
307 using Elem = std::decay_t<decltype (elem)>;
308 if (bindPrimaryKey || !IsPKey<Elem>::value)
309 insertQuery->bindValue (*pos++, ToVariantF (elem));
313 if (!insertQuery->exec ())
316 throw QueryException (
"insert query execution failed", insertQuery);
321 template<
typename Seq,
int Idx>
322 using ValueAtC_t =
typename boost::fusion::result_of::value_at_c<Seq, Idx>::type;
324 template<
typename Seq,
typename Idx>
325 using ValueAt_t =
typename boost::fusion::result_of::value_at<Seq, Idx>::type;
327 template<
typename Seq,
typename MemberIdx = boost::mpl::
int_<0>>
330 static_assert ((boost::fusion::result_of::size<Seq>::value) != (MemberIdx::value),
331 "Primary key not found");
346 template<
typename Seq>
349 template<
typename Seq>
350 constexpr auto HasPKey = IsDetected_v<FindPKeyDetector, Seq>;
352 template<
typename Seq>
355 if constexpr (HasPKey<Seq>)
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; });
368 return { table, fields, qualified, boundFields };
374 static CachedFieldsData result = BuildCachedFieldsData<T> (T::ClassName ());
378 template<
typename Seq>
381 const QSqlDatabase DB_;
384 constexpr static bool HasAutogen_ = HasAutogenPKey<Seq> ();
388 template<
typename ImplFactory>
390 : Data_ { RemovePKey (data) }
391 , QueryBuilder_ { factory.MakeInsertQueryBuilder (db, Data_) }
397 return Run<true> (t, action);
402 return Run<false> (t, action);
405 template<
bool UpdatePKey,
typename Val>
408 const auto query = QueryBuilder_->GetQuery (action);
410 MakeInserter<Seq> (Data_, query, !HasAutogen_) (t);
412 if constexpr (HasAutogen_)
417 if constexpr (UpdatePKey)
418 boost::fusion::at_c<index> (t) = lastId;
424 static CachedFieldsData RemovePKey (CachedFieldsData data)
noexcept
426 if constexpr (HasAutogen_)
428 constexpr auto index = FindPKey<Seq>::result_type::value;
429 data.Fields_.removeAt (index);
430 data.BoundFields_.removeAt (index);
436 template<
typename Seq,
bool HasPKey = HasPKey<Seq>>
441 template<
bool B = HasPKey>
447 const auto& del =
"DELETE FROM " + data.
Table_ +
448 " WHERE " + data.
Fields_.at (index) +
" = " + boundName;
450 const auto deleteQuery = std::make_shared<QSqlQuery> (db);
451 deleteQuery->prepare (del);
453 Deleter_ = [deleteQuery, boundName] (
const Seq& t)
456 deleteQuery->bindValue (boundName,
ToVariantF (boost::fusion::at_c<index> (t)));
457 if (!deleteQuery->exec ())
458 throw QueryException (
"delete query execution failed", deleteQuery);
462 template<
bool B = HasPKey>
467 template<
bool B = HasPKey>
474 template<
typename T,
typename... Args>
477 template<
typename T,
size_t...
Indices>
480 if constexpr (IsDetected_v<AggregateDetector_t, T, ValueAtC_t<T, Indices>...>)
485 const auto dummy = std::initializer_list<int>
540 return "invalid type";
573 WrapDirect<T>>::value_type;
575 template<
typename Seq,
typename L,
typename R>
576 using ComparableDetector =
decltype (std::declval<UnwrapIndirect_t<typename L::template ValueType_t<Seq>>> () ==
579 template<
typename Seq,
typename L,
typename R>
580 constexpr auto AreComparableTypes = IsDetected_v<ComparableDetector, Seq, L, R> || IsDetected_v<ComparableDetector, Seq, R, L>;
582 template<
typename Seq,
typename L,
typename R,
typename =
void>
585 template<
typename Seq,
typename L,
typename R>
588 template<ExprType Type,
typename Seq,
typename L,
typename R,
typename =
void>
591 template<ExprType Type,
typename Seq,
typename L,
typename R>
594 template<ExprType Type,
typename L =
void,
typename R =
void>
600 template<ExprType Type,
typename L,
typename R>
603 template<
typename L,
typename R>
619 return Left_.GetFieldName () +
" = " + Right_.ToSql (state);
621 return Left_.ToSql (state) +
", " + Right_.ToSql (state);
624 template<
typename OL,
typename OR>
631 template<ExprType Type,
typename L,
typename R>
647 "Incompatible types passed to a relational operator.");
649 return Left_.ToSql (state) +
" " +
TypeToSql (Type) +
" " + Right_.ToSql (state);
655 return Left_.template AdditionalTables<T> () + Right_.template AdditionalTables<T> ();
661 return L::template HasAdditionalTables<T> () || R::template HasAdditionalTables<T> ();
678 template<
typename ObjT>
681 const auto& name =
":bound_" + QString::number (++state.LastID_);
682 state.BoundMembers_ [name] =
ToVariantF (Data_);
708 template<
auto... Ptr>
727 return detail::GetFieldNamePtr<Ptr> ();
734 if constexpr (std::is_same_v<Seq, T>)
737 return { Seq::ClassName () };
743 return !std::is_same_v<MemberPtrStruct_t<Ptr>, T>;
746 auto operator= (
const ExpectedType_t& r)
const noexcept
757 template<ExprType Type,
typename L,
typename R>
765 template<
typename L,
typename R>
775 template<
typename L,
typename R>
778 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
781 return MakeExprTree<ExprType::Less> (left, right);
784 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
787 return MakeExprTree<ExprType::Greater> (left, right);
790 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
793 return MakeExprTree<ExprType::Equal> (left, right);
796 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
799 return MakeExprTree<ExprType::Neq> (left, right);
802 template<ExprType Op>
813 template<
typename L, ExprType Op>
819 template<
typename L, ExprType Op>
825 template<
typename L, ExprType Op,
typename R>
828 return MakeExprTree<Op> (left.Left_, right);
831 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
834 return MakeExprTree<ExprType::And> (left, right);
837 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
840 return MakeExprTree<ExprType::Or> (left, right);
852 ,
Binder_ { std::move (binder) }
864 template<
typename Seq,
typename Tree,
865 typename =
decltype (std::declval<Tree> ().ToSql (std::declval<ToSqlState<Seq>&> ()))>
870 const auto& sql = tree.ToSql (state);
875 [state] (QSqlQuery& query)
877 for (
const auto& pair :
Stlize (state.BoundMembers_))
878 query.bindValue (pair.first, pair.second);
891 template<AggregateFunction, auto Ptr>
898 template<
typename... MemberDirectionList>
901 template<
auto... Ptrs>
906 template<
typename L,
typename R>
915 template<AggregateFunction Fun, auto Ptr>
918 template<
auto... Ptrs>
921 template<
typename L,
typename R>
924 template<
typename L,
typename R,
typename = std::enable_if_t<IsSelector<L> {} && IsSelector<R> {}>>
936 template<
auto... Ptrs>
941 template<
auto... Ptrs>
944 template<
auto... Ptrs>
947 template<auto Ptr = detail::CountAllPtr>
957 template<
typename... Orders>
960 template<
auto... Ptrs>
985 template<
auto... Ptrs,
size_t... Idxs>
988 return [] (
const QSqlQuery& q,
int startIdx = 0)
noexcept
990 if constexpr (
sizeof... (Ptrs) == 1)
1000 return [] (
const QSqlQuery& q,
int startIdx = 0)
noexcept
1006 template<
auto... Ptrs>
1009 return { BuildCachedFieldsData<MemberPtrStruct_t<Ptrs>> ().QualifiedFields_.value (FieldIndex<Ptrs> ())... };
1019 template<
size_t RepIdx,
size_t TupIdx,
typename Tuple,
typename NewType>
1022 if constexpr (RepIdx == TupIdx)
1023 return std::forward<NewType> (arg);
1025 return std::get<TupIdx> (tuple);
1028 template<
size_t RepIdx,
typename NewType,
typename Tuple,
size_t... TupIdxs>
1033 GetReplaceTupleElem<RepIdx, TupIdxs> (std::forward<Tuple> (tuple), std::forward<NewType> (arg))...
1037 template<
size_t RepIdx,
typename NewType,
typename... TupleArgs>
1040 return ReplaceTupleElemImpl<RepIdx> (std::move (tuple),
1041 std::forward<NewType> (arg),
1042 std::index_sequence_for<TupleArgs...> {});
1045 template<
typename Seq,
typename T>
1051 template<
typename Seq,
typename... Args>
1057 template<
typename Seq>
1060 constexpr static int Value = SeqSize<Seq>;
1063 template<
typename... LArgs,
typename... RArgs>
1064 auto Combine (std::tuple<LArgs...>&& left, std::tuple<RArgs...>&& right)
noexcept
1066 return std::tuple_cat (std::move (left), std::move (right));
1069 template<
typename... LArgs,
typename R>
1070 auto Combine (std::tuple<LArgs...>&& left,
const R& right)
noexcept
1072 return std::tuple_cat (std::move (left), std::tuple { right });
1075 template<
typename L,
typename... RArgs>
1076 auto Combine (
const L& left, std::tuple<RArgs...>&& right)
noexcept
1078 return std::tuple_cat (std::tuple { left }, std::move (right));
1081 template<
typename L,
typename R>
1082 auto Combine (
const L& left,
const R& right)
noexcept
1084 return std::tuple { left, right };
1093 template<
typename L,
typename R>
1096 if constexpr (std::is_same_v<L, ResultBehaviour::First> && std::is_same_v<R, ResultBehaviour::First>)
1102 template<
typename ResList>
1105 return std::forward<ResList> (list);
1108 template<
typename ResList>
1111 return list.value (0);
1114 template<
typename F,
typename R>
1122 template<
typename F,
typename R>
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
1143 if (!where.isEmpty ())
1144 where.prepend (
" WHERE ");
1146 const auto& queryStr =
"SELECT " + fields +
1153 QSqlQuery query {
DB_ };
1154 query.prepare (queryStr);
1161 throw QueryException (
"fetch query execution failed", std::make_shared<QSqlQuery> (query));
1174 return " LIMIT " + QString::number (limit.Count);
1177 template<
typename L>
1181 if constexpr (std::is_same_v<std::decay_t<L>,
LimitNone>)
1186 else if constexpr (std::is_integral_v<L>)
1187 limitStr = QString::number (limit);
1189 limitStr = QString::number (limit.Count);
1190 return " LIMIT " + limitStr +
1191 " OFFSET " + QString::number (offset.Count);
1195 template<
typename T, SelectBehaviour SelectBehaviour>
1200 template<
typename ParamsTuple>
1204 ParamsTuple Params_;
1206 template<
typename NewTuple>
1207 constexpr auto RepTuple (NewTuple&& tuple)
noexcept
1209 return Builder<NewTuple> { W_, tuple };
1212 template<
typename U>
1213 constexpr auto Select (U&& selector) &&
noexcept
1215 return RepTuple (ReplaceTupleElem<0> (std::move (Params_), std::forward<U> (selector)));
1218 template<
typename U>
1219 constexpr auto Where (U&& tree) &&
noexcept
1221 return RepTuple (ReplaceTupleElem<1> (std::move (Params_), std::forward<U> (tree)));
1224 template<
typename U>
1225 constexpr auto Order (U&& order) &&
noexcept
1227 return RepTuple (ReplaceTupleElem<2> (std::move (Params_), std::forward<U> (order)));
1230 template<
typename U>
1231 constexpr auto Group (U&& group) &&
noexcept
1233 return RepTuple (ReplaceTupleElem<3> (std::move (Params_), std::forward<U> (group)));
1236 template<
typename U = Limit>
1237 constexpr auto Limit (U&& limit) &&
noexcept
1239 return RepTuple (ReplaceTupleElem<4> (std::move (Params_), std::forward<U> (limit)));
1242 template<
typename U = Offset>
1243 constexpr auto Offset (U&& offset) &&
noexcept
1245 return RepTuple (ReplaceTupleElem<5> (std::move (Params_), std::forward<U> (offset)));
1250 return std::apply (W_, Params_);
1253 template<
auto... Ptrs>
1254 constexpr auto Group () &&
noexcept
1260 template<
typename ImplFactory>
1269 std::tuple defParams
1278 return Builder<
decltype (defParams)> { *
this, defParams };
1286 template<
typename Single>
1290 return (*
this) (
SelectWhole {}, std::forward<Single> (single));
1297 ExprType Type,
typename L,
typename R,
1307 Limit limit = LimitNone {},
1308 Offset offset = OffsetNone {})
const
1310 const auto& [where, binder, _] = HandleExprTree<T> (tree);
1312 const auto& [fields, initializer, resultBehaviour] = HandleSelector (std::forward<Selector> (selector));
1314 Select (fields, BuildFromClause (tree),
1317 HandleOrder (std::forward<Order> (order)),
1318 HandleGroup (std::forward<Group> (group)),
1319 HandleLimitOffset (std::forward<Limit> (limit), std::forward<Offset> (offset))));
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
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);
1337 QList<std::result_of_t<Initializer (QSqlQuery)>> result;
1338 while (query.next ())
1339 result << initializer (query);
1344 using RetType_t = std::optional<std::result_of_t<Initializer (QSqlQuery)>>;
1345 return query.next () ?
1351 template<ExprType Type,
typename L,
typename R>
1352 QString BuildFromClause (
const ExprTree<Type, L, R>& tree)
const noexcept
1356 auto result = Cached_.
Table_;
1357 for (
const auto& item : tree.template AdditionalTables<T> ())
1358 result +=
", " + item;
1365 auto HandleSelector (SelectWhole)
const noexcept
1370 [] (
const QSqlQuery& q,
int startIdx = 0)
1372 return InitializeFromQuery<T> (q, SeqIndices<T>, startIdx);
1374 ResultBehaviour::All {}
1378 template<
auto... Ptrs>
1379 auto HandleSelector (MemberPtrs<Ptrs...> ptrs)
const noexcept
1385 ResultBehaviour::All {}
1389 auto HandleSelector (AggregateType<AggregateFunction::Count, CountAllPtr>)
const noexcept
1394 [] (
const QSqlQuery& q,
int startIdx = 0) {
return q.value (startIdx).toLongLong (); },
1395 ResultBehaviour::First {}
1400 auto HandleSelector (AggregateType<AggregateFunction::Count, Ptr>)
const noexcept
1404 "count(" + GetQualifiedFieldNamePtr<Ptr> () +
")",
1405 [] (
const QSqlQuery& q,
int startIdx = 0) {
return q.value (startIdx).toLongLong (); },
1406 ResultBehaviour::First {}
1411 auto HandleSelector (AggregateType<AggregateFunction::Min, Ptr>)
const noexcept
1415 "min(" + GetQualifiedFieldNamePtr<Ptr> () +
")",
1416 MakeIndexedQueryHandler<Ptr> (),
1417 ResultBehaviour::First {}
1422 auto HandleSelector (AggregateType<AggregateFunction::Max, Ptr>)
const noexcept
1426 "max(" + GetQualifiedFieldNamePtr<Ptr> () +
")",
1427 MakeIndexedQueryHandler<Ptr> (),
1428 ResultBehaviour::First {}
1432 template<
typename L,
typename R>
1433 auto HandleSelector (SelectorUnion<L, R>)
const noexcept
1435 const auto& lSel = HandleSelector (L {});
1436 const auto& rSel = HandleSelector (R {});
1438 const auto& lHandler = lSel.Initializer_;
1439 const auto& rHandler = rSel.Initializer_;
1443 lSel.Fields_ +
", " + rSel.Fields_,
1444 [lHandler, rHandler] (
const QSqlQuery& q,
int startIdx = 0)
1446 constexpr auto shift = DetectShift<T,
decltype (lHandler (q))>::Value;
1447 return Combine (lHandler (q, startIdx), rHandler (q, startIdx + shift));
1453 QString HandleOrder (OrderNone)
const noexcept
1458 template<
auto... Ptrs>
1461 return { (GetQualifiedFieldNamePtr<Ptrs> () +
" ASC")... };
1464 template<
auto... Ptrs>
1465 QList<QString> HandleSuborder (sph::desc<Ptrs...>)
const noexcept
1467 return { (GetQualifiedFieldNamePtr<Ptrs> () +
" DESC")... };
1470 template<
typename... Suborders>
1471 QString HandleOrder (OrderBy<Suborders...>)
const noexcept
1473 return " ORDER BY " + QStringList {
Concat (
QList { HandleSuborder (Suborders {})... }) }.join (
", ");
1476 QString HandleGroup (GroupNone)
const noexcept
1481 template<
auto... Ptrs>
1482 QString HandleGroup (GroupBy<Ptrs...>)
const noexcept
1484 return " GROUP BY " + QStringList { GetQualifiedFieldNamePtr<Ptrs> ()... }.join (
", ");
1488 template<
typename T>
1491 const QSqlDatabase DB_;
1492 const QString Table_;
1496 , Table_ (data.Table_)
1500 template<ExprType Type,
typename L,
typename R>
1503 const auto& [where, binder, _] = HandleExprTree<T> (tree);
1506 const auto& selectAll =
"DELETE FROM " + Table_ +
1509 QSqlQuery query { DB_ };
1510 query.prepare (selectAll);
1516 template<
typename T,
bool HasPKey = HasPKey<T>>
1519 const QSqlDatabase DB_;
1520 const QString Table_;
1522 std::function<void (T)> Updater_;
1526 , Table_ { data.Table_ }
1530 constexpr auto index = FindPKey<T>::result_type::value;
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;
1539 const auto updateQuery = std::make_shared<QSqlQuery> (db);
1540 updateQuery->prepare (update);
1541 Updater_ = MakeInserter<T> (data, updateQuery,
true);
1545 template<
bool B = HasPKey>
1551 template<
typename SL,
typename SR, ExprType WType,
typename WL,
typename WR>
1555 "joins in update statements are not supported by SQL");
1557 const auto& [setClause, setBinder, setLast] = HandleExprTree<T> (set);
1558 const auto& [whereClause, whereBinder, _] = HandleExprTree<T> (where, setLast);
1560 const auto& update =
"UPDATE " + Table_ +
1561 " SET " + setClause +
1562 " WHERE " + whereClause;
1564 QSqlQuery query { DB_ };
1565 query.prepare (update);
1567 whereBinder (query);
1571 throw QueryException (
"update query execution failed", std::make_shared<QSqlQuery> (query));
1574 return query.numRowsAffected ();
1578 template<
typename T>
1581 template<
typename T>
1584 template<
typename T>
1587 template<
int... Fields>
1592 return "UNIQUE (" + QStringList { data.Fields_.value (Fields)... }.join (
", ") +
")";
1596 template<
int... Fields>
1601 return "PRIMARY KEY (" + QStringList { data.Fields_.value (Fields)... }.join (
", ") +
")";
1605 template<
typename... Args>
1611 template<
typename ImplFactory,
typename T,
size_t...
Indices>
1617 template<
typename ImplFactory,
typename T>
1620 const auto& types = GetTypes<ImplFactory, T> (SeqIndices<T>);
1623 const auto& constraintsStr = constraints.isEmpty () ?
1625 (
", " + constraints.join (
", "));
1627 const auto& statements = Util::ZipWith<QList> (types, data.Fields_,
1628 [] (
const QString& type,
const QString& field) { return field +
" " + type; });
1629 return "CREATE TABLE " +
1632 statements.join (
", ") +
1638 template<
auto... Ptrs>
1641 return { { detail::BuildCachedFieldsData<MemberPtrStruct_t<Ptrs>> ().
Fields_.value (detail::FieldIndex<Ptrs> ())... } };
1644 template<
typename Seq>
1647 static_assert (detail::HasPKey<Seq>,
"Sequence does not have any primary keys");
1648 return { { detail::GetFieldName<Seq, detail::FindPKey<Seq>::result_type::value> () } };
1651 template<
typename T>
1665 template<
typename T,
typename ImplFactory = detail::SQLite::ImplFactory>
1668 const auto& cachedData = detail::BuildCachedFieldsData<T> ();
1670 if (!db.tables ().contains (cachedData.Table_, Qt::CaseInsensitive))
1671 RunTextQuery (db, detail::AdaptCreateTable<ImplFactory, T> (cachedData));
1673 ImplFactory factory;
1677 { db, cachedData, factory },
1681 { db, cachedData, factory },
1682 { db, cachedData, factory },
1687 template<
typename T>
1690 template<
typename T,
typename ImplFactory = SQLiteImplFactory>
1693 return std::make_shared<ObjectInfo<T>> (Adapt<T, ImplFactory> (db));
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;
1701 template<
typename ImplFactory,
typename Tuple,
size_t... Idxs>
1702 void AdaptPtrs (
const QSqlDatabase& db, Tuple& tuple, std::index_sequence<Idxs...>)
1704 ((std::get<Idxs> (tuple) = AdaptPtr<UnderlyingObject_t<Idxs, Tuple>, ImplFactory> (db)), ...);
1708 template<
typename ImplFactory,
typename Tuple>
1711 detail::AdaptPtrs<ImplFactory> (db, tuple, std::make_index_sequence<std::tuple_size_v<Tuple>> {});
static UTIL_DB_API void DumpError(const QSqlError &error)
Dumps the error to the qWarning() stream.
A somewhat "strong" typedef.
QueryException(const std::string &str, const QSqlQuery_ptr &q)
const QSqlQuery & GetQuery() const
~QueryException() noexcept=default
const QSqlQuery_ptr & GetQueryPtr() const
AdaptInsert(const QSqlDatabase &db, CachedFieldsData data, ImplFactory &&factory) noexcept
auto operator()(Seq &t, InsertAction action=InsertAction::Default) const
AdaptUpdate(const QSqlDatabase &db, const CachedFieldsData &data) noexcept
std::enable_if_t< B > operator()(const T &seq)
AssignList(const L &l, const R &r) noexcept
auto operator,(const AssignList< OL, OR > &tail) noexcept
QString ToSql(ToSqlState< T > &state) const noexcept
DeleteByFieldsWrapper(const QSqlDatabase &db, const CachedFieldsData &data) noexcept
void operator()(const ExprTree< Type, L, R > &tree) const noexcept
QString ToSql(ToSqlState< ObjT > &state) const noexcept
ExprTree(const T &t) noexcept
QSet< QString > AdditionalTables() const noexcept
static constexpr bool HasAdditionalTables() noexcept
ExpectedType_t ValueType_t
QString ToSql(ToSqlState< T > &) const noexcept
QString GetFieldName() const noexcept
static constexpr bool HasAdditionalTables() noexcept
QSet< QString > AdditionalTables() const noexcept
static constexpr bool HasAdditionalTables() noexcept
QString ToSql(ToSqlState< T > &state) const noexcept
QSet< QString > AdditionalTables() const noexcept
ExprTree(const L &l, const R &r) noexcept
QString HandleLimitOffset(Limit limit, OffsetNone) const noexcept
QString HandleLimitOffset(L limit, Offset offset) const noexcept
QString HandleLimitOffset(LimitNone, OffsetNone) const noexcept
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
SelectWrapperCommon(const QSqlDatabase &db, const QString &limitNone)
SelectWrapper(const QSqlDatabase &db, const CachedFieldsData &data, ImplFactory &&factory) noexcept
auto Build() const noexcept
QSqlQuery RunTextQuery(const QSqlDatabase &db, const QString &text)
Runs the given query text on the given db.
Type
Describes the various types of XDG .desktop files.
auto operator>(const L &left, const R &right) noexcept
QString GetQualifiedFieldNamePtr() noexcept
typename boost::fusion::result_of::value_at< Seq, Idx >::type ValueAt_t
constexpr auto AsLeafData(const T &node) noexcept
auto operator||(const L &left, const R &right) noexcept
T InitializeFromQuery(const QSqlQuery &q, std::index_sequence< Indices... >, int startIdx) noexcept
auto Combine(std::tuple< LArgs... > &&left, std::tuple< RArgs... > &&right) noexcept
constexpr bool BaseTypeCustomized
decltype(std::declval< UnwrapIndirect_t< typename L::template ValueType_t< Seq > > >()==std::declval< UnwrapIndirect_t< typename R::template ValueType_t< Seq > > >()) ComparableDetector
QList< QString > GetTypes(std::index_sequence< Indices... >) noexcept
QString GetFieldName() noexcept
typename std::conditional_t< IsIndirect< T > {}, T, WrapDirect< T > >::value_type UnwrapIndirect_t
constexpr CountAll * CountAllPtr
constexpr auto AreComparableTypes
constexpr auto ConstTrueTree_v
void AdaptPtrs(const QSqlDatabase &db, Tuple &tuple, std::index_sequence< Idxs... >)
typename T::Constraints ConstraintsDetector
QVariant ToVariantF(const T &t) noexcept
constexpr bool IsRelational(ExprType type) noexcept
auto MakeIndexedQueryHandler() noexcept
std::enable_if_t< EitherIsExprTree< L, R >()> EnableRelOp_t
typename boost::fusion::result_of::value_at_c< Seq, Idx >::type ValueAtC_t
boost::mpl::int_< FindPKey< Seq >::result_type::value > FindPKeyDetector
std::unique_ptr< IInsertQueryBuilder > IInsertQueryBuilder_ptr
decltype(new T { std::declval< Args >()... }) AggregateDetector_t
constexpr decltype(auto) GetReplaceTupleElem(Tuple &&tuple, NewType &&arg) noexcept
SelectorUnion< L, R > operator+(L, R) noexcept
constexpr bool TypeNameCustomized
constexpr auto ReplaceTupleElem(std::tuple< TupleArgs... > &&tuple, NewType &&arg) noexcept
decltype(auto) HandleResultBehaviour(ResultBehaviour::All, ResList &&list) noexcept
QStringList GetConstraintsStringList(Constraints< Args... >, const CachedFieldsData &data) noexcept
auto operator!=(const L &left, const R &right) noexcept
constexpr bool EitherIsExprTree() noexcept
HandleSelectorResult(QString, F, R) -> HandleSelectorResult< F, R >
auto MakeExprTree(const L &left, const R &right) noexcept
constexpr size_t FieldIndex() noexcept
constexpr auto ReplaceTupleElemImpl(Tuple &&tuple, NewType &&arg, std::index_sequence< TupIdxs... >) noexcept
auto MakeInserter(const CachedFieldsData &data, const QSqlQuery_ptr &insertQuery, bool bindPrimaryKey) noexcept
typename T::BaseType BaseTypeDetector
QStringList BuildFieldNames() noexcept
auto operator==(const L &left, const R &right) noexcept
decltype(T::TypeName) TypeNameDetector
QString GetFieldNamePtr() noexcept
auto operator<(const L &left, const R &right) noexcept
constexpr auto SeqIndices
Util::IsDetected_t< Constraints<>, ConstraintsDetector, T > ConstraintsType
constexpr auto HasAutogenPKey() noexcept
auto HandleExprTree(const ExprTree< ExprType::ConstTrue > &, int lastId=0) noexcept
decltype(std::declval< U >().FieldNameMorpher(QString {})) MorpherDetector
constexpr auto CombineBehaviour(L, R) noexcept
typename std::decay_t< std::tuple_element_t< Idx, Tuple > >::element_type::ObjectType_t UnderlyingObject_t
QString TypeToSql(ExprType type) noexcept
QString MorphFieldName(QString str) noexcept
auto operator|(const L &left, InfixBinary< Op >) noexcept
CachedFieldsData BuildCachedFieldsData() noexcept
auto operator&&(const L &left, const R &right) noexcept
QString AdaptCreateTable(const CachedFieldsData &data) noexcept
constexpr detail::InfixBinary< detail::ExprType::Like > like
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptr > > f
constexpr detail::SelectWhole all
constexpr detail::AggregateType< detail::AggregateFunction::Count, Ptr > count
constexpr detail::AggregateType< detail::AggregateFunction::Min, Ptr > min
constexpr detail::MemberPtrs< Ptrs... > fields
constexpr detail::AggregateType< detail::AggregateFunction::Max, Ptr > max
ObjectInfo_ptr< T > AdaptPtr(const QSqlDatabase &db)
void AdaptPtrs(const QSqlDatabase &db, Tuple &tuple)
constexpr detail::OrderBy< Orders... > OrderBy
std::shared_ptr< QSqlQuery > QSqlQuery_ptr
constexpr detail::GroupBy< Ptrs... > GroupBy
std::shared_ptr< ObjectInfo< T > > ObjectInfo_ptr
ObjectInfo< T > Adapt(const QSqlDatabase &db)
typename AsTypelist< T >::Result_t AsTypelist_t
auto Stlize(Assoc &&assoc)
Converts an Qt's associative sequence assoc to an STL-like iteratable range.
Container< T > Concat(const Container< Container< T > > &containers)
MemberTypeStruct_t< decltype(Ptr)> MemberPtrStruct_t
std::tuple_element_t< 0, decltype(detail::TypeGetter(*static_cast< F * >(nullptr)))> RetType_t
auto Map(Container &&c, F f)
typename detail::IsDetected< Type, void, Op, Args... >::type IsDetected_t
MemberTypeType_t< decltype(Ptr)> MemberPtrType_t
T operator()(const QVariant &var) const noexcept
static struct LC::Util::oral::InsertAction::DefaultTag Default
Limit(uint64_t count) noexcept
detail::AdaptUpdate< T > Update
detail::SelectWrapper< T, detail::SelectBehaviour::Some > Select
detail::AdaptDelete< T > Delete
detail::AdaptInsert< T > Insert
detail::DeleteByFieldsWrapper< T > DeleteBy
detail::SelectWrapper< T, detail::SelectBehaviour::One > SelectOne
Offset(uint64_t count) noexcept
QVariant operator()(const T &t) const noexcept
QString operator()() const noexcept
AdaptDelete(const QSqlDatabase &, const CachedFieldsData &, std::enable_if_t<!B > *=nullptr) noexcept
AdaptDelete(const QSqlDatabase &db, const CachedFieldsData &data, std::enable_if_t< B > *=nullptr) noexcept
std::function< void(Seq)> Deleter_
std::enable_if_t< B > operator()(const Seq &seq)
static constexpr auto Ptr() noexcept
static constexpr auto Index() noexcept
QStringList QualifiedFields_
static constexpr int Value
ExprTreeHandler(const QString &sql, F &&binder, int lastId) noexcept
typename std::conditional_t< IsPKey< ValueAt_t< Seq, MemberIdx > >::value, Lazy< MemberIdx >, Lazy< FindPKey< Seq, typename boost::mpl::next< MemberIdx >::type > > >::type result_type
QStringList operator()() const noexcept
QVariantMap BoundMembers_