mirror of
https://invent.kde.org/network/falkon.git
synced 2024-12-19 18:26:34 +01:00
Add SqlQueryJob to run queries on separate thread
This commit is contained in:
parent
0d2776a261
commit
8a5c69b8a1
@ -22,6 +22,7 @@ falkon_tests(
|
|||||||
locationbartest
|
locationbartest
|
||||||
webviewtest
|
webviewtest
|
||||||
webtabtest
|
webtabtest
|
||||||
|
sqldatabasetest
|
||||||
)
|
)
|
||||||
|
|
||||||
set(falkon_autotests_SRCS ${CMAKE_SOURCE_DIR}/tests/modeltest/modeltest.cpp)
|
set(falkon_autotests_SRCS ${CMAKE_SOURCE_DIR}/tests/modeltest/modeltest.cpp)
|
||||||
|
90
autotests/sqldatabasetest.cpp
Normal file
90
autotests/sqldatabasetest.cpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/* ============================================================
|
||||||
|
* Falkon - Qt web browser
|
||||||
|
* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* ============================================================ */
|
||||||
|
#include "sqldatabasetest.h"
|
||||||
|
#include "sqldatabase.h"
|
||||||
|
|
||||||
|
#include <QtTest/QTest>
|
||||||
|
#include <QtTest/QSignalSpy>
|
||||||
|
#include <QSqlDatabase>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
|
||||||
|
void SqlDatabaseTest::initTestCase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SqlDatabaseTest::cleanupTestCase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool waitForFinished(SqlQueryJob *job)
|
||||||
|
{
|
||||||
|
QSignalSpy spy(job, &SqlQueryJob::finished);
|
||||||
|
return spy.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SqlDatabaseTest::sqlQueryJobTest()
|
||||||
|
{
|
||||||
|
QTemporaryFile file;
|
||||||
|
file.open();
|
||||||
|
|
||||||
|
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
|
||||||
|
db.setDatabaseName(file.fileName());
|
||||||
|
db.open();
|
||||||
|
|
||||||
|
SqlDatabase::instance()->setDatabase(db);
|
||||||
|
|
||||||
|
QCOMPARE(db.tables().count(), 0);
|
||||||
|
|
||||||
|
SqlQueryJob *job = new SqlQueryJob();
|
||||||
|
job->setQuery("CREATE TABLE test1 (data TEXT, id INTEGER PRIMARY KEY)");
|
||||||
|
job->start();
|
||||||
|
QVERIFY(waitForFinished(job));
|
||||||
|
QVERIFY(!job->error().isValid());
|
||||||
|
|
||||||
|
QCOMPARE(db.tables(), QStringList{"test1"});
|
||||||
|
|
||||||
|
job = new SqlQueryJob();
|
||||||
|
job->setQuery("INSERT INTO test1 (data) VALUES (?)");
|
||||||
|
job->addBindValue("test-value");
|
||||||
|
job->start();
|
||||||
|
QVERIFY(waitForFinished(job));
|
||||||
|
QVERIFY(!job->error().isValid());
|
||||||
|
|
||||||
|
QCOMPARE(job->lastInsertId().toInt(), 1);
|
||||||
|
QSqlQuery query("SELECT data FROM test1", db);
|
||||||
|
query.next();
|
||||||
|
QCOMPARE(query.value(0).toString(), QString("test-value"));
|
||||||
|
QVERIFY(!query.next());
|
||||||
|
|
||||||
|
job = new SqlQueryJob();
|
||||||
|
job->setQuery("SELECT data FROM test1");
|
||||||
|
job->start();
|
||||||
|
QVERIFY(waitForFinished(job));
|
||||||
|
QVERIFY(!job->error().isValid());
|
||||||
|
|
||||||
|
QCOMPARE(job->records().size(), 1);
|
||||||
|
QCOMPARE(job->records().at(0).value(0).toString(), QString("test-value"));
|
||||||
|
|
||||||
|
job = new SqlQueryJob();
|
||||||
|
job->setQuery("SELECT invalid sql syntax; 1321sdsa from");
|
||||||
|
job->start();
|
||||||
|
QVERIFY(waitForFinished(job));
|
||||||
|
QVERIFY(job->error().isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN(SqlDatabaseTest)
|
31
autotests/sqldatabasetest.h
Normal file
31
autotests/sqldatabasetest.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/* ============================================================
|
||||||
|
* Falkon - Qt web browser
|
||||||
|
* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* ============================================================ */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class SqlDatabaseTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void initTestCase();
|
||||||
|
void cleanupTestCase();
|
||||||
|
|
||||||
|
void sqlQueryJobTest();
|
||||||
|
};
|
@ -19,13 +19,90 @@
|
|||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QThreadStorage>
|
#include <QThreadStorage>
|
||||||
|
#include <QFutureWatcher>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
QThreadStorage<QSqlDatabase> s_databases;
|
QThreadStorage<QSqlDatabase> s_databases;
|
||||||
|
|
||||||
Q_GLOBAL_STATIC(SqlDatabase, qz_sql_database)
|
Q_GLOBAL_STATIC(SqlDatabase, qz_sql_database)
|
||||||
|
|
||||||
|
// SqlQueryJob
|
||||||
|
SqlQueryJob::SqlQueryJob(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SqlQueryJob::SqlQueryJob(const QString &query, QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
setQuery(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SqlQueryJob::setQuery(const QString &query)
|
||||||
|
{
|
||||||
|
m_query = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SqlQueryJob::addBindValue(const QVariant &value)
|
||||||
|
{
|
||||||
|
m_boundValues.append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSqlError SqlQueryJob::error() const
|
||||||
|
{
|
||||||
|
return m_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SqlQueryJob::lastInsertId() const
|
||||||
|
{
|
||||||
|
return m_lastInsertId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<QSqlRecord> SqlQueryJob::records() const
|
||||||
|
{
|
||||||
|
return m_records;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SqlQueryJob::start()
|
||||||
|
{
|
||||||
|
struct Result {
|
||||||
|
QSqlError error;
|
||||||
|
QVariant lastInsertId;
|
||||||
|
QVector<QSqlRecord> records;
|
||||||
|
};
|
||||||
|
|
||||||
|
const QString query = m_query;
|
||||||
|
m_query.clear();
|
||||||
|
const QVector<QVariant> boundValues = m_boundValues;
|
||||||
|
m_boundValues.clear();
|
||||||
|
|
||||||
|
auto watcher = new QFutureWatcher<Result>(this);
|
||||||
|
connect(watcher, &QFutureWatcher<Result>::finished, this, [=]() {
|
||||||
|
deleteLater();
|
||||||
|
const auto result = watcher->result();
|
||||||
|
m_error = result.error;
|
||||||
|
m_lastInsertId = result.lastInsertId;
|
||||||
|
m_records = result.records;
|
||||||
|
emit finished(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
watcher->setFuture(QtConcurrent::run([=]() {
|
||||||
|
QSqlQuery q(SqlDatabase::instance()->database());
|
||||||
|
q.prepare(query);
|
||||||
|
for (const QVariant &value : boundValues) {
|
||||||
|
q.addBindValue(value);
|
||||||
|
}
|
||||||
|
q.exec();
|
||||||
|
Result res;
|
||||||
|
res.error = q.lastError();
|
||||||
|
res.lastInsertId = q.lastInsertId();
|
||||||
|
while (q.next()) {
|
||||||
|
res.records.append(q.record());
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
// SqlDatabase
|
// SqlDatabase
|
||||||
SqlDatabase::SqlDatabase(QObject* parent)
|
SqlDatabase::SqlDatabase(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
|
@ -18,13 +18,40 @@
|
|||||||
#ifndef SQLDATABASE_H
|
#ifndef SQLDATABASE_H
|
||||||
#define SQLDATABASE_H
|
#define SQLDATABASE_H
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QFuture>
|
|
||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
|
#include <QSqlError>
|
||||||
|
#include <QSqlRecord>
|
||||||
|
|
||||||
#include "qzcommon.h"
|
#include "qzcommon.h"
|
||||||
|
|
||||||
|
class FALKON_EXPORT SqlQueryJob : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SqlQueryJob(QObject *parent = nullptr);
|
||||||
|
explicit SqlQueryJob(const QString &query, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
void setQuery(const QString &query);
|
||||||
|
void addBindValue(const QVariant &value);
|
||||||
|
|
||||||
|
QSqlError error() const;
|
||||||
|
QVariant lastInsertId() const;
|
||||||
|
QVector<QSqlRecord> records() const;
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void finished(SqlQueryJob *job);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_query;
|
||||||
|
QVector<QVariant> m_boundValues;
|
||||||
|
QSqlError m_error;
|
||||||
|
QVariant m_lastInsertId;
|
||||||
|
QVector<QSqlRecord> m_records;
|
||||||
|
};
|
||||||
|
|
||||||
class FALKON_EXPORT SqlDatabase : public QObject
|
class FALKON_EXPORT SqlDatabase : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -120,6 +120,7 @@ set(GENERATED_SOURCES
|
|||||||
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/delayedfilewatcher_wrapper.cpp
|
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/delayedfilewatcher_wrapper.cpp
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/iconprovider_wrapper.cpp
|
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/iconprovider_wrapper.cpp
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/qztools_wrapper.cpp
|
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/qztools_wrapper.cpp
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/sqlqueryjob_wrapper.cpp
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/sqldatabase_wrapper.cpp
|
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/sqldatabase_wrapper.cpp
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/toolbutton_wrapper.cpp
|
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/toolbutton_wrapper.cpp
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/wheelhelper_wrapper.cpp
|
${CMAKE_CURRENT_BINARY_DIR}/PyFalkon/wheelhelper_wrapper.cpp
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
</inject-code>
|
</inject-code>
|
||||||
</modify-function>
|
</modify-function>
|
||||||
</object-type>
|
</object-type>
|
||||||
|
<object-type name="SqlQueryJob"/>
|
||||||
<object-type name="SqlDatabase"/>
|
<object-type name="SqlDatabase"/>
|
||||||
<object-type name="ToolButton"/>
|
<object-type name="ToolButton"/>
|
||||||
<value-type name="WheelHelper">
|
<value-type name="WheelHelper">
|
||||||
|
Loading…
Reference in New Issue
Block a user