mirror of
https://github.com/silverqx/TinyORM.git
synced 2026-01-06 02:49:31 -06:00
added whereBetween and whereBetweenColumns
- added proxies - added unit and functional tests - added docs - updated number of unit tests to 1417
This commit is contained in:
@@ -74,7 +74,7 @@ Whole library is documented as markdown documents:
|
||||
- the `tom` console application with tab completion for all shells (pwsh, bash, zsh) 🥳
|
||||
- scaffolding of models, migrations, and seeders
|
||||
- overhauled models scaffolding, every feature that is supported by models can be generated using the `tom make:model` cli command
|
||||
- a huge amount of code is unit tested, currently __1408 unit tests__ 🤯
|
||||
- a huge amount of code is unit tested, currently __1417 unit tests__ 🤯
|
||||
- C++20 only, with all the latest features used like concepts/constraints, ranges, smart pointers (no `new` keyword in the whole code 😎), folding expressions
|
||||
- qmake and CMake build systems support
|
||||
- CMake FetchContent module support 🤙
|
||||
|
||||
@@ -482,6 +482,38 @@ The `whereNot` and `orWhereNot` methods may be used to negate a given group of q
|
||||
|
||||
### Additional Where Clauses
|
||||
|
||||
**whereBetween / orWhereBetween**
|
||||
|
||||
The `whereBetween` method verifies that a column's value is between two values:
|
||||
|
||||
auto users = DB::table("users")
|
||||
->whereBetween("votes", {1, 100})
|
||||
.get();
|
||||
|
||||
**whereNotBetween / orWhereNotBetween**
|
||||
|
||||
The `whereNotBetween` method verifies that a column's value lies outside of two values:
|
||||
|
||||
auto users = DB::table("users")
|
||||
->whereNotBetween("votes", {1, 100})
|
||||
.get();
|
||||
|
||||
**whereBetweenColumns / orWhereBetweenColumns**
|
||||
|
||||
The `whereBetweenColumns` method verifies that a column's value is between two values in given columns:
|
||||
|
||||
auto files = DB::table("files")
|
||||
->whereBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})
|
||||
.get();
|
||||
|
||||
**whereNotBetweenColumns / orWhereNotBetweenColumns**
|
||||
|
||||
The `whereNotBetweenColumns` method verifies that a column's value lies outside of two values in given columns:
|
||||
|
||||
auto files = DB::table("files")
|
||||
->whereNotBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})
|
||||
.get();
|
||||
|
||||
**whereIn / whereNotIn / orWhereIn / orWhereNotIn**
|
||||
|
||||
The `whereIn` method verifies that a given column's value is contained within the given `QVector<QVariant>`:
|
||||
|
||||
@@ -46,7 +46,7 @@ The following list fastly summarizes all `TinyORM` features.
|
||||
- the `tom` console application with tab completion for all shells (pwsh, bash, zsh) 🥳
|
||||
- scaffolding of models, migrations, and seeders
|
||||
- overhauled models scaffolding, every feature that is supported by models can be generated using the `tom make:model` cli command
|
||||
- a huge amount of code is unit tested, currently __1408 unit tests__ 🤯
|
||||
- a huge amount of code is unit tested, currently __1417 unit tests__ 🤯
|
||||
- C++20 only, with all the latest features used like concepts/constraints, ranges, smart pointers (no `new` keyword in the whole code 😎), folding expressions
|
||||
- qmake and CMake build systems support
|
||||
- vcpkg support (also the vcpkg port, currently not committed to the vcpkg repository ☹️)
|
||||
|
||||
@@ -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 __1408 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 __1417 unit tests__ 😮💥.
|
||||
|
||||
<div id="supported-compilers">
|
||||
|
||||
|
||||
@@ -79,21 +79,8 @@ namespace Query
|
||||
EXISTS,
|
||||
NOT_EXISTS,
|
||||
ROW_VALUES,
|
||||
};
|
||||
|
||||
/*! Where clause item, primarily used in grammars to build sql query. */
|
||||
struct WhereConditionItem
|
||||
{
|
||||
Column column {};
|
||||
QVariant value {};
|
||||
QString comparison {Orm::Constants::EQ};
|
||||
QString condition {Orm::Constants::AND};
|
||||
WhereType type {WhereType::UNDEFINED};
|
||||
std::shared_ptr<QueryBuilder> nestedQuery {nullptr};
|
||||
QVector<Column> columns {};
|
||||
QVector<QVariant> values {};
|
||||
Column columnTwo {};
|
||||
QString sql {}; // for the raw version
|
||||
BETWEEN,
|
||||
BETWEEN_COLUMNS,
|
||||
};
|
||||
|
||||
/*! Supported having types. */
|
||||
@@ -148,6 +135,38 @@ namespace Query
|
||||
QString condition {};
|
||||
};
|
||||
|
||||
/*! Where item that stores values for the where between clause. */
|
||||
struct WhereBetweenItem
|
||||
{
|
||||
QVariant min {};
|
||||
QVariant max {};
|
||||
};
|
||||
|
||||
/*! Where item that stores column names for the where between clause. */
|
||||
struct WhereBetweenColumnsItem
|
||||
{
|
||||
Column min {};
|
||||
Column max {};
|
||||
};
|
||||
|
||||
/*! Where clause item, primarily used in grammars to build sql query. */
|
||||
struct WhereConditionItem
|
||||
{
|
||||
Column column {};
|
||||
QVariant value {};
|
||||
QString comparison {Orm::Constants::EQ};
|
||||
QString condition {Orm::Constants::AND};
|
||||
WhereType type {WhereType::UNDEFINED};
|
||||
std::shared_ptr<QueryBuilder> nestedQuery {nullptr};
|
||||
QVector<Column> columns {};
|
||||
QVector<QVariant> values {};
|
||||
Column columnTwo {};
|
||||
QString sql {}; // for the raw version
|
||||
bool nope {false};
|
||||
WhereBetweenItem between {};
|
||||
WhereBetweenColumnsItem betweenColumns {};
|
||||
};
|
||||
|
||||
} // namespace Orm
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -182,6 +182,10 @@ namespace Orm::Query::Grammars
|
||||
QString whereNotExists(const WhereConditionItem &where) const;
|
||||
/*! Compile a where row values condition. */
|
||||
QString whereRowValues(const WhereConditionItem &where) const;
|
||||
/*! Compile a "between" where clause. */
|
||||
QString whereBetween(const WhereConditionItem &where) const;
|
||||
/*! Compile a "between" where clause using columns. */
|
||||
QString whereBetweenColumns(const WhereConditionItem &where) const;
|
||||
|
||||
/*! Compile a insert values lists. */
|
||||
QStringList compileInsertToVector(const QVector<QVariantMap> &values) const;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Orm::Query
|
||||
concept Remove = std::convertible_to<T, quint64> ||
|
||||
std::same_as<T, Query::Expression>;
|
||||
|
||||
// TODO querybuilder, whereDay/Month/..., whereBetween, whereFullText silverqx
|
||||
// TODO querybuilder, whereDay/Month/..., whereFullText silverqx
|
||||
// FUTURE querybuilder, paginator silverqx
|
||||
/*! Database query builder. */
|
||||
class SHAREDLIB_EXPORT Builder : public Concerns::BuildsQueries // clazy:exclude=copyable-polymorphic
|
||||
@@ -453,6 +453,34 @@ namespace Orm::Query
|
||||
/*! Add an "or where not null" clause to the query. */
|
||||
Builder &orWhereNotNull(const Column &column);
|
||||
|
||||
/* where between */
|
||||
/*! Add a "where between" statement to the query. */
|
||||
Builder &whereBetween(const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition = AND, bool nope = false);
|
||||
/*! Add an "or where between" statement to the query. */
|
||||
Builder &orWhereBetween(const Column &column, const WhereBetweenItem &values);
|
||||
/*! Add a "where not between" statement to the query. */
|
||||
Builder &whereNotBetween(const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition = AND);
|
||||
/*! Add an "or where not between" statement to the query. */
|
||||
Builder &orWhereNotBetween(const Column &column, const WhereBetweenItem &values);
|
||||
|
||||
/* where between columns */
|
||||
/*! Add a "where between" statement using columns to the query. */
|
||||
Builder &whereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition = AND, bool nope = false);
|
||||
/*! Add an "or where between" statement using columns to the query. */
|
||||
Builder &orWhereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns);
|
||||
/*! Add a "where not between" statement using columns to the query. */
|
||||
Builder &whereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition = AND);
|
||||
/*! Add an "or where not between" statement using columns to the query. */
|
||||
Builder &orWhereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns);
|
||||
|
||||
/* where sub-queries */
|
||||
/*! Add a basic where clause to the query with a full sub-select column. */
|
||||
template<Queryable C, WhereValue V>
|
||||
@@ -738,6 +766,8 @@ namespace Orm::Query
|
||||
QVector<QVariant> cleanBindings(const QVector<QVariant> &bindings) const;
|
||||
/*! Remove all of the expressions from a list of bindings. */
|
||||
QVector<QVariant> cleanBindings(QVector<QVariant> &&bindings) const;
|
||||
/*! Remove all of the expressions from the WhereBetweenItem bindings. */
|
||||
QVector<QVariant> cleanBindings(const WhereBetweenItem &bindings) const;
|
||||
|
||||
/*! Add a vector of basic where clauses to the query. */
|
||||
Builder &
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace Orm::Tiny
|
||||
// TODO model missing methods Model::replicate() silverqx
|
||||
// TODO model missing methods Comparing Models silverqx
|
||||
// TODO model missing methods Model::loadMissing() silverqx
|
||||
// TODO model missing methods Model::whereBetween() silverqx
|
||||
// TODO model missing methods EloquentCollection::toQuery() silverqx
|
||||
// TODO model missing saveOrFail(), updateOrFail(), deleteOrFail(), I will need to implement ManagesTransaction::transaction(callback) method silverqx
|
||||
/*! Base model class. */
|
||||
|
||||
@@ -550,6 +550,42 @@ namespace Tiny
|
||||
static std::unique_ptr<TinyBuilder<Derived>>
|
||||
orWhereNotNull(const Column &column);
|
||||
|
||||
/* where between */
|
||||
/*! Add a "where between" statement to the query. */
|
||||
static std::unique_ptr<TinyBuilder<Derived>>
|
||||
whereBetween(const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition = AND, bool nope = false);
|
||||
/*! Add an "or where between" statement to the query. */
|
||||
static std::unique_ptr<TinyBuilder<Derived>>
|
||||
orWhereBetween(const Column &column, const WhereBetweenItem &values);
|
||||
/*! Add a "where not between" statement to the query. */
|
||||
static std::unique_ptr<TinyBuilder<Derived>>
|
||||
whereNotBetween(const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition = AND);
|
||||
/*! Add an "or where not between" statement to the query. */
|
||||
static std::unique_ptr<TinyBuilder<Derived>>
|
||||
orWhereNotBetween(const Column &column, const WhereBetweenItem &values);
|
||||
|
||||
/* where between columns */
|
||||
/*! Add a "where between" statement using columns to the query. */
|
||||
static std::unique_ptr<TinyBuilder<Derived>>
|
||||
whereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition = AND, bool nope = false);
|
||||
/*! Add an "or where between" statement using columns to the query. */
|
||||
static std::unique_ptr<TinyBuilder<Derived>>
|
||||
orWhereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns);
|
||||
/*! Add a "where not between" statement using columns to the query. */
|
||||
static std::unique_ptr<TinyBuilder<Derived>>
|
||||
whereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition = AND);
|
||||
/*! Add an "or where not between" statement using columns to the query. */
|
||||
static std::unique_ptr<TinyBuilder<Derived>>
|
||||
orWhereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns);
|
||||
|
||||
/* where sub-queries */
|
||||
/*! Add a basic where clause to the query with a full sub-select column. */
|
||||
template<Queryable C, WhereValue V>
|
||||
@@ -2305,6 +2341,110 @@ namespace Tiny
|
||||
return builder;
|
||||
}
|
||||
|
||||
/* where between */
|
||||
|
||||
template<typename Derived, AllRelationsConcept ...AllRelations>
|
||||
std::unique_ptr<TinyBuilder<Derived>>
|
||||
ModelProxies<Derived, AllRelations...>::whereBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition, const bool nope)
|
||||
{
|
||||
auto builder = query();
|
||||
|
||||
builder->whereBetween(column, values, condition, nope);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
template<typename Derived, AllRelationsConcept ...AllRelations>
|
||||
std::unique_ptr<TinyBuilder<Derived>>
|
||||
ModelProxies<Derived, AllRelations...>::orWhereBetween(
|
||||
const Column &column, const WhereBetweenItem &values)
|
||||
{
|
||||
auto builder = query();
|
||||
|
||||
builder->whereBetween(column, values, OR);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
template<typename Derived, AllRelationsConcept ...AllRelations>
|
||||
std::unique_ptr<TinyBuilder<Derived>>
|
||||
ModelProxies<Derived, AllRelations...>::whereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition)
|
||||
{
|
||||
auto builder = query();
|
||||
|
||||
builder->whereBetween(column, values, condition, true);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
template<typename Derived, AllRelationsConcept ...AllRelations>
|
||||
std::unique_ptr<TinyBuilder<Derived>>
|
||||
ModelProxies<Derived, AllRelations...>::orWhereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values)
|
||||
{
|
||||
auto builder = query();
|
||||
|
||||
builder->whereBetween(column, values, OR, true);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/* where between columns */
|
||||
|
||||
template<typename Derived, AllRelationsConcept ...AllRelations>
|
||||
std::unique_ptr<TinyBuilder<Derived>>
|
||||
ModelProxies<Derived, AllRelations...>::whereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition, const bool nope)
|
||||
{
|
||||
auto builder = query();
|
||||
|
||||
builder->whereBetweenColumns(column, betweenColumns, condition, nope);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
template<typename Derived, AllRelationsConcept ...AllRelations>
|
||||
std::unique_ptr<TinyBuilder<Derived>>
|
||||
ModelProxies<Derived, AllRelations...>::orWhereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns)
|
||||
{
|
||||
auto builder = query();
|
||||
|
||||
builder->whereBetweenColumns(column, betweenColumns, OR);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
template<typename Derived, AllRelationsConcept ...AllRelations>
|
||||
std::unique_ptr<TinyBuilder<Derived>>
|
||||
ModelProxies<Derived, AllRelations...>::whereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition)
|
||||
{
|
||||
auto builder = query();
|
||||
|
||||
builder->whereBetweenColumns(column, betweenColumns, condition, true);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
template<typename Derived, AllRelationsConcept ...AllRelations>
|
||||
std::unique_ptr<TinyBuilder<Derived>>
|
||||
ModelProxies<Derived, AllRelations...>::orWhereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns)
|
||||
{
|
||||
auto builder = query();
|
||||
|
||||
builder->whereBetweenColumns(column, betweenColumns, OR, true);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/* where sub-queries */
|
||||
|
||||
template<typename Derived, AllRelationsConcept ...AllRelations>
|
||||
|
||||
@@ -543,6 +543,40 @@ namespace Tiny::Relations
|
||||
/*! Add an "or where not null" clause to the query. */
|
||||
const Relation<Model, Related> &orWhereNotNull(const Column &column) const;
|
||||
|
||||
/* where between */
|
||||
/*! Add a "where between" statement to the query. */
|
||||
const Relation<Model, Related> &whereBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition = AND, bool nope = false) const;
|
||||
/*! Add an "or where between" statement to the query. */
|
||||
const Relation<Model, Related> &orWhereBetween(
|
||||
const Column &column, const WhereBetweenItem &values) const;
|
||||
/*! Add a "where not between" statement to the query. */
|
||||
const Relation<Model, Related> &whereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition = AND) const;
|
||||
/*! Add an "or where not between" statement to the query. */
|
||||
const Relation<Model, Related> &orWhereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values) const;
|
||||
|
||||
/* where between columns */
|
||||
/*! Add a "where between" statement using columns to the query. */
|
||||
const Relation<Model, Related> &whereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition = AND, bool nope = false) const;
|
||||
/*! Add an "or where between" statement using columns to the query. */
|
||||
const Relation<Model, Related> &orWhereBetweenColumns(
|
||||
const Column &column,
|
||||
const WhereBetweenColumnsItem &betweenColumns) const;
|
||||
/*! Add a "where not between" statement using columns to the query. */
|
||||
const Relation<Model, Related> &whereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition = AND) const;
|
||||
/*! Add an "or where not between" statement using columns to the query. */
|
||||
const Relation<Model, Related> &orWhereNotBetweenColumns(
|
||||
const Column &column,
|
||||
const WhereBetweenColumnsItem &betweenColumns) const;
|
||||
|
||||
/* where sub-queries */
|
||||
/*! Add a basic where clause to the query with a full sub-select column. */
|
||||
template<Queryable C, WhereValue V>
|
||||
@@ -2140,6 +2174,94 @@ namespace Tiny::Relations
|
||||
return relation();
|
||||
}
|
||||
|
||||
/* where between */
|
||||
|
||||
template<class Model, class Related>
|
||||
const Relation<Model, Related> &
|
||||
RelationProxies<Model, Related>::whereBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition, const bool nope) const
|
||||
{
|
||||
getQuery().whereBetween(column, values, condition, nope);
|
||||
|
||||
return relation();
|
||||
}
|
||||
|
||||
template<class Model, class Related>
|
||||
const Relation<Model, Related> &
|
||||
RelationProxies<Model, Related>::orWhereBetween(
|
||||
const Column &column, const WhereBetweenItem &values) const
|
||||
{
|
||||
getQuery().whereBetween(column, values, OR);
|
||||
|
||||
return relation();
|
||||
}
|
||||
|
||||
template<class Model, class Related>
|
||||
const Relation<Model, Related> &
|
||||
RelationProxies<Model, Related>::whereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition) const
|
||||
{
|
||||
getQuery().whereBetween(column, values, condition, true);
|
||||
|
||||
return relation();
|
||||
}
|
||||
|
||||
template<class Model, class Related>
|
||||
const Relation<Model, Related> &
|
||||
RelationProxies<Model, Related>::orWhereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values) const
|
||||
{
|
||||
getQuery().whereBetween(column, values, OR, true);
|
||||
|
||||
return relation();
|
||||
}
|
||||
|
||||
/* where between columns */
|
||||
|
||||
template<class Model, class Related>
|
||||
const Relation<Model, Related> &
|
||||
RelationProxies<Model, Related>::whereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition, const bool nope) const
|
||||
{
|
||||
getQuery().whereBetweenColumns(column, betweenColumns, condition, nope);
|
||||
|
||||
return relation();
|
||||
}
|
||||
|
||||
template<class Model, class Related>
|
||||
const Relation<Model, Related> &
|
||||
RelationProxies<Model, Related>::orWhereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns) const
|
||||
{
|
||||
getQuery().whereBetweenColumns(column, betweenColumns, OR);
|
||||
|
||||
return relation();
|
||||
}
|
||||
|
||||
template<class Model, class Related>
|
||||
const Relation<Model, Related> &
|
||||
RelationProxies<Model, Related>::whereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition) const
|
||||
{
|
||||
getQuery().whereBetweenColumns(column, betweenColumns, condition, true);
|
||||
|
||||
return relation();
|
||||
}
|
||||
|
||||
template<class Model, class Related>
|
||||
const Relation<Model, Related> &
|
||||
RelationProxies<Model, Related>::orWhereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns) const
|
||||
{
|
||||
getQuery().whereBetweenColumns(column, betweenColumns, OR, true);
|
||||
|
||||
return relation();
|
||||
}
|
||||
|
||||
/* where sub-queries */
|
||||
|
||||
template<class Model, class Related>
|
||||
|
||||
@@ -382,6 +382,38 @@ namespace Tiny
|
||||
/*! Add an "or where not null" clause to the query. */
|
||||
TinyBuilder<Model> &orWhereNotNull(const Column &column);
|
||||
|
||||
/* where between */
|
||||
/*! Add a "where between" statement to the query. */
|
||||
TinyBuilder<Model> &whereBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition = AND, bool nope = false);
|
||||
/*! Add an "or where between" statement to the query. */
|
||||
TinyBuilder<Model> &orWhereBetween(
|
||||
const Column &column, const WhereBetweenItem &values);
|
||||
/*! Add a "where not between" statement to the query. */
|
||||
TinyBuilder<Model> &whereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition = AND);
|
||||
/*! Add an "or where not between" statement to the query. */
|
||||
TinyBuilder<Model> &orWhereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values);
|
||||
|
||||
/* where between columns */
|
||||
/*! Add a "where between" statement using columns to the query. */
|
||||
TinyBuilder<Model> &whereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition = AND, bool nope = false);
|
||||
/*! Add an "or where between" statement using columns to the query. */
|
||||
TinyBuilder<Model> &orWhereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns);
|
||||
/*! Add a "where not between" statement using columns to the query. */
|
||||
TinyBuilder<Model> &whereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition = AND);
|
||||
/*! Add an "or where not between" statement using columns to the query. */
|
||||
TinyBuilder<Model> &orWhereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns);
|
||||
|
||||
/* where sub-queries */
|
||||
/*! Add a basic where clause to the query with a full sub-select column. */
|
||||
template<Queryable C, WhereValue V>
|
||||
@@ -1436,6 +1468,86 @@ namespace Tiny
|
||||
return builder();
|
||||
}
|
||||
|
||||
/* where between columns */
|
||||
|
||||
template<typename Model>
|
||||
TinyBuilder<Model> &
|
||||
BuilderProxies<Model>::whereBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition, const bool nope)
|
||||
{
|
||||
toBase().whereBetween(column, values, condition, nope);
|
||||
return builder();
|
||||
}
|
||||
|
||||
template<typename Model>
|
||||
TinyBuilder<Model> &
|
||||
BuilderProxies<Model>::orWhereBetween(
|
||||
const Column &column, const WhereBetweenItem &values)
|
||||
{
|
||||
toBase().whereBetween(column, values, OR);
|
||||
return builder();
|
||||
}
|
||||
|
||||
template<typename Model>
|
||||
TinyBuilder<Model> &
|
||||
BuilderProxies<Model>::whereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition)
|
||||
{
|
||||
toBase().whereBetween(column, values, condition, true);
|
||||
return builder();
|
||||
}
|
||||
|
||||
template<typename Model>
|
||||
TinyBuilder<Model> &
|
||||
BuilderProxies<Model>::orWhereNotBetween(
|
||||
const Column &column, const WhereBetweenItem &values)
|
||||
{
|
||||
toBase().whereBetween(column, values, OR, true);
|
||||
return builder();
|
||||
}
|
||||
|
||||
/* where between columns */
|
||||
|
||||
template<typename Model>
|
||||
TinyBuilder<Model> &
|
||||
BuilderProxies<Model>::whereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition, const bool nope)
|
||||
{
|
||||
toBase().whereBetweenColumns(column, betweenColumns, condition, nope);
|
||||
return builder();
|
||||
}
|
||||
|
||||
template<typename Model>
|
||||
TinyBuilder<Model> &
|
||||
BuilderProxies<Model>::orWhereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns)
|
||||
{
|
||||
toBase().whereBetweenColumns(column, betweenColumns, OR);
|
||||
return builder();
|
||||
}
|
||||
|
||||
template<typename Model>
|
||||
TinyBuilder<Model> &
|
||||
BuilderProxies<Model>::whereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition)
|
||||
{
|
||||
toBase().whereBetweenColumns(column, betweenColumns, condition, true);
|
||||
return builder();
|
||||
}
|
||||
|
||||
template<typename Model>
|
||||
TinyBuilder<Model> &
|
||||
BuilderProxies<Model>::orWhereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns)
|
||||
{
|
||||
toBase().whereBetweenColumns(column, betweenColumns, OR, true);
|
||||
return builder();
|
||||
}
|
||||
|
||||
/* where sub-queries */
|
||||
|
||||
template<typename Model>
|
||||
|
||||
@@ -449,6 +449,28 @@ QString Grammar::whereRowValues(const WhereConditionItem &where) const
|
||||
parametrize(where.values));
|
||||
}
|
||||
|
||||
QString Grammar::whereBetween(const WhereConditionItem &where) const
|
||||
{
|
||||
auto between = where.nope ? QStringLiteral("not between")
|
||||
: QStringLiteral("between");
|
||||
|
||||
return QStringLiteral("%1 %2 %3 and %4").arg(wrap(where.column),
|
||||
std::move(between),
|
||||
parameter(where.between.min),
|
||||
parameter(where.between.max));
|
||||
}
|
||||
|
||||
QString Grammar::whereBetweenColumns(const WhereConditionItem &where) const
|
||||
{
|
||||
auto between = where.nope ? QStringLiteral("not between")
|
||||
: QStringLiteral("between");
|
||||
|
||||
return QStringLiteral("%1 %2 %3 and %4").arg(wrap(where.column),
|
||||
std::move(between),
|
||||
wrap(where.betweenColumns.min),
|
||||
wrap(where.betweenColumns.max));
|
||||
}
|
||||
|
||||
QStringList
|
||||
Grammar::compileInsertToVector(const QVector<QVariantMap> &values) const
|
||||
{
|
||||
|
||||
@@ -216,6 +216,8 @@ MySqlGrammar::getWhereMethod(const WhereType whereType) const
|
||||
bind(&MySqlGrammar::whereExists),
|
||||
bind(&MySqlGrammar::whereNotExists),
|
||||
bind(&MySqlGrammar::whereRowValues),
|
||||
bind(&MySqlGrammar::whereBetween),
|
||||
bind(&MySqlGrammar::whereBetweenColumns),
|
||||
};
|
||||
|
||||
T_THREAD_LOCAL
|
||||
|
||||
@@ -200,6 +200,8 @@ PostgresGrammar::getWhereMethod(const WhereType whereType) const
|
||||
bind(&PostgresGrammar::whereExists),
|
||||
bind(&PostgresGrammar::whereNotExists),
|
||||
bind(&PostgresGrammar::whereRowValues),
|
||||
bind(&PostgresGrammar::whereBetween),
|
||||
bind(&PostgresGrammar::whereBetweenColumns),
|
||||
};
|
||||
|
||||
T_THREAD_LOCAL
|
||||
|
||||
@@ -176,6 +176,8 @@ SQLiteGrammar::getWhereMethod(const WhereType whereType) const
|
||||
bind(&SQLiteGrammar::whereExists),
|
||||
bind(&SQLiteGrammar::whereNotExists),
|
||||
bind(&SQLiteGrammar::whereRowValues),
|
||||
bind(&SQLiteGrammar::whereBetween),
|
||||
bind(&SQLiteGrammar::whereBetweenColumns),
|
||||
};
|
||||
|
||||
T_THREAD_LOCAL
|
||||
|
||||
@@ -700,6 +700,68 @@ Builder &Builder::orWhereNotNull(const Column &column)
|
||||
return orWhereNotNull(QVector<Column> {column});
|
||||
}
|
||||
|
||||
/* where between */
|
||||
|
||||
Builder &Builder::whereBetween(const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition, const bool nope)
|
||||
{
|
||||
m_wheres.append({.column = column, .condition = condition,
|
||||
.type = WhereType::BETWEEN, .nope = nope,
|
||||
.between = values});
|
||||
|
||||
addBinding(cleanBindings(values), BindingType::WHERE);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Builder &Builder::orWhereBetween(const Column &column, const WhereBetweenItem &values)
|
||||
{
|
||||
return whereBetween(column, values, OR);
|
||||
}
|
||||
|
||||
Builder &Builder::whereNotBetween(const Column &column, const WhereBetweenItem &values,
|
||||
const QString &condition)
|
||||
{
|
||||
return whereBetween(column, values, condition, true);
|
||||
}
|
||||
|
||||
Builder &Builder::orWhereNotBetween(const Column &column, const WhereBetweenItem &values)
|
||||
{
|
||||
return whereBetween(column, values, OR, true);
|
||||
}
|
||||
|
||||
/* where between columns */
|
||||
|
||||
Builder &Builder::whereBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition, const bool nope)
|
||||
{
|
||||
m_wheres.append({.column = column, .condition = condition,
|
||||
.type = WhereType::BETWEEN_COLUMNS, .nope = nope,
|
||||
.betweenColumns = betweenColumns});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Builder &Builder::orWhereBetweenColumns(const Column &column,
|
||||
const WhereBetweenColumnsItem &betweenColumns)
|
||||
{
|
||||
return whereBetweenColumns(column, betweenColumns, OR);
|
||||
}
|
||||
|
||||
Builder &Builder::whereNotBetweenColumns(
|
||||
const Column &column, const WhereBetweenColumnsItem &betweenColumns,
|
||||
const QString &condition)
|
||||
{
|
||||
return whereBetweenColumns(column, betweenColumns, condition, true);
|
||||
}
|
||||
|
||||
Builder &Builder::orWhereNotBetweenColumns(const Column &column,
|
||||
const WhereBetweenColumnsItem &betweenColumns)
|
||||
{
|
||||
return whereBetweenColumns(column, betweenColumns, OR, true);
|
||||
}
|
||||
|
||||
/* where exists */
|
||||
|
||||
Builder &Builder::whereExists(
|
||||
@@ -1283,6 +1345,24 @@ QVector<QVariant> Builder::cleanBindings(QVector<QVariant> &&bindings) const
|
||||
return cleanedBindings;
|
||||
}
|
||||
|
||||
QVector<QVariant> Builder::cleanBindings(const WhereBetweenItem &bindings) const
|
||||
{
|
||||
QVector<QVariant> cleanedBindings;
|
||||
cleanedBindings.reserve(2);
|
||||
|
||||
if (const auto &min = bindings.min;
|
||||
!min.canConvert<Expression>()
|
||||
)
|
||||
cleanedBindings << min;
|
||||
|
||||
if (const auto &max = bindings.max;
|
||||
!max.canConvert<Expression>()
|
||||
)
|
||||
cleanedBindings << max;
|
||||
|
||||
return cleanedBindings;
|
||||
}
|
||||
|
||||
Builder &
|
||||
Builder::addArrayOfWheres(const QVector<WhereItem> &values, const QString &condition,
|
||||
const QString &defaultCondition)
|
||||
|
||||
@@ -52,6 +52,8 @@ private Q_SLOTS:
|
||||
void implode_EmptyResult() const;
|
||||
void implode_QualifiedColumnOrKey() const;
|
||||
|
||||
void whereBetween() const;
|
||||
|
||||
void updateOrInsert() const;
|
||||
void updateOrInsert_EmptyValues() const;
|
||||
|
||||
@@ -460,6 +462,29 @@ void tst_QueryBuilder::implode_QualifiedColumnOrKey() const
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QueryBuilder::whereBetween() const
|
||||
{
|
||||
QFETCH_GLOBAL(QString, connection);
|
||||
|
||||
auto result = createQuery(connection)->from("torrents")
|
||||
.whereBetween("size", {12, 14})
|
||||
.orderBy(ID)
|
||||
.get();
|
||||
|
||||
QVERIFY(result.isActive() && result.isSelect() && !result.isValid());
|
||||
QVERIFY(QueryUtils::queryResultSize(result) == 3);
|
||||
|
||||
QVector<quint64> expectedIds {2, 3, 4};
|
||||
|
||||
QVector<quint64> actualIds;
|
||||
actualIds.reserve(expectedIds.size());
|
||||
|
||||
while (result.next())
|
||||
actualIds << result.value("id").value<quint64>();
|
||||
|
||||
QCOMPARE(actualIds, expectedIds);
|
||||
}
|
||||
|
||||
void tst_QueryBuilder::updateOrInsert() const
|
||||
{
|
||||
QFETCH_GLOBAL(QString, connection);
|
||||
|
||||
@@ -176,6 +176,14 @@ private Q_SLOTS:
|
||||
void whereNull_WithVectorValue() const;
|
||||
void whereNotNull_WithVectorValue() const;
|
||||
|
||||
void whereBetween() const;
|
||||
void whereNotBetween() const;
|
||||
void whereBetween_ColumnExpression() const;
|
||||
|
||||
void whereBetweenColumns() const;
|
||||
void whereNotBetweenColumns() const;
|
||||
void whereBetweenColumns_ColumnExpression() const;
|
||||
|
||||
void whereExists() const;
|
||||
void whereNotExists() const;
|
||||
void orWhereExists() const;
|
||||
@@ -2427,6 +2435,181 @@ void tst_MySql_QueryBuilder::whereNotNull_WithVectorValue() const
|
||||
}
|
||||
}
|
||||
|
||||
void tst_MySql_QueryBuilder::whereBetween() const
|
||||
{
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").whereBetween("size", {12, 14});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `size` between ? and ?");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(12), QVariant(14)}));
|
||||
}
|
||||
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereBetween("size", {12, 14});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or `size` between ? and ?");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2), QVariant(12), QVariant(14)}));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_MySql_QueryBuilder::whereNotBetween() const
|
||||
{
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").whereNotBetween("size", {12, 14});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `size` not between ? and ?");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(12), QVariant(14)}));
|
||||
}
|
||||
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereNotBetween("size", {12, 14});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or `size` not between ? and ?");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2), QVariant(12), QVariant(14)}));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_MySql_QueryBuilder::whereBetween_ColumnExpression() const
|
||||
{
|
||||
// min. value as expression
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereBetween("size", {DB::raw(12), 14});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or `size` between 12 and ?");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2), QVariant(14)}));
|
||||
}
|
||||
// max. value as expression
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereBetween("size", {12, DB::raw(14)});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or `size` between ? and 14");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2), QVariant(12)}));
|
||||
}
|
||||
// Both min. and max. values as expressions
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereBetween("size", {DB::raw(12), DB::raw(14)});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or `size` between 12 and 14");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2)}));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_MySql_QueryBuilder::whereBetweenColumns() const
|
||||
{
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents")
|
||||
.whereBetweenColumns("size", {"min", "max"});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `size` between `min` and `max`");
|
||||
QVERIFY(builder->getBindings().isEmpty());
|
||||
}
|
||||
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereBetweenColumns("size", {"min", "max"});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or "
|
||||
"`size` between `min` and `max`");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2)}));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_MySql_QueryBuilder::whereNotBetweenColumns() const
|
||||
{
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents")
|
||||
.whereNotBetweenColumns("size", {"min", "max"});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `size` not between `min` and `max`");
|
||||
QVERIFY(builder->getBindings().isEmpty());
|
||||
}
|
||||
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereNotBetweenColumns("size", {"min", "max"});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or "
|
||||
"`size` not between `min` and `max`");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2)}));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_MySql_QueryBuilder::whereBetweenColumns_ColumnExpression() const
|
||||
{
|
||||
// min. column name as expression
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereBetweenColumns("size", {DB::raw("min"), "max"});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or "
|
||||
"`size` between min and `max`");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2)}));
|
||||
}
|
||||
// max. column name as expression
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereBetweenColumns("size", {"min", DB::raw("max")});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or "
|
||||
"`size` between `min` and max");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2)}));
|
||||
}
|
||||
// Both min. and max. column names as expressions
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
builder->select("*").from("torrents").where(ID, GT, 2)
|
||||
.orWhereBetweenColumns("size", {DB::raw("min"), DB::raw("max")});
|
||||
QCOMPARE(builder->toSql(),
|
||||
"select * from `torrents` where `id` > ? or "
|
||||
"`size` between min and max");
|
||||
QCOMPARE(builder->getBindings(),
|
||||
QVector<QVariant>({QVariant(2)}));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_MySql_QueryBuilder::whereExists() const
|
||||
{
|
||||
auto builder = createQuery();
|
||||
|
||||
Reference in New Issue
Block a user