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>
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>> {};
115 template<
size_t...
Vals>
116 QStringList Run (std::index_sequence<Vals...>)
const noexcept
136 return &boost::fusion::at_c<Idx> (
Obj_);
140 template<auto Ptr,
size_t Idx = 0>
151 if constexpr (std::is_same_v<
decltype (
direct),
decltype (
indexed)>)
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;
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>
234 template<
typename ImplFactory, auto Ptr>
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);
257 return t.ToVariant ();
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> ());
277 return T::FromVariant (
var);
281 return var.value<T> ();
290 template<
typename U,
typename... Tags>
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));
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>
352 template<
typename Seq>
378 template<
typename Seq>
388 template<
typename ImplFactory>
390 : Data_ { RemovePKey (data) }
391 , QueryBuilder_ {
factory.MakeInsertQueryBuilder (
db, Data_) }
405 template<
bool UpdatePKey,
typename Val>
408 const auto query = QueryBuilder_->GetQuery (
action);
412 if constexpr (HasAutogen_)
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_ +
462 template<
bool B = HasPKey>
467 template<
bool B = HasPKey>
474 template<
typename T,
typename...
Args>
477 template<
typename T,
size_t...
Indices>
485 const auto dummy = std::initializer_list<int>
540 return "invalid 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>
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.");
678 template<
typename ObjT>
681 const auto&
name =
":bound_" + QString::number (++
state.LastID_);
708 template<
auto... 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>>
784 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
790 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
796 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
802 template<ExprType Op>
813 template<
typename L, ExprType Op>
819 template<
typename L, ExprType Op>
825 template<
typename L, ExprType Op,
typename R>
831 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
837 template<
typename L,
typename R,
typename = EnableRelOp_t<L, R>>
864 template<
typename Seq,
typename Tree,
865 typename =
decltype (std::declval<Tree> ().ToSql (std::declval<
ToSqlState<Seq>&> ()))>
877 for (
const auto& pair :
Stlize (
state.BoundMembers_))
878 query.bindValue (pair.first, pair.second);
891 template<AggregateFunction, auto Ptr>
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>
990 if constexpr (
sizeof... (
Ptrs) == 1)
1006 template<
auto...
Ptrs>
1019 template<
size_t RepIdx,
size_t TupIdx,
typename Tuple,
typename NewType>
1023 return std::forward<NewType> (
arg);
1025 return std::get<TupIdx> (
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>
1063 template<
typename...
LArgs,
typename...
RArgs>
1066 return std::tuple_cat (std::move (
left), std::move (
right));
1069 template<
typename...
LArgs,
typename R>
1072 return std::tuple_cat (std::move (
left), std::tuple {
right });
1075 template<
typename L,
typename...
RArgs>
1078 return std::tuple_cat (std::tuple {
left }, std::move (
right));
1081 template<
typename L,
typename R>
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>
1143 if (!
where.isEmpty ())
1144 where.prepend (
" WHERE ");
1146 const auto&
queryStr =
"SELECT " + fields +
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>)
1191 " OFFSET " + QString::number (
offset.Count);
1195 template<
typename T, SelectBehaviour SelectBehaviour>
1200 template<
typename ParamsTuple>
1206 template<
typename NewTuple>
1209 return Builder<NewTuple> { W_,
tuple };
1212 template<
typename U>
1213 constexpr auto Select (
U&&
selector) &&
noexcept
1218 template<
typename U>
1219 constexpr auto Where (
U&&
tree) &&
noexcept
1224 template<
typename U>
1225 constexpr auto Order (
U&&
order) &&
noexcept
1230 template<
typename U>
1231 constexpr auto Group (
U&&
group) &&
noexcept
1236 template<
typename U = Limit>
1242 template<
typename U = Offset>
1250 return std::apply (W_, Params_);
1253 template<
auto...
Ptrs>
1254 constexpr auto Group () &&
noexcept
1260 template<
typename ImplFactory>
1286 template<
typename Single>
1308 Offset
offset = OffsetNone {})
const
1314 Select (fields, BuildFromClause (
tree),
1317 HandleOrder (std::forward<Order> (
order)),
1318 HandleGroup (std::forward<Group> (
group)),
1322 template<
typename Binder,
typename Initializer>
1331 if constexpr (!std::is_same_v<Void, std::decay_t<Binder>>)
1338 while (
query.next ())
1345 return query.next () ?
1351 template<ExprType Type,
typename L,
typename R>
1365 auto HandleSelector (SelectWhole)
const noexcept
1374 ResultBehaviour::All {}
1378 template<
auto...
Ptrs>
1385 ResultBehaviour::All {}
1395 ResultBehaviour::First {}
1406 ResultBehaviour::First {}
1417 ResultBehaviour::First {}
1428 ResultBehaviour::First {}
1432 template<
typename L,
typename R>
1435 const auto&
lSel = HandleSelector (
L {});
1436 const auto&
rSel = HandleSelector (
R {});
1443 lSel.Fields_ +
", " +
rSel.Fields_,
1446 constexpr auto shift = DetectShift<T,
decltype (
lHandler (
q))>::Value;
1453 QString HandleOrder (OrderNone)
const noexcept
1458 template<
auto...
Ptrs>
1464 template<
auto...
Ptrs>
1465 QList<QString> HandleSuborder (sph::desc<Ptrs...>)
const noexcept
1476 QString HandleGroup (GroupNone)
const noexcept
1481 template<
auto...
Ptrs>
1488 template<
typename T>
1496 , Table_ (data.Table_)
1500 template<ExprType Type,
typename L,
typename R>
1506 const auto&
selectAll =
"DELETE FROM " + Table_ +
1516 template<
typename T,
bool HasPKey = HasPKey<T>>
1522 std::function<
void (T)> Updater_;
1526 , Table_ { data.Table_ }
1530 constexpr auto index = FindPKey<T>::result_type::value;
1535 const auto&
update =
"UPDATE " + data.Table_ +
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");
1560 const auto&
update =
"UPDATE " + Table_ +
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>
1629 return "CREATE TABLE " +
1638 template<
auto...
Ptrs>
1644 template<
typename Seq>
1651 template<
typename T>
1665 template<
typename T,
typename ImplFactory = detail::SQLite::ImplFactory>
1670 if (!
db.tables ().contains (
cachedData.Table_, Qt::CaseInsensitive))
1687 template<
typename T>
1690 template<
typename T,
typename ImplFactory = SQLiteImplFactory>
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>
1708 template<
typename ImplFactory,
typename 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.
typename boost::fusion::result_of::value_at_c< Seq, Idx >::type ValueAtC_t
auto operator>(const L &left, const R &right) noexcept
QString GetQualifiedFieldNamePtr() noexcept
decltype(std::declval< UnwrapIndirect_t< typename L::template ValueType_t< Seq > > >()== std::declval< UnwrapIndirect_t< typename R::template ValueType_t< Seq > > >()) ComparableDetector
typename T::BaseType BaseTypeDetector
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
std::enable_if_t< EitherIsExprTree< L, R >()> EnableRelOp_t
QList< QString > GetTypes(std::index_sequence< Indices... >) noexcept
QString GetFieldName() noexcept
constexpr CountAll * CountAllPtr
constexpr auto AreComparableTypes
constexpr auto ConstTrueTree_v
typename T::Constraints ConstraintsDetector
typename std::decay_t< std::tuple_element_t< Idx, Tuple > >::element_type::ObjectType_t UnderlyingObject_t
void AdaptPtrs(const QSqlDatabase &db, Tuple &tuple, std::index_sequence< Idxs... >)
QVariant ToVariantF(const T &t) noexcept
constexpr bool IsRelational(ExprType type) noexcept
auto MakeIndexedQueryHandler() noexcept
decltype(T::TypeName) TypeNameDetector
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
decltype(std::declval< U >().FieldNameMorpher(QString {})) MorpherDetector
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 std::conditional_t< IsIndirect< T > {}, T, WrapDirect< T > >::value_type UnwrapIndirect_t
QStringList BuildFieldNames() noexcept
auto operator==(const L &left, const R &right) noexcept
QString GetFieldNamePtr() noexcept
auto operator<(const L &left, const R &right) noexcept
typename boost::fusion::result_of::value_at< Seq, Idx >::type ValueAt_t
constexpr auto SeqIndices
constexpr auto HasAutogenPKey() noexcept
auto HandleExprTree(const ExprTree< ExprType::ConstTrue > &, int lastId=0) noexcept
constexpr auto CombineBehaviour(L, R) noexcept
Util::IsDetected_t< Constraints<>, ConstraintsDetector, T > ConstraintsType
std::unique_ptr< IInsertQueryBuilder > IInsertQueryBuilder_ptr
QString TypeToSql(ExprType type) noexcept
QString MorphFieldName(QString str) noexcept
auto operator|(const L &left, InfixBinary< Op >) noexcept
decltype(new T { std::declval< Args >()... }) AggregateDetector_t
CachedFieldsData BuildCachedFieldsData() noexcept
auto operator&&(const L &left, const R &right) noexcept
boost::mpl::int_< FindPKey< Seq >::result_type::value > FindPKeyDetector
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
constexpr detail::GroupBy< Ptrs... > GroupBy
ObjectInfo< T > Adapt(const QSqlDatabase &db)
std::shared_ptr< ObjectInfo< T > > ObjectInfo_ptr
std::shared_ptr< QSqlQuery > QSqlQuery_ptr
typename AsTypelist< T >::Result_t AsTypelist_t
Container< T > Filter(const Container< T > &c, F f)
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)
std::tuple_element_t< 0, decltype(detail::TypeGetter(*static_cast< F * >(nullptr)))> RetType_t
auto Map(Container &&c, F f)
MemberTypeType_t< decltype(Ptr)> MemberPtrType_t
typename detail::IsDetected< Type, void, Op, Args... >::type IsDetected_t
MemberTypeStruct_t< decltype(Ptr)> MemberPtrStruct_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_