diff --git a/docs/query-builder.md b/docs/query-builder.md
index 3db7f8666..845e9787a 100644
--- a/docs/query-builder.md
+++ b/docs/query-builder.md
@@ -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();
+
+#### `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();
+
+
+#### `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();
+
+
+### `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();
+
+
+#### `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();
+
+
+#### `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();
+
## Joins
diff --git a/include/orm/ormtypes.hpp b/include/orm/ormtypes.hpp
index 7549764bc..528fb98c1 100644
--- a/include/orm/ormtypes.hpp
+++ b/include/orm/ormtypes.hpp
@@ -69,6 +69,7 @@ namespace Query
NOT_IN,
NULL_,
NOT_NULL,
+ RAW,
};
struct WhereConditionItem
@@ -81,13 +82,16 @@ namespace Query
QSharedPointer nestedQuery {nullptr};
QVector 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
diff --git a/include/orm/query/grammars/grammar.hpp b/include/orm/query/grammars/grammar.hpp
index 92d905b1e..64e7e3367 100644
--- a/include/orm/query/grammars/grammar.hpp
+++ b/include/orm/query/grammars/grammar.hpp
@@ -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. */
diff --git a/include/orm/query/querybuilder.hpp b/include/orm/query/querybuilder.hpp
index f12d8c0ef..cdc59a128 100644
--- a/include/orm/query/querybuilder.hpp
+++ b/include/orm/query/querybuilder.hpp
@@ -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 &bindings = {});
-
/*! Makes "from" fetch from a subquery. */
template
Builder &fromSub(T &&query, const QString &as);
+ /*! Set the table which the query is targeting. */
+ Builder &fromRaw(const QString &expression,
+ const QVector &bindings = {});
/*! Add a join clause to the query. */
template
@@ -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 &bindings = {},
+ const QString &condition = "and");
+ /*! Add a raw "or where" clause to the query. */
+ Builder &orWhereRaw(const QString &sql, const QVector &bindings = {});
+
/*! Add a "group by" clause to the query. */
Builder &groupBy(const QVector &groups);
/*! Add a "group by" clause to the query. */
@@ -307,6 +312,9 @@ namespace Query
template
Builder &groupBy(Args &&...groups);
+ /*! Add a raw "groupBy" clause to the query. */
+ Builder &groupByRaw(const QString &sql, const QVector &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 &bindings = {},
+ const QString &condition = "and");
+ /*! Add a raw "or having" clause to the query. */
+ Builder &orHavingRaw(const QString &sql, const QVector &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 &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. */
diff --git a/include/orm/tiny/model.hpp b/include/orm/tiny/model.hpp
index f0823af52..30fd961a0 100644
--- a/include/orm/tiny/model.hpp
+++ b/include/orm/tiny/model.hpp
@@ -499,6 +499,14 @@ namespace Relations {
static std::unique_ptr>
orWhereNotNull(const Column &column);
+ /*! Add a raw "where" clause to the query. */
+ static std::unique_ptr>
+ whereRaw(const QString &sql, const QVector &bindings = {},
+ const QString &condition = "and");
+ /*! Add a raw "or where" clause to the query. */
+ static std::unique_ptr>
+ orWhereRaw(const QString &sql, const QVector &bindings = {});
+
/*! Add a "group by" clause to the query. */
static std::unique_ptr>
groupBy(const QVector &groups);
@@ -510,6 +518,10 @@ namespace Relations {
static std::unique_ptr>
groupBy(Args &&...groups);
+ /*! Add a raw "groupBy" clause to the query. */
+ static std::unique_ptr>
+ groupByRaw(const QString &sql, const QVector &bindings = {});
+
/*! Add a "having" clause to the query. */
static std::unique_ptr>
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>
+ havingRaw(const QString &sql, const QVector &bindings = {},
+ const QString &condition = "and");
+ /*! Add a raw "or having" clause to the query. */
+ static std::unique_ptr>
+ orHavingRaw(const QString &sql, const QVector &bindings = {});
+
/*! Add an "order by" clause to the query. */
static std::unique_ptr>
orderBy(const Column &column, const QString &direction = "asc");
@@ -526,6 +546,10 @@ namespace Relations {
static std::unique_ptr>
orderByDesc(const Column &column);
+ /*! Add a raw "order by" clause to the query. */
+ static std::unique_ptr>
+ orderByRaw(const QString &sql, const QVector &bindings = {});
+
/*! Add an "order by" clause for a timestamp to the query. */
static std::unique_ptr>
latest(const Column &column = "");
@@ -2379,6 +2403,31 @@ namespace Relations {
return builder;
}
+ template
+ std::unique_ptr>
+ Model::whereRaw(
+ const QString &sql, const QVector &bindings,
+ const QString &condition)
+ {
+ auto builder = query();
+
+ builder->whereRaw(sql, bindings, condition);
+
+ return builder;
+ }
+
+ template
+ std::unique_ptr>
+ Model::orWhereRaw(
+ const QString &sql, const QVector &bindings)
+ {
+ auto builder = query();
+
+ builder->whereRaw(sql, bindings, QStringLiteral("or"));
+
+ return builder;
+ }
+
template
std::unique_ptr>
Model::groupBy(const QVector &groups)
@@ -2401,6 +2450,18 @@ namespace Relations {
return builder;
}
+ template
+ std::unique_ptr>
+ Model::groupByRaw(
+ const QString &sql, const QVector &bindings)
+ {
+ auto builder = query();
+
+ builder->groupByRaw(sql, bindings);
+
+ return builder;
+ }
+
template
template
std::unique_ptr>
@@ -2438,6 +2499,31 @@ namespace Relations {
return builder;
}
+ template
+ std::unique_ptr>
+ Model::havingRaw(
+ const QString &sql, const QVector &bindings,
+ const QString &condition)
+ {
+ auto builder = query();
+
+ builder->havingRaw(sql, bindings, condition);
+
+ return builder;
+ }
+
+ template
+ std::unique_ptr>
+ Model::orHavingRaw(
+ const QString &sql, const QVector &bindings)
+ {
+ auto builder = query();
+
+ builder->havingRaw(sql, bindings, QStringLiteral("or"));
+
+ return builder;
+ }
+
template
std::unique_ptr>
Model::orderBy(const Column &column,
@@ -2461,6 +2547,18 @@ namespace Relations {
return builder;
}
+ template
+ std::unique_ptr>
+ Model::orderByRaw(const QString &sql,
+ const QVector &bindings)
+ {
+ auto builder = query();
+
+ builder->orderByRaw(sql, bindings);
+
+ return builder;
+ }
+
template
std::unique_ptr>
Model::latest(const Column &column)
diff --git a/include/orm/tiny/relations/relation.hpp b/include/orm/tiny/relations/relation.hpp
index 2b23efc59..dab894f63 100644
--- a/include/orm/tiny/relations/relation.hpp
+++ b/include/orm/tiny/relations/relation.hpp
@@ -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 &bindings = {},
+ const QString &condition = "and") const;
+ /*! Add a raw "or where" clause to the query. */
+ const Relation &orWhereRaw(const QString &sql,
+ const QVector &bindings = {}) const;
+
/*! Add a "group by" clause to the query. */
const Relation &groupBy(const QVector &groups) const;
/*! Add a "group by" clause to the query. */
@@ -451,6 +459,10 @@ namespace Relations
template
const Relation &groupBy(Args &&...groups) const;
+ /*! Add a raw "groupBy" clause to the query. */
+ const Relation &groupByRaw(const QString &sql,
+ const QVector &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 &bindings = {},
+ const QString &condition = "and") const;
+ /*! Add a raw "or having" clause to the query. */
+ const Relation &orHavingRaw(const QString &sql,
+ const QVector &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 &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
+ const Relation &
+ Relation::whereRaw(
+ const QString &sql, const QVector &bindings,
+ const QString &condition) const
+ {
+ m_query->whereRaw(sql, bindings, condition);
+
+ return *this;
+ }
+
+ template
+ const Relation &
+ Relation::orWhereRaw(
+ const QString &sql, const QVector &bindings) const
+ {
+ m_query->whereRaw(sql, bindings, QStringLiteral("or"));
+
+ return *this;
+ }
+
template
const Relation &
Relation::groupBy(const QVector &groups) const
@@ -1494,6 +1539,16 @@ namespace Relations
return *this;
}
+ template
+ const Relation &
+ Relation::groupByRaw(const QString &sql,
+ const QVector &bindings) const
+ {
+ m_query->groupByRaw(sql, bindings);
+
+ return *this;
+ }
+
template
const Relation &
Relation::having(
@@ -1515,6 +1570,27 @@ namespace Relations
return *this;
}
+ template
+ const Relation &
+ Relation::havingRaw(
+ const QString &sql, const QVector &bindings,
+ const QString &condition) const
+ {
+ m_query->havingRaw(sql, bindings, condition);
+
+ return *this;
+ }
+
+ template
+ const Relation &
+ Relation::orHavingRaw(
+ const QString &sql, const QVector &bindings) const
+ {
+ m_query->havingRaw(sql, bindings, QStringLiteral("or"));
+
+ return *this;
+ }
+
template
const Relation &
Relation::orderBy(const Column &column,
@@ -1534,6 +1610,16 @@ namespace Relations
return *this;
}
+ template
+ const Relation &
+ Relation::orderByRaw(const QString &sql,
+ const QVector &bindings) const
+ {
+ m_query->orderByRaw(sql, bindings);
+
+ return *this;
+ }
+
template
const Relation &
Relation::latest(const Column &column) const
diff --git a/include/orm/tiny/tinybuilder.hpp b/include/orm/tiny/tinybuilder.hpp
index 4a1b0304b..fb48816b1 100644
--- a/include/orm/tiny/tinybuilder.hpp
+++ b/include/orm/tiny/tinybuilder.hpp
@@ -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 &bindings = {},
+ const QString &condition = "and");
+ /*! Add a raw "or where" clause to the query. */
+ Builder &orWhereRaw(const QString &sql, const QVector &bindings = {});
+
/*! Add a "group by" clause to the query. */
Builder &groupBy(const QVector &groups);
/*! Add a "group by" clause to the query. */
@@ -350,6 +356,9 @@ namespace Relations
template
Builder &groupBy(Args &&...groups);
+ /*! Add a raw "groupBy" clause to the query. */
+ Builder &groupByRaw(const QString &sql, const QVector &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 &bindings = {},
+ const QString &condition = "and");
+ /*! Add a raw "or having" clause to the query. */
+ Builder &orHavingRaw(const QString &sql, const QVector &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 &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
+ Builder &
+ Builder::whereRaw(const QString &sql, const QVector &bindings,
+ const QString &condition)
+ {
+ toBase().whereRaw(sql, bindings, condition);
+ return *this;
+ }
+
+ template
+ Builder &
+ Builder::orWhereRaw(const QString &sql, const QVector &bindings)
+ {
+ toBase().whereRaw(sql, bindings, QStringLiteral("or"));
+ return *this;
+ }
+
template
Builder &Builder::groupBy(const QVector &groups)
{
@@ -1402,6 +1437,14 @@ namespace Relations
return *this;
}
+ template
+ Builder &
+ Builder::groupByRaw(const QString &sql, const QVector &bindings)
+ {
+ toBase().groupByRaw(sql, bindings);
+ return *this;
+ }
+
template
Builder &
Builder::having(const Column &column, const QString &comparison,
@@ -1420,6 +1463,23 @@ namespace Relations
return *this;
}
+ template
+ Builder &
+ Builder::havingRaw(const QString &sql, const QVector &bindings,
+ const QString &condition)
+ {
+ toBase().havingRaw(sql, bindings, condition);
+ return *this;
+ }
+
+ template
+ Builder &
+ Builder::orHavingRaw(const QString &sql, const QVector &bindings)
+ {
+ toBase().havingRaw(sql, bindings, QStringLiteral("or"));
+ return *this;
+ }
+
template
Builder &
Builder::orderBy(const Column &column, const QString &direction)
@@ -1435,6 +1495,14 @@ namespace Relations
return *this;
}
+ template
+ Builder &Builder::orderByRaw(const QString &sql,
+ const QVector &bindings)
+ {
+ toBase().orderByRaw(sql, bindings);
+ return *this;
+ }
+
template
Builder &
Builder::latest(const Column &column)
diff --git a/src/orm/query/grammars/grammar.cpp b/src/orm/query/grammars/grammar.cpp
index 7879d4308..6c455f813 100644
--- a/src/orm/query/grammars/grammar.cpp
+++ b/src/orm/query/grammars/grammar.cpp
@@ -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(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;
}
diff --git a/src/orm/query/grammars/mysqlgrammar.cpp b/src/orm/query/grammars/mysqlgrammar.cpp
index 9fb7eb398..3d61001af 100644
--- a/src/orm/query/grammars/mysqlgrammar.cpp
+++ b/src/orm/query/grammars/mysqlgrammar.cpp
@@ -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();
diff --git a/src/orm/query/grammars/postgresgrammar.cpp b/src/orm/query/grammars/postgresgrammar.cpp
index 698c73d21..7b94e09eb 100644
--- a/src/orm/query/grammars/postgresgrammar.cpp
+++ b/src/orm/query/grammars/postgresgrammar.cpp
@@ -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();
diff --git a/src/orm/query/grammars/sqlitegrammar.cpp b/src/orm/query/grammars/sqlitegrammar.cpp
index adf111661..97ad62e23 100644
--- a/src/orm/query/grammars/sqlitegrammar.cpp
+++ b/src/orm/query/grammars/sqlitegrammar.cpp
@@ -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();
diff --git a/src/orm/query/querybuilder.cpp b/src/orm/query/querybuilder.cpp
index 227d188a0..baf24b483 100644
--- a/src/orm/query/querybuilder.cpp
+++ b/src/orm/query/querybuilder.cpp
@@ -438,6 +438,21 @@ Builder &Builder::orWhereNotNull(const Column &column)
return orWhereNotNull(QVector {column});
}
+Builder &Builder::whereRaw(const QString &sql, const QVector &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 &bindings)
+{
+ return whereRaw(sql, bindings, QStringLiteral("or"));
+}
+
Builder &Builder::groupBy(const QVector &groups)
{
if (groups.isEmpty())
@@ -453,6 +468,15 @@ Builder &Builder::groupBy(const Column &group)
return groupBy(QVector {group});
}
+Builder &Builder::groupByRaw(const QString &sql, const QVector &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 &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 &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 &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,