From 2a54fb581d7304cd71049ef1af66eac483e754e9 Mon Sep 17 00:00:00 2001 From: APTX Date: Tue, 19 Mar 2013 23:22:09 +0100 Subject: [PATCH] Add SqlAsyncQuery class. --- localmylist/asyncquerytask.cpp | 75 ++++++++ localmylist/asyncquerytask.h | 32 ++++ localmylist/include/LocalMyList/SqlAsyncQuery | 1 + localmylist/localmylist.pro | 10 +- localmylist/sqlasyncquery.cpp | 79 +++++++++ localmylist/sqlasyncquery.h | 47 +++++ localmylist/sqlasyncqueryinternal.cpp | 166 ++++++++++++++++++ localmylist/sqlasyncqueryinternal.h | 81 +++++++++ 8 files changed, 489 insertions(+), 2 deletions(-) create mode 100644 localmylist/asyncquerytask.cpp create mode 100644 localmylist/asyncquerytask.h create mode 100644 localmylist/include/LocalMyList/SqlAsyncQuery create mode 100644 localmylist/sqlasyncquery.cpp create mode 100644 localmylist/sqlasyncquery.h create mode 100644 localmylist/sqlasyncqueryinternal.cpp create mode 100644 localmylist/sqlasyncqueryinternal.h diff --git a/localmylist/asyncquerytask.cpp b/localmylist/asyncquerytask.cpp new file mode 100644 index 0000000..78f3a25 --- /dev/null +++ b/localmylist/asyncquerytask.cpp @@ -0,0 +1,75 @@ +#include "asyncquerytask.h" + +#include +#include +#include +#include +#include "database.h" + +namespace LocalMyList { + +AsyncQueryTask::AsyncQueryTask(QObject *parent) : + AbstractTask(parent), m_query(0), m_result(0) +{ +} + +AsyncQueryTask::~AsyncQueryTask() +{ +} + +void AsyncQueryTask::setQuery(AsyncQuery *query) +{ + m_query = query; +} + +Result *AsyncQueryTask::result() const +{ + return m_result; +} + + +QString AsyncQueryTask::taskSubject() const +{ + if (!m_query) + return QString(); + return m_query->query; +} + +bool AsyncQueryTask::canUseThreads() const +{ + return true; +} + +void AsyncQueryTask::start() +{ + QSqlQuery q(db->connection()); + + q.prepare(m_query->query); + + foreach(const BoundValue &v, m_query->boundValues) + { + q.bindValue(v.name, v.value, v.paramType); + } + + m_result = new Internal::Result; + if (!q.exec()) + { + m_result->error = q.lastError().text(); + } + else + { + while (q.next()) + { + Internal::Row row(q.record().count()); + for (int i = 0; i < row.count(); ++i) + { + row[i].name = q.record().fieldName(i); + row[i].value = q.value(i); + } + m_result->rows << row; + } + } + emit finished(); +} + +} // namespace LocalMyList diff --git a/localmylist/asyncquerytask.h b/localmylist/asyncquerytask.h new file mode 100644 index 0000000..ff7557b --- /dev/null +++ b/localmylist/asyncquerytask.h @@ -0,0 +1,32 @@ +#ifndef ASYNCQUERYTASK_H +#define ASYNCQUERYTASK_H + +#include "abstracttask.h" +#include "sqlasyncqueryinternal.h" + +namespace LocalMyList { + +using namespace Internal; + +class AsyncQueryTask : public AbstractTask +{ + Q_OBJECT +public: + explicit AsyncQueryTask(QObject *parent = 0); + ~AsyncQueryTask(); + + void setQuery(AsyncQuery *query); + Result *result() const; + + QString taskSubject() const; + bool canUseThreads() const; + + void start(); +private: + AsyncQuery *m_query; + Result *m_result; +}; + +} // namespace LocalMyList + +#endif // ASYNCQUERYTASK_H diff --git a/localmylist/include/LocalMyList/SqlAsyncQuery b/localmylist/include/LocalMyList/SqlAsyncQuery new file mode 100644 index 0000000..cb1ab36 --- /dev/null +++ b/localmylist/include/LocalMyList/SqlAsyncQuery @@ -0,0 +1 @@ +#include "../../sqlasyncquery.h" diff --git a/localmylist/localmylist.pro b/localmylist/localmylist.pro index ea22659..ba79b19 100644 --- a/localmylist/localmylist.pro +++ b/localmylist/localmylist.pro @@ -27,7 +27,10 @@ SOURCES += \ scriptablesql.cpp \ reportengine.cpp \ databaseclasses.cpp \ - sqlquery.cpp + sqlquery.cpp \ + sqlasyncquery.cpp \ + sqlasyncqueryinternal.cpp \ + asyncquerytask.cpp HEADERS += \ localmylist_global.h \ @@ -48,7 +51,10 @@ HEADERS += \ scriptablesql.h \ reportengine.h \ databaseclasses.h \ - sqlquery.h + sqlquery.h \ + sqlasyncquery.h \ + sqlasyncqueryinternal.h \ + asyncquerytask.h CONV_HEADERS += \ include/LocalMyList/AbstractTask \ diff --git a/localmylist/sqlasyncquery.cpp b/localmylist/sqlasyncquery.cpp new file mode 100644 index 0000000..c09d4c1 --- /dev/null +++ b/localmylist/sqlasyncquery.cpp @@ -0,0 +1,79 @@ +#include "sqlasyncquery.h" + +#include "sqlasyncqueryinternal.h" +#include "asyncquerytask.h" + +namespace LocalMyList { + +using namespace Internal; + +SqlAsyncQuery::SqlAsyncQuery(QObject *parent) : + QObject(parent), d(new SqlAsyncQueryInternal(this)) +{ +} + +bool SqlAsyncQuery::prepare(const QString &query) +{ + return d->prepare(query); +} + +void SqlAsyncQuery::bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType) +{ + d->bindValue(placeholder, val, paramType); +} + +bool SqlAsyncQuery::exec() +{ + return d->exec(); +} + +bool SqlAsyncQuery::exec(const QString &query) +{ + return d->exec(query); +} + +bool SqlAsyncQuery::next() +{ + return d->next(); +} + +QVariant SqlAsyncQuery::value(int index) const +{ + return d->value(index); +} + +QVariant SqlAsyncQuery::value(const QString &name) const +{ + return d->value(name); +} + +int SqlAsyncQuery::indexOf(const QString &name) const +{ + return d->indexOf(name); +} + +void SqlAsyncQuery::finish() +{ + return d->finish(); +} + +QString SqlAsyncQuery::executedQuery() const +{ + return d->executedQuery(); +} + +QString SqlAsyncQuery::lastError() const +{ + return d->lastError(); +} + +void SqlAsyncQuery::resultRecieved() +{ + AsyncQueryTask *t = qobject_cast(sender()); + if (!t) + return; + + d->resultReady(t->result()); +} + +} // namespace LocalMyList diff --git a/localmylist/sqlasyncquery.h b/localmylist/sqlasyncquery.h new file mode 100644 index 0000000..1381357 --- /dev/null +++ b/localmylist/sqlasyncquery.h @@ -0,0 +1,47 @@ +#ifndef SQLASYNCQUERY_H +#define SQLASYNCQUERY_H + +#include "localmylist_global.h" +#include +#include + +namespace LocalMyList { + +namespace Internal { + class SqlAsyncQueryInternal; +} +class LOCALMYLISTSHARED_EXPORT SqlAsyncQuery : public QObject +{ + Q_OBJECT +public: + explicit SqlAsyncQuery(QObject *parent = 0); + + bool prepare(const QString &query); + void bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType = QSql::In); + bool exec(); + + bool exec(const QString &query); + + bool next(); + QVariant value(int index) const; + QVariant value(const QString &name) const; + int indexOf(const QString &name ) const; + void finish(); + + QString executedQuery() const; + QString lastError() const; + +signals: + void resultReady(); + +private slots: + void resultRecieved(); + +private: + Internal::SqlAsyncQueryInternal *d; +}; + +} // namespace LocalMyList + + +#endif // SQLASYNCQUERY_H diff --git a/localmylist/sqlasyncqueryinternal.cpp b/localmylist/sqlasyncqueryinternal.cpp new file mode 100644 index 0000000..f4419c3 --- /dev/null +++ b/localmylist/sqlasyncqueryinternal.cpp @@ -0,0 +1,166 @@ +#include "sqlasyncqueryinternal.h" + +#include +#include "sqlasyncquery.h" +#include "asyncquerytask.h" +#include "mylist.h" + +namespace LocalMyList { +namespace Internal { + +SqlAsyncQueryInternal::SqlAsyncQueryInternal(SqlAsyncQuery *p_) + : p(p_), q(0), result(0), currentRow(-1), working(false) +{ +} + +SqlAsyncQueryInternal::~SqlAsyncQueryInternal() +{ + if (q) + delete q; + if (result) + delete result; +} + +bool SqlAsyncQueryInternal::prepare(const QString &query) +{ + if (working) + { + m_lastError = QObject::tr("Can not prepare new query while waiting for result"); + return false; + } + + if (q) + delete q; + + q = new AsyncQuery; + + q->query = query; + return true; +} + +void SqlAsyncQueryInternal::bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType) +{ + if (working) + return; + if (!q) + return; + + BoundValue b; + b.name = placeholder; + b.value = val; + b.paramType = paramType; + + q->boundValues << b; +} + +bool SqlAsyncQueryInternal::exec() +{ + if (working) + return false; + + working = true; + + AsyncQueryTask *task = new AsyncQueryTask; + task->setQuery(q); + QObject::connect(task, SIGNAL(finished()), p, SLOT(resultRecieved())); + + MyList::instance()->executeTask(task); + return true; +} + +bool SqlAsyncQueryInternal::exec(const QString &query) +{ + if (!prepare(query)) + return false; + return exec(); +} + +bool SqlAsyncQueryInternal::next() +{ + if (!result) + return false; + if (currentRow == -2) + return false; + + ++currentRow; + bool ret = currentRow < result->rows.count(); + + if (!ret) + currentRow = -2; + + return ret; +} + +QVariant SqlAsyncQueryInternal::value(int index) const +{ + if (!result) + return QVariant(); + if (currentRow < 0) + return QVariant(); + if (index < 0 || index >= result->rows.at(currentRow).count()) + return QVariant(); + + return result->rows.at(currentRow).at(index).value; +} + +QVariant SqlAsyncQueryInternal::value(const QString &name) const +{ + return value(indexOf(name)); +} + +int SqlAsyncQueryInternal::indexOf(const QString &name) const +{ + if (!result) + return -1; + if (currentRow < 0) + return -1; + + int idx = -1; + for (int i = 0; i < result->rows.at(currentRow).count(); ++i) + { + if (result->rows.at(currentRow).at(i).name == name) + { + idx = i; + break; + } + } + return idx; +} + +void SqlAsyncQueryInternal::finish() +{ + if (working) + return; + + if (result) + delete result; + currentRow = -1; +} + +QString SqlAsyncQueryInternal::executedQuery() const +{ + if (!q) + return QString(); + + return q->query; +} + +QString SqlAsyncQueryInternal::lastError() const +{ + return m_lastError; +} + +void SqlAsyncQueryInternal::resultReady(Result *newResult) +{ + if (result) + delete result; + result = newResult; + currentRow = -1; + working = false; +} + +} // namespace Internal +} // namespace LocalMyList + + + diff --git a/localmylist/sqlasyncqueryinternal.h b/localmylist/sqlasyncqueryinternal.h new file mode 100644 index 0000000..596cfdc --- /dev/null +++ b/localmylist/sqlasyncqueryinternal.h @@ -0,0 +1,81 @@ +#ifndef SQLASYNCQUERYINTERNAL_H +#define SQLASYNCQUERYINTERNAL_H + +#include +#include +#include +#include + +namespace LocalMyList { + +class SqlAsyncQuery; + +namespace Internal { + +struct BoundValue +{ + QString name; + QVariant value; + QSql::ParamType paramType; +}; + +typedef QList BoundValues; + +struct AsyncQuery +{ + QString query; + BoundValues boundValues; +}; + +struct Field +{ + QString name; + QVariant value; +}; + +typedef QVector Row; + +struct Result +{ + QList rows; + QString error; +}; + + +class SqlAsyncQueryInternal +{ +public: + SqlAsyncQueryInternal(SqlAsyncQuery *p_); + ~SqlAsyncQueryInternal(); + + bool prepare(const QString &query); + void bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType = QSql::In); + bool exec(); + + bool exec(const QString &query); + + bool next(); + QVariant value(int index) const; + QVariant value(const QString &name) const; + int indexOf(const QString &name) const; + void finish(); + + QString executedQuery() const; + QString lastError() const; + + void resultReady(Result *newResult); + + SqlAsyncQuery *p; + AsyncQuery *q; + Result *result; + int currentRow; + + bool working; + + QString m_lastError; +}; + +} // namespace Internal +} // namespace LocalMyList + +#endif // SQLASYNCQUERYINTERNAL_H -- 2.52.0