12 #include <type_traits>
15 #include <boost/fusion/include/for_each.hpp>
16 #include <boost/fusion/include/fold.hpp>
17 #include <boost/fusion/include/filter_if.hpp>
18 #include <boost/fusion/container/vector.hpp>
19 #include <boost/fusion/include/vector.hpp>
20 #include <boost/fusion/include/transform.hpp>
21 #include <boost/fusion/include/zip.hpp>
22 #include <boost/fusion/container/generation/make_vector.hpp>
23 #include <QStringList>
54 class QueryException :
public std::runtime_error
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>> {};
108 struct GetFieldsNames
112 return Run (SeqIndices<S>);
115 template<
size_t... Vals>
116 QStringList Run (std::index_sequence<Vals...>)
const noexcept
118 return { GetFieldName<S, Vals> ()... };
125 inline static S
Obj_ {};
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;
204 return
Type2Name<ImplFactory, typename T::BaseType> {} ();
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>
223 struct Type2Name<ImplFactory, PKey<T,
Tags...>>
225 QString
operator() () const noexcept {
return Type2Name<ImplFactory, T> () () +
" PRIMARY KEY"; }
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>
248 QVariant
operator() (
const T& t)
const noexcept
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>
268 T
operator() (
const QVariant& var)
const noexcept
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> ();
288 struct IsPKey : std::false_type {};
290 template<
typename U,
typename...
Tags>
291 struct IsPKey<
PKey<U,
Tags...>> : std::true_type {};
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>
347 using FindPKeyDetector = boost::mpl::int_<FindPKey<Seq>::result_type::value>;
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;
426 if constexpr (HasAutogen_)
436 template<
typename Seq,
bool HasPKey = HasPKey<Seq>>
439 std::function<void (Seq)> Deleter_;
441 template<
bool B = HasPKey>
442 AdaptDelete (
const QSqlDatabase& db,
const CachedFieldsData& data, std::enable_if_t<B>* =
nullptr) noexcept
444 const auto index = FindPKey<Seq>::result_type::value;
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>
468 std::enable_if_t<B>
operator() (
const Seq& seq)
474 template<
typename T,
typename... Args>
477 template<
typename T,
size_t...
Indices>
478 T
InitializeFromQuery (
const QSqlQuery& q, std::index_sequence<Indices...>,
int startIdx) noexcept
485 const auto dummy = std::initializer_list<int>
540 return "invalid type";
561 QVariantMap BoundMembers_;
567 using value_type = T;
573 WrapDirect<T>>::value_type;
575 template<
typename Seq,
typename L,
typename R>
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>
637 ExprTree (
const L& l,
const R& r) noexcept
647 "Incompatible types passed to a relational operator.");
649 return Left_.ToSql (state) +
" " +
TypeToSql (
Type) +
" " + Right_.ToSql (state);
653 QSet<QString> AdditionalTables () const noexcept
655 return Left_.template AdditionalTables<T> () + Right_.template AdditionalTables<T> ();
659 constexpr
static bool HasAdditionalTables () noexcept
661 return L::template HasAdditionalTables<T> () || R::template HasAdditionalTables<T> ();
666 class ExprTree<
ExprType::LeafData, T, void>
678 template<
typename ObjT>
681 const auto& name =
":bound_" + QString::number (++state.LastID_);
682 state.BoundMembers_ [name] =
ToVariantF (Data_);
687 QSet<QString> AdditionalTables () const noexcept
693 constexpr
static bool HasAdditionalTables () noexcept
700 constexpr
auto AsLeafData (
const T& node) noexcept
708 template<
auto... Ptr>
709 struct MemberPtrs {};
727 return detail::GetFieldNamePtr<Ptr> ();
731 QSet<QString> AdditionalTables () const noexcept
734 if constexpr (std::is_same_v<Seq, T>)
737 return { Seq::ClassName () };
741 constexpr
static bool HasAdditionalTables () noexcept
743 return !std::is_same_v<MemberPtrStruct_t<Ptr>, T>;
746 auto operator= (
const ExpectedType_t& r)
const noexcept
753 class ExprTree<
ExprType::ConstTrue, void, void> {};
757 template<ExprType Type,
typename L,
typename R>
758 auto MakeExprTree (
const L& left,
const R& right) noexcept
765 template<
typename L,
typename R>
775 template<
typename L,
typename R>
778 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
779 auto operator< (
const L& left,
const R& right) noexcept
781 return MakeExprTree<ExprType::Less> (left, right);
784 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
785 auto operator> (
const L& left,
const R& right) noexcept
787 return MakeExprTree<ExprType::Greater> (left, right);
790 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
791 auto operator== (
const L& left,
const R& right) noexcept
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>
808 constexpr detail::InfixBinary<detail::ExprType::Like>
like {};
813 template<
typename L, ExprType Op>
814 struct InfixBinaryProxy
819 template<
typename L, ExprType Op>
820 auto operator| (
const L& left, InfixBinary<Op>) noexcept
825 template<
typename L, ExprType Op,
typename R>
826 auto operator| (
const InfixBinaryProxy<L, Op>& left,
const R& right) noexcept
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) }
859 auto HandleExprTree (
const ExprTree<ExprType::ConstTrue>&,
int lastId = 0) noexcept
861 return ExprTreeHandler {
"1 = 1", [] (
auto&&) {}, lastId };
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>
892 struct AggregateType {};
898 template<
typename... MemberDirectionList>
901 template<
auto... Ptrs>
904 struct SelectWhole {};
906 template<
typename L,
typename R>
907 struct SelectorUnion {};
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> ())... };
1014 struct OrderNone {};
1015 struct GroupNone {};
1017 struct OffsetNone {};
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>
1048 constexpr
static int Value = 1;
1051 template<
typename Seq,
typename... Args>
1052 struct DetectShift<Seq, std::tuple<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 };
1087 struct ResultBehaviour
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>
1128 const QSqlDatabase DB_;
1129 const QString LimitNone_;
1133 , LimitNone_ { limitNone }
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 ");
1153 QSqlQuery query { DB_ };
1154 query.prepare (queryStr);
1161 throw QueryException (
"fetch query execution failed", std::make_shared<QSqlQuery> (query));
1167 QString HandleLimitOffset (LimitNone, OffsetNone)
const noexcept
1172 QString HandleLimitOffset (Limit limit, OffsetNone)
const noexcept
1174 return " LIMIT " + QString::number (limit.Count);
1177 template<
typename L>
1178 QString HandleLimitOffset (L limit, Offset offset)
const noexcept
1181 if constexpr (std::is_same_v<std::decay_t<L>, LimitNone>)
1184 limitStr = 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
1256 return std::move (*this).Group (GroupBy<Ptrs...> {});
1260 template<
typename ImplFactory>
1261 SelectWrapper (
const QSqlDatabase& db,
const CachedFieldsData& data, ImplFactory&& factory) noexcept
1262 : SelectWrapperCommon { db, factory.LimitNone }
1267 auto Build () const noexcept
1269 std::tuple defParams
1278 return Builder<decltype (defParams)> { *
this, defParams };
1286 template<
typename Single>
1289 if constexpr (
IsExprTree<std::decay_t<Single>> {})
1290 return (*
this) (
SelectWhole {}, std::forward<Single> (single));
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>
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 (); },
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 (); },
1411 auto HandleSelector (AggregateType<AggregateFunction::Min, Ptr>)
const noexcept
1415 "min(" + GetQualifiedFieldNamePtr<Ptr> () +
")",
1416 MakeIndexedQueryHandler<Ptr> (),
1422 auto HandleSelector (AggregateType<AggregateFunction::Max, Ptr>)
const noexcept
1426 "max(" + GetQualifiedFieldNamePtr<Ptr> () +
")",
1427 MakeIndexedQueryHandler<Ptr> (),
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>
1489 class DeleteByFieldsWrapper
1491 const QSqlDatabase DB_;
1492 const QString Table_;
1494 DeleteByFieldsWrapper (
const QSqlDatabase& db,
const CachedFieldsData& data) noexcept
1496 , Table_ (data.Table_)
1500 template<ExprType Type,
typename L,
typename R>
1501 void operator() (
const ExprTree<Type, L, R>& tree)
const noexcept
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>
1546 std::enable_if_t<B>
operator() (
const T& seq)
1551 template<
typename SL,
typename SR, ExprType WType,
typename WL,
typename WR>
1552 int operator() (
const AssignList<SL, SR>& set,
const ExprTree<WType, WL, WR>& where)
1554 static_assert (!ExprTree<WType, WL, WR>::template HasAdditionalTables<T> (),
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>
1585 struct ExtractConstraintFields;
1587 template<
int... Fields>
1588 struct ExtractConstraintFields<UniqueSubset<Fields...>>
1590 QString
operator() (
const CachedFieldsData& data)
const noexcept
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>
1645 InsertAction::Replace::PKeyType<Seq>::operator InsertAction::Replace ()
const
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>
1654 detail::AdaptInsert<T> Insert;
1655 detail::AdaptUpdate<T> Update;
1656 detail::AdaptDelete<T> Delete;
1662 using ObjectType_t = 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>
1691 ObjectInfo_ptr<T>
AdaptPtr (
const QSqlDatabase& db)
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>> {});