Skip to content

Commit

Permalink
fixed TinyBuilder::pluck() 🤯
Browse files Browse the repository at this point in the history
Apply u_date QDateTime transformations during the pluck algorithm.

 - also added unit tests for pluck-ing with QDateTime/u_dates
  • Loading branch information
silverqx committed Jul 29, 2022
1 parent 2e376c2 commit a166922
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 57 deletions.
2 changes: 1 addition & 1 deletion docs/supported-compilers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ keywords: [c++ orm, supported compilers, supported build systems, tinyorm]

# Supported Compilers

Following compilers are backed up by the GitHub Action [workflows](https://github.com/silverqx/TinyORM/tree/main/.github/workflows) (CI pipelines), these workflows also include more then __1220 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 __1223 unit tests__ 😮💥.

<div id="supported-compilers">

Expand Down
9 changes: 5 additions & 4 deletions include/orm/basegrammar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ namespace Query
/*! Get the column name without the table name, a string after last dot. */
QString unqualifyColumn(const QString &column) const;

/*! Get the table name without an alias. */
QString getFromWithoutAlias(const QString &from) const;
/*! Get an alias from the 'from' clause. */
QString getAliasFromFrom(const QString &from) const;

protected:
/*! Convert the vector of column names into a wrapped comma delimited string. */
template<ColumnContainer T>
Expand All @@ -103,10 +108,6 @@ namespace Query

/*! Get individual segments from the 'from' clause. */
QStringList getSegmentsFromFrom(const QString &from) const;
/*! Get the table name without an alias. */
QString getFromWithoutAlias(const QString &from) const;
/*! Get an alias from the 'from' clause. */
QString getAliasFromFrom(const QString &from) const;

// FEATURE qt6, use everywhere QLatin1String("") instead of = "", BUT Qt6 has char8_t ctor, so u"" can be used, I will wait with this problem silverqx
/*! The grammar table prefix. */
Expand Down
12 changes: 6 additions & 6 deletions include/orm/query/querybuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,9 @@ namespace Orm::Query
Builder cloneWithoutBindings(
const std::unordered_set<BindingType> &except) const;

/*! Strip off the table name or alias from a column identifier. */
QString stripTableForPluck(const QString &column) const;

protected:
/*! Determine if the given operator is supported. */
bool invalidOperator(const QString &comparison) const;
Expand Down Expand Up @@ -753,9 +756,6 @@ namespace Orm::Query
/*! Prepend the database name if the given query is on another database. */
Builder &prependDatabaseNameIfCrossDatabaseQuery(Builder &query) const;

/*! Strip off the table name or alias from a column identifier. */
QString stripTableForPluck(const QString &column) const;

/*! Throw an exception if the query doesn't have an orderBy clause. */
void enforceOrderBy() const;
/*! Get an array with all orders with a given column removed. */
Expand Down Expand Up @@ -903,9 +903,9 @@ namespace Orm::Query
if (size == 0)
return {};

/* If the columns are qualified with a table or have an alias, we cannot use
those directly in the "pluck" operations since the results from the DB
are only keyed by the column itself. We'll strip the table out here. */
/* If the column is qualified with a table or have an alias, we cannot use
those directly in the "pluck" operations, we have to strip the table out or
use the alias name instead. */
const auto unqualifiedColumn = stripTableForPluck(column);

const auto unqualifiedKey = stripTableForPluck(key);
Expand Down
58 changes: 51 additions & 7 deletions include/orm/tiny/tinybuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ TINY_SYSTEM_HEADER

#include <QtSql/QSqlRecord>

#include <range/v3/action/transform.hpp>
#include <range/v3/algorithm/contains.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/remove_if.hpp>
Expand Down Expand Up @@ -73,10 +74,10 @@ namespace Orm::Tiny
QVariant soleValue(const Column &column);

/*! Get the vector with the values of a given column. */
QVector<QVariant> pluck(const QString &column) const;
QVector<QVariant> pluck(const QString &column);
/*! Get the vector with the values of a given column. */
template<typename T>
std::map<T, QVariant> pluck(const QString &column, const QString &key) const;
std::map<T, QVariant> pluck(const QString &column, const QString &key);

/*! Find a model by its primary key. */
std::optional<Model>
Expand Down Expand Up @@ -335,18 +336,61 @@ namespace Orm::Tiny
}

