groupBy column expressions and new overload

groupBy() methods now take column expressions.

 - added all proxies
 - added new perfectly forwarded groupBy(&&...args) overload
 - all new code tested manually in the TinyOrmPlayground
This commit is contained in:
silverqx
2021-07-05 11:57:12 +02:00
parent 4dbc564704
commit 7298d72623
8 changed files with 116 additions and 30 deletions

View File

@@ -2,6 +2,7 @@ INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/orm/basegrammar.hpp \
$$PWD/orm/concepts.hpp \
$$PWD/orm/concerns/detectslostconnections.hpp \
$$PWD/orm/concerns/hasconnectionresolver.hpp \
$$PWD/orm/configuration.hpp \

44
include/orm/concepts.hpp Normal file
View File

@@ -0,0 +1,44 @@
#ifndef ORM_CONCEPTS_HPP
#define ORM_CONCEPTS_HPP
#ifdef TINYORM_COMMON_NAMESPACE
namespace TINYORM_COMMON_NAMESPACE
{
#endif
namespace Orm
{
namespace Query
{
class Builder;
class Expression;
}
using QueryBuilder = Query::Builder;
/*! Concept for the subquery, used in the from clause (tablename), join clause, ... */
template<typename T>
concept SubQuery = std::convertible_to<T, Orm::QueryBuilder &> ||
std::convertible_to<T, QString> ||
std::invocable<T, Orm::QueryBuilder &>;
/*! Concept for the join's table. */
template<typename T>
concept JoinTable = std::same_as<T, Query::Expression> ||
std::convertible_to<T, QString>;
/*! Concept for the table column. */
template<typename T>
concept ColumnConcept =
std::convertible_to<T, std::variant<QString, Query::Expression>>;
/*! Concept for the QString. */
template<typename T>
concept QStringConcept = std::convertible_to<T, const QString &> ||
std::convertible_to<T, QString>;
} // namespace Orm
#ifdef TINYORM_COMMON_NAMESPACE
} // namespace TINYORM_COMMON_NAMESPACE
#endif
#endif // ORM_CONCEPTS_HPP

View File

@@ -31,17 +31,6 @@ namespace Query
}
using QueryBuilder = Query::Builder;
/*! Concept for the subquery, used in the from clause (tablename), join clause, ... */
template<typename T>
concept SubQuery = std::convertible_to<T, Orm::QueryBuilder &> ||
std::convertible_to<T, QString> ||
std::invocable<T, Orm::QueryBuilder &>;
/*! Concept for the join's table. */
template<typename T>
concept JoinTable = std::same_as<T, Query::Expression> ||
std::convertible_to<T, QString>;
/*! Type for the database column. */
using Column = std::variant<QString, Query::Expression>;

View File

