allowed to pass QueryBuilder to whereExists

Refactored whereExists() to accept the std::shared_ptr<QueryBuilder> and
QueryBuilder &.

 - added unit and functional test
 - updated docs
 - updated all proxies
This commit is contained in:
silverqx
2023-02-20 16:50:48 +01:00
parent 09780885ab
commit 362be240c6
10 changed files with 400 additions and 135 deletions

View File

@@ -657,7 +657,26 @@ The `whereExists` method allows you to write "where exists" SQL clauses. The `wh
})
.get();
The query above will produce the following SQL:
Alternatively, you may provide a query object to the `whereExists` method instead of a lambda expression:
// Ownership of the std::shared_ptr<QueryBuilder>
auto builder = DB::table("orders");
auto orders = builder->select(DB::raw(1))
.whereColumnEq("orders.user_id", "users.id");
auto users = DB::table("users")
->whereExists(orders)
.get();
Or directly:
auto users = DB::table("users")
->whereExists(DB::table("orders")
->select(DB::raw(1))
.whereColumnEq("orders.user_id", "users.id"))
.get();
All of the examples above will produce the following SQL:
```sql
select * from users

View File

@@ -39,6 +39,12 @@ namespace Query
concept Queryable = std::convertible_to<T, Orm::QueryBuilder &> ||
std::invocable<T, Orm::QueryBuilder &>;
/*! Concept for a queryable parameter (adds the std::shared_ptr<QueryBuilder>). */
template<typename T>
concept QueryableShared =
Queryable<T> ||
std::convertible_to<T, const std::shared_ptr<Orm::QueryBuilder> &>;
/*! Concept for whereSub()'s value parameter. */
template<typename T>
concept WhereValueSubQuery = Queryable<T>;

View File

@@ -532,16 +532,18 @@ namespace Orm::Query
/* where exists */
/*! Add an exists clause to the query. */
Builder &whereExists(const std::function<void(Builder &)> &callback,
const QString &condition = AND, bool nope = false);
template<QueryableShared C>
Builder &whereExists(C &&callback, const QString &condition = AND,
bool nope = false);
/*! Add an or exists clause to the query. */
Builder &orWhereExists(const std::function<void(Builder &)> &callback,
bool nope = false);
template<QueryableShared C>
Builder &orWhereExists(C &&callback, bool nope = false);
/*! Add a where not exists clause to the query. */
Builder &whereNotExists(const std::function<void(Builder &)> &callback,
const QString &condition = AND);
template<QueryableShared C>
Builder &whereNotExists(C &&callback, const QString &condition = AND);
/*! Add a where not exists clause to the query. */
Builder &orWhereNotExists(const std::function<void(Builder &)> &callback);
template<QueryableShared C>
Builder &orWhereNotExists(C &&callback);
/* where row values */
/*! Adds a where condition using row values. */
@@ -802,6 +804,9 @@ namespace Orm::Query
/*! Add an "exists" clause to the query. */
Builder &addWhereExistsQuery(const std::shared_ptr<Builder> &query,
const QString &condition = AND, bool nope = false);
/*! Add an "exists" clause to the query. */
Builder &addWhereExistsQuery(Builder &query, const QString &condition = AND,
bool nope = false);
/*! Merge an array of where clauses and bindings. */
Builder &mergeWheres(const QVector<WhereConditionItem> &wheres,
@@ -1484,6 +1489,47 @@ namespace Orm::Query
condition);
}
/* where exists */
template<QueryableShared C>
Builder &Builder::whereExists(C &&callback, const QString &condition,
const bool nope)
{
if constexpr (std::invocable<C, Builder &>) {
// Ownership of the std::shared_ptr<QueryBuilder>
const auto query = forSubQuery();
/* Similar to the sub-select clause, we will create a new query instance so
the developer may cleanly specify the entire exists query and we will
compile the whole thing in the grammar and insert it into the SQL. */
std::invoke(callback, *query);
return addWhereExistsQuery(query, condition, nope);
}
// For the QueryBuilder & or std::shared_ptr<QueryBuilder>
else
return addWhereExistsQuery(callback, condition, nope);
}
template<QueryableShared C>
Builder &Builder::orWhereExists(C &&callback, const bool nope)
{
return whereExists(callback, OR, nope);
}
template<QueryableShared C>
Builder &Builder::whereNotExists(C &&callback, const QString &condition)
{
return whereExists(callback, condition, true);
}
template<QueryableShared C>
Builder &Builder::orWhereNotExists(C &&callback)
{
return whereExists(callback, OR, true);
}
/* where dates */
Builder &

View File

