12 #include <type_traits> 15 #include <boost/preprocessor/stringize.hpp> 16 #include <boost/preprocessor/tuple.hpp> 17 #include <QStringList> 33 #ifndef ORAL_ADAPT_STRUCT 35 #define ORAL_STRING_FIELD_IMPL(index, sname, field) \ 37 constexpr auto MemberNameByIdx<sname, index> = CtString { BOOST_PP_STRINGIZE(field) }; \ 39 constexpr auto MemberNameByPtr<&sname::field> = CtString { BOOST_PP_STRINGIZE(field) }; 41 #define ORAL_STRING_FIELD(_, index, args) \ 42 ORAL_STRING_FIELD_IMPL(index, BOOST_PP_TUPLE_ELEM(0, args), BOOST_PP_TUPLE_ELEM(index, BOOST_PP_TUPLE_ELEM(1, args))) 44 #define ORAL_ADAPT_STRUCT(sname, ...) \ 45 namespace LC::Util::oral \ 48 constexpr auto BeenAdapted<sname> = true; \ 51 constexpr auto SeqSize<sname> = BOOST_PP_TUPLE_SIZE((__VA_ARGS__)); \ 53 static_assert (SeqSize<sname> == detail::FullSize<sname>); \ 55 BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE((__VA_ARGS__)), ORAL_STRING_FIELD, (sname, (__VA_ARGS__))) \ 66 using std::runtime_error::runtime_error;
82 template<
typename,
int>
90 template<
size_t Idx,
typename Seq>
91 constexpr decltype (
auto)
Get (const Seq& seq)
93 const auto& [...fields] = seq;
97 template<
size_t Idx,
typename Seq>
98 constexpr decltype (
auto)
Get (Seq& seq)
100 auto& [...fields] = seq;
104 template<
typename Seq>
107 const auto& [...fields] = seq;
108 return std::integral_constant<size_t,
sizeof... (
fields)> {};
111 template<
typename Seq>
114 template<
typename T, CtString str>
117 if constexpr (
requires { T::template FieldNameMorpher<str> (); })
118 return T::template FieldNameMorpher<str> ();
119 else if constexpr (str.EndsWith (
'_'))
120 return str.template Chop<1> ();
125 template<
typename Seq,
int Idx>
128 constexpr
auto str = MemberNameByIdx<Seq, Idx>;
129 return MorphFieldName<Seq, str> ();
133 constexpr
auto SeqIndices = std::make_index_sequence<SeqSize<S>> {};
136 constexpr
auto FieldNames = []<
size_t... Ix> (std::index_sequence<Ix...>) constexpr
138 return std::tuple { GetFieldName<S, Ix> ()... };
142 constexpr
auto BoundFieldNames = []<
size_t... Ix> (std::index_sequence<Ix...>) constexpr
144 return std::tuple { (
":" + GetFieldName<S, Ix> ())... };
150 return std::tuple { (S::ClassName +
"." + GetFieldName<S, Ix> ())... };
154 constexpr
auto FieldNameByPtr = MorphFieldName<MemberPtrStruct_t<Ptr>, MemberNameByPtr<Ptr>> ();
166 template<
typename ImplFactory,
typename T>
171 if constexpr (detail::TypeNameCustomizedMember<T>)
173 else if constexpr (detail::BaseTypeCustomized<T>)
177 else if constexpr (std::is_same_v<T, double>)
179 else if constexpr (std::is_same_v<T, QString> || std::is_same_v<T, QDateTime> || std::is_same_v<T, QUrl>)
181 else if constexpr (std::is_same_v<T, QByteArray>)
182 return ImplFactory::TypeLits::Binary;
184 static_assert (std::is_same_v<T, struct Dummy>,
"Unsupported type");
188 template<
typename ImplFactory,
typename T>
194 template<
typename ImplFactory,
typename T>
200 template<
typename ImplFactory,
typename T,
typename... Tags>
206 template<
typename ImplFactory,
typename... Tags>
212 template<
typename ImplFactory,
typename T>
218 template<
typename ImplFactory, auto Ptr>
225 " REFERENCES " + className +
" (" + detail::FieldNameByPtr<Ptr> +
") ON DELETE CASCADE";
230 requires (!std::same_as<T, QVariant>)
240 static QVariant operator() (
const T& t)
noexcept 242 if constexpr (detail::TypeNameCustomizedMember<T>)
243 return t.ToVariant ();
244 else if constexpr (detail::BaseTypeCustomized<T>)
245 return Convert<typename T::BaseType> (t.ToBaseType ());
246 else if constexpr (std::is_same_v<T, QDateTime>)
247 return t.toString (Qt::ISODateWithMs);
248 else if constexpr (std::is_enum_v<T>)
249 return static_cast<qint64
> (t);
251 return Convert<typename T::value_type> (t);
256 static T operator() (
const QVariant& var)
noexcept 258 if constexpr (detail::TypeNameCustomizedMember<T>)
259 return T::FromVariant (var);
260 else if constexpr (detail::BaseTypeCustomized<T>)
261 return T::FromBaseType (Convert<typename T::BaseType> (var));
262 else if constexpr (std::is_same_v<T, QDateTime>)
263 return QDateTime::fromString (var.toString (), Qt::ISODateWithMs);
264 else if constexpr (std::is_enum_v<T>)
265 return static_cast<T
> (var.value<qint64> ());
267 return Convert<typename T::value_type> (var);
269 return var.value<T> ();
274 struct ConvertT<
std::optional<T>>
276 static QVariant operator() (
const std::optional<T>& t)
noexcept 278 return t ? Convert<T> (*t) : QVariant {};
281 static std::optional<T> operator() (
const QVariant& var)
noexcept 283 return var.isNull () ? std::nullopt : std::optional { Convert<T> (var) };
289 template<
typename Seq,
int Idx>
290 using ValueAtC_t = std::decay_t<decltype (Get<Idx> (std::declval<Seq> ()))>;
295 template<
typename U,
typename... Tags>
301 return Convert<T> (t);
304 template<
size_t Ix,
typename Seq>
305 void BindAtIndex (
const Seq& seq, QSqlQuery& query,
bool bindPrimaryKey)
308 query.bindValue (
ToString<std::get<Ix> (BoundFieldNames<Seq>)> (),
ToVariantF (Get<Ix> (seq)));
311 template<
typename Seq>
312 auto DoInsert (
const Seq& seq, QSqlQuery& insertQuery,
bool bindPrimaryKey)
314 [&]<
size_t... Ix> (std::index_sequence<Ix...>)
316 (BindAtIndex<Ix> (seq, insertQuery, bindPrimaryKey), ...);
319 if (!insertQuery.exec ())
321 qCritical () <<
"insert query execution failed";
327 template<
typename Seq>
330 auto run = []<
size_t... Idxes> (std::index_sequence<Idxes...>)
333 ((IsPKey<ValueAtC_t<Seq, Idxes>> ? (result = Idxes) : 0), ...);
336 return run (SeqIndices<Seq>);
339 template<
typename Seq>
342 const auto idx = PKeyIndexUnsafe<Seq> ();
343 static_assert (idx >= 0);
347 template<
typename Seq>
350 template<
typename Seq>
351 concept
HasPKey = PKeyIndexUnsafe<Seq> () >= 0;
353 template<
typename Seq>
356 if constexpr (HasPKey<Seq>)
362 template<
typename Seq>
365 constexpr
static auto allNames = FieldNames<Seq>;
366 if constexpr (HasAutogenPKey<Seq> ())
367 return []<
size_t... Idxs> (std::index_sequence<Idxs...>)
369 const auto [...namesPack] = allNames;
370 return std::tuple { namesPack... [Idxs >= PKeyIndex_v<Seq> ? Idxs + 1 : Idxs]... };
371 } (std::make_index_sequence<SeqSize<Seq> - 1> ());
376 template<
typename Seq,
auto... Ptrs>
379 return std::tuple { detail::FieldNameByPtr<Ptrs>... };
382 template<
typename Seq>
385 const QSqlDatabase DB_;
386 constexpr
static bool HasAutogen_ = HasAutogenPKey<Seq> ();
393 template<
typename Action = InsertAction::DefaultTag>
396 return Run<SQLite::ImplFactory> (t, action);
399 template<
typename ImplFactory>
402 return Run<ImplFactory> (t, action);
405 template<
typename Action = InsertAction::DefaultTag>
408 return Run<SQLite::ImplFactory> (t, action);
411 template<
typename ImplFactory>
412 auto operator() (ImplFactory,
const Seq& t,
auto action)
const 414 return Run<ImplFactory> (t, action);
417 template<
typename ImplFactory,
typename Action>
418 constexpr
static auto MakeInsertSuffix (Action action)
420 if constexpr (HasAutogen_)
422 constexpr
auto pkIdx = PKeyIndex_v<Seq>;
423 if constexpr (std::is_same_v<Action, InsertAction::DefaultTag> || std::is_same_v<Action, InsertAction::IgnoreTag>)
424 return ImplFactory::GetInsertSuffix (action, GetFieldName<Seq, pkIdx> ());
427 ExtractReplaceFields<Seq> (action),
428 GetFieldName<Seq, pkIdx> ());
432 if constexpr (std::is_same_v<Action, InsertAction::DefaultTag> || std::is_same_v<Action, InsertAction::IgnoreTag>)
433 return ImplFactory::GetInsertSuffix (action);
436 ExtractReplaceFields<Seq> (action));
440 template<
typename ImplFactory>
441 constexpr
static auto MakeQueryForAction (
auto action)
443 return ImplFactory::GetInsertPrefix (action) +
444 " INTO " + Seq::ClassName +
445 " (" +
JoinTup (FieldNames<Seq>,
", ") +
") " +
446 "VALUES (" +
JoinTup (BoundFieldNames<Seq>,
", ") +
") " +
447 MakeInsertSuffix<ImplFactory> (action);
450 template<
typename ImplFactory,
typename T,
typename Action>
451 auto Run (T& t, Action action)
const 453 QSqlQuery query { DB_ };
454 constexpr
auto queryText = MakeQueryForAction<ImplFactory> (action);
455 query.prepare (ToString<queryText> ());
459 if constexpr (HasAutogen_)
461 constexpr
auto pkIndex = PKeyIndex_v<Seq>;
462 constexpr
auto mightBeMissing = std::same_as<Action, InsertAction::IgnoreTag>;
467 if constexpr (mightBeMissing)
468 return std::optional<FieldType_t> {};
469 throw QueryException {
"unable to fetch last inserted rowid" };
472 const auto& lastId = Convert<FieldType_t> (query.value (0));
474 if constexpr (!std::is_const_v<T>)
475 Get<pkIndex> (t) = lastId;
477 if constexpr (mightBeMissing)
478 return std::optional { lastId };
485 template<
typename Seq>
493 if constexpr (HasPKey<Seq>)
495 constexpr
auto index = PKeyIndex_v<Seq>;
496 constexpr
auto del =
"DELETE FROM " + Seq::ClassName +
497 " WHERE " + std::get<index> (FieldNames<Seq>) +
" = ?";
504 constexpr
auto index = PKeyIndex_v<Seq>;
511 template<
typename T,
size_t...
Indices>
514 if constexpr (
requires { T { Convert<ValueAtC_t<T, Indices>> (QVariant {})... }; })
515 return T { Convert<ValueAtC_t<T, Indices>> (q.value (startIdx +
Indices))... };
545 template<ExprType Type>
567 static_assert (std::is_same_v<struct D1, ExprType>,
"Invalid expression type");
582 template<ExprType Type>
586 return "lower(" + subexpr +
")";
602 template<ExprType Type,
typename Seq,
typename L,
typename R>
609 return requires (LReal l, RReal r) { l == r; };
615 template<ExprType Type,
typename L =
void,
typename R =
void>
621 template<ExprType Type,
typename L,
typename R>
622 constexpr
bool IsExprTree<ExprTree<Type, L, R>> =
true;
624 template<
typename L,
typename R>
636 template<
typename Seq, CtString S>
639 if constexpr (IsExprTree<L>)
642 return L::template
ToSql<Seq, S +
"l"> () +
", " + R::template ToSql<Seq, S + "r"> ();
645 template<
typename Seq, CtString S>
648 Left_.template
BindValues<Seq, S +
"l"> (query);
649 Right_.template
BindValues<Seq, S +
"r"> (query);
652 template<
typename OL,
typename OR>
659 template<ExprType Type,
typename L,
typename R>
671 template<
typename Seq, CtString S>
674 static_assert (Typecheck<Type, Seq, L, R> (),
675 "Incompatible types passed to a relational operator.");
677 return WrapSubexpr<Type> (L::template
ToSql<Seq, S +
"l"> ()) +
678 " " + TypeToSql<Type> () +
" " +
679 WrapSubexpr<Type> (R::template ToSql<Seq, S + "r"> ());
682 template<
typename Seq, CtString S>
685 Left_.template
BindValues<Seq, S +
"l"> (query);
686 Right_.template
BindValues<Seq, S +
"r"> (query);
692 return std::tuple_cat (L::template AdditionalTables<T> (), R::template AdditionalTables<T> ());
698 return L::template HasAdditionalTables<T> () || R::template HasAdditionalTables<T> ();
715 template<
typename, CtString S>
718 return ":bound_" + S;
721 template<
typename Seq, CtString S>
724 constexpr
auto varName = ToSql<Seq, S> ();
725 query.bindValue (ToString<varName> (),
ToVariantF (Data_));
741 template<
typename... Ts>
746 template<
size_t Idx, CtString S>
747 constexpr
static auto BoundVarName =
":bound_" + S + IntegralToString<Idx> ();
757 template<
typename, CtString S>
762 return "(" +
Join (
", "_ct, BoundVarName<Indices, S>...) +
")";
763 } (std::index_sequence_for<Ts...> {});
766 template<
typename Seq, CtString S>
771 (query.bindValue (
ToString<BoundVarName<Indices, S>> (),
ToVariantF (std::get<Indices> (Data_))), ...);
772 } (std::index_sequence_for<Ts...> {});
791 if constexpr (IsExprTree<T>)
797 template<
auto... Ptr>
808 template<
typename Seq, CtString S>
814 template<
typename Seq, CtString S>
821 return detail::FieldNameByPtr<Ptr>;
828 if constexpr (std::is_same_v<Seq, T>)
837 return !std::is_same_v<MemberPtrStruct_t<Ptr>, T>;
840 constexpr
auto operator= (
const ExpectedType_t& r)
const noexcept 846 template<
auto... Ptrs>
848 class ExprTree<
ExprType::LeafStaticPlaceholder, MemberPtrs<Ptrs...>,
void>
850 using ExpectedType_t = std::tuple<MemberPtrType_t<Ptrs>...>;
853 using ValueType_t = ExpectedType_t;
855 template<
typename Seq, CtString S>
856 constexpr
static auto ToSql ()
noexcept 861 template<
typename Seq, CtString S>
862 void BindValues (QSqlQuery&)
const noexcept 867 constexpr
static auto AdditionalTables ()
noexcept 869 return std::tuple_cat ([]
871 using Seq = MemberPtrStruct_t<Ptrs>;
872 if constexpr (std::is_same_v<Seq, T>)
880 constexpr
static bool HasAdditionalTables ()
noexcept 882 return !(std::is_same_v<MemberPtrStruct_t<Ptrs>, T> || ...);
890 template<
typename, CtString>
896 template<
typename, CtString>
910 template<ExprType Type,
typename L,
typename R>
918 template<
typename L,
typename R>
921 template<
typename L,
typename R>
925 return MakeExprTree<ExprType::Equal> (left, right);
928 template<
typename L,
typename R>
932 return MakeExprTree<ExprType::Less> (left, right);
935 template<
typename L,
typename R>
939 return MakeExprTree<ExprType::Leq> (left, right);
942 template<
typename L,
typename R>
946 return MakeExprTree<ExprType::Greater> (left, right);
949 template<
typename L,
typename R>
953 return MakeExprTree<ExprType::Geq> (left, right);
956 template<
typename L,
typename R>
960 return MakeExprTree<ExprType::Neq> (left, right);
963 template<ExprType Op>
975 template<
typename L, ExprType Op>
981 template<
typename L, ExprType Op>
987 template<
typename L, ExprType Op,
typename R>
990 return MakeExprTree<Op> (left.Left_, right);
993 template<
typename L,
typename R>
997 return MakeExprTree<ExprType::And> (left, right);
1000 template<
typename L,
typename R>
1004 return MakeExprTree<ExprType::Or> (left, right);
1007 template<CtString BindPrefix,
typename Seq,
typename Tree>
1010 return Tree::template ToSql<Seq, BindPrefix> ();
1013 template<CtString BindPrefix,
typename Seq,
typename Tree>
1016 tree.template BindValues<Seq, BindPrefix> (query);
1026 template<AggregateFunction, auto Ptr>
1029 template<
typename FunRetType, CtString Fun, auto Ptr>
1034 template<
typename... MemberDirectionList>
1037 template<
auto... Ptrs>
1042 template<
typename L,
typename R>
1045 template<
typename T>
1051 template<
typename T>
1057 template<AggregateFunction Fun, auto Ptr>
1058 constexpr
bool IsSelector<AggregateType<Fun, Ptr>> =
true;
1060 template<
typename FunRetType, CtString Fun, auto Ptr>
1061 constexpr
bool IsSelector<CustomFunctionType<FunRetType, Fun, Ptr>> =
true;
1063 template<
auto... Ptrs>
1066 template<
typename L,
typename R>
1067 constexpr
bool IsSelector<SelectorUnion<L, R>> =
true;
1069 template<
typename T>
1070 constexpr
bool IsSelector<SelectDistinct<T>> =
true;
1072 template<
typename L,
typename R>
1073 requires IsSelector<L> && IsSelector<R>
1085 template<
auto... Ptrs>
1088 template<
auto... Ptrs>
1093 template<
typename T>
1096 template<
auto... Ptrs>
1099 template<
auto... Ptrs>
1103 template<
auto Ptr = std::true_type {}>
1112 template<
typename FunRetType, CtString Fun, auto Ptr>
1116 template<
typename... Orders>
1119 template<
auto... Ptrs>
1137 return Convert<UnwrapIndirect_t<MemberPtrType_t<Ptr>>> (var);
1143 return MemberFromVariant<Ptr> (q.value (startIdx));
1146 template<
auto... Ptrs>
1149 if constexpr (
sizeof... (Ptrs) == 1)
1152 return [&]<
size_t... Ix> (std::index_sequence<Ix...>)
1154 return std::tuple { MemberFromVariant<Ptrs> (q.value (startIdx + Ix))... };
1155 } (std::make_index_sequence<
sizeof... (Ptrs)> {});
1165 template<
size_t RepIdx,
size_t TupIdx,
typename Tuple,
typename NewType>
1168 if constexpr (RepIdx == TupIdx)
1169 return std::forward<NewType> (arg);
1171 return std::get<TupIdx> (
tuple);
1174 template<
size_t RepIdx,
typename NewType,
typename Tuple,
size_t... TupIdxs>
1179 GetReplaceTupleElem<RepIdx, TupIdxs> (std::forward<Tuple> (
tuple), std::forward<NewType> (arg))...
1183 template<
size_t RepIdx,
typename NewType,
typename... TupleArgs>
1186 return ReplaceTupleElemImpl<RepIdx> (std::move (
tuple),
1187 std::forward<NewType> (arg),
1188 std::index_sequence_for<TupleArgs...> {});
1191 template<
typename Seq,
typename T>
1197 template<
typename Seq,
typename... Args>
1203 template<
typename Seq>
1206 constexpr
static int Value = SeqSize<Seq>;
1209 template<
typename... LArgs,
typename... RArgs>
1212 return std::tuple_cat (std::move (left), std::move (right));
1215 template<
typename... LArgs,
typename R>
1218 return std::tuple_cat (std::move (left),
std::tuple { right });
1221 template<
typename L,
typename... RArgs>
1224 return std::tuple_cat (
std::tuple { left }, std::move (right));
1227 template<
typename L,
typename R>
1239 template<ResultBehaviour ResultBehaviour,
typename ResList>
1243 return std::forward<ResList> (list);
1245 return list.value (0);
1250 const QSqlDatabase DB_;
1258 auto&& binder)
const 1260 QSqlQuery query { DB_ };
1261 query.prepare (queryStr);
1266 qCritical () <<
"select query execution failed";
1275 template<
typename L,
typename O>
1278 if constexpr (std::is_same_v<L, LimitNone>)
1280 static_assert (std::is_same_v<O, OffsetNone>,
"LIMIT-less queries currently cannot have OFFSET");
1284 return " LIMIT :limit "_ct +
1287 if constexpr (std::is_same_v<O, OffsetNone>)
1290 return " OFFSET :offset"_ct;
1294 template<
typename L,
typename O>
1297 if constexpr (!std::is_same_v<std::decay_t<L>,
LimitNone>)
1298 query.bindValue (
":limit", qulonglong { limit.Count });
1299 if constexpr (!std::is_same_v<std::decay_t<O>,
OffsetNone>)
1300 query.bindValue (
":offset", qulonglong { offset.Count });
1303 template<
typename T,
typename Selector>
1309 template<
typename T>
1312 constexpr
static auto Fields =
JoinTup (QualifiedFieldNames<T>,
", "_ct);
1316 return InitializeFromQuery<T> (q, SeqIndices<T>, startIdx);
1320 template<
typename T,
typename U>
1326 template<
typename T,
auto... Ptrs>
1329 constexpr
static auto Fields =
Join (
", ", QualifiedFieldNameByPtr<Ptrs>...);
1337 template<
typename T,
typename FunRetType, CtString Fun, auto Ptr>
1340 constexpr
static auto Fields = ReplaceAll<Fun, '@'> (QualifiedFieldNameByPtr<Ptr>);
1344 return Convert<FunRetType> (q.value (startIdx));
1348 template<
typename T>
1351 constexpr
static auto Fields =
"count(1)"_ct;
1355 return q.value (startIdx).toLongLong ();
1359 template<
typename T, auto Ptr>
1362 constexpr
static auto Fields =
"count(" + QualifiedFieldNameByPtr<Ptr> +
")";
1366 return q.value (startIdx).toLongLong ();
1370 template<CtString Aggregate,
typename T, auto Ptr>
1373 constexpr
static auto Fields = Aggregate +
"(" + QualifiedFieldNameByPtr<Ptr> +
")";
1377 const auto& var = q.value (startIdx);
1378 return var.isNull () ?
1380 std::optional { Convert<UnwrapIndirect_t<MemberPtrType_t<Ptr>>> (var) };
1384 template<
typename T, auto Ptr>
1387 template<
typename T, auto Ptr>
1397 template<
typename T,
typename L,
typename R>
1403 constexpr
static auto ResultBehaviour_v =
CombineBehaviour (HL::ResultBehaviour_v, HR::ResultBehaviour_v);
1405 constexpr
static auto Fields = HL::Fields +
", " + HR::Fields;
1410 return Combine (HL::Initializer (q, startIdx), HR::Initializer (q, startIdx + shift));
1414 template<
typename T, SelectBehaviour SelectBehaviour>
1417 template<
typename ParamsTuple>
1421 ParamsTuple Params_;
1423 template<
typename NewTuple>
1426 return Builder<NewTuple> { W_,
tuple };
1429 template<
typename U>
1430 constexpr
auto Select (U&& selector) &&
noexcept 1432 return RepTuple (ReplaceTupleElem<0> (std::move (Params_), std::forward<U> (selector)));
1435 template<
typename U>
1436 constexpr
auto Where (U&& tree) &&
noexcept 1438 return RepTuple (ReplaceTupleElem<1> (std::move (Params_), std::forward<U> (tree)));
1441 template<
typename U>
1442 constexpr
auto AndWhere (U&& tree) &&
noexcept 1444 return std::move (*this).Where (std::get<1> (Params_) && std::forward<U> (tree));
1447 template<
typename U>
1448 constexpr
auto Order (U&& order) &&
noexcept 1450 return RepTuple (ReplaceTupleElem<2> (std::move (Params_), std::forward<U> (order)));
1453 template<
typename U>
1454 constexpr
auto Group (U&& group) &&
noexcept 1456 return RepTuple (ReplaceTupleElem<3> (std::move (Params_), std::forward<U> (group)));
1461 return RepTuple (ReplaceTupleElem<4> (std::move (Params_), limit));
1466 return std::move (*this).Limit (
oral::Limit { limit });
1471 return RepTuple (ReplaceTupleElem<5> (std::move (Params_), offset));
1476 return std::move (*this).Offset (
oral::Offset { offset });
1481 return std::apply (W_, Params_);
1484 template<
auto... Ptrs>
1485 constexpr
auto Group () &&
noexcept 1504 return Builder<decltype (defParams)> { *
this, defParams };
1512 template<
typename Single>
1515 if constexpr (
IsExprTree<std::decay_t<Single>>)
1516 return (*
this) (
SelectWhole {}, std::forward<Single> (single));
1533 Limit limit = LimitNone {},
1534 Offset offset = OffsetNone {})
const 1536 using TreeType_t = ExprTree<Type, L, R>;
1539 constexpr
auto wherePrefix = [where]
1541 if constexpr (where.IsEmpty ())
1544 return " WHERE "_ct;
1546 constexpr
auto from = BuildFromClause<TreeType_t> ();
1547 const auto binder = [&] (QSqlQuery& query)
1552 using HS = HandleSelector<T, Selector>;
1554 constexpr
auto query =
"SELECT " + HS::Fields +
1556 wherePrefix + where +
1557 HandleOrder (std::forward<Order> (order)) +
1558 HandleGroup (std::forward<Group> (group)) +
1559 LimitOffsetToString<Limit, Offset> ();
1560 auto selectResult = Select<HS> (ToString<query> (), binder);
1561 return HandleResultBehaviour<HS::ResultBehaviour_v> (std::move (selectResult));
1564 template<
typename HS,
typename Binder>
1565 auto Select (
const QString& queryStr,
1566 Binder&& binder)
const 1568 auto query =
RunQuery (queryStr, binder);
1573 while (query.next ())
1574 result << HS::Initializer (query, 0);
1579 using RetType_t = std::optional<decltype (HS::Initializer (query, 0))>;
1580 return query.next () ?
1581 RetType_t { HS::Initializer (query, 0) } :
1586 template<
typename Tree>
1587 consteval
static auto BuildFromClause ()
noexcept 1589 if constexpr (Tree::template HasAdditionalTables<T> ())
1590 return T::ClassName + ", " +
JoinTup (
Nub<Tree::template AdditionalTables<T>> (), ", ");
1592 return T::ClassName;
1595 constexpr static auto HandleOrder (OrderNone)
noexcept 1600 template<
auto... Ptrs>
1601 constexpr
static auto HandleSuborder (sph::asc<Ptrs...>)
noexcept 1603 return std::tuple { (QualifiedFieldNameByPtr<Ptrs> +
" ASC")... };
1606 template<
auto... Ptrs>
1607 constexpr
static auto HandleSuborder (sph::desc<Ptrs...>)
noexcept 1609 return std::tuple { (QualifiedFieldNameByPtr<Ptrs> +
" DESC")... };
1612 template<
typename... Suborders>
1613 constexpr
static auto HandleOrder (OrderBy<Suborders...>)
noexcept 1615 return " ORDER BY " +
JoinTup (std::tuple_cat (HandleSuborder (Suborders {})...),
", ");
1618 constexpr
static auto HandleGroup (GroupNone)
noexcept 1623 template<
auto... Ptrs>
1624 constexpr
static auto HandleGroup (GroupBy<Ptrs...>)
noexcept 1626 return " GROUP BY " +
Join (
", ", QualifiedFieldNameByPtr<Ptrs>...);
1630 template<
typename T>
1633 const QSqlDatabase DB_;
1640 template<ExprType Type,
typename L,
typename R>
1645 constexpr
auto selectAll =
"DELETE FROM " + T::ClassName +
" WHERE " + where;
1647 QSqlQuery query { DB_ };
1648 query.prepare (ToString<selectAll> ());
1654 template<
typename T>
1657 const QSqlDatabase DB_;
1660 QSqlQuery UpdateByPKey_ { DB_ };
1665 if constexpr (HasPKey<T>)
1667 constexpr
auto pkeyIdx = PKeyIndex_v<T>;
1668 constexpr
auto statements =
ZipWith (FieldNames<T>,
" = ", BoundFieldNames<T>);
1669 constexpr
auto update =
"UPDATE " + T::ClassName +
1670 " SET " +
JoinTup (statements,
", ") +
1671 " WHERE " + std::get<pkeyIdx> (statements);
1672 UpdateByPKey_.prepare (ToString<update> ());
1678 DoInsert (seq, UpdateByPKey_,
true);
1681 template<
typename SL,
typename SR, ExprType WType,
typename WL,
typename WR>
1685 "joins in update statements are not supported by SQL");
1690 constexpr
auto update =
"UPDATE " + T::ClassName +
1691 " SET " + setClause +
1692 " WHERE " + whereClause;
1694 QSqlQuery query { DB_ };
1695 query.prepare (ToString<update> ());
1700 qCritical () <<
"update query execution failed";
1705 return query.numRowsAffected ();
1710 template<
typename...>
typename Tgt =
std::tuple,
1711 template<
typename...>
typename Src,
1716 return Tgt {
f (Vals {})... };
1719 template<
typename Seq,
auto... Ptrs>
1722 constexpr
auto query =
"CREATE INDEX IF NOT EXISTS "_ct +
1723 "idx_" + Seq::ClassName +
"_" +
Join (
"_", FieldNameByPtr<Ptrs>...) +
1724 " ON " + Seq::ClassName +
" (" +
Join (
", ", FieldNameByPtr<Ptrs>...) +
")";
1729 template<
typename Seq>
1733 MapTy (
typename Seq::Indices {}, [&db] (
auto index) {
return CreateIndex<Seq> (db, index); });
1736 template<
auto... Ptrs>
1739 return "UNIQUE (" +
Join (
", ", FieldNameByPtr<Ptrs>...) +
")";
1742 template<
auto... Ptrs>
1745 return "PRIMARY KEY (" +
Join (
", ", FieldNameByPtr<Ptrs>...) +
")";
1748 template<
typename T>
1757 template<
typename ImplFactory,
typename T,
size_t...
Indices>
1763 template<auto Name,
typename ImplFactory,
typename T>
1766 constexpr
auto types = GetTypes<ImplFactory, T> (SeqIndices<T>);
1768 constexpr
auto constraints = GetConstraintsStrings<T> ();
1769 constexpr
auto constraintsStr = [&]
1771 if constexpr (!std::tuple_size_v<decltype (constraints)>)
1774 return ", " +
JoinTup (constraints,
", ");
1777 constexpr
auto statements =
ZipWith (FieldNames<T>,
" ", types);
1778 return "CREATE TABLE " +
1786 template<
typename ImplFactory,
typename T>
1789 return AdaptCreateTableNamed<T::ClassName, ImplFactory, T> ();
1793 template<
typename T>
1807 template<
typename T,
typename ImplFactory = detail::SQLite::ImplFactory>
1810 static_assert (BeenAdapted<T>,
"Please use ORAL_ADAPT_STRUCT");
1812 if (!db.tables ().contains (ToString<T::ClassName> (), Qt::CaseInsensitive))
1814 constexpr
auto query = detail::AdaptCreateTable<ImplFactory, T> ();
1818 detail::AdaptCreateIndices<T> (db);
1832 template<
typename T>
1835 template<
typename T,
typename ImplFactory = SQLiteImplFactory>
1838 return std::make_unique<ObjectInfo<T>> (Adapt<T, ImplFactory> (db));
1844 ((objects = AdaptPtr<Ts, ImplFactory> (db)), ...);
DeleteByFieldsWrapper(const QSqlDatabase &db) noexcept
constexpr auto QualifiedFieldNameByPtr
constexpr auto ExtractReplaceFields(InsertAction::Replace::WholeType)
requires EitherIsExprTree< L, R > auto operator<=(const L &left, const R &right) noexcept
static constexpr auto ToSql() noexcept
constexpr bool IsRelational(ExprType type) noexcept
constexpr detail::AggregateType< detail::AggregateFunction::Count, Ptr > count
detail::DeleteByFieldsWrapper< T > DeleteBy
void operator()(const Seq &seq) requires HasPKey< Seq >
constexpr detail::OrderBy< Orders... > OrderBy
constexpr auto HasAutogenPKey() noexcept
constexpr auto LimitOffsetToString() noexcept
SelectWrapperCommon(const QSqlDatabase &db) noexcept
constexpr auto Join(auto &&) noexcept
static constexpr auto ToSql() noexcept
constexpr auto operator()() const noexcept
concept TypeNameCustomizedMember
constexpr bool IsSelector
auto MemberFromVariant(const QVariant &var) noexcept
constexpr auto WrapSubexpr(auto subexpr)
void AdaptPtrs(const QSqlDatabase &db, ObjectInfo_ptr< Ts > &... objects)
requires EitherIsExprTree< L, R > auto operator>=(const L &left, const R &right) noexcept
constexpr detail::AggregateType< detail::AggregateFunction::Max, Ptr > max
static auto Initializer(const QSqlQuery &q, int startIdx)
constexpr auto JoinTup(auto &&stringsTuple, auto &&sep) noexcept
constexpr detail::GroupBy< Ptrs... > GroupBy
constexpr auto ExprTreeToSql() noexcept
static auto Initializer(const QSqlQuery &q, int startIdx)
void AdaptCreateIndices(const QSqlDatabase &db)
requires IsSelector< L > &&IsSelector< R > SelectorUnion< L, R > operator+(L, R) noexcept
void BindExprTree(const Tree &tree, QSqlQuery &query)
static UTIL_DB_API void DumpError(const QSqlError &error)
Dumps the error to the qWarning() stream.
void BindLimitOffset(QSqlQuery &query, L limit, O offset) noexcept
static auto Initializer(const QSqlQuery &q, int startIdx) noexcept
constexpr auto FieldNameByPtr
auto Build() const noexcept
Q_DECL_IMPORT const QString Count
The new total event count (int).
constexpr auto GetFullSize(const Seq &seq)
MemberTypeType_t< decltype(Ptr)> MemberPtrType_t
~QueryException() noexcept=default
T InitializeFromQuery(const QSqlQuery &q, std::index_sequence< Indices... >, int startIdx) noexcept
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptrs... > > tuple
static constexpr bool HasAdditionalTables() noexcept
constexpr ExprTree(const std::tuple< Ts... > &t) noexcept
constexpr auto CreateIndex(const QSqlDatabase &db, Index< Ptrs... >)
static constexpr auto Fields
Q_DECL_IMPORT const QString Tags
consteval int PKeyIndex()
constexpr auto MapTy(Src< Vals... >, auto f)
std::unique_ptr< ObjectInfo< T > > ObjectInfo_ptr
decltype(GetFieldAt< I >(std::declval< T >())) FieldType_t
requires EitherIsExprTree< L, R > auto operator!=(const L &left, const R &right) noexcept
auto DoInsert(const Seq &seq, QSqlQuery &insertQuery, bool bindPrimaryKey)
constexpr auto TypeToSql() noexcept
std::shared_ptr< QSqlQuery > QSqlQuery_ptr
constexpr auto ExtractConstraintFields(UniqueSubset< Ptrs... >)
constexpr auto GetTypes(std::index_sequence< Indices... >) noexcept
auto MakeExprTree(const L &left, const R &right) noexcept
consteval auto GetFieldName()
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptr > > f
constexpr bool IsSelector< SelectWhole >
constexpr auto ReplaceTupleElemImpl(Tuple &&tuple, NewType &&arg, std::index_sequence< TupIdxs... >) noexcept
void BindValues(QSqlQuery &query) const noexcept
static constexpr auto ToSql() noexcept
static constexpr bool HasAdditionalTables() noexcept
Type
Describes the various types of XDG .desktop files.
constexpr detail::CustomFunctionType< FunRetType, Fun, Ptr > fun
static constexpr auto ResultBehaviour_v
constexpr auto SeqIndices
detail::SQLite::ImplFactory SQLiteImplFactory
detail::AdaptUpdate< T > Update
void BindValues(QSqlQuery &query) const noexcept
constexpr auto AdaptCreateTableNamed() noexcept
QString ToString() noexcept
static auto Initializer(const QSqlQuery &q, int startIdx) noexcept
consteval auto MorphFieldName()
static constexpr bool HasAdditionalTables() noexcept
auto operator()(Seq &t, Action action={}) const
requires EitherIsExprTree< L, R > auto operator>(const L &left, const R &right) noexcept
SelectDistinct(T) noexcept
constexpr int PKeyIndex_v
ObjectInfo_ptr< T > AdaptPtr(const QSqlDatabase &db)
constexpr detail::InfixBinary< detail::ExprType::ILike > ilike
static constexpr auto AdditionalTables() noexcept
consteval int PKeyIndexUnsafe()
A somewhat "strong" typedef.
typename AsTypelist< T >::Result_t AsTypelist_t
void BindAtIndex(const Seq &seq, QSqlQuery &query, bool bindPrimaryKey)
static constexpr auto ToSql() noexcept
void BindValues(QSqlQuery &query) const noexcept
static constexpr auto ToSql() noexcept
AdaptUpdate(const QSqlDatabase &db) noexcept
detail::AdaptInsert< T > Insert
requires(!std::same_as< T, QVariant >) struct ConvertT
auto ZipWith(const Container< T1 > &c1, const Container< T2 > &c2, F f)
std::decay_t< decltype(Get< Idx >(std::declval< Seq >()))> ValueAtC_t
static constexpr auto AdditionalTables() noexcept
void BindValues(QSqlQuery &) const noexcept
static constexpr int Value
decltype(auto) constexpr Get(const Seq &seq)
constexpr auto ReplaceTupleElem(std::tuple< TupleArgs... > &&tuple, NewType &&arg) noexcept
static auto Initializer(const QSqlQuery &q, int startIdx)
detail::SelectWrapper< T, detail::SelectBehaviour::Some > Select
auto Combine(std::tuple< LArgs... > &&left, std::tuple< RArgs... > &&right) noexcept
constexpr detail::InfixBinary< detail::ExprType::Like > like
constexpr auto MemberNameByPtr
auto Tup2 &&tup2 noexcept
decltype(auto) HandleResultBehaviour(ResList &&list) noexcept
constexpr detail::MemberPtrs< Ptrs... > fields
static constexpr auto ResultBehaviour_v
QSqlQuery RunTextQuery(const QSqlDatabase &db, const QString &text)
Runs the given query text on the given db.
constexpr auto operator,(const AssignList< OL, OR > &tail) noexcept
constexpr detail::AggregateType< detail::AggregateFunction::Min, Ptr > min
requires EitherIsExprTree< L, R > auto operator &&(const L &left, const R &right) noexcept
constexpr auto AsLeafData(const T &node) noexcept
typename std::conditional_t< IsIndirect< T > {}, T, WrapDirect< T > >::value_type UnwrapIndirect_t
MemberTypeStruct_t< decltype(Ptr)> MemberPtrStruct_t
static auto Initializer(const QSqlQuery &q, int startIdx) noexcept
constexpr ExprTree(const L &l, const R &r) noexcept
constexpr auto MemberNameByIdx
constexpr auto FieldNames
ExpectedType_t ValueType_t
ObjectInfo< T > Adapt(const QSqlDatabase &db)
decltype(auto) constexpr GetReplaceTupleElem(Tuple &&tuple, NewType &&arg) noexcept
detail::SelectWrapper< T, detail::SelectBehaviour::One > SelectOne
auto RunQuery(const QString &queryStr, auto &&binder) const
void BindValues(QSqlQuery &) const noexcept
constexpr detail::SelectWhole all
constexpr AssignList(const L &l, const R &r) noexcept
Typelist< Args... > Constraints
static constexpr auto AdditionalTables() noexcept
requires EitherIsExprTree< L, R > auto operator||(const L &left, const R &right) noexcept
constexpr auto GetConstraintsStrings() noexcept
constexpr ExprTree(const T &t) noexcept
std::tuple< Ts... > ValueType_t
requires EitherIsExprTree< L, R > auto operator<(const L &left, const R &right) noexcept
detail::AdaptDelete< T > Delete
requires EitherIsExprTree< L, R > auto operator==(const L &left, const R &right) noexcept
constexpr auto QualifiedFieldNames
auto operator|(const L &left, InfixBinary< Op >) noexcept
Typelist< Args... > Indices
constexpr auto BoundFieldNames
static constexpr auto GetFieldName() noexcept
void BindValues(QSqlQuery &query) const noexcept
constexpr bool BeenAdapted
static constexpr auto ToSql() noexcept
static constexpr bool HasAdditionalTables() noexcept
static constexpr bool HasAdditionalTables() noexcept
constexpr auto CombineBehaviour(ResultBehaviour l, ResultBehaviour r) noexcept
auto MakeIndexedQueryHandler(const QSqlQuery &q, int startIdx=0) noexcept
static auto Initializer(const QSqlQuery &q, int startIdx)
constexpr auto AdaptCreateTable() noexcept
constexpr bool IsExprTree
std::tuple_element_t< 0, detail::CallTypeGetter_t< F > > RetType_t
static constexpr auto AdditionalTables() noexcept
QVariant ToVariantF(const T &t) noexcept
concept BaseTypeCustomized
constexpr auto ConstTrueTree_v
AdaptDelete(const QSqlDatabase &db) noexcept
AdaptInsert(const QSqlDatabase &db) noexcept
constexpr bool Typecheck()
A proper void type, akin to unit (or ()) type in functional languages.