added missing raw methods

or/whereRaw(), groupByRaw(), or/havingRaw(), orderByRaw().

 - added docs
 - tested manually in Playground
This commit is contained in:
silverqx
2021-07-06 18:28:58 +02:00
parent 4dfb8ce44d
commit 867a5f6587
12 changed files with 403 additions and 8 deletions

View File

@@ -148,6 +148,55 @@ The `selectRaw` method can be used in place of `addSelect(DB::raw(...))`. This m
->selectRaw("price * ? as price_with_tax", {1.0825})
.get();
<a name="fromraw"></a>
#### `fromRaw`
The `fromRaw` method may be used to provide a raw string as the value of the "from" clause:
auto users = DB::connection("postgres").query()
->fromRaw("(select id, name from users where id < ?) as u", {5})
.where("id", "<", 3)
.get();
<a name="whereraw-orwhereraw"></a>
#### `whereRaw / orWhereRaw`
The `whereRaw` and `orWhereRaw` methods can be used to inject a raw "where" clause into your query. These methods accept an optional vector of bindings as their second argument:
auto orders = DB::table("orders")
->whereRaw("price > IF(state = \"TX\", ?, 100)", {200})
.get();
<a name="groupbyraw"></a>
### `groupByRaw`
The `groupByRaw` method may be used to provide a raw string as the value of the `group by` clause:
auto orders = DB::table("orders")
->select({"city", "state"})
.groupByRaw("city, state")
.get();
<a name="havingraw-orhavingraw"></a>
#### `havingRaw / orHavingRaw`
The `havingRaw` and `orHavingRaw` methods may be used to provide a raw string as the value of the "having" clause. These methods accept an optional vector of bindings as their second argument:
auto orders = DB::table("orders")
->select({"department", DB::raw("SUM(price) as total_sales")})
.groupBy("department")
.havingRaw("SUM(price) > ?", {2500})
.get();
<a name="orderbyraw"></a>
#### `orderByRaw`
The `orderByRaw` method may be used to provide a raw string as the value of the "order by" clause:
auto orders = DB::table("orders")
->orderByRaw("updated_at - created_at DESC")
.get();
<a name="joins"></a>
## Joins

View File

@@ -69,6 +69,7 @@ namespace Query
NOT_IN,
NULL_,
NOT_NULL,
RAW,
};
struct WhereConditionItem
@@ -81,13 +82,16 @@ namespace Query
QSharedPointer<QueryBuilder> nestedQuery {nullptr};
QVector<QVariant> values {};
Column columnTwo {};
QString sql {};
};
enum struct HavingType
{
UNDEFINED = -1,
BASIC,
RAW,
};
struct HavingConditionItem
{
Column column;
@@ -95,12 +99,14 @@ namespace Query
QString comparison {"="};
QString condition {"and"};
HavingType type {HavingType::UNDEFINED};
QString sql {};
};
struct OrderByItem
{
Column column;
QString direction {"asc"};
Column column;
QString direction {"asc"};
QString sql {};
};
struct SHAREDLIB_EXPORT UpdateItem

View File

@@ -140,7 +140,10 @@ namespace Orm::Query::Grammars
QString whereNull(const WhereConditionItem &where) const;
/*! Compile a "where not null" clause. */
QString whereNotNull(const WhereConditionItem &where) const;
/*! Compile a raw where clause. */
QString whereRaw(const WhereConditionItem &where) const;
// CUR reorder silverqx
/*! Compile the "order by" portions of the query. */
QString compileOrders(const QueryBuilder &query) const;
/*! Compile the query orders to the vector. */

View File

