You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

228 lines
9.4 KiB

/****************************************************************************
**
** https://www.qxorm.com/
** Copyright (C) 2013 Lionel Marty (contact@qxorm.com)
**
** This file is part of the QxOrm library
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any
** damages arising from the use of this software
**
** Commercial Usage
** Licensees holding valid commercial QxOrm licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Lionel Marty
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file 'license.gpl3.txt' included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met : http://www.gnu.org/copyleft/gpl.html
**
** If you are unsure which license is appropriate for your use, or
** if you have questions regarding the use of this file, please contact :
** contact@qxorm.com
**
****************************************************************************/
#ifndef _QX_DAO_ASYNC_H_
#define _QX_DAO_ASYNC_H_
#ifdef _MSC_VER
#pragma once
#endif
/*!
* \file QxDaoAsync.h
* \author Lionel Marty
* \ingroup QxDao
* \brief Helper class to execute SQL queries in another thread (asynchronous way) using qx::IxPersistable interface
*/
#ifdef _QX_NO_PRECOMPILED_HEADER
#ifndef Q_MOC_RUN
#include <QxPrecompiled.h> // Need to include precompiled header for the generated moc file
#endif // Q_MOC_RUN
#endif // _QX_NO_PRECOMPILED_HEADER
#include <QtCore/qqueue.h>
#include <QtSql/qsqlerror.h>
#ifndef Q_MOC_RUN
#include <QxDao/IxPersistable.h>
#include <QxDao/QxSqlQuery.h>
#endif // Q_MOC_RUN
namespace qx {
namespace dao {
namespace detail {
/*!
* \ingroup QxDao
* \brief qx::dao::detail::QxDaoAsyncParams : all parameters for qx::QxDaoAsync class to execute queries
*/
struct QxDaoAsyncParams
{
enum dao_action { dao_none, dao_count, dao_fetch_by_id, dao_fetch_all, dao_fetch_by_query, dao_insert,
dao_update, dao_save, dao_delete_by_id, dao_delete_all, dao_delete_by_query,
dao_destroy_by_id, dao_destroy_all, dao_destroy_by_query, dao_execute_query, dao_call_query };
dao_action daoAction; //!< Action to execute into the thread (asynchronous way)
QString className; //!< Classname parameter to execute action (must implement qx::IxPersistable interface)
qx::QxSqlQuery query; //!< Query parameter to execute action
QSqlDatabase * pDatabase; //!< Database parameter to execute action
IxPersistable_ptr pInstance; //!< Current instance parameter to execute action
IxPersistableCollection_ptr pListOfInstances; //!< List of instances fetched by query
QStringList listColumns; //!< List of columns parameter to execute action
QStringList listRelations; //!< List of relationships parameter to execute action
QVariant id; //!< Current instance id parameter to execute action
long daoCount; //!< Dao count value returned by qx::dao::count query
bool useExecBatch; //!< If true then use the QSqlQuery::execBatch() method to improve performance inserting/updating/deleting a list of instances to database (but doesn't fill the last inserted identifier in the C++ instances)
QxDaoAsyncParams() : daoAction(dao_none), pDatabase(NULL), daoCount(0), useExecBatch(false) { ; }
~QxDaoAsyncParams() { ; }
};
typedef std::shared_ptr<QxDaoAsyncParams> QxDaoAsyncParams_ptr;
/*!
* \ingroup QxDao
* \brief qx::dao::detail::QxDaoAsyncRunner : class with a slot to execute queries in another thread
*/
class QX_DLL_EXPORT QxDaoAsyncRunner : public QObject
{
Q_OBJECT
public:
QxDaoAsyncRunner();
virtual ~QxDaoAsyncRunner();
protected:
QSqlError runQuery(qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
Q_SIGNALS:
void queryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
public Q_SLOTS:
void onQueryStarted(qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
};
} // namespace detail
} // namespace dao
/*!
* \ingroup QxDao
* \brief qx::QxDaoAsync : helper class to execute SQL queries in another thread (asynchronous way) using qx::IxPersistable interface
*
* To use <i>qx::QxDaoAsync</i> helper class :
* 1- be careful to work only with classes implementing <i>qx::IxPersistable</i> interface ;
* 2- create an instance of <i>qx::QxDaoAsync</i> type (for example, a property of a QWidget derived class) ;
* 3- connect a SLOT to the <i>qx::QxDaoAsync::queryFinished()</i> SIGNAL (for example, a SLOT of a QWidget derived class) ;
* 4- run a query using one of <i>qx::QxDaoAsync::asyncXXXX()</i> methods.
*
* For example, with a <i>MyWidget</i> class :
* \code
class MyWidget : public QWidget
{
Q_OBJECT
//...
qx::QxDaoAsync m_daoAsync;
//...
Q_SLOTS:
void onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
//...
};
* \endcode
* And here is the implementation of <i>MyWidget</i> class :
* \code
MyWidget::MyWidget() : QObject()
{
//...
QObject::connect((& m_daoAsync), SIGNAL(queryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)), this, SLOT(onQueryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)));
//...
}
void MyWidget::onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams)
{
if (! pDaoParams) { return; }
qx::QxSqlQuery query = pDaoParams->query;
if (! daoError.isValid()) { ; }
// If the async query is associated to a simple object, just use 'pDaoParams->pInstance' method
qx::IxPersistable_ptr ptr = pDaoParams->pInstance;
// If the async query is associated to a list of objects, just use 'pDaoParams->pListOfInstances' method
qx::IxPersistableCollection_ptr lst = pDaoParams->pListOfInstances;
//...
}
* \endcode
*/
class QX_DLL_EXPORT QxDaoAsync : public QThread
{
Q_OBJECT
protected:
QMutex m_mutex; //!< Mutex => qx::QxDaoAsync is thread-safe
qx::dao::detail::QxDaoAsyncParams_ptr m_pDaoParams; //!< Parameters to execute query
public:
QxDaoAsync();
virtual ~QxDaoAsync();
bool asyncCount(const QString & className, const qx::QxSqlQuery & query = qx::QxSqlQuery(), QSqlDatabase * pDatabase = NULL);
bool asyncFetchById(IxPersistable_ptr pToFetch, const QVariant & id = QVariant(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
bool asyncFetchAll(const QString & className, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
bool asyncFetchByQuery(const QString & className, const qx::QxSqlQuery & query, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
bool asyncInsert(IxPersistable_ptr pToInsert, const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
bool asyncUpdate(IxPersistable_ptr pToUpdate, const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
bool asyncSave(IxPersistable_ptr pToSave, const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
bool asyncDeleteById(IxPersistable_ptr pToDelete, const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
bool asyncDeleteAll(const QString & className, QSqlDatabase * pDatabase = NULL);
bool asyncDeleteByQuery(const QString & className, const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
bool asyncDestroyById(IxPersistable_ptr pToDestroy, const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
bool asyncDestroyAll(const QString & className, QSqlDatabase * pDatabase = NULL);
bool asyncDestroyByQuery(const QString & className, const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
bool asyncExecuteQuery(const QString & className, qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
bool asyncCallQuery(qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
bool isQueryRunning() const { return (m_pDaoParams.get() != NULL); }
protected:
virtual void run();
void startQuery();
Q_SIGNALS:
void queryStarted(qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
void queryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
private Q_SLOTS:
void onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
};
typedef std::shared_ptr<QxDaoAsync> QxDaoAsync_ptr;
} // namespace qx
QX_DLL_EXPORT QDataStream & operator<< (QDataStream & stream, const qx::dao::detail::QxDaoAsyncParams & t) QX_USED;
QX_DLL_EXPORT QDataStream & operator>> (QDataStream & stream, qx::dao::detail::QxDaoAsyncParams & t) QX_USED;
#endif // _QX_DAO_ASYNC_H_