33 #include <type_traits>
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>
75 class QueryException :
public std::runtime_error
80 : std::runtime_error (str)
101 using MorpherDetector = decltype (std::declval<U> ().FieldNameMorpher (QString {}));
106 if constexpr (IsDetected_v<MorpherDetector, T>)
107 return T::FieldNameMorpher (str);
110 if (str.endsWith (
'_'))
116 template<
typename Seq,
int Idx>
119 return MorphFieldName<Seq> (boost::fusion::extension::struct_member_name<Seq, Idx>::call ());
123 constexpr
auto SeqSize = boost::fusion::result_of::size<S>::type::value;
126 constexpr
auto SeqIndices = std::make_index_sequence<SeqSize<S>> {};
129 struct GetFieldsNames
133 return Run (SeqIndices<S>);
136 template<
size_t... Vals>
137 QStringList Run (std::index_sequence<Vals...>)
const noexcept
139 return { GetFieldName<S, Vals> ()... };
146 inline static S
Obj_ {};
149 static constexpr
auto Ptr () noexcept
155 static constexpr
auto Index () noexcept
157 return &boost::fusion::at_c<Idx> (
Obj_);
161 template<auto Ptr,
size_t Idx = 0>
166 if constexpr (Idx == SeqSize<S>)
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)>)
174 if (indexed == direct)
178 return FieldIndex<Ptr, Idx + 1> ();
186 return GetFieldName<S, FieldIndex<Ptr> ()> ();
193 return S::ClassName () +
"." + GetFieldName<S, FieldIndex<Ptr> ()> ();
209 template<
typename ImplFactory,
typename T,
typename =
void>
216 else if constexpr (std::is_same_v<T, double>)
218 else if constexpr (std::is_same_v<T, QString> || std::is_same_v<T, QDateTime> || std::is_same_v<T, QUrl>)
220 else if constexpr (std::is_same_v<T, QByteArray>)
221 return ImplFactory::TypeLits::Binary;
222 else if constexpr (detail::TypeNameCustomized<T>)
224 else if constexpr (detail::BaseTypeCustomized<T>)
227 static_assert (std::is_same_v<T, struct Dummy>,
"Unsupported type");
231 template<
typename ImplFactory,
typename T>
237 template<
typename ImplFactory,
typename T>
243 template<
typename ImplFactory,
typename T,
typename... Tags>
244 struct Type2Name<ImplFactory, PKey<T, Tags...>>
246 QString
operator() () const noexcept {
return Type2Name<ImplFactory, T> () () +
" PRIMARY KEY"; }
249 template<
typename ImplFactory,
typename... Tags>
250 struct Type2Name<ImplFactory, PKey<int, Tags...>>
252 QString
operator() () const noexcept {
return ImplFactory::TypeLits::IntAutoincrement; }
255 template<
typename ImplFactory, auto Ptr>
256 struct Type2Name<ImplFactory, References<Ptr>>
260 const auto& className = MemberPtrStruct_t<Ptr>::ClassName ();
262 " REFERENCES " + className +
" (" + detail::GetFieldNamePtr<Ptr> () +
") ON DELETE CASCADE";
266 template<
typename T,
typename =
void>
269 QVariant
operator() (
const T& t)
const noexcept
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);
277 else if constexpr (detail::TypeNameCustomized<T>)
280 return
ToVariant<typename T::BaseType> {} (t.ToBaseType ());
286 template<
typename T,
typename =
void>
289 T
operator() (
const QVariant& var)
const noexcept
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> ());
297 else if constexpr (detail::TypeNameCustomized<T>)
298 return T::FromVariant (var);
299 else if constexpr (detail::BaseTypeCustomized<T>)
302 return var.value<T> ();
309 struct IsPKey : std::false_type {};
311 template<
typename U,
typename... Tags>
312 struct IsPKey<
PKey<U, Tags...>> : std::true_type {};
323 return [data, insertQuery, bindPrimaryKey] (
const T& t)
325 boost::fusion::fold (t, data.BoundFields_.begin (),
326 [&] (
auto pos,
const auto& elem)
328 using Elem = std::decay_t<decltype (elem)>;
329 if (bindPrimaryKey || !IsPKey<Elem>::value)
334 if (!insertQuery->exec ())
337 throw QueryException (
"insert query execution failed", insertQuery);
342 template<
typename Seq,
int Idx>
343 using ValueAtC_t =
typename boost::fusion::result_of::value_at_c<Seq, Idx>::type;
345 template<
typename Seq,
typename Idx>
346 using ValueAt_t =
typename boost::fusion::result_of::value_at<Seq, Idx>::type;
348 template<
typename Seq,
typename MemberIdx = boost::mpl::
int_<0>>
351 static_assert ((boost::fusion::result_of::size<Seq>::value) != (MemberIdx::value),
352 "Primary key not found");
361 IsPKey<ValueAt_t<Seq, MemberIdx>>::value,
367 template<
typename Seq>
368 using FindPKeyDetector = boost::mpl::int_<FindPKey<Seq>::result_type::value>;
370 template<
typename Seq>
371 constexpr
auto HasPKey = IsDetected_v<FindPKeyDetector, Seq>;
373 template<
typename Seq>
376 if constexpr (HasPKey<Seq>)
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; });
389 return { table,
fields, qualified, boundFields };
395 static CachedFieldsData result = BuildCachedFieldsData<T> (T::ClassName ());
399 template<
typename Seq>
402 const QSqlDatabase DB_;
405 constexpr
static bool HasAutogen_ = HasAutogenPKey<Seq> ();
409 template<
typename ImplFactory>
411 : Data_ { RemovePKey (data) }
412 , QueryBuilder_ { factory.MakeInsertQueryBuilder (db, Data_) }
418 return Run<true> (t, action);
423 return Run<false> (t, action);
426 template<
bool UpdatePKey,
typename Val>
429 const auto query = QueryBuilder_->GetQuery (action);
431 MakeInserter<Seq> (Data_, query, !HasAutogen_) (t);
433 if constexpr (HasAutogen_)
438 if constexpr (UpdatePKey)
439 boost::fusion::at_c<index> (t) = lastId;
445 static CachedFieldsData RemovePKey (CachedFieldsData data) noexcept
447 if constexpr (HasAutogen_)
457 template<
typename Seq,
bool HasPKey = HasPKey<Seq>>
462 template<
bool B = HasPKey>
468 const auto& del =
"DELETE FROM " + data.
Table_ +
469 " WHERE " + data.
Fields_.at (index) +
" = " + boundName;
471 const auto deleteQuery = std::make_shared<QSqlQuery> (db);
472 deleteQuery->prepare (del);
474 Deleter_ = [deleteQuery, boundName] (
const Seq& t)
477 deleteQuery->bindValue (boundName,
ToVariantF (boost::fusion::at_c<index> (t)));
478 if (!deleteQuery->exec ())
479 throw QueryException (
"delete query execution failed", deleteQuery);
483 template<
bool B = HasPKey>
484 AdaptDelete (
const QSqlDatabase&,
const CachedFieldsData&, std::enable_if_t<!B>* =
nullptr) noexcept
488 template<
bool B = HasPKey>
489 std::enable_if_t<B>
operator() (
const Seq& seq)
495 template<
typename T,
typename... Args>
498 template<
typename T,
size_t...
Indices>
506 const auto dummy = std::initializer_list<int>
561 return "invalid type";
596 template<
typename Seq,
typename L,
typename R>
600 template<
typename Seq,
typename L,
typename R>
601 constexpr
auto AreComparableTypes = IsDetected_v<ComparableDetector, Seq, L, R> || IsDetected_v<ComparableDetector, Seq, R, L>;
603 template<
typename Seq,
typename L,
typename R,
typename =
void>
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 {};
609 template<ExprType Type,
typename Seq,
typename L,
typename R,
typename =
void>
610 struct RelationalTypesChecker : std::true_type {};
612 template<ExprType Type,
typename Seq,
typename L,
typename R>
615 template<ExprType Type,
typename L =
void,
typename R =
void>
619 struct IsExprTree : std::false_type {};
621 template<ExprType Type,
typename L,
typename R>
622 struct IsExprTree<ExprTree<
Type, L, R>> : std::true_type {};
624 template<
typename L,
typename R>
637 QString
ToSql (ToSqlState<T>& state)
const noexcept
639 if constexpr (IsExprTree<L> {})
640 return Left_.GetFieldName () +
" = " + Right_.ToSql (state);
642 return Left_.ToSql (state) +
", " + Right_.ToSql (state);
645 template<
typename OL,
typename OR>
652 template<ExprType Type,
typename L,
typename R>
658 ExprTree (
const L& l,
const R& r) noexcept
668 "Incompatible types passed to a relational operator.");
670 return Left_.ToSql (state) +
" " +
TypeToSql (
Type) +
" " + Right_.ToSql (state);
676 return Left_.template AdditionalTables<T> () + Right_.template AdditionalTables<T> ();
682 return L::template HasAdditionalTables<T> () || R::template HasAdditionalTables<T> ();
686 template<
auto... Ptr>
704 return detail::GetFieldNamePtr<Ptr> ();
711 if constexpr (std::is_same_v<Seq, T>)
714 return { Seq::ClassName () };
720 return !std::is_same_v<MemberPtrStruct_t<Ptr>, T>;
724 auto operator= (
const R&)
const noexcept;
740 template<
typename ObjT>
743 const auto& name =
":bound_" + QString::number (++state.LastID_);
744 state.BoundMembers_ [name] =
ToVariantF (Data_);
762 class ExprTree<
ExprType::ConstTrue, void, void> {};
767 constexpr
auto AsLeafData (
const T& node) noexcept
782 template<ExprType Type,
typename L,
typename R>
783 auto MakeExprTree (
const L& left,
const R& right) noexcept
790 template<
typename L,
typename R>
793 if (IsExprTree<L> {})
795 if (IsExprTree<R> {})
800 template<
typename L,
typename R>
801 using EnableRelOp_t = std::enable_if_t<EitherIsExprTree<L, R> ()>;
803 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
804 auto operator< (
const L& left,
const R& right) noexcept
806 return MakeExprTree<ExprType::Less> (left, right);
809 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
810 auto operator> (
const L& left,
const R& right) noexcept
812 return MakeExprTree<ExprType::Greater> (left, right);
815 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
816 auto operator== (
const L& left,
const R& right) noexcept
818 return MakeExprTree<ExprType::Equal> (left, right);
821 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
822 auto operator!= (
const L& left,
const R& right) noexcept
824 return MakeExprTree<ExprType::Neq> (left, right);
827 template<ExprType Op>
838 template<
typename L, ExprType Op>
839 struct InfixBinaryProxy
844 template<
typename L, ExprType Op>
850 template<
typename L, ExprType Op,
typename R>
851 auto operator| (
const InfixBinaryProxy<L, Op>& left,
const R& right) noexcept
853 return MakeExprTree<Op> (left.Left_, right);
856 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
857 auto operator&& (
const L& left,
const R& right) noexcept
859 return MakeExprTree<ExprType::And> (left, right);
862 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
863 auto operator|| (
const L& left,
const R& right) noexcept
865 return MakeExprTree<ExprType::Or> (left, right);
877 ,
Binder_ { std::move (binder) }
889 template<
typename Seq,
typename Tree,
890 typename = decltype (std::declval<Tree> ().ToSql (std::declval<
ToSqlState<Seq>&> ()))>
895 const auto& sql = tree.ToSql (state);
900 [state] (QSqlQuery& query)
902 for (
const auto& pair :
Stlize (state.BoundMembers_))
903 query.bindValue (pair.first, pair.second);
916 template<AggregateFunction, auto Ptr>
923 template<
typename... MemberDirectionList>
926 template<
auto... Ptrs>
931 template<
typename L,
typename R>
932 struct SelectorUnion {};
938 struct IsSelector<SelectWhole> : std::true_type {};
940 template<AggregateFunction Fun, auto Ptr>
943 template<
auto... Ptrs>
944 struct IsSelector<MemberPtrs<Ptrs...>> : std::true_type {};
946 template<
typename L,
typename R>
949 template<
typename L,
typename R,
typename = std::enable_if_t<IsSelector<L> {} && IsSelector<R> {}>>
961 template<
auto... Ptrs>
966 template<
auto... Ptrs>
969 template<
auto... Ptrs>
972 template<auto Ptr = detail::CountAllPtr>
976 constexpr detail::AggregateType<detail::AggregateFunction::Min, Ptr>
min {};
979 constexpr detail::AggregateType<detail::AggregateFunction::Max, Ptr>
max {};
982 template<
typename... Orders>
985 template<
auto... Ptrs>
1010 template<
auto... Ptrs,
size_t... Idxs>
1013 return [] (
const QSqlQuery& q,
int startIdx = 0) noexcept
1015 if constexpr (
sizeof... (Ptrs) == 1)
1025 return [] (
const QSqlQuery& q,
int startIdx = 0) noexcept
1031 template<
auto... Ptrs>
1034 return { BuildCachedFieldsData<MemberPtrStruct_t<Ptrs>> ().QualifiedFields_.value (FieldIndex<Ptrs> ())... };
1039 struct OrderNone {};
1040 struct GroupNone {};
1041 struct LimitNone {};
1042 struct OffsetNone {};
1044 template<
size_t RepIdx,
size_t TupIdx,
typename Tuple,
typename NewType>
1047 if constexpr (RepIdx == TupIdx)
1050 return std::get<TupIdx> (tuple);
1053 template<
size_t RepIdx, typename
NewType, typename Tuple,
size_t... TupIdxs>
1058 GetReplaceTupleElem<RepIdx, TupIdxs> (std::forward<Tuple> (tuple), std::forward<NewType> (arg))...
1062 template<
size_t RepIdx,
typename NewType,
typename... TupleArgs>
1065 return ReplaceTupleElemImpl<RepIdx> (std::move (tuple),
1066 std::forward<NewType> (arg),
1067 std::index_sequence_for<TupleArgs...> {});
1070 template<
typename Seq,
typename T>
1073 constexpr
static int Value = 1;
1076 template<
typename Seq,
typename... Args>
1077 struct DetectShift<Seq, std::tuple<Args...>>
1082 template<
typename Seq>
1083 struct DetectShift<Seq, Seq>
1085 constexpr
static int Value = SeqSize<Seq>;
1088 template<
typename... LArgs,
typename... RArgs>
1089 auto Combine (std::tuple<LArgs...>&& left, std::tuple<RArgs...>&& right) noexcept
1091 return std::tuple_cat (std::move (left), std::move (right));
1094 template<
typename... LArgs,
typename R>
1095 auto Combine (std::tuple<LArgs...>&& left,
const R& right) noexcept
1097 return std::tuple_cat (std::move (left), std::tuple { right });
1100 template<
typename L,
typename... RArgs>
1101 auto Combine (
const L& left, std::tuple<RArgs...>&& right) noexcept
1103 return std::tuple_cat (std::tuple { left }, std::move (right));
1106 template<
typename L,
typename R>
1107 auto Combine (
const L& left,
const R& right) noexcept
1109 return std::tuple { left, right };
1112 struct ResultBehaviour
1118 template<
typename L,
typename R>
1121 if constexpr (std::is_same_v<L, ResultBehaviour::First> && std::is_same_v<R, ResultBehaviour::First>)
1127 template<
typename ResList>
1130 return std::forward<ResList> (list);
1133 template<
typename ResList>
1136 return list.value (0);
1139 template<
typename F,
typename R>
1147 template<
typename F,
typename R>
1153 const QSqlDatabase
DB_;
1163 QString where, std::function<
void (QSqlQuery&)>&& binder,
1164 const QString& orderStr,
1165 const QString& groupStr,
1166 const QString& limitOffsetStr)
const
1168 if (!where.isEmpty ())
1169 where.prepend (
" WHERE ");
1171 const auto& queryStr =
"SELECT " +
fields +
1178 QSqlQuery query {
DB_ };
1179 query.prepare (queryStr);
1186 throw QueryException (
"fetch query execution failed", std::make_shared<QSqlQuery> (query));
1199 return " LIMIT " + QString::number (limit.Count);
1202 template<
typename L>
1211 else if constexpr (std::is_integral_v<L>)
1212 limitStr = QString::number (limit);
1214 limitStr = QString::number (limit.
Count);
1215 return " LIMIT " + limitStr +
1216 " OFFSET " + QString::number (offset.
Count);
1225 template<
typename ParamsTuple>
1229 ParamsTuple Params_;
1231 template<
typename NewTuple>
1232 constexpr
auto RepTuple (NewTuple&& tuple) noexcept
1234 return Builder<NewTuple> { W_, tuple };
1237 template<
typename U>
1238 constexpr
auto Select (U&& selector) && noexcept
1240 return RepTuple (ReplaceTupleElem<0> (std::move (Params_), std::forward<U> (selector)));
1243 template<
typename U>
1244 constexpr
auto Where (U&& tree) && noexcept
1246 return RepTuple (ReplaceTupleElem<1> (std::move (Params_), std::forward<U> (tree)));
1249 template<
typename U>
1250 constexpr
auto Order (U&& order) && noexcept
1252 return RepTuple (ReplaceTupleElem<2> (std::move (Params_), std::forward<U> (order)));
1255 template<
typename U>
1256 constexpr
auto Group (U&& group) && noexcept
1258 return RepTuple (ReplaceTupleElem<3> (std::move (Params_), std::forward<U> (group)));
1261 template<
typename U = Limit>
1262 constexpr
auto Limit (U&& limit) && noexcept
1264 return RepTuple (ReplaceTupleElem<4> (std::move (Params_), std::forward<U> (limit)));
1267 template<
typename U = Offset>
1268 constexpr
auto Offset (U&& offset) && noexcept
1270 return RepTuple (ReplaceTupleElem<5> (std::move (Params_), std::forward<U> (offset)));
1273 auto operator() () &&
1275 return std::apply (W_, Params_);
1278 template<
auto... Ptrs>
1279 constexpr
auto Group () && noexcept
1285 template<
typename ImplFactory>
1286 SelectWrapper (
const QSqlDatabase& db,
const CachedFieldsData& data, ImplFactory&& factory) noexcept
1292 auto Build () const noexcept
1294 std::tuple defParams
1303 return Builder<decltype (defParams)> { *
this, defParams };
1306 auto operator() ()
const
1311 template<
typename Single>
1312 auto operator() (Single&& single)
const
1314 if constexpr (IsExprTree<std::decay_t<Single>> {})
1315 return (*
this) (SelectWhole {}, std::forward<Single> (single));
1323 typename Order = OrderNone,
1324 typename Group = GroupNone,
1325 typename Limit = LimitNone,
1326 typename Offset = OffsetNone
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
1335 const auto& [where, binder, _] = HandleExprTree<T> (tree);
1337 const auto& [
fields, initializer, resultBehaviour] = HandleSelector (std::forward<Selector> (selector));
1339 Select (
fields, BuildFromClause (tree),
1342 HandleOrder (std::forward<Order> (order)),
1343 HandleGroup (std::forward<Group> (group)),
1344 HandleLimitOffset (std::forward<Limit> (limit), std::forward<Offset> (offset))));
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
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);
1362 QList<std::result_of_t<Initializer (QSqlQuery)>> result;
1363 while (query.next ())
1364 result << initializer (query);
1369 using RetType_t = std::optional<std::result_of_t<Initializer (QSqlQuery)>>;
1370 return query.next () ?
1376 template<ExprType Type,
typename L,
typename R>
1377 QString BuildFromClause (
const ExprTree<Type, L, R>& tree)
const noexcept
1381 auto result = Cached_.
Table_;
1382 for (
const auto& item : tree.template AdditionalTables<T> ())
1383 result +=
", " + item;
1395 [] (
const QSqlQuery& q,
int startIdx = 0)
1397 return InitializeFromQuery<T> (q, SeqIndices<T>, startIdx);
1403 template<
auto... Ptrs>
1414 auto HandleSelector (AggregateType<AggregateFunction::Count, CountAllPtr>)
const noexcept
1419 [] (
const QSqlQuery& q,
int startIdx = 0) {
return q.value (startIdx).toLongLong (); },
1425 auto HandleSelector (AggregateType<AggregateFunction::Count, Ptr>)
const noexcept
1429 "count(" + GetQualifiedFieldNamePtr<Ptr> () +
")",
1430 [] (
const QSqlQuery& q,
int startIdx = 0) {
return q.value (startIdx).toLongLong (); },
1436 auto HandleSelector (AggregateType<AggregateFunction::Min, Ptr>)
const noexcept
1440 "min(" + GetQualifiedFieldNamePtr<Ptr> () +
")",
1441 MakeIndexedQueryHandler<Ptr> (),
1447 auto HandleSelector (AggregateType<AggregateFunction::Max, Ptr>)
const noexcept
1451 "max(" + GetQualifiedFieldNamePtr<Ptr> () +
")",
1452 MakeIndexedQueryHandler<Ptr> (),
1457 template<
typename L,
typename R>
1458 auto HandleSelector (SelectorUnion<L, R>)
const noexcept
1460 const auto& lSel = HandleSelector (L {});
1461 const auto& rSel = HandleSelector (R {});
1463 const auto& lHandler = lSel.Initializer_;
1464 const auto& rHandler = rSel.Initializer_;
1468 lSel.Fields_ +
", " + rSel.Fields_,
1469 [lHandler, rHandler] (
const QSqlQuery& q,
int startIdx = 0)
1471 constexpr
auto shift = DetectShift<T, decltype (lHandler (q))>::Value;
1472 return Combine (lHandler (q, startIdx), rHandler (q, startIdx + shift));
1478 QString HandleOrder (OrderNone)
const noexcept
1483 template<
auto... Ptrs>
1486 return { (GetQualifiedFieldNamePtr<Ptrs> () +
" ASC")... };
1489 template<
auto... Ptrs>
1490 QList<QString> HandleSuborder (sph::desc<Ptrs...>)
const noexcept
1492 return { (GetQualifiedFieldNamePtr<Ptrs> () +
" DESC")... };
1495 template<
typename... Suborders>
1496 QString HandleOrder (OrderBy<Suborders...>)
const noexcept
1498 return " ORDER BY " + QStringList {
Concat (
QList { HandleSuborder (Suborders {})... }) }.join (
", ");
1501 QString HandleGroup (GroupNone)
const noexcept
1506 template<
auto... Ptrs>
1507 QString HandleGroup (GroupBy<Ptrs...>)
const noexcept
1509 return " GROUP BY " + QStringList { GetQualifiedFieldNamePtr<Ptrs> ()... }.join (
", ");
1513 template<
typename T>
1514 class DeleteByFieldsWrapper
1516 const QSqlDatabase
DB_;
1517 const QString Table_;
1519 DeleteByFieldsWrapper (
const QSqlDatabase& db,
const CachedFieldsData& data) noexcept
1525 template<ExprType Type,
typename L,
typename R>
1526 void operator() (
const ExprTree<Type, L, R>& tree)
const noexcept
1528 const auto& [where, binder, _] = HandleExprTree<T> (tree);
1531 const auto& selectAll =
"DELETE FROM " + Table_ +
1534 QSqlQuery query {
DB_ };
1535 query.prepare (selectAll);
1541 template<
typename T,
bool HasPKey = HasPKey<T>>
1544 const QSqlDatabase
DB_;
1545 const QString Table_;
1547 std::function<void (T)> Updater_;
1549 AdaptUpdate (
const QSqlDatabase& db,
const CachedFieldsData& data) noexcept
1555 constexpr
auto index = FindPKey<T>::result_type::value;
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;
1564 const auto updateQuery = std::make_shared<QSqlQuery> (db);
1565 updateQuery->prepare (update);
1566 Updater_ = MakeInserter<T> (data, updateQuery,
true);
1570 template<
bool B = HasPKey>
1571 std::enable_if_t<B> operator() (
const T& seq)
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)
1579 static_assert (!ExprTree<WType, WL, WR>::template HasAdditionalTables<T> (),
1580 "joins in update statements are not supported by SQL");
1582 const auto& [setClause, setBinder, setLast] = HandleExprTree<T> (set);
1583 const auto& [whereClause, whereBinder, _] = HandleExprTree<T> (where, setLast);
1585 const auto& update =
"UPDATE " + Table_ +
1586 " SET " + setClause +
1587 " WHERE " + whereClause;
1589 QSqlQuery query {
DB_ };
1590 query.prepare (update);
1592 whereBinder (query);
1596 throw QueryException (
"update query execution failed", std::make_shared<QSqlQuery> (query));
1599 return query.numRowsAffected ();
1603 template<
typename T>
1606 template<
typename T>
1609 template<
typename T>
1612 template<
int... Fields>
1617 return "UNIQUE (" + QStringList { data.
Fields_.value (Fields)... }.join (
", ") +
")";
1621 template<
int... Fields>
1626 return "PRIMARY KEY (" + QStringList { data.
Fields_.value (Fields)... }.join (
", ") +
")";
1630 template<
typename... Args>
1633 return { ExtractConstraintFields<Args> {} (data)... };
1636 template<
typename ImplFactory,
typename T,
size_t...
Indices>
1639 return { Type2Name<ImplFactory, ValueAtC_t<T, Indices>> {} ()... };
1642 template<
typename ImplFactory,
typename T>
1645 const auto& types = GetTypes<ImplFactory, T> (SeqIndices<T>);
1648 const auto& constraintsStr = constraints.isEmpty () ?
1650 (
", " + constraints.join (
", "));
1652 const auto& statements = Util::ZipWith<QList> (types, data.
Fields_,
1653 [] (
const QString& type,
const QString& field) { return field +
" " + type; });
1654 return "CREATE TABLE " +
1657 statements.join (
", ") +
1663 template<
auto... Ptrs>
1666 return { { detail::BuildCachedFieldsData<MemberPtrStruct_t<Ptrs>> ().
Fields_.value (detail::FieldIndex<Ptrs> ())... } };
1669 template<
typename Seq>
1672 static_assert (detail::HasPKey<Seq>,
"Sequence does not have any primary keys");
1673 return { { detail::GetFieldName<Seq, detail::FindPKey<Seq>::result_type::value> () } };
1676 template<
typename T>
1679 detail::AdaptInsert<T> Insert;
1680 detail::AdaptUpdate<T> Update;
1681 detail::AdaptDelete<T> Delete;
1690 using ObjectType_t = T;
1693 template<
typename T,
typename ImplFactory = detail::SQLite::ImplFactory>
1696 const auto& cachedData = detail::BuildCachedFieldsData<T> ();
1698 if (!db.tables ().contains (cachedData.Table_, Qt::CaseInsensitive))
1699 RunTextQuery (db, detail::AdaptCreateTable<ImplFactory, T> (cachedData));
1701 ImplFactory factory;
1705 { db, cachedData, factory },
1709 { db, cachedData, factory },
1710 { db, cachedData, factory },
1715 template<
typename T>
1718 template<
typename T,
typename ImplFactory = SQLiteImplFactory>
1721 return std::make_shared<ObjectInfo<T>> (Adapt<T, ImplFactory> (db));
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;
1729 template<
typename ImplFactory,
typename Tuple,
size_t... Idxs>
1730 void AdaptPtrs (
const QSqlDatabase& db, Tuple& tuple, std::index_sequence<Idxs...>)
1732 ((std::get<Idxs> (tuple) = AdaptPtr<UnderlyingObject_t<Idxs, Tuple>, ImplFactory> (db)), ...);
1736 template<
typename ImplFactory,
typename Tuple>
1737 void AdaptPtrs (
const QSqlDatabase& db, Tuple& tuple)
1739 detail::AdaptPtrs<ImplFactory> (db, tuple, std::make_index_sequence<std::tuple_size_v<Tuple>> {});