diff --git a/README.md b/README.md index 9c6fb27..4ed3344 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,14 @@ int main(int argc, char *argv[]) { qDebug() << "Value for 'key_a':" << cache->fetch("key_a"); qDebug() << "Value for 'key_b':" << cache->fetch("key_b"); + cache->store("key_c", "a special value", 1); + + qDebug() << "Has 'key_c' before sleep? -" << (cache->has("key_c") ? "yes" : "no"); + + sleep(2); + + qDebug() << "Has 'key_c' after sleep? -" << (cache->has("key_c") ? "yes" : "no"); + return 0; } ``` diff --git a/abstractadapter.hpp b/abstractadapter.hpp index 4c6a291..b6b60dd 100644 --- a/abstractadapter.hpp +++ b/abstractadapter.hpp @@ -14,6 +14,7 @@ namespace Bidstack { public: virtual bool store(QString key, QString data) =0; + virtual bool store(QString key, QString data, int ttl) =0; virtual bool has(QString key) =0; virtual bool remove(QString key) =0; virtual bool clear() =0; diff --git a/devnulladapter.cpp b/devnulladapter.cpp index 0c99906..676cd9c 100644 --- a/devnulladapter.cpp +++ b/devnulladapter.cpp @@ -7,8 +7,13 @@ DevNullAdapter::DevNullAdapter(QObject *parent) : AbstractAdapter(parent) { } bool DevNullAdapter::store(QString key, QString data) { + return store(key, data, 0); +} + +bool DevNullAdapter::store(QString key, QString data, int ttl) { Q_UNUSED(key); Q_UNUSED(data); + Q_UNUSED(ttl); return true; } diff --git a/devnulladapter.hpp b/devnulladapter.hpp index 40d2da6..fdbc7c1 100644 --- a/devnulladapter.hpp +++ b/devnulladapter.hpp @@ -16,6 +16,7 @@ namespace Bidstack { public: bool store(QString key, QString data); + bool store(QString key, QString data, int ttl); bool has(QString key); bool remove(QString key); bool clear(); diff --git a/sqliteadapter.cpp b/sqliteadapter.cpp index f10ffc9..e7cd859 100644 --- a/sqliteadapter.cpp +++ b/sqliteadapter.cpp @@ -1,5 +1,7 @@ #include "sqliteadapter.hpp" +#include + using namespace Bidstack::Cache; SqliteAdapter::SqliteAdapter(QString filename, QObject *parent) : AbstractAdapter(parent) { @@ -19,7 +21,8 @@ bool SqliteAdapter::init(QString filename) { const QString sql = "CREATE TABLE IF NOT EXISTS cache (" "key CHAR(32) PRIMARY KEY NOT NULL," - "data TEXT NOT NULL" + "data TEXT NOT NULL," + "expires_at INTEGER" ")"; QSqlQuery stmt(sql, m_connection); @@ -29,12 +32,19 @@ bool SqliteAdapter::init(QString filename) { } bool SqliteAdapter::store(QString key, QString data) { - const QString sql = "INSERT OR REPLACE INTO cache (key, data) VALUES (:key, :data)"; + return store(key, data, 0); +} + +bool SqliteAdapter::store(QString key, QString data, int ttl) { + const QString sql = + "INSERT OR REPLACE INTO cache (key, data, expires_at) " + "VALUES (:key, :data, :expires_at)"; QSqlQuery stmt(m_connection); stmt.prepare(sql); stmt.bindValue(":key", key); stmt.bindValue(":data", data); + stmt.bindValue(":expires_at", now() + ttl); stmt.exec(); return !stmt.lastError().isValid(); @@ -66,7 +76,7 @@ bool SqliteAdapter::clear() { } QString SqliteAdapter::fetch(QString key) { - const QString sql = "SELECT data FROM cache WHERE key = :key"; + const QString sql = "SELECT expires_at, data FROM cache WHERE key = :key"; QSqlQuery stmt(m_connection); stmt.prepare(sql); @@ -74,7 +84,15 @@ QString SqliteAdapter::fetch(QString key) { stmt.exec(); if (!stmt.lastError().isValid() && stmt.next()) { - return stmt.value(0).toString(); + uint expires_at = stmt.value(0).toUInt(); + + if ((expires_at == 0) || (expires_at >= now())) { + return stmt.value(1).toString(); + } + + if (!remove(key)) { + throw "Could not expire key '" + key + "'"; + } } return ""; @@ -83,3 +101,7 @@ QString SqliteAdapter::fetch(QString key) { QString SqliteAdapter::fetch(QString key, QString defaultValue) { return has(key) ? fetch(key) : defaultValue; } + +uint SqliteAdapter::now() { + return QDateTime::currentDateTime().toTime_t(); +} diff --git a/sqliteadapter.hpp b/sqliteadapter.hpp index c2722f8..ce9c462 100644 --- a/sqliteadapter.hpp +++ b/sqliteadapter.hpp @@ -20,6 +20,7 @@ namespace Bidstack { public: bool store(QString key, QString data); + bool store(QString key, QString data, int ttl); bool has(QString key); bool remove(QString key); bool clear(); @@ -28,6 +29,7 @@ namespace Bidstack { private: bool init(QString filename); + uint now(); private: QSqlDatabase m_connection;