@@ -144,13 +144,12 @@ namespace Query
/*! Set the table which the query is targeting. */
Builder &from(Expression &&table);
/*! Set the table which the query is targeting. */
Builder &fromRaw(const QString &expression,
const QVector<QVariant> &bindings = {});
/*! Makes "from" fetch from a subquery. */
template<SubQuery T>
Builder &fromSub(T &&query, const QString &as);
/*! Set the table which the query is targeting. */
Builder &fromRaw(const QString &expression,
const QVector<QVariant> &bindings = {});
/*! Add a join clause to the query. */
template<JoinTable T>
@@ -299,6 +298,12 @@ namespace Query
/*! Add an "or where not null" clause to the query. */
Builder &orWhereNotNull(const Column &column);
/*! Add a raw "where" clause to the query. */
Builder &whereRaw(const QString &sql, const QVector<QVariant> &bindings = {},
const QString &condition = "and");
/*! Add a raw "or where" clause to the query. */
Builder &orWhereRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add a "group by" clause to the query. */
Builder &groupBy(const QVector<Column> &groups);
/*! Add a "group by" clause to the query. */
@@ -307,6 +312,9 @@ namespace Query
template<ColumnConcept ...Args>
Builder &groupBy(Args &&...groups);
/*! Add a raw "groupBy" clause to the query. */
Builder &groupByRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add a "having" clause to the query. */
Builder &having(const Column &column, const QString &comparison,
const QVariant &value, const QString &condition = "and");
@@ -314,11 +322,20 @@ namespace Query
Builder &orHaving(const Column &column, const QString &comparison,
const QVariant &value);
/*! Add a raw "having" clause to the query. */
Builder &havingRaw(const QString &sql, const QVector<QVariant> &bindings = {},
const QString &condition = "and");
/*! Add a raw "or having" clause to the query. */
Builder &orHavingRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add an "order by" clause to the query. */
Builder &orderBy(const Column &column, const QString &direction = "asc");
/*! Add a descending "order by" clause to the query. */
Builder &orderByDesc(const Column &column);
/*! Add a raw "order by" clause to the query. */
Builder &orderByRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add an "order by" clause for a timestamp to the query. */
Builder &latest(const Column &column = "created_at");
/*! Add an "order by" clause for a timestamp to the query. */

View File

