mirror of
https://github.com/silverqx/TinyORM.git
synced 2026-02-12 13:28:59 -06:00
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:
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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 &
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user