@@ -636,20 +636,21 @@ namespace Tiny
/* where exists */
/*! Add an exists clause to the query. */
template<QueryableShared C>
static std::unique_ptr<TinyBuilder<Derived>>
whereExists(const std::function<void(QueryBuilder &)> &callback,
const QString &condition = AND, bool nope = false);
whereExists(C &&callback, const QString &condition = AND, bool nope = false);
/*! Add an or exists clause to the query. */
template<QueryableShared C>
static std::unique_ptr<TinyBuilder<Derived>>
orWhereExists(const std::function<void(QueryBuilder &)> &callback,
bool nope = false);
orWhereExists(C &&callback, bool nope = false);
/*! Add a where not exists clause to the query. */
template<QueryableShared C>
static std::unique_ptr<TinyBuilder<Derived>>
whereNotExists(const std::function<void(QueryBuilder &)> &callback,
const QString &condition = AND);
whereNotExists(C &&callback, const QString &condition = AND);
/*! Add a where not exists clause to the query. */
template<QueryableShared C>
static std::unique_ptr<TinyBuilder<Derived>>
orWhereNotExists(const std::function<void(QueryBuilder &)> &callback);
orWhereNotExists(C &&callback);
/* where row values */
/*! Adds a where condition using row values. */
@@ -2647,10 +2648,10 @@ namespace Tiny
/* where exists */
template<typename Derived, AllRelationsConcept ...AllRelations>
template<QueryableShared C>
std::unique_ptr<TinyBuilder<Derived>>
ModelProxies<Derived, AllRelations...>::whereExists(
const std::function<void(QueryBuilder &)> &callback,
const QString &condition, const bool nope)
C &&callback, const QString &condition, const bool nope)
{
auto builder = query();
@@ -2660,9 +2661,9 @@ namespace Tiny
}
template<typename Derived, AllRelationsConcept ...AllRelations>
template<QueryableShared C>
std::unique_ptr<TinyBuilder<Derived>>
ModelProxies<Derived, AllRelations...>::orWhereExists(
const std::function<void(QueryBuilder &)> &callback, const bool nope)
ModelProxies<Derived, AllRelations...>::orWhereExists(C &&callback, const bool nope)
{
auto builder = query();
@@ -2672,10 +2673,10 @@ namespace Tiny
}
template<typename Derived, AllRelationsConcept ...AllRelations>
template<QueryableShared C>
std::unique_ptr<TinyBuilder<Derived>>
ModelProxies<Derived, AllRelations...>::whereNotExists(
const std::function<void(QueryBuilder &)> &callback,
const QString &condition)
C &&callback, const QString &condition)
{
auto builder = query();
@@ -2685,9 +2686,9 @@ namespace Tiny
}
template<typename Derived, AllRelationsConcept ...AllRelations>
template<QueryableShared C>
std::unique_ptr<TinyBuilder<Derived>>
ModelProxies<Derived, AllRelations...>::orWhereNotExists(
const std::function<void(QueryBuilder &)> &callback)
ModelProxies<Derived, AllRelations...>::orWhereNotExists(C &&callback)
{
auto builder = query();

View File

@@ -624,20 +624,22 @@ namespace Tiny::Relations
/* where exists */
/*! Add an exists clause to the query. */
template<QueryableShared C>
const Relation<Model, Related> &
whereExists(const std::function<void(QueryBuilder &)> &callback,
const QString &condition = AND, bool nope = false) const;
whereExists(C &&callback, const QString &condition = AND,
bool nope = false) const;
/*! Add an or exists clause to the query. */
template<QueryableShared C>
const Relation<Model, Related> &
orWhereExists(const std::function<void(QueryBuilder &)> &callback,
bool nope = false) const;
orWhereExists(C &&callback, bool nope = false) const;
/*! Add a where not exists clause to the query. */
template<QueryableShared C>
const Relation<Model, Related> &
whereNotExists(const std::function<void(QueryBuilder &)> &callback,
const QString &condition = AND) const;
whereNotExists(C &&callback, const QString &condition = AND) const;
/*! Add a where not exists clause to the query. */
template<QueryableShared C>
const Relation<Model, Related> &
orWhereNotExists(const std::function<void(QueryBuilder &)> &callback) const;
orWhereNotExists(C &&callback) const;
/* where row values */
/*! Adds a where condition using row values. */
@@ -2482,10 +2484,10 @@ namespace Tiny::Relations
/* where exists */
template<class Model, class Related>
template<QueryableShared C>
const Relation<Model, Related> &
RelationProxies<Model, Related>::whereExists(
const std::function<void(QueryBuilder &)> &callback,
const QString &condition, const bool nope) const
C &&callback, const QString &condition, const bool nope) const
{
getQuery().whereExists(callback, condition, nope);
@@ -2493,9 +2495,9 @@ namespace Tiny::Relations
}
template<class Model, class Related>
template<QueryableShared C>
const Relation<Model, Related> &
RelationProxies<Model, Related>::orWhereExists(
const std::function<void(QueryBuilder &)> &callback, const bool nope) const
RelationProxies<Model, Related>::orWhereExists(C &&callback, const bool nope) const
{
getQuery().whereExists(callback, OR, nope);
@@ -2503,10 +2505,10 @@ namespace Tiny::Relations
}
template<class Model, class Related>
template<QueryableShared C>
const Relation<Model, Related> &
RelationProxies<Model, Related>::whereNotExists(
const std::function<void(QueryBuilder &)> &callback,
const QString &condition) const
C &&callback, const QString &condition) const
{
getQuery().whereExists(callback, condition, true);
@@ -2514,9 +2516,9 @@ namespace Tiny::Relations
}
template<class Model, class Related>
template<QueryableShared C>
const Relation<Model, Related> &
RelationProxies<Model, Related>::orWhereNotExists(
const std::function<void(QueryBuilder &)> &callback) const
RelationProxies<Model, Related>::orWhereNotExists(C &&callback) const
{
getQuery().whereExists(callback, OR, true);

View File

@@ -476,20 +476,21 @@ namespace Tiny
/* where exists */
/*! Add an exists clause to the query. */
template<QueryableShared C>
TinyBuilder<Model> &
whereExists(const std::function<void(QueryBuilder &)> &callback,
const QString &condition = AND, bool nope = false);
whereExists(C &&callback, const QString &condition = AND, bool nope = false);
/*! Add an or exists clause to the query. */
template<QueryableShared C>
TinyBuilder<Model> &
orWhereExists(const std::function<void(QueryBuilder &)> &callback,
bool nope = false);
orWhereExists(C &&callback, bool nope = false);
/*! Add a where not exists clause to the query. */
template<QueryableShared C>
TinyBuilder<Model> &
whereNotExists(const std::function<void(QueryBuilder &)> &callback,
const QString &condition = AND);
whereNotExists(C &&callback, const QString &condition = AND);
/*! Add a where not exists clause to the query. */
template<QueryableShared C>
TinyBuilder<Model> &
orWhereNotExists(const std::function<void(QueryBuilder &)> &callback);
orWhereNotExists(C &&callback);
/* where row values */
/*! Adds a where condition using row values. */
@@ -1750,38 +1751,37 @@ namespace Tiny
/* where exists */
template<typename Model>
template<QueryableShared C>
TinyBuilder<Model> &
BuilderProxies<Model>::whereExists(
const std::function<void(QueryBuilder &)> &callback,
const QString &condition, const bool nope)
BuilderProxies<Model>::whereExists(C &&callback, const QString &condition,
const bool nope)
{
getQuery().whereExists(callback, condition, nope);
return builder();
}
template<typename Model>
template<QueryableShared C>
TinyBuilder<Model> &
BuilderProxies<Model>::orWhereExists(
const std::function<void(QueryBuilder &)> &callback, const bool nope)
BuilderProxies<Model>::orWhereExists(C &&callback, const bool nope)
{
getQuery().whereExists(callback, OR, nope);
return builder();
}
template<typename Model>
template<QueryableShared C>
TinyBuilder<Model> &
BuilderProxies<Model>::whereNotExists(
const std::function<void(QueryBuilder &)> &callback,
const QString &condition)
BuilderProxies<Model>::whereNotExists(C &&callback, const QString &condition)
{
getQuery().whereExists(callback, condition, true);
return builder();
}
template<typename Model>
template<QueryableShared C>
TinyBuilder<Model> &
BuilderProxies<Model>::orWhereNotExists(
const std::function<void(QueryBuilder &)> &callback)
BuilderProxies<Model>::orWhereNotExists(C &&callback)
{
getQuery().whereExists(callback, OR, true);
return builder();

View File

@@ -454,12 +454,26 @@ QString Grammar::whereRaw(const WhereConditionItem &where) const // NOLINT(reada
QString Grammar::whereExists(const WhereConditionItem &where) const
{
return QStringLiteral("exists (%1)").arg(compileSelect(*where.nestedQuery));
// Compile the nested query (QueryBuilder instance)
if (where.nestedQuery)
return QStringLiteral("exists (%1)").arg(compileSelect(*where.nestedQuery));
Q_ASSERT(std::holds_alternative<Expression>(where.column));
// Sub-query already compiled in the QueryBuilder using the createSub()
return QStringLiteral("exists %1").arg(wrap(where.column));
}
QString Grammar::whereNotExists(const WhereConditionItem &where) const
{
return QStringLiteral("not exists (%1)").arg(compileSelect(*where.nestedQuery));
// Compile the nested query (QueryBuilder instance)
if (where.nestedQuery)
return QStringLiteral("not exists (%1)").arg(compileSelect(*where.nestedQuery));
Q_ASSERT(std::holds_alternative<Expression>(where.column));
// Sub-query already compiled in the QueryBuilder using the createSub()
return QStringLiteral("not exists %1").arg(wrap(where.column));
}
QString Grammar::whereRowValues(const WhereConditionItem &where) const

View File

@@ -786,40 +786,6 @@ Builder &Builder::orWhereNotBetweenColumns(const Column &column,
return whereBetweenColumns(column, betweenColumns, OR, true);
}
/* where exists */
Builder &Builder::whereExists(
const std::function<void(Builder &)> &callback, const QString &condition,
const bool nope)
{
// Ownership of the std::shared_ptr<QueryBuilder>
const auto query = forSubQuery();
/* Similar to the sub-select clause, we will create a new query instance so
the developer may cleanly specify the entire exists query and we will
compile the whole thing in the grammar and insert it into the SQL. */
std::invoke(callback, *query);
return addWhereExistsQuery(query, condition, nope);
}
Builder &Builder::orWhereExists(const std::function<void(Builder &)> &callback,
const bool nope)
{
return whereExists(callback, OR, nope);
}
Builder &Builder::whereNotExists(const std::function<void(Builder &)> &callback,
const QString &condition)
{
return whereExists(callback, condition, true);
}
Builder &Builder::orWhereNotExists(const std::function<void(Builder &)> &callback)
{
return whereExists(callback, OR, true);
}
/* where row values */
Builder &
@@ -1393,6 +1359,22 @@ Builder &Builder::addWhereExistsQuery(const std::shared_ptr<Builder> &query,
return *this;
}
Builder &Builder::addWhereExistsQuery(Builder &query, const QString &condition,
const bool nope)
{
const auto type = nope ? WhereType::NOT_EXISTS : WhereType::EXISTS;
// Compile the sub-query right here and pass it down to the grammar as a expression
auto [queryString, bindings] = createSub(query);
m_wheres.append({.column = Expression(PARENTH_ONE.arg(queryString)),
.condition = condition, .type = type});
addBinding(std::move(bindings), BindingType::WHERE);
return *this;
}
Builder &Builder::mergeWheres(const QVector<WhereConditionItem> &wheres,
const QVector<QVariant> &bindings)
{

View File

@@ -15,6 +15,7 @@
using Orm::Constants::ASTERISK;
using Orm::Constants::CREATED_AT;
using Orm::Constants::ID;
using Orm::Constants::LT;
using Orm::Constants::NAME;
using Orm::Constants::QMYSQL;
using Orm::Constants::QSQLITE;
@@ -73,6 +74,8 @@ private Q_SLOTS:
void where_WithVector() const;
void where_WithVector_Condition() const;
void whereExists() const;
void find() const;
void findOrNew_Found() const;
void findOrNew_NotFound() const;
@@ -671,6 +674,62 @@ void tst_Model::where_WithVector_Condition() const
}
}
void tst_Model::whereExists() const
{
QFETCH_GLOBAL(QString, connection);
ConnectionOverride::connection = connection;
// With lambda expression
{
const auto actualIds = TorrentPeer::whereExists([](Orm::QueryBuilder &query)
{
query.from("torrents").where(SIZE, LT, 15);
})
->where(ID, LT, 7)
.select(ID)
.orderBy(ID)
.pluck(ID);
QVector<QVariant> expectedIds {1, 2, 3, 4};
QCOMPARE(actualIds, expectedIds);
}
// With QueryBuilder &
{
auto builder = DB::connection(connection).query();
const auto actualIds = TorrentPeer::whereExists(builder->from("torrents")
.where(SIZE, LT, 15))
->where(ID, LT, 7)
.select(ID)
.orderBy(ID)
.pluck(ID);
QVector<QVariant> expectedIds {1, 2, 3, 4};
QCOMPARE(actualIds, expectedIds);
}
// With std::shared_ptr<QueryBuilder>
{
auto builder = DB::connection(connection).query();
// Ownership of the std::shared_ptr<QueryBuilder>
const auto builderForExists = DB::connection(connection).query();
builderForExists->from("torrents").where(SIZE, LT, 15);
const auto actualIds = TorrentPeer::whereExists(builderForExists)
->where(ID, LT, 7)
.select(ID)
.orderBy(ID)
.pluck(ID);
QVector<QVariant> expectedIds {1, 2, 3, 4};
QCOMPARE(actualIds, expectedIds);
}
}
void tst_Model::find() const
{
QFETCH_GLOBAL(QString, connection);

View File

@@ -2613,70 +2613,206 @@ void tst_MySql_QueryBuilder::whereBetweenColumns_ColumnExpression() const
void tst_MySql_QueryBuilder::whereExists() const
{
auto builder = createQuery();
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.whereExists([](Builder &query)
// With lambda expression
{
query.from("torrents").where(SIZE, LT, 15);
});
auto builder = createQuery();
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? and "
"exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.whereExists([](Builder &query)
{
query.from("torrents").where(SIZE, LT, 15);
});
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? and "
"exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
// With QueryBuilder &
{
auto builder = createQuery();
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.whereExists(createQuery()->from("torrents")
.where(SIZE, LT, 15));
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? and "
"exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
// With std::shared_ptr<QueryBuilder>
{
auto builder = createQuery();
// Ownership of the std::shared_ptr<QueryBuilder>
const auto builderForExists = createQuery();
builderForExists->from("torrents").where(SIZE, LT, 15);
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.whereExists(builderForExists);
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? and "
"exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
}
void tst_MySql_QueryBuilder::whereNotExists() const
{
auto builder = createQuery();
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.whereNotExists([](Builder &query)
// With lambda expression
{
query.from("torrents").where(SIZE, LT, 15);
});
auto builder = createQuery();
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? and "
"not exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.whereNotExists([](Builder &query)
{
query.from("torrents").where(SIZE, LT, 15);
});
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? and "
"not exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
// With QueryBuilder &
{
auto builder = createQuery();
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.whereNotExists(createQuery()->from("torrents")
.where(SIZE, LT, 15));
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? and "
"not exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
// With std::shared_ptr<QueryBuilder>
{
auto builder = createQuery();
// Ownership of the std::shared_ptr<QueryBuilder>
const auto builderForExists = createQuery();
builderForExists->from("torrents").where(SIZE, LT, 15);
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.whereNotExists(builderForExists);
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? and "
"not exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
}
void tst_MySql_QueryBuilder::orWhereExists() const
{
auto builder = createQuery();
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.orWhereExists([](Builder &query)
// With lambda expression
{
query.from("torrents").where(SIZE, LT, 15);
});
auto builder = createQuery();
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? or "
"exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.orWhereExists([](Builder &query)
{
query.from("torrents").where(SIZE, LT, 15);
});
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? or "
"exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
// With QueryBuilder &
{
auto builder = createQuery();
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.orWhereExists(createQuery()->from("torrents")
.where(SIZE, LT, 15));
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? or "
"exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
// With std::shared_ptr<QueryBuilder>
{
auto builder = createQuery();
// Ownership of the std::shared_ptr<QueryBuilder>
const auto builderForExists = createQuery();
builderForExists->from("torrents").where(SIZE, LT, 15);
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.orWhereExists(builderForExists);
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? or "
"exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
}
void tst_MySql_QueryBuilder::orWhereNotExists() const
{
auto builder = createQuery();
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.orWhereNotExists([](Builder &query)
// With lambda expression
{
query.from("torrents").where(SIZE, LT, 15);
});
auto builder = createQuery();
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? or "
"not exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.orWhereNotExists([](Builder &query)
{
query.from("torrents").where(SIZE, LT, 15);
});
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? or "
"not exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
// With QueryBuilder &
{
auto builder = createQuery();
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.orWhereNotExists(createQuery()->from("torrents")
.where(SIZE, LT, 15));
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? or "
"not exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
// With std::shared_ptr<QueryBuilder>
{
auto builder = createQuery();
// Ownership of the std::shared_ptr<QueryBuilder>
const auto builderForExists = createQuery();
builderForExists->from("torrents").where(SIZE, LT, 15);
builder->select("*").from("torrent_peers").where(ID, LT, 7)
.orWhereNotExists(builderForExists);
QCOMPARE(builder->toSql(),
"select * from `torrent_peers` where `id` < ? or "
"not exists (select * from `torrents` where `size` < ?)");
QCOMPARE(builder->getBindings(),
QVector<QVariant>({QVariant(7), QVariant(15)}));
}
}
void tst_MySql_QueryBuilder::whereRowValues() const