5#include "qx/sql/qx_sql_export.h"
14#include "qx/sql/qx-sqlerror.h"
15#include "qx/sql/qx-sqlresult.h"
16#include "qx/sql/qx-sqlstring.h"
17#include "qx/sql/__private/qx-sqlquery_p.h"
18#include "qx/sql/__private/qx-sqlstring_helpers.h"
23using namespace Qt::StringLiterals;
27#define __QX_SQL_META_STRUCT_INSIDE(id, meta_tuple) \
28 template <typename StructT> \
29 struct QxSqlMetaStructInside \
31 static inline constexpr Qx::CStringLiteral ID = id; \
32 static inline constexpr Qx::CStringLiteral ID_QUOTED = "\"" id "\""; \
33 static inline constexpr auto memberMetadata() \
39#define __QX_SQL_META_STRUCT_OUTSIDE(self_type, id, meta_tuple) \
42 template <typename StructT> \
43 struct QxSqlMetaStructOutside<self_type, StructT> \
45 static inline constexpr Qx::CStringLiteral ID = id; \
46 static inline constexpr Qx::CStringLiteral ID_QUOTED = "\"" id "\""; \
47 static inline constexpr auto memberMetadata() \
54#define __QX_SQL_QUERY_STRUCT_MEMBER(member) static inline const Qx::SqlString member = Qx::SqlString::makeIdentifier(u ## #member);
57#define QX_SQL_QUERY_STRUCT(struct_name, id, ...) \
60 static inline const Qx::SqlString _ = Qx::SqlString::makeIdentifier(u ## id); \
61 QX_FOR_EACH(__QX_SQL_QUERY_STRUCT_MEMBER, __VA_ARGS__) \
64#define QX_SQL_MEMBER(member) QxSqlPrivate::makeMemberMetadata<#member>(&StructT::member)
65#define QX_SQL_MEMBER_ALIASED(member, field) QxSqlPrivate::makeMemberMetadata<field>(&StructT::member)
73#define QX_SQL_STRUCT(id, ...) __QX_SQL_META_STRUCT_INSIDE(id, std::make_tuple(QX_FOR_EACH_DELIM(QX_SQL_MEMBER, __VA_ARGS__)))
74#define QX_SQL_STRUCT_X(id, ...) __QX_SQL_META_STRUCT_INSIDE(id, std::make_tuple(__VA_ARGS__))
76#define QX_SQL_STRUCT_FULL(id, query_struct, ...) \
77 QX_SQL_STRUCT(id, __VA_ARGS__) \
78 QX_SQL_QUERY_STRUCT(query_struct, id, __VA_ARGS__)
80#define QX_SQL_STRUCT_OUTSIDE(Struct, id, ...) __QX_SQL_META_STRUCT_OUTSIDE(Struct, id, std::make_tuple(QX_FOR_EACH_DELIM(QX_SQL_MEMBER, __VA_ARGS__)))
81#define QX_SQL_STRUCT_OUTSIDE_X(Struct, id, ...) __QX_SQL_META_STRUCT_OUTSIDE(Struct, id, std::make_tuple(__VA_ARGS__))
83#define QX_SQL_STRUCT_OUTSIDE_FULL(Struct, id, query_struct, ...) \
84 QX_SQL_STRUCT_OUTSIDE(Struct, id, __VA_ARGS__) \
85 QX_SQL_QUERY_STRUCT(query_struct, id, __VA_ARGS__)
88#define QX_SQL_STRUCT_OUTSIDE_FRIEND(struct_type) friend QxSql::QxSqlMetaStructOutside<struct_type, struct_type>;
90#define QX_SQL_MEMBER_OVERRIDE(Struct, member, ...) \
94 struct MemberOverrideConverter<Struct, #member> \
101#define __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG_X(keyword, method) \
104 appendKeyword(u ## #keyword ## _s); \
108#define __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG(keyword) __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG_X(keyword, keyword)
110#define __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_X(keyword, method) \
111 template<sql_stringable First> \
112 auto& method(First&& fs) \
114 appendKeyword(u ## #keyword ## _s, std::forward<First>(fs)); \
118#define __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_PAREN_X(keyword, method) \
119 template<sql_stringable First> \
120 auto& method(First&& fs) \
122 using namespace QxSql; \
123 appendKeywordParen(u ## #keyword ## _s, std::forward<First>(fs)); \
127#define __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(keyword) __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_X(keyword, keyword)
128#define __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_PAREN(keyword) __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_PAREN_X(keyword, keyword)
130#define __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_X(keyword, method) \
131 template<sql_stringable First, sql_stringable ...Rest> \
132 auto& method(First&& fs, Rest&&... s) \
134 appendKeyword(u ## #keyword ## _s, std::forward<First>(fs), std::forward<Rest>(s)...); \
138#define __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_PAREN_X(keyword, method) \
139 template<sql_stringable First, sql_stringable ...Rest> \
140 auto& method(First&& fs, Rest&&... s) \
142 using namespace QxSql; \
143 appendKeywordParen(u ## #keyword ## _s, std::forward<First>(fs), std::forward<Rest>(s)...); \
147#define __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG(keyword) __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_X(keyword, keyword)
148#define __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_PAREN(keyword) __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_PAREN_X(keyword, keyword)
151#define __QX_SQL_QUERY_ADD_KEYWORD_SUB_QUERY_X(keyword, method) \
152 auto& method(const SqlQuery& q) \
154 appendKeywordParen(u ## #keyword ## _s, q.string()); \
158#define __QX_SQL_QUERY_ADD_KEYWORD_SUB_QUERY(keyword) __QX_SQL_QUERY_ADD_KEYWORD_SUB_QUERY_X(keyword, keyword)
183 inline Binding(
const QString& ph,
const QVariant& d) : ph(ph), data(d) {}
190 QList<Binding> mBindings;
205 template<
typename FirstArg,
typename ...RestArgs>
206 void appendKeyword(
const QString& word, FirstArg&& firstArg, RestArgs&&... restArgs)
208 _QxPrivate::appendKeyword(mQueryStr, word, std::forward<FirstArg>(firstArg), std::forward<RestArgs>(restArgs)...);
211 template<
typename FirstArg,
typename ...RestArgs>
212 void appendKeywordParen(
const QString& word, FirstArg&& firstArg, RestArgs&&... restArgs)
214 _QxPrivate::appendKeywordParen(mQueryStr, word, std::forward<FirstArg>(firstArg), std::forward<RestArgs>(restArgs)...);
217 template <std::ranges::input_range R>
218 void appendKeywordParen(
const QString& word,
const R& range)
220 _QxPrivate::appendKeywordParen(mQueryStr, word, range);
223 void appendKeyword(
const QString& word);
224 void append(QStringView sql,
bool space =
true);
230 QString autoBindValue(QVariant&& d);
231 SqlError executeQuery(QSqlQuery& result,
bool forwardOnly);
240 void bindValue(
const QString& placeholder,
const QVariant& val);
244template<
typename Derived>
250 Derived* this_d =
static_cast<Derived*
>(
this);
263 Derived& select_impl(
bool distinct,
First&& fsel, Rest&&... sel)
265 appendKeyword(distinct ? u
"SELECT DISTINCT"_s : u
"SELECT"_s, std::forward<First>(fsel), std::forward<Rest>(sel)...);
270 Derived& select_impl(
bool distinct)
274 auto getColumnNames = []<
typename Struct>() {
275 constexpr auto members = QxSqlPrivate::getMemberMeta<Struct>();
278 return std::apply([](
auto const&... m) {
279 if constexpr (
sizeof...(Structs) == 1)
280 return std::make_tuple(QLatin1String(m.M_NAME_QUOTED)...);
283 constexpr auto idq = QxSqlPrivate::getStructIdQuoted<Struct>().view();
284 return std::make_tuple(idq +
"."_L1 + QLatin1String(m.M_NAME_QUOTED)...);
290 auto allColumnNames = std::tuple_cat(getColumnNames.template
operator()<Structs>()...);
293 std::apply([&](
auto const&... cols) {
294 appendKeyword(distinct ? u
"SELECT DISTINCT"_s : u
"SELECT"_s, cols...);
320 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
AS);
323 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
BETWEEN);
327 __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG(
CASE);
333 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
ELSE);
336 __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG(
END);
339 __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG(
FROM);
344 constexpr auto idqs = std::make_tuple(
345 (QxSqlPrivate::getStructIdQuoted<First>()).view(),
346 (QxSqlPrivate::getStructIdQuoted<Rest>()).view()...
348 std::apply([&](
const auto&... idqs) {
349 appendKeyword(u
"FROM"_s, idqs...);
356 __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_PAREN(
IN);
357 __QX_SQL_QUERY_ADD_KEYWORD_SUB_QUERY(
IN);
359 template <std::ranges::input_range R>
361 Derived&
IN(
const R& range)
363 appendKeywordParen(u
"IN"_s, range);
368 __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG(
IS);
369 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
IS);
372 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
ON);
378 return select_impl(
false, std::forward<First>(fsel), std::forward<Rest>(sel)...);
384 return select_impl(
true, std::forward<First>(fsel), std::forward<Rest>(sel)...);
394 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
THEN);
397 __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG(
WHEN);
398 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
WHEN);
401 __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG(
WHERE);
402 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
WHERE);
404 Derived&
verbatim(
const QString& sql,
bool space =
true) { append(sql, space);
return *this_d; }
418 SqlError selectSizeWorkaround(
int& size);
419 SqlError executeQueryWithSize(QSqlQuery& result,
int& size,
bool forwardOnly);
423 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
ESCAPE);
426 __QX_SQL_QUERY_ADD_KEYWORD_SUB_QUERY(
EXISTS);
429 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_X(GROUP BY,
GROUP_BY);
432 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
HAVING);
435 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
ILIKE);
438 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
JOIN);
441 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
LIKE);
444 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
LIMIT);
447 __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG(
NOT);
448 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
NOT);
451 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
OFFSET);
454 __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_X(ORDER BY,
ORDER_BY);
457 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_X(SIMILAR TO,
SIMILAR_TO);
460 template<QxSql::sql_containing Container>
464 QSqlQuery queryResult;
465 if(
auto err = executeQuery(queryResult,
true); err.isValid())
472 if(!queryResult.isValid())
476 if(
auto err = QxSqlPrivate::RowConverter<Container>::fromSql(result, queryResult); err.isValid())
477 return err.withQuery(*
this);
483 template<QxSql::sql_containing Container>
498 QSqlQuery queryResult;
500 if(
auto err = executeQueryWithSize(queryResult, queryResultSize,
true); err.isValid())
501 return err.withQuery(*
this);
504 if(queryResultSize < 1)
508 if(
auto err = QxSqlPrivate::RowChecker<T>::check(queryResult.record()); err.isValid())
512 result =
SqlResult<T>(std::move(queryResult), queryResultSize);
521 static_assert(std::default_initializable<T>,
"T must be default constructable to use this overload!");
525 result = (!err && !res.isEmpty()) ? res.first() : T{};
540 __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG(
DELETE);
546 appendKeyword(u
"INSERT INTO"_s, table, u
"("_s, std::forward<First>(first), std::forward<Rest>(rest)..., u
")"_s);
550 template<QxSql::sql_struct Struct>
553 constexpr auto table = QxSqlPrivate::getStructIdQuoted<Struct>().view();
554 constexpr auto members = QxSqlPrivate::getMemberMeta<Struct>();
555 std::apply([&](
const auto&... m) {
556 appendKeyword(u
"INSERT INTO"_s, table, u
"("_s, QLatin1String(m.M_NAME_QUOTED)..., u
")"_s);
566 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_X(MERGE INTO,
MERGE_INTO);
569 template<QxSql::sql_struct Struct>
570 auto&
SET(
const Struct& s)
573 constexpr auto members = QxSqlPrivate::getMemberMeta<Struct>();
574 std::apply([&](
auto&&... m) {
578 using Meta = std::remove_reference_t<
decltype(m)>;
579 using mType =
typename Meta::M_TYPE;
580 constexpr QLatin1StringView mFieldId(Meta::M_NAME_QUOTED);
581 auto& mRef = s.*(m.mPtr);
582 return mFieldId + u
" = "_s + autoBindValue(QxSql::Converter<mType>::toSql(mRef));
590 __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG(
SET);
596 __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(
UPDATE);
598 template<QxSql::sql_struct Struct>
601 appendKeyword(u
"UPDATE"_s, QxSqlPrivate::getStructIdQuoted<Struct>().view());
606 template<QxSql::sql_struct Struct>
610 constexpr auto members = QxSqlPrivate::getMemberMeta<Struct>();
611 std::apply([&](
auto&&... m) {
615 using Meta = std::remove_reference_t<
decltype(m)>;
616 using mType =
typename Meta::M_TYPE;
617 auto& mRef = s.*(m.mPtr);
619 return autoBindValue(QxSql::Converter<mType>::toSql(mRef));
628 __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_PAREN(
VALUES);
635#undef __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG_X
636#undef __QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG
637#undef __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_X
638#undef __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_PAREN_X
639#undef __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG
640#undef __QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_PAREN
641#undef __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_X
642#undef __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_PAREN_X
643#undef __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG
644#undef __QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_PAREN
645#undef __QX_SQL_QUERY_ADD_KEYWORD_SUB_QUERY_X
646#undef __QX_SQL_QUERY_ADD_KEYWORD_SUB_QUERY
AbstractSqlQuery is a common base class from which all query types are derived, and provides common S...
Definition qx-sqlquery.h:246
Derived & verbatim(const QString &sql, bool space=true)
Definition qx-sqlquery.h:404
Derived & FROM()
Definition qx-sqlquery.h:342
Derived & SELECT_DISTINCT()
Definition qx-sqlquery.h:391
Derived & SELECT_DISTINCT(First &&fsel, Rest &&... sel)
Definition qx-sqlquery.h:382
Derived & SELECT()
Definition qx-sqlquery.h:388
Derived & SELECT(First &&fsel, Rest &&... sel)
Definition qx-sqlquery.h:376
auto & BETWEEN(First &&fs)
auto & FROM(First &&fs, Rest &&... s)
auto & IN(First &&fs, Rest &&... s)
Derived & IN(const R &range)
Definition qx-sqlquery.h:361
The SqlDatabase class provides straightforward access to an SQL database.
Definition qx-sqldatabase.h:36
auto & MERGE_INTO(First &&fs)
auto & INSERT_INTO(const SqlString &table, First &&first, Rest &&... rest)
Definition qx-sqlquery.h:544
SqlError execute(int &affected)
Definition qx-sqlquery.cpp:536
auto & INSERT_INTO()
Definition qx-sqlquery.h:551
auto & UPDATE(First &&fs)
auto & UPDATE()
Definition qx-sqlquery.h:599
auto & VALUES(const Struct &s)
Definition qx-sqlquery.h:607
auto & SET(const Struct &s)
Definition qx-sqlquery.h:570
SqlDmlQuery()
Definition qx-sqlquery.cpp:483
SqlError execute(T &result)
Definition qx-sqlquery.h:519
SqlError execute(Container &result)
Definition qx-sqlquery.h:484
SqlDqlQuery()
Definition qx-sqlquery.cpp:354
auto & GROUP_BY(First &&fs)
auto & EXISTS(const SqlQuery &q)
auto & ORDER_BY(First &&fs, Rest &&... s)
auto & HAVING(First &&fs)
auto & OFFSET(First &&fs)
SqlError appendExecute(Container &result)
Definition qx-sqlquery.h:461
auto & ESCAPE(First &&fs)
auto & SIMILAR_TO(First &&fs)
SqlError execute(SqlResult< T > &result)
Definition qx-sqlquery.h:492
The SqlError class is used to report errors related to database configuration and SQL queries.
Definition qx-sqlerror.h:21
SqlError & withQuery(const SqlQuery &q)
Definition qx-sqlerror.cpp:112
SqlQuery is a base class from which all query types derive.
Definition qx-sqlquery.h:171
SqlDatabase * database()
Definition qx-sqlquery.cpp:251
bool hasDatabase() const
Definition qx-sqlquery.cpp:246
QString string() const
Definition qx-sqlquery.cpp:240
void bindValue(const QString &placeholder, const QVariant &val)
Definition qx-sqlquery.cpp:265
The SqlResult class provides sequential, efficient access to a SELECT/DQL query result.
Definition qx-sqlresult.h:29
The SqlString class is a convenience class for more easily building SQL statements in a natural manne...
Definition qx-sqlstring.h:36
Specifies that a type is a SQL-tied struct.
Definition qx-sqlconcepts.h:42
Specifies that a type can be converted to SqlString, or used to construct a SqlString.
Definition qx-sqlstring.h:33
The Qx namespace is the main namespace through which all non-global functionality of the Qx library i...
Definition qx-abstracterror.cpp:13
@ First
Definition qx-global.h:19
The qx-concepts header file provides a set of various object-like and function-like macros that are d...
The qx-sqlconcepts header file provides a set of concepts that are specific to the Qx SQL module.