Skip to content

Commit

Permalink
added TinyBuilder::touch()
Browse files Browse the repository at this point in the history
 - added unit tests
 - added model proxy touchAll()
 - added docs
  • Loading branch information
silverqx committed Aug 27, 2022
1 parent 374526b commit 0946ad6
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 0 deletions.
18 changes: 18 additions & 0 deletions docs/tinyorm/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,24 @@ You can make these static constants non-inline and initialize them in the cpp fi
You may also use `Orm::CREATED_AT` and `Orm::UPDATED_AT` string constants instead of `QStringLiteral("created_at")`.
:::

#### Touching timestamps

You can explicitly touch timestamps using the `touch` method defined on the Model:

auto flight = Flight::find(1);

flight->touch();
flight->touch("added_on"); // Custom column name

You can also touch multiple rows at once using the `touch` method defined on the TinyBuilder:

auto [affected, query] = Flight::whereEq("status", "new")->touch();

The `touch` method may also be called when building a [relationship](/tinyorm/relationships.mdx) query:

flight->history()->touch();
flight->history()->whereEq("status", "new").touch();

### Database Connections

By default, all TinyORM models will use the default database connection that is configured for your application. If you would like to specify a different connection that should be used when interacting with a particular model, you should define a `u_connection` private data member on the model:
Expand Down
14 changes: 14 additions & 0 deletions include/orm/tiny/modelproxies.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@ namespace Tiny
/*! Run a truncate statement on the table. */
static void truncate();

/* Touching timestamps */
/*! Update the column's update timestamp on all Models. */
static std::tuple<int, std::optional<QSqlQuery>>
touchAll(const QString &column = "");

/* Select */
/*! Retrieve the "count" result of the query. */
static quint64 count(const QVector<Column> &columns = {ASTERISK});
Expand Down Expand Up @@ -1417,6 +1422,15 @@ namespace Tiny
query()->truncate();
}

/* Touching timestamps */

template<typename Derived, AllRelationsConcept ...AllRelations>
std::tuple<int, std::optional<QSqlQuery>>
ModelProxies<Derived, AllRelations...>::touchAll(const QString &column)
{
return query()->touch(column);
}

/* Select */

template<typename Derived, AllRelationsConcept ...AllRelations>
Expand Down
21 changes: 21 additions & 0 deletions include/orm/tiny/tinybuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ namespace Orm::Tiny
Model updateOrCreate(const QVector<WhereItem> &attributes,
const QVector<AttributeItem> &values = {});

/*! Update the column's update timestamp. */
std::tuple<int, std::optional<QSqlQuery>>
touch(const QString &column = "");

/* QueryBuilder proxy methods that need modifications */
/*! Update records in the database. */
std::tuple<int, QSqlQuery>
Expand Down Expand Up @@ -838,6 +842,23 @@ namespace Orm::Tiny
return instance;
}

template<typename Model>
std::tuple<int, std::optional<QSqlQuery>>
Builder<Model>::touch(const QString &column)
{
auto time = m_model.freshTimestamp();

if (!column.isEmpty())
return toBase().update({{column, std::move(time)}});

const auto &updatedAtColumn = m_model.getUpdatedAtColumn();

if (!m_model.usesTimestamps() || updatedAtColumn.isEmpty())
return {0, std::nullopt};

return toBase().update({{updatedAtColumn, std::move(time)}});
}

/* QueryBuilder proxy methods that need modifications */

template<typename Model>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ class tst_MySql_TinyBuilder : public QObject // clazy:exclude=ctor-missing-paren
private slots:
void initTestCase();

void touch() const;
void touch_CustomColumn() const;
void touch_NotUsesTimestamps() const;

/* Querying Relationship Existence/Absence on HasMany */
void has_Basic_OnHasMany() const;
void has_Count_OnHasMany() const;
Expand Down Expand Up @@ -113,6 +117,79 @@ void tst_MySql_TinyBuilder::initTestCase()
.toUtf8().constData(), );
}

void tst_MySql_TinyBuilder::touch() const
{
auto timeBeforeTouch = QDateTime::currentDateTime();
// Reset milliseconds to 0
{
auto time = timeBeforeTouch.time();
timeBeforeTouch.setTime(QTime(time.hour(), time.minute(), time.second()));
}

auto log = DB::connection(m_connection).pretend([this]
{
User::on(m_connection)
->whereEq("status", "new")
.touch();
});

QCOMPARE(log.size(), 1);
const auto &firstLog = log.first();

QCOMPARE(firstLog.query,
"update `users` "
"set `updated_at` = ? "
"where `status` = ? and `users`.`deleted_at` is null");
QVERIFY(firstLog.boundValues.size() == 2);
QVERIFY(firstLog.boundValues.at(0).value<QDateTime>() >= timeBeforeTouch);
QCOMPARE(firstLog.boundValues.at(1), QVariant(QString("new")));
}

void tst_MySql_TinyBuilder::touch_CustomColumn() const
{
auto timeBeforeTouch = QDateTime::currentDateTime();
// Reset milliseconds to 0
{
auto time = timeBeforeTouch.time();
timeBeforeTouch.setTime(QTime(time.hour(), time.minute(), time.second()));
}

auto log = DB::connection(m_connection).pretend([this]
{
User::on(m_connection)
->whereEq("status", "new")
.touch("updated_on");
});

QCOMPARE(log.size(), 1);
const auto &firstLog = log.first();

QCOMPARE(firstLog.query,
"update `users` "
"set `updated_on` = ? "
"where `status` = ? and `users`.`deleted_at` is null");
QVERIFY(firstLog.boundValues.size() == 2);
QVERIFY(firstLog.boundValues.at(0).value<QDateTime>() >= timeBeforeTouch);
QCOMPARE(firstLog.boundValues.at(1), QVariant(QString("new")));
}

void tst_MySql_TinyBuilder::touch_NotUsesTimestamps() const
{
int affected = -1;
std::optional<QSqlQuery> query = std::nullopt;

auto log = DB::connection(m_connection).pretend([this, &affected, &query]
{
std::tie(affected, query) = Phone::on(m_connection)
->whereEq("status", "new")
.touch();
});

QVERIFY(log.isEmpty());
QCOMPARE(affected, 0);
QCOMPARE(query, std::nullopt);
}

void tst_MySql_TinyBuilder::has_Basic_OnHasMany() const
{
auto builder = createTinyQuery<Torrent>();
Expand Down

0 comments on commit 0946ad6

Please sign in to comment.