template<typename Model>
QVector<QVariant> Builder<Model>::pluck(const QString &column) const
QVector<QVariant> Builder<Model>::pluck(const QString &column)
{
// CUR now, use newFromBuilder() to make and fill models and return attribute/column silverqx
return toBase().pluck(column);
auto result = toBase().pluck(column);

// Nothing to pluck-ing 😎
if (result.empty())
return result;

/* If the column is qualified with a table or have an alias, we cannot use
those directly in the "pluck" operations, we have to strip the table out or
use the alias name instead. */
const auto unqualifiedColumn = getQuery().stripTableForPluck(column);

/* If the model has a mutator for the requested column, we will spin through
the results and mutate the values so that the mutated version of these
columns are returned as you would expect from these Eloquent models. */
if (!m_model.getDates().contains(unqualifiedColumn))
return result;

return result |= ranges::actions::transform([this, &unqualifiedColumn]
(auto &&value)
{
return m_model.newFromBuilder({{unqualifiedColumn,
std::forward<decltype (value)>(value)}})
.getAttribute(unqualifiedColumn);
});
}

template<typename Model>
template<typename T>
std::map<T, QVariant>
Builder<Model>::pluck(const QString &column, const QString &key) const
Builder<Model>::pluck(const QString &column, const QString &key)
{
return toBase().template pluck<T>(column, key);
auto result = toBase().template pluck<T>(column, key);

// Nothing to pluck-ing 😎
if (result.empty())
return result;

/* If the column is qualified with a table or have an alias, we cannot use
those directly in the "pluck" operations, we have to strip the table out or
use the alias name instead. */
const auto unqualifiedColumn = getQuery().stripTableForPluck(column);

/* If the model has a mutator for the requested column, we will spin through
the results and mutate the values so that the mutated version of these
columns are returned as you would expect from these Eloquent models. */
if (!m_model.getDates().contains(unqualifiedColumn))
return result;

for (auto &&[_, value] : result)
value = m_model.newFromBuilder({{unqualifiedColumn, std::move(value)}})
.getAttribute(unqualifiedColumn);

return result;
}

// FEATURE dilemma primarykey, Model::KeyType for id silverqx
Expand Down
26 changes: 10 additions & 16 deletions src/orm/basegrammar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ QString BaseGrammar::unqualifyColumn(const QString &column) const
return column.split(DOT).last().trimmed();
}

QString BaseGrammar::getFromWithoutAlias(const QString &from) const
{
return std::move(getSegmentsFromFrom(from).first()); // clazy:exclude=detaching-temporary
}

QString BaseGrammar::getAliasFromFrom(const QString &from) const
{
return std::move(getSegmentsFromFrom(from).last()); // clazy:exclude=detaching-temporary
}

/* protected */

QString BaseGrammar::parameter(const QVariant &value) const
Expand Down Expand Up @@ -177,22 +187,6 @@ QStringList BaseGrammar::getSegmentsFromFrom(const QString &from) const
return segments;
}

QString BaseGrammar::getFromWithoutAlias(const QString &from) const
{
// Prevent clazy warning
const auto segments = getSegmentsFromFrom(from);

return segments.first();
}

QString BaseGrammar::getAliasFromFrom(const QString &from) const
{
// Prevent clazy warning
const auto segments = getSegmentsFromFrom(from);

return segments.last();
}

} // namespace Orm

TINYORM_END_COMMON_NAMESPACE
26 changes: 13 additions & 13 deletions src/orm/query/querybuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ QVector<QVariant> Builder::pluck(const QString &column)
if (size == 0)
return {};

/* If the columns are qualified with a table or have an alias, we cannot use
those directly in the "pluck" operations since the results from the DB
are only keyed by the column itself. We'll strip the table out here. */
/* If the column is qualified with a table or have an alias, we cannot use
those directly in the "pluck" operations, we have to strip the table out or
use the alias name instead. */
const auto unqualifiedColumn = stripTableForPluck(column);

QVector<QVariant> result;
Expand Down Expand Up @@ -1125,6 +1125,16 @@ Builder Builder::cloneWithoutBindings(
return copy;
}

QString Builder::stripTableForPluck(const QString &column) const
{
static const auto as = QStringLiteral(" as ");

if (!column.contains(as))
return m_grammar.unqualifyColumn(column);

return m_grammar.getAliasFromFrom(column);
}

/* protected */

bool Builder::invalidOperator(const QString &comparison) const
Expand Down Expand Up @@ -1279,16 +1289,6 @@ Builder &Builder::prependDatabaseNameIfCrossDatabaseQuery(Builder &query) const
return query;
}

QString Builder::stripTableForPluck(const QString &column) const
{
static const auto as = QStringLiteral(" as ");

if (!column.contains(as))
return m_grammar.unqualifyColumn(column);

return column.split(as).last().trimmed();
}

void Builder::enforceOrderBy() const
{
if (m_orders.isEmpty())
Expand Down
Loading

0 comments on commit a166922

Please sign in to comment.