@@ -7,6 +7,7 @@
#include <optional>
#include <unordered_set>
#include "orm/concepts.hpp"
#include "orm/ormtypes.hpp"
#include "orm/query/grammars/grammar.hpp"
@@ -286,9 +287,12 @@ namespace Query
Builder &orWhereNotNull(const Column &column);
/*! Add a "group by" clause to the query. */
Builder &groupBy(const QStringList &groups);
Builder &groupBy(const QVector<Column> &groups);
/*! Add a "group by" clause to the query. */
Builder &groupBy(const QString &group);
Builder &groupBy(const Column &group);
/*! Add a "group by" clause to the query. */
template<ColumnConcept ...Args>
Builder &groupBy(Args &&...groups);
/*! Add a "having" clause to the query. */
Builder &having(const QString &column, const QString &comparison,
@@ -389,7 +393,7 @@ namespace Query
inline const QVector<WhereConditionItem> &getWheres() const
{ return m_wheres; }
/*! Get the groupings for the query. */
inline const QStringList &getGroups() const
inline const QVector<Column> &getGroups() const
{ return m_groups; }
/*! Get the having constraints for the query. */
inline const QVector<HavingConditionItem> &getHavings() const
@@ -562,7 +566,7 @@ namespace Query
/*! The where constraints for the query. */
QVector<WhereConditionItem> m_wheres;
/*! The groupings for the query. */
QStringList m_groups;
QVector<Column> m_groups;
/*! The having constraints for the query. */
QVector<HavingConditionItem> m_havings;
/*! The orderings for the query. */
@@ -779,6 +783,12 @@ namespace Query
QStringLiteral("right"));
}
template<ColumnConcept ...Args>
inline Builder &Builder::groupBy(Args &&...groups)
{
return groupBy(QVector<Column> {std::forward<Args>(groups)...});
}
inline const std::optional<AggregateItem> &Builder::getAggregate() const
{
return m_aggregate;

View File

@@ -78,6 +78,7 @@ namespace Relations {
// TODO perf, run TinyOrmPlayground 30 times with disabled terminal output and calculate sum value of execution times to compare perf silverqx
// TODO dilemma, function params. like direction asc/desc for orderBy, operators for where are QStrings, but they should be flags for performance reasons, how to solve this and preserve nice clean api? that is the question 🤔 silverqx
// BUG Qt sql drivers do not work with mysql json columns silverqx
// CUR solve all cur task about expressions, remove commented code in basegrammar and add new tasks about left column expressions in orderby, incerement/decrement, having and maybe groupby that I finish it later or something silverqx
template<typename Derived, AllRelationsConcept ...AllRelations>
class Model :
public Concerns::HasRelationStore<Derived, AllRelations...>,
@@ -465,10 +466,14 @@ namespace Relations {
/*! Add a "group by" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
groupBy(const QStringList &groups);
groupBy(const QVector<Column> &groups);
/*! Add a "group by" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
groupBy(const QString &group);
groupBy(const Column &group);
/*! Add a "group by" clause to the query. */
template<ColumnConcept ...Args>
static std::unique_ptr<TinyBuilder<Derived>>
groupBy(Args &&...groups);
/*! Add a "having" clause to the query. */
static std::unique_ptr<TinyBuilder<Derived>>
@@ -2247,7 +2252,7 @@ namespace Relations {
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::groupBy(const QStringList &groups)
Model<Derived, AllRelations...>::groupBy(const QVector<Column> &groups)
{
auto builder = query();
@@ -2258,7 +2263,7 @@ namespace Relations {
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::groupBy(const QString &group)
Model<Derived, AllRelations...>::groupBy(const Column &group)
{
auto builder = query();
@@ -2267,6 +2272,18 @@ namespace Relations {
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
template<ColumnConcept ...Args>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::groupBy(Args &&...groups)
{
auto builder = query();
builder->groupBy(QVector<Column> {std::forward<Args>(groups)...});
return builder;
}
template<typename Derived, AllRelationsConcept ...AllRelations>
std::unique_ptr<TinyBuilder<Derived>>
Model<Derived, AllRelations...>::having(

View File

@@ -9,6 +9,7 @@
#include <range/v3/action/sort.hpp>
#include <range/v3/action/unique.hpp>
#include "orm/concepts.hpp"
#include "orm/ormtypes.hpp"
#ifdef TINYORM_COMMON_NAMESPACE
@@ -407,9 +408,12 @@ namespace Relations
const Relation &orWhereNotNull(const Column &column) const;
/*! Add a "group by" clause to the query. */
const Relation &groupBy(const QStringList &groups) const;
const Relation &groupBy(const QVector<Column> &groups) const;
/*! Add a "group by" clause to the query. */
const Relation &groupBy(const QString &group) const;
const Relation &groupBy(const Column &group) const;
/*! Add a "group by" clause to the query. */
template<ColumnConcept ...Args>
const Relation &groupBy(Args &&...groups) const;
/*! Add a "having" clause to the query. */
const Relation &having(const QString &column, const QString &comparison,
@@ -1340,7 +1344,7 @@ namespace Relations
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::groupBy(const QStringList &groups) const
Relation<Model, Related>::groupBy(const QVector<Column> &groups) const
{
m_query->groupBy(groups);
@@ -1349,13 +1353,23 @@ namespace Relations
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::groupBy(const QString &group) const
Relation<Model, Related>::groupBy(const Column &group) const
{
m_query->groupBy(group);
return *this;
}
template<class Model, class Related>
template<ColumnConcept ...Args>
const Relation<Model, Related> &
Relation<Model, Related>::groupBy(Args &&...groups) const
{
m_query->groupBy(QVector<Column> {std::forward<Args>(groups)...});
return *this;
}
template<class Model, class Related>
const Relation<Model, Related> &
Relation<Model, Related>::having(

View File

@@ -310,9 +310,12 @@ namespace Relations
Builder &orWhereNotNull(const Column &column);
/*! Add a "group by" clause to the query. */
Builder &groupBy(const QStringList &groups);
Builder &groupBy(const QVector<Column> &groups);
/*! Add a "group by" clause to the query. */
Builder &groupBy(const QString &group);
Builder &groupBy(const Column &group);
/*! Add a "group by" clause to the query. */
template<ColumnConcept ...Args>
Builder &groupBy(Args &&...groups);
/*! Add a "having" clause to the query. */
Builder &having(const QString &column, const QString &comparison,
@@ -1264,19 +1267,27 @@ namespace Relations
}
template<typename Model>
Builder<Model> &Builder<Model>::groupBy(const QStringList &groups)
Builder<Model> &Builder<Model>::groupBy(const QVector<Column> &groups)
{
toBase().groupBy(groups);
return *this;
}
template<typename Model>
Builder<Model> &Builder<Model>::groupBy(const QString &group)
Builder<Model> &Builder<Model>::groupBy(const Column &group)
{
toBase().groupBy(group);
return *this;
}
template<typename Model>
template<ColumnConcept ...Args>
Builder<Model> &Builder<Model>::groupBy(Args &&...groups)
{
toBase().groupBy(QVector<Column> {std::forward<Args>(groups)...});
return *this;
}
template<typename Model>
Builder<Model> &
Builder<Model>::having(const QString &column, const QString &comparison,

View File

@@ -440,7 +440,7 @@ Builder &Builder::orWhereNotNull(const Column &column)
return orWhereNotNull(QVector<Column> {column});
}
Builder &Builder::groupBy(const QStringList &groups)
Builder &Builder::groupBy(const QVector<Column> &groups)
{
if (groups.isEmpty())
return *this;
@@ -450,9 +450,9 @@ Builder &Builder::groupBy(const QStringList &groups)
return *this;
}
Builder &Builder::groupBy(const QString &group)
Builder &Builder::groupBy(const Column &group)
{
return groupBy(QStringList {group});
return groupBy(QVector<Column> {group});
}
Builder &Builder::having(const QString &column, const QString &comparison,