@@ -499,6 +499,14 @@ namespace Relations {
static std::unique_ptr<TinyBuilder<Derived>>
orWhereNotNull(const Column &column);
/*! Add a raw "where" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
whereRaw(const QString &sql, const QVector<QVariant> &bindings = {},
const QString &condition = "and");
/*! Add a raw "or where" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
orWhereRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add a "group by" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
groupBy(const QVector<Column> &groups);
@@ -510,6 +518,10 @@ namespace Relations {
static std::unique_ptr<TinyBuilder<Derived>>
groupBy(Args &&...groups);
/*! Add a raw "groupBy" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
groupByRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add a "having" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
having(const Column &column, const QString &comparison,
@@ -519,6 +531,14 @@ namespace Relations {
orHaving(const Column &column, const QString &comparison,
const QVariant &value);
/*! Add a raw "having" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
havingRaw(const QString &sql, const QVector<QVariant> &bindings = {},
const QString &condition = "and");
/*! Add a raw "or having" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
orHavingRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add an "order by" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
orderBy(const Column &column, const QString &direction = "asc");
@@ -526,6 +546,10 @@ namespace Relations {
static std::unique_ptr<TinyBuilder<Derived>>
orderByDesc(const Column &column);
/*! Add a raw "order by" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
orderByRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add an "order by" clause for a timestamp to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
latest(const Column &column = "");
@@ -2379,6 +2403,31 @@ namespace Relations {
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::whereRaw(
const QString &sql, const QVector<QVariant> &bindings,
const QString &condition)
{
auto builder = query();
builder->whereRaw(sql, bindings, condition);
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::orWhereRaw(
const QString &sql, const QVector<QVariant> &bindings)
{
auto builder = query();
builder->whereRaw(sql, bindings, QStringLiteral("or"));
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::groupBy(const QVector<Column> &groups)
@@ -2401,6 +2450,18 @@ namespace Relations {
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::groupByRaw(
const QString &sql, const QVector<QVariant> &bindings)
{
auto builder = query();
builder->groupByRaw(sql, bindings);
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
template<ColumnConcept ...Args>
std::unique_ptr<TinyBuilder<Derived>>
@@ -2438,6 +2499,31 @@ namespace Relations {
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::havingRaw(
const QString &sql, const QVector<QVariant> &bindings,
const QString &condition)
{
auto builder = query();
builder->havingRaw(sql, bindings, condition);
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::orHavingRaw(
const QString &sql, const QVector<QVariant> &bindings)
{
auto builder = query();
builder->havingRaw(sql, bindings, QStringLiteral("or"));
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::orderBy(const Column &column,
@@ -2461,6 +2547,18 @@ namespace Relations {
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::orderByRaw(const QString &sql,
const QVector<QVariant> &bindings)
{
auto builder = query();
builder->orderByRaw(sql, bindings);
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::latest(const Column &column)

View File

@@ -443,6 +443,14 @@ namespace Relations
/*! Add an "or where not null" clause to the query. */
const Relation &orWhereNotNull(const Column &column) const;
/*! Add a raw "where" clause to the query. */
const Relation &whereRaw(const QString &sql,
const QVector<QVariant> &bindings = {},
const QString &condition = "and") const;
/*! Add a raw "or where" clause to the query. */
const Relation &orWhereRaw(const QString &sql,
const QVector<QVariant> &bindings = {}) const;
/*! Add a "group by" clause to the query. */
const Relation &groupBy(const QVector<Column> &groups) const;
/*! Add a "group by" clause to the query. */
@@ -451,6 +459,10 @@ namespace Relations
template<ColumnConcept ...Args>
const Relation &groupBy(Args &&...groups) const;
/*! Add a raw "groupBy" clause to the query. */
const Relation &groupByRaw(const QString &sql,
const QVector<QVariant> &bindings = {}) const;
/*! Add a "having" clause to the query. */
const Relation &having(const Column &column, const QString &comparison,
const QVariant &value,
@@ -459,12 +471,24 @@ namespace Relations
const Relation &orHaving(const Column &column, const QString &comparison,
const QVariant &value) const;
/*! Add a raw "having" clause to the query. */
const Relation &havingRaw(const QString &sql,
const QVector<QVariant> &bindings = {},
const QString &condition = "and") const;
/*! Add a raw "or having" clause to the query. */
const Relation &orHavingRaw(const QString &sql,
const QVector<QVariant> &bindings = {}) const;
/*! Add an "order by" clause to the query. */
const Relation &orderBy(const Column &column,
const QString &direction = "asc") const;
/*! Add a descending "order by" clause to the query. */
const Relation &orderByDesc(const Column &column) const;
/*! Add a raw "order by" clause to the query. */
const Relation &orderByRaw(const QString &sql,
const QVector<QVariant> &bindings = {}) const;
/*! Add an "order by" clause for a timestamp to the query. */
const Relation &latest(const Column &column = "") const;
/*! Add an "order by" clause for a timestamp to the query. */
@@ -1466,6 +1490,27 @@ namespace Relations
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::whereRaw(
const QString &sql, const QVector<QVariant> &bindings,
const QString &condition) const
{
m_query->whereRaw(sql, bindings, condition);
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::orWhereRaw(
const QString &sql, const QVector<QVariant> &bindings) const
{
m_query->whereRaw(sql, bindings, QStringLiteral("or"));
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::groupBy(const QVector<Column> &groups) const
@@ -1494,6 +1539,16 @@ namespace Relations
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::groupByRaw(const QString &sql,
const QVector<QVariant> &bindings) const
{
m_query->groupByRaw(sql, bindings);
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::having(
@@ -1515,6 +1570,27 @@ namespace Relations
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::havingRaw(
const QString &sql, const QVector<QVariant> &bindings,
const QString &condition) const
{
m_query->havingRaw(sql, bindings, condition);
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::orHavingRaw(
const QString &sql, const QVector<QVariant> &bindings) const
{
m_query->havingRaw(sql, bindings, QStringLiteral("or"));
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::orderBy(const Column &column,
@@ -1534,6 +1610,16 @@ namespace Relations
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::orderByRaw(const QString &sql,
const QVector<QVariant> &bindings) const
{
m_query->orderByRaw(sql, bindings);
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::latest(const Column &column) const

View File

@@ -342,6 +342,12 @@ namespace Relations
/*! Add an "or where not null" clause to the query. */
Builder &orWhereNotNull(const Column &column);
/*! Add a raw "where" clause to the query. */
Builder &whereRaw(const QString &sql, const QVector<QVariant> &bindings = {},
const QString &condition = "and");
/*! Add a raw "or where" clause to the query. */
Builder &orWhereRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add a "group by" clause to the query. */
Builder &groupBy(const QVector<Column> &groups);
/*! Add a "group by" clause to the query. */
@@ -350,6 +356,9 @@ namespace Relations
template<ColumnConcept ...Args>
Builder &groupBy(Args &&...groups);
/*! Add a raw "groupBy" clause to the query. */
Builder &groupByRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add a "having" clause to the query. */
Builder &having(const Column &column, const QString &comparison,
const QVariant &value, const QString &condition = "and");
@@ -357,11 +366,20 @@ namespace Relations
Builder &orHaving(const Column &column, const QString &comparison,
const QVariant &value);
/*! Add a raw "having" clause to the query. */
Builder &havingRaw(const QString &sql, const QVector<QVariant> &bindings = {},
const QString &condition = "and");
/*! Add a raw "or having" clause to the query. */
Builder &orHavingRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add an "order by" clause to the query. */
Builder &orderBy(const Column &column, const QString &direction = "asc");
/*! Add a descending "order by" clause to the query. */
Builder &orderByDesc(const Column &column);
/*! Add a raw "order by" clause to the query. */
Builder &orderByRaw(const QString &sql, const QVector<QVariant> &bindings = {});
/*! Add an "order by" clause for a timestamp to the query. */
Builder &latest(const Column &column = "");
/*! Add an "order by" clause for a timestamp to the query. */
@@ -1380,6 +1398,23 @@ namespace Relations
return *this;
}
template<typename Model>
Builder<Model> &
Builder<Model>::whereRaw(const QString &sql, const QVector<QVariant> &bindings,
const QString &condition)
{
toBase().whereRaw(sql, bindings, condition);
return *this;
}
template<typename Model>
Builder<Model> &
Builder<Model>::orWhereRaw(const QString &sql, const QVector<QVariant> &bindings)
{
toBase().whereRaw(sql, bindings, QStringLiteral("or"));
return *this;
}
template<typename Model>
Builder<Model> &Builder<Model>::groupBy(const QVector<Column> &groups)
{
@@ -1402,6 +1437,14 @@ namespace Relations
return *this;
}
template<typename Model>
Builder<Model> &
Builder<Model>::groupByRaw(const QString &sql, const QVector<QVariant> &bindings)
{
toBase().groupByRaw(sql, bindings);
return *this;
}
template<typename Model>
Builder<Model> &
Builder<Model>::having(const Column &column, const QString &comparison,
@@ -1420,6 +1463,23 @@ namespace Relations
return *this;
}
template<typename Model>
Builder<Model> &
Builder<Model>::havingRaw(const QString &sql, const QVector<QVariant> &bindings,
const QString &condition)
{
toBase().havingRaw(sql, bindings, condition);
return *this;
}
template<typename Model>
Builder<Model> &
Builder<Model>::orHavingRaw(const QString &sql, const QVector<QVariant> &bindings)
{
toBase().havingRaw(sql, bindings, QStringLiteral("or"));
return *this;
}
template<typename Model>
Builder<Model> &
Builder<Model>::orderBy(const Column &column, const QString &direction)
@@ -1435,6 +1495,14 @@ namespace Relations
return *this;
}
template<typename Model>
Builder<Model> &Builder<Model>::orderByRaw(const QString &sql,
const QVector<QVariant> &bindings)
{
toBase().orderByRaw(sql, bindings);
return *this;
}
template<typename Model>
Builder<Model> &
Builder<Model>::latest(const Column &column)

View File

@@ -284,10 +284,19 @@ QString Grammar::compileHavings(const QueryBuilder &query) const
QString Grammar::compileHaving(const HavingConditionItem &having) const
{
/* If the having clause is "raw", we can just return the clause straight away
without doing any more processing on it. Otherwise, we will compile the
clause into SQL based on the components that make it up from builder. */
switch (having.type) {
T_LIKELY
case HavingType::BASIC:
return compileBasicHaving(having);
T_UNLIKELY
case HavingType::RAW:
return QStringLiteral("%1 %2").arg(having.condition, having.sql);
T_UNLIKELY
default:
throw RuntimeError(QStringLiteral("Unknown HavingType (%1).")
.arg(static_cast<int>(having.type)));
@@ -357,6 +366,11 @@ QString Grammar::whereNotNull(const WhereConditionItem &where) const
return QStringLiteral("%1 is not null").arg(wrap(where.column));
}
QString Grammar::whereRaw(const WhereConditionItem &where) const
{
return where.sql;
}
QString Grammar::compileOrders(const QueryBuilder &query) const
{
if (query.getOrders().isEmpty())
@@ -373,8 +387,11 @@ QStringList Grammar::compileOrdersToVector(const QueryBuilder &query) const
compiledOrders.reserve(orders.size());
for (const auto &order : orders)
compiledOrders << QStringLiteral("%1 %2")
.arg(wrap(order.column), order.direction.toLower());
if (order.sql.isEmpty()) T_LIKELY
compiledOrders << QStringLiteral("%1 %2")
.arg(wrap(order.column), order.direction.toLower());
else T_UNLIKELY
compiledOrders << order.sql;
return compiledOrders;
}

View File

@@ -155,6 +155,7 @@ MySqlGrammar::getWhereMethod(const WhereType whereType) const
getBind(&MySqlGrammar::whereNotIn),
getBind(&MySqlGrammar::whereNull),
getBind(&MySqlGrammar::whereNotNull),
getBind(&MySqlGrammar::whereRaw),
};
static const auto size = cached.size();

View File

@@ -160,6 +160,7 @@ PostgresGrammar::getWhereMethod(const WhereType whereType) const
getBind(&PostgresGrammar::whereNotIn),
getBind(&PostgresGrammar::whereNull),
getBind(&PostgresGrammar::whereNotNull),
getBind(&PostgresGrammar::whereRaw),
};
static const auto size = cached.size();

View File

@@ -136,6 +136,7 @@ SQLiteGrammar::getWhereMethod(const WhereType whereType) const
getBind(&SQLiteGrammar::whereNotIn),
getBind(&SQLiteGrammar::whereNull),
getBind(&SQLiteGrammar::whereNotNull),
getBind(&SQLiteGrammar::whereRaw),
};
static const auto size = cached.size();

View File

@@ -438,6 +438,21 @@ Builder &Builder::orWhereNotNull(const Column &column)
return orWhereNotNull(QVector<Column> {column});
}
Builder &Builder::whereRaw(const QString &sql, const QVector<QVariant> &bindings,
const QString &condition)
{
m_wheres.append({.condition = condition, .type = WhereType::RAW, .sql = sql});
addBinding(bindings, BindingType::WHERE);
return *this;
}
Builder &Builder::orWhereRaw(const QString &sql, const QVector<QVariant> &bindings)
{
return whereRaw(sql, bindings, QStringLiteral("or"));
}
Builder &Builder::groupBy(const QVector<Column> &groups)
{
if (groups.isEmpty())
@@ -453,6 +468,15 @@ Builder &Builder::groupBy(const Column &group)
return groupBy(QVector<Column> {group});
}
Builder &Builder::groupByRaw(const QString &sql, const QVector<QVariant> &bindings)
{
m_groups.append(Expression(sql));
addBinding(bindings, BindingType::GROUPBY);
return *this;
}
Builder &Builder::having(const Column &column, const QString &comparison,
const QVariant &value, const QString &condition)
{
@@ -474,6 +498,21 @@ Builder &Builder::orHaving(const Column &column, const QString &comparison,
return having(column, comparison, value, QStringLiteral("or"));
}
Builder &Builder::havingRaw(const QString &sql, const QVector<QVariant> &bindings,
const QString &condition)
{
m_havings.append({.condition = condition, .type = HavingType::RAW, .sql = sql});
addBinding(bindings, BindingType::HAVING);
return *this;
}
Builder &Builder::orHavingRaw(const QString &sql, const QVector<QVariant> &bindings)
{
return havingRaw(sql, bindings, QStringLiteral("or"));
}
Builder &Builder::orderBy(const Column &column, const QString &direction)
{
const auto &directionLower = direction.toLower();
@@ -494,6 +533,15 @@ Builder &Builder::orderByDesc(const Column &column)
return orderBy(column, QStringLiteral("desc"));
}
Builder &Builder::orderByRaw(const QString &sql, const QVector<QVariant> &bindings)
{
m_orders.append({.sql = sql});
addBinding(bindings, BindingType::ORDER);
return *this;
}
Builder &Builder::latest(const Column &column)
{
/* Default value "created_at" is ok, because we are in the QueryBuilder,