Skip to content

Commit

Permalink
added whereNot/whereNotXyz counterparts
Browse files Browse the repository at this point in the history
Added the whereNot counterparts for the basic, nested, array, and
sub-query where methods.

 - updated docs
 - added unit tests
  • Loading branch information
silverqx committed Jul 22, 2022
1 parent 81b0196 commit a477825
Show file tree
Hide file tree
Showing 7 changed files with 1,000 additions and 14 deletions.
12 changes: 12 additions & 0 deletions docs/database/query-builder.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ keywords: [c++ orm, sql, c++ sql, c++ query builder, database, query builder, ti
- [Basic Where Clauses](#basic-where-clauses)
- [Where Clauses](#where-clauses)
- [Or Where Clauses](#or-where-clauses)
- [Where Not Clauses](#where-not-clauses)
- [Additional Where Clauses](#additional-where-clauses)
- [Condition Operator Overriding](#condition-operator-overriding)
- [Logical Grouping](#logical-grouping)
Expand Down Expand Up @@ -405,6 +406,17 @@ select * from users where (first_name = "John" or last_name = "Smith" and votes
Still, it is a better idea to use [Logical Grouping](#logical-grouping) described few lines below, which allows better control of the parentheses.
:::

### Where Not Clauses

The `whereNot` and `orWhereNot` methods may be used to negate a given group of query constraints. For example, the following query excludes products that are on clearance or which have a price that is less than ten:

auto products = DB::table("products")
->whereNot([](auto &query) {
query.whereEq("clearance", true)
.orWhere("price", "<", 10);
})
.get();

### Additional Where Clauses

**whereIn / whereNotIn / orWhereIn / orWhereNotIn**
Expand Down
2 changes: 1 addition & 1 deletion docs/supported-compilers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ keywords: [c++ orm, supported compilers, supported build systems, tinyorm]

# Supported Compilers

Following compilers are backed up by the GitHub Action [workflows](https://github.com/silverqx/TinyORM/tree/main/.github/workflows) (CI pipelines), these workflows also include more then __1027 unit tests__ 😮💥.
Following compilers are backed up by the GitHub Action [workflows](https://github.com/silverqx/TinyORM/tree/main/.github/workflows) (CI pipelines), these workflows also include more then __1058 unit tests__ 😮💥.

<div id="supported-compilers">

Expand Down
132 changes: 128 additions & 4 deletions include/orm/query/querybuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ namespace Orm::Query
rightJoinSub(T &&query, const QString &as,
const std::function<void(JoinClause &)> &callback);

/* General where */
/*! Add a basic where clause to the query. */
template<WhereValue T>
Builder &where(const Column &column, const QString &comparison,
Expand All @@ -290,18 +291,51 @@ namespace Orm::Query
template<WhereValue T>
Builder &orWhereEq(const Column &column, T &&value);

/* General where not */
/*! Add a basic "where not" clause to the query. */
template<WhereValue T>
Builder &whereNot(const Column &column, const QString &comparison,
T &&value, const QString &condition = AND);
/*! Add an "or where not" clause to the query. */
template<WhereValue T>
Builder &orWhereNot(const Column &column, const QString &comparison, T &&value);
/*! Add a basic equal "where not" clause to the query. */
template<WhereValue T>
Builder &whereNotEq(const Column &column, T &&value,
const QString &condition = AND);
/*! Add an equal "or where not" clause to the query. */
template<WhereValue T>
Builder &orWhereNotEq(const Column &column, T &&value);

/* Nested where */
/*! Add a nested where clause to the query. */
Builder &where(const std::function<void(Builder &)> &callback,
const QString &condition = AND);
/*! Add a nested "or where" clause to the query. */
Builder &orWhere(const std::function<void(Builder &)> &callback);
/*! Add a nested "where not" clause to the query. */
Builder &whereNot(const std::function<void(Builder &)> &callback,
const QString &condition = AND);
/*! Add a nested "or where not" clause to the query. */
Builder &orWhereNot(const std::function<void(Builder &)> &callback);

/* Array where */
/*! Add a vector of basic where clauses to the query. */
Builder &where(const QVector<WhereItem> &values,
const QString &condition = AND);
const QString &condition = AND,
const QString &defaultCondition = "");
/*! Add a vector of basic "or where" clauses to the query. */
Builder &orWhere(const QVector<WhereItem> &values);

Builder &orWhere(const QVector<WhereItem> &values,
const QString &defaultCondition = "");
/*! Add a vector of basic "where not" clauses to the query. */
Builder &whereNot(const QVector<WhereItem> &values,
const QString &condition = AND,
const QString &defaultCondition = "");
/*! Add a vector of basic "or where not" clauses to the query. */
Builder &orWhereNot(const QVector<WhereItem> &values,
const QString &defaultCondition = "");

/* where column */
/*! Add a vector of where clauses comparing two columns to the query. */
Builder &whereColumn(const QVector<WhereColumnItem> &values,
const QString &condition = AND);
Expand All @@ -320,6 +354,7 @@ namespace Orm::Query
/*! Add an equal "or where" clause comparing two columns to the query. */
Builder &orWhereColumnEq(const Column &first, const Column &second);

/* where IN */
/*! Add a "where in" clause to the query. */
Builder &whereIn(const Column &column, const QVector<QVariant> &values,
const QString &condition = AND, bool nope = false);
Expand All @@ -331,6 +366,7 @@ namespace Orm::Query
/*! Add an "or where not in" clause to the query. */
Builder &orWhereNotIn(const Column &column, const QVector<QVariant> &values);

/* where null */
/*! Add a "where null" clause to the query. */
Builder &whereNull(const QVector<Column> &columns = {ASTERISK},
const QString &condition = AND, bool nope = false);
Expand All @@ -352,6 +388,7 @@ namespace Orm::Query
/*! Add an "or where not null" clause to the query. */
Builder &orWhereNotNull(const Column &column);

/* where sub-queries */
/*! Add a basic where clause to the query with a full sub-select column. */
template<Queryable C, WhereValue V>
Builder &where(C &&column, const QString &comparison, V &&value,
Expand All @@ -366,11 +403,29 @@ namespace Orm::Query
template<Queryable C, WhereValue V>
inline Builder &orWhereEq(C &&column, V &&value);

/* where not sub-queries */
/*! Add a basic "where not" clause to the query with a full sub-select column. */
template<Queryable C, WhereValue V>
Builder &whereNot(C &&column, const QString &comparison, V &&value,
const QString &condition = AND);
/*! Add an "or where not" clause to the query with a full sub-select column. */
template<Queryable C, WhereValue V>
inline Builder &orWhereNot(C &&column, const QString &comparison, V &&value);
/*! Add a basic equal "where not" clause to the query with a full sub-select
column. */
template<Queryable C, WhereValue V>
inline Builder &whereNotEq(C &&column, V &&value, const QString &condition = AND);
/*! Add an equal "or where not" clause to the query with a full sub-select
column. */
template<Queryable C, WhereValue V>
inline Builder &orWhereNotEq(C &&column, V &&value);

/*! Add a full sub-select to the "where" clause. */
template<WhereValueSubQuery T>
Builder &whereSub(const Column &column, const QString &comparison, T &&query,
const QString &condition = AND);

/* where raw */
/*! Add a raw "where" clause to the query. */
Builder &whereRaw(const QString &sql, const QVector<QVariant> &bindings = {},
const QString &condition = AND);
Expand Down Expand Up @@ -565,7 +620,8 @@ namespace Orm::Query
/*! Add a vector of basic where clauses to the query. */
Builder &
addArrayOfWheres(const QVector<WhereItem> &values,
const QString &condition = AND);
const QString &condition = AND,
const QString &defaultCondition = "");
/*! Add a vector of where clauses comparing two columns to the query. */
Builder &
addArrayOfWheres(const QVector<WhereColumnItem> &values,
Expand Down Expand Up @@ -993,6 +1049,8 @@ namespace Orm::Query
return joinSub(std::forward<T>(query), as, callback, RIGHT);
}

/* Basic where */

template<WhereValue T>
Builder &
Builder::where(const Column &column, const QString &comparison, T &&value,
Expand Down Expand Up @@ -1027,6 +1085,40 @@ namespace Orm::Query
return where(column, EQ, std::forward<T>(value), OR);
}

/* Genral where not */

template<WhereValue T>
Builder &
Builder::whereNot(const Column &column, const QString &comparison, T &&value,
const QString &condition)
{
return where(column, comparison, std::forward<T>(value),
SPACE_IN.arg(condition, NOT));
}

template<WhereValue T>
Builder &
Builder::orWhereNot(const Column &column, const QString &comparison, T &&value)
{
return where(column, comparison, std::forward<T>(value),
SPACE_IN.arg(OR, NOT));
}

template<WhereValue T>
Builder &
Builder::whereNotEq(const Column &column, T &&value, const QString &condition)
{
return where(column, EQ, std::forward<T>(value), SPACE_IN.arg(condition, NOT));
}

template<WhereValue T>
Builder &Builder::orWhereNotEq(const Column &column, T &&value)
{
return where(column, EQ, std::forward<T>(value), SPACE_IN.arg(OR, NOT));
}

/* where sub-queries */

template<Queryable C, WhereValue V>
Builder &
Builder::where(C &&column, const QString &comparison, V &&value,
Expand Down Expand Up @@ -1064,6 +1156,38 @@ namespace Orm::Query
return where(std::forward<C>(column), EQ, std::forward<V>(value), OR);
}

/* where not sub-queries */

template<Queryable C, WhereValue V>
Builder &
Builder::whereNot(C &&column, const QString &comparison, V &&value,
const QString &condition)
{
return where(std::forward<C>(column), comparison, std::forward<V>(value),
SPACE_IN.arg(condition, NOT));
}

template<Queryable C, WhereValue V>
Builder &Builder::orWhereNot(C &&column, const QString &comparison, V &&value)
{
return where(std::forward<C>(column), comparison, std::forward<V>(value),
SPACE_IN.arg(OR, NOT));
}

template<Queryable C, WhereValue V>
Builder &Builder::whereNotEq(C &&column, V &&value, const QString &condition)
{
return where(std::forward<C>(column), EQ, std::forward<V>(value),
SPACE_IN.arg(condition, NOT));
}

template<Queryable C, WhereValue V>
Builder &Builder::orWhereNotEq(C &&column, V &&value)
{
return where(std::forward<C>(column), EQ, std::forward<V>(value),
SPACE_IN.arg(OR, NOT));
}

template<WhereValueSubQuery T>
Builder &
Builder::whereSub(const Column &column, const QString &comparison,
Expand Down
59 changes: 52 additions & 7 deletions src/orm/query/querybuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ Builder &Builder::fromRaw(const QString &expression, const QVector<QVariant> &bi
return *this;
}

/* Nested where */

Builder &Builder::where(const std::function<void(Builder &)> &callback,
const QString &condition)
{
Expand All @@ -341,20 +343,53 @@ Builder &Builder::orWhere(const std::function<void(Builder &)> &callback)
return where(callback, OR);
}

Builder &Builder::where(const QVector<WhereItem> &values, const QString &condition)
Builder &Builder::whereNot(const std::function<void(Builder &)> &callback,
const QString &condition)
{
return where(callback, SPACE_IN.arg(condition, NOT));
}

Builder &Builder::orWhereNot(const std::function<void(Builder &)> &callback)
{
return where(callback, SPACE_IN.arg(OR, NOT));
}

/* Array where */

Builder &Builder::where(const QVector<WhereItem> &values, const QString &condition,
const QString &defaultCondition)
{
/* We will maintain the boolean we received when the method was called and pass it
into the nested where.
The parentheses in this query are ok:
select * from xyz where (id = ?) */
return addArrayOfWheres(values, condition);
return addArrayOfWheres(values, condition, defaultCondition);
}

Builder &Builder::orWhere(const QVector<WhereItem> &values)
Builder &Builder::orWhere(const QVector<WhereItem> &values,
const QString &defaultCondition)
{
return where(values, OR);
return where(values, OR, defaultCondition);
}

Builder &Builder::whereNot(const QVector<WhereItem> &values, const QString &condition,
const QString &defaultCondition)
{
return where(values, SPACE_IN.arg(condition, NOT),
// Avoid "and/... not" between all WhereItem-s
defaultCondition.isEmpty() ? condition : defaultCondition);
}

Builder &Builder::orWhereNot(const QVector<WhereItem> &values,
const QString &defaultCondition)
{
return where(values, SPACE_IN.arg(OR, NOT),
// Avoid "or not" between all WhereItem-s
defaultCondition.isEmpty() ? OR : defaultCondition);
}

/* where column */

Builder &Builder::whereColumn(const QVector<WhereColumnItem> &values,
const QString &condition)
{
Expand Down Expand Up @@ -395,6 +430,8 @@ Builder &Builder::orWhereColumnEq(const Column &first, const Column &second)
return whereColumn(first, EQ, second, OR);
}

/* where IN */

Builder &Builder::whereIn(const Column &column, const QVector<QVariant> &values,
const QString &condition, const bool nope)
{
Expand Down Expand Up @@ -427,6 +464,8 @@ Builder &Builder::orWhereNotIn(const Column &column, const QVector<QVariant> &va
return whereNotIn(column, values, OR);
}

/* where null */

Builder &Builder::whereNull(const QVector<Column> &columns, const QString &condition,
const bool nope)
{
Expand Down Expand Up @@ -474,6 +513,8 @@ Builder &Builder::orWhereNotNull(const Column &column)
return orWhereNotNull(QVector<Column> {column});
}

/* where raw */

Builder &Builder::whereRaw(const QString &sql, const QVector<QVariant> &bindings,
const QString &condition)
{
Expand Down Expand Up @@ -893,13 +934,17 @@ QVector<QVariant> Builder::cleanBindings(QVector<QVariant> &&bindings) const
}

Builder &
Builder::addArrayOfWheres(const QVector<WhereItem> &values, const QString &condition)
Builder::addArrayOfWheres(const QVector<WhereItem> &values, const QString &condition,
const QString &defaultCondition)
{
return where([&values, &condition](Builder &query)
return where([&values, &condition, &defaultCondition](Builder &query)
{
for (const auto &where : values)
query.where(where.column, where.comparison, where.value,
where.condition.isEmpty() ? condition : where.condition);
where.condition.isEmpty()
// Allow to pass a default condition for the QVector<WhereItem>
? (defaultCondition.isEmpty() ? condition : defaultCondition)
: where.condition);

}, condition);
}
Expand Down
Loading

0 comments on commit a477825

Please sign in to comment.