2016-05-12 14:08:58 +08:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Nut project.
|
|
|
|
|
** https://github.com/HamedMasafi/Nut
|
|
|
|
|
**
|
|
|
|
|
** Nut is free software: you can redistribute it and/or modify
|
|
|
|
|
** it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
** (at your option) any later version.
|
|
|
|
|
**
|
|
|
|
|
** Nut 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 Lesser General Public License for more details.
|
|
|
|
|
**
|
|
|
|
|
** You should have received a copy of the GNU Lesser General Public License
|
|
|
|
|
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
|
|
#ifndef QUERY_H
|
|
|
|
|
#define QUERY_H
|
|
|
|
|
|
|
|
|
|
#include <QtCore/QVariant>
|
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
|
#include <QtCore/QScopedPointer>
|
|
|
|
|
#include <QtCore/QRegularExpression>
|
2017-06-12 00:50:43 +08:00
|
|
|
#include <QtCore/QMetaObject>
|
2018-01-13 23:59:55 +08:00
|
|
|
#include <QtSql/QSqlResult>
|
2018-01-15 22:18:49 +08:00
|
|
|
#include <QtSql/QSqlError>
|
2018-02-13 23:39:21 +08:00
|
|
|
#include <QtSql/QSqlQueryModel>
|
2019-06-18 21:40:40 +08:00
|
|
|
#include <QtSql/QSqlQuery>
|
|
|
|
|
|
|
|
|
|
#ifdef NUT_SHARED_POINTER
|
|
|
|
|
#include <QtCore/QSharedPointer>
|
|
|
|
|
#endif
|
2016-05-12 14:08:58 +08:00
|
|
|
|
2019-06-07 16:19:20 +08:00
|
|
|
#include "table.h"
|
2016-06-05 20:22:26 +08:00
|
|
|
#include "query_p.h"
|
2016-05-12 14:08:58 +08:00
|
|
|
#include "database.h"
|
|
|
|
|
#include "databasemodel.h"
|
|
|
|
|
#include "tablesetbase_p.h"
|
2017-10-07 18:26:05 +08:00
|
|
|
#include "generators/sqlgeneratorbase_p.h"
|
2016-05-12 14:08:58 +08:00
|
|
|
#include "querybase_p.h"
|
2018-02-17 23:44:39 +08:00
|
|
|
#include "phrase.h"
|
2017-02-01 18:01:21 +08:00
|
|
|
#include "tablemodel.h"
|
2019-06-18 21:40:40 +08:00
|
|
|
#include "sqlmodel.h"
|
2016-05-12 14:08:58 +08:00
|
|
|
|
2017-02-01 18:01:21 +08:00
|
|
|
NUT_BEGIN_NAMESPACE
|
2016-05-12 14:08:58 +08:00
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2018-01-13 23:59:55 +08:00
|
|
|
class NUT_EXPORT Query : public QueryBase
|
2016-05-12 14:08:58 +08:00
|
|
|
{
|
2016-06-05 20:22:26 +08:00
|
|
|
QueryPrivate *d_ptr;
|
|
|
|
|
Q_DECLARE_PRIVATE(Query)
|
|
|
|
|
|
2017-06-01 00:10:35 +08:00
|
|
|
bool m_autoDelete;
|
|
|
|
|
|
2016-05-12 14:08:58 +08:00
|
|
|
public:
|
2018-02-26 18:14:36 +08:00
|
|
|
explicit Query(Database *database, TableSetBase *tableSet, bool autoDelete);
|
2016-06-05 20:22:26 +08:00
|
|
|
~Query();
|
2016-05-21 16:09:03 +08:00
|
|
|
|
2018-01-09 17:33:54 +08:00
|
|
|
//ddl
|
2016-06-05 20:22:26 +08:00
|
|
|
|
2018-01-10 01:32:28 +08:00
|
|
|
Query<T> *join(const QString &className);
|
2018-01-09 17:33:54 +08:00
|
|
|
Query<T> *join(Table *c);
|
2016-06-05 20:22:26 +08:00
|
|
|
|
2018-01-09 00:59:16 +08:00
|
|
|
template<class TABLE>
|
|
|
|
|
Query<T> *join()
|
|
|
|
|
{
|
|
|
|
|
join(TABLE::staticMetaObject.className());
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-13 23:59:55 +08:00
|
|
|
// Query<T> *orderBy(QString fieldName, QString type);
|
2018-01-09 17:33:54 +08:00
|
|
|
Query<T> *skip(int n);
|
|
|
|
|
Query<T> *take(int n);
|
2018-02-17 23:44:39 +08:00
|
|
|
Query<T> *fields(const PhraseList &ph);
|
|
|
|
|
Query<T> *orderBy(const PhraseList &ph);
|
|
|
|
|
Query<T> *where(const ConditionalPhrase &ph);
|
|
|
|
|
Query<T> *setWhere(const ConditionalPhrase &ph);
|
|
|
|
|
|
2018-01-09 17:33:54 +08:00
|
|
|
//data selecting
|
2019-06-18 23:37:03 +08:00
|
|
|
Row<T> first();
|
|
|
|
|
RowList<T> toList(int count = -1);
|
2018-01-09 17:33:54 +08:00
|
|
|
template <typename F>
|
|
|
|
|
QList<F> select(const FieldPhrase<F> f);
|
2019-06-08 16:40:00 +08:00
|
|
|
|
|
|
|
|
template<typename O>
|
|
|
|
|
QList<O> select(const std::function<O(const QSqlQuery &q)> allocator);
|
|
|
|
|
|
2017-07-25 22:10:43 +08:00
|
|
|
int count();
|
2018-01-16 04:04:42 +08:00
|
|
|
QVariant max(const FieldPhrase<int> &f);
|
|
|
|
|
QVariant min(const FieldPhrase<int> &f);
|
|
|
|
|
QVariant average(const FieldPhrase<int> &f);
|
2017-07-25 22:10:43 +08:00
|
|
|
|
2019-03-09 23:29:24 +08:00
|
|
|
QVariant insert(const AssignmentPhraseList &p);
|
2018-10-15 22:34:50 +08:00
|
|
|
|
2018-01-09 17:33:54 +08:00
|
|
|
//data mailpulation
|
2018-02-17 23:44:39 +08:00
|
|
|
int update(const AssignmentPhraseList &ph);
|
|
|
|
|
// int insert(const AssignmentPhraseList &ph);
|
2017-06-01 00:10:35 +08:00
|
|
|
int remove();
|
2017-07-25 22:10:43 +08:00
|
|
|
|
2018-10-15 22:34:50 +08:00
|
|
|
QSqlQueryModel *toModel();
|
2019-03-09 23:29:24 +08:00
|
|
|
void toModel(QSqlQueryModel *model);
|
2019-06-18 21:40:40 +08:00
|
|
|
void toModel(SqlModel *model);
|
2018-02-13 23:39:21 +08:00
|
|
|
|
2018-01-09 17:33:54 +08:00
|
|
|
//debug purpose
|
2017-07-25 22:10:43 +08:00
|
|
|
QString sqlCommand() const;
|
2016-05-12 14:08:58 +08:00
|
|
|
};
|
|
|
|
|
|
2019-06-08 16:40:00 +08:00
|
|
|
template<typename T>
|
|
|
|
|
template<typename O>
|
|
|
|
|
Q_OUTOFLINE_TEMPLATE QList<O> Query<T>::select(const std::function<O (const QSqlQuery &)> allocator)
|
|
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
QList<O> ret;
|
|
|
|
|
|
|
|
|
|
d->joins.prepend(d->tableName);
|
|
|
|
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
|
|
|
|
d->tableName,
|
|
|
|
|
SqlGeneratorBase::SignleField, "*",
|
|
|
|
|
d->wherePhrase,
|
|
|
|
|
d->relations,
|
|
|
|
|
d->skip, d->take);
|
|
|
|
|
|
|
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
|
|
|
|
|
|
|
|
|
while (q.next()) {
|
|
|
|
|
O obj = allocator(q);
|
|
|
|
|
ret.append(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_autoDelete)
|
|
|
|
|
deleteLater();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-07 16:19:20 +08:00
|
|
|
//template <typename T>
|
|
|
|
|
//inline Query<T> *createQuery(TableSet<T> *tableSet)
|
|
|
|
|
//{
|
|
|
|
|
// return tableSet->query();
|
|
|
|
|
//}
|
2017-02-01 18:01:21 +08:00
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
|
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T>::Query(Database *database, TableSetBase *tableSet,
|
|
|
|
|
bool autoDelete)
|
|
|
|
|
: QueryBase(database), d_ptr(new QueryPrivate(this)),
|
|
|
|
|
m_autoDelete(autoDelete)
|
2016-06-05 20:22:26 +08:00
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
|
|
|
|
|
d->database = database;
|
|
|
|
|
d->tableSet = tableSet;
|
2018-01-11 17:36:48 +08:00
|
|
|
d->className = T::staticMetaObject.className();
|
2018-01-15 22:18:49 +08:00
|
|
|
d->tableName =
|
2018-01-13 23:59:55 +08:00
|
|
|
d->database->model()
|
2019-06-08 16:20:52 +08:00
|
|
|
.tableByClassName(d->className)
|
2017-08-10 23:09:41 +08:00
|
|
|
->name();
|
2016-06-05 20:22:26 +08:00
|
|
|
}
|
2016-05-12 14:08:58 +08:00
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2016-06-05 20:22:26 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T>::~Query()
|
2016-05-12 14:08:58 +08:00
|
|
|
{
|
2016-06-05 20:22:26 +08:00
|
|
|
Q_D(Query);
|
|
|
|
|
delete d;
|
2016-05-12 14:08:58 +08:00
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2019-06-18 23:37:03 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
|
2016-05-12 14:08:58 +08:00
|
|
|
{
|
2018-01-12 00:14:29 +08:00
|
|
|
Q_UNUSED(count);
|
2016-06-05 20:22:26 +08:00
|
|
|
Q_D(Query);
|
2019-06-18 23:37:03 +08:00
|
|
|
RowList<T> returnList;
|
2016-06-05 20:22:26 +08:00
|
|
|
d->select = "*";
|
2018-01-11 17:36:48 +08:00
|
|
|
|
2017-07-25 22:10:43 +08:00
|
|
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
2018-02-17 23:44:39 +08:00
|
|
|
d->tableName, d->fieldPhrase, d->wherePhrase, d->orderPhrase,
|
|
|
|
|
d->relations, d->skip, d->take);
|
2019-06-19 17:24:58 +08:00
|
|
|
|
2017-07-25 22:10:43 +08:00
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
2018-01-14 22:03:24 +08:00
|
|
|
if (q.lastError().isValid()) {
|
2018-01-14 04:43:51 +08:00
|
|
|
qDebug() << q.lastError().text();
|
2018-01-14 22:03:24 +08:00
|
|
|
return returnList;
|
|
|
|
|
}
|
2018-01-14 04:43:51 +08:00
|
|
|
|
2018-01-15 06:12:46 +08:00
|
|
|
QSet<TableModel*> relatedTables;
|
|
|
|
|
relatedTables << d->database->model().tableByName(d->tableName);
|
2018-01-14 04:43:51 +08:00
|
|
|
foreach (RelationModel *rel, d->relations)
|
2018-01-15 06:12:46 +08:00
|
|
|
relatedTables << rel->slaveTable << rel->masterTable;
|
2018-01-14 04:43:51 +08:00
|
|
|
|
2018-01-11 17:36:48 +08:00
|
|
|
struct LevelData{
|
2018-01-13 23:59:55 +08:00
|
|
|
QList<int> masters;
|
|
|
|
|
QList<int> slaves;
|
2018-01-15 21:50:40 +08:00
|
|
|
QList<QString> masterFields;
|
2018-01-15 06:12:46 +08:00
|
|
|
QString keyFiledname;
|
|
|
|
|
QVariant lastKeyValue;
|
|
|
|
|
TableModel *table;
|
2018-01-11 17:36:48 +08:00
|
|
|
Table *lastRow;
|
|
|
|
|
};
|
|
|
|
|
QVector<LevelData> levels;
|
2018-01-15 06:12:46 +08:00
|
|
|
QSet<QString> importedTables;
|
|
|
|
|
auto add_table = [&](int i, TableModel* table) {
|
|
|
|
|
if (importedTables.contains(table->name()))
|
|
|
|
|
return;
|
|
|
|
|
importedTables.insert(table->name());
|
2018-01-13 23:59:55 +08:00
|
|
|
|
2018-01-11 17:36:48 +08:00
|
|
|
LevelData data;
|
2018-01-15 06:12:46 +08:00
|
|
|
data.table = table;
|
|
|
|
|
data.keyFiledname = data.table->name() + "." + data.table->primaryKey();
|
|
|
|
|
data.lastKeyValue = QVariant();
|
|
|
|
|
|
2018-01-15 21:50:40 +08:00
|
|
|
QHash<QString, QString> masters;
|
2018-01-15 06:12:46 +08:00
|
|
|
foreach (RelationModel *rel, d->relations)
|
|
|
|
|
if (rel->slaveTable->name() == table->name())
|
2018-01-15 21:50:40 +08:00
|
|
|
masters.insert(rel->masterTable->name(), rel->localProperty);
|
2018-01-15 06:12:46 +08:00
|
|
|
|
|
|
|
|
for (int j = 0; j < levels.count(); ++j) {
|
|
|
|
|
LevelData &dt = levels[j];
|
2018-01-15 21:50:40 +08:00
|
|
|
|
|
|
|
|
QHashIterator<QString, QString> it(masters);
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
|
|
|
|
|
if (dt.table->name() == it.key()) {
|
2018-01-15 06:12:46 +08:00
|
|
|
data.masters.append(j);
|
2018-01-15 21:50:40 +08:00
|
|
|
data.masterFields.append(it.value());
|
2018-01-15 06:12:46 +08:00
|
|
|
dt.slaves.append(i);
|
|
|
|
|
}
|
2018-01-15 21:50:40 +08:00
|
|
|
}
|
2018-01-12 00:14:29 +08:00
|
|
|
}
|
2018-01-15 22:18:49 +08:00
|
|
|
|
2018-01-11 17:36:48 +08:00
|
|
|
levels.append(data);
|
2018-01-15 06:12:46 +08:00
|
|
|
};
|
|
|
|
|
for (int i = 0; i < d->relations.count(); ++i) {
|
|
|
|
|
RelationModel *rel = d->relations[i];
|
|
|
|
|
add_table(i, rel->masterTable);
|
|
|
|
|
add_table(i, rel->slaveTable);
|
|
|
|
|
}
|
2018-01-11 15:13:01 +08:00
|
|
|
|
2018-01-15 21:50:40 +08:00
|
|
|
if (!importedTables.count()) {
|
|
|
|
|
LevelData data;
|
|
|
|
|
data.table = d->database->model().tableByName(d->tableName);
|
|
|
|
|
data.keyFiledname = d->tableName + "." + data.table->primaryKey();
|
|
|
|
|
data.lastKeyValue = QVariant();
|
|
|
|
|
|
|
|
|
|
levels.append(data);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-15 06:12:46 +08:00
|
|
|
QVector<bool> checked;
|
|
|
|
|
checked.reserve(levels.count());
|
|
|
|
|
for (int i = 0; i < levels.count(); ++i)
|
|
|
|
|
checked.append(false);
|
2018-01-15 22:18:49 +08:00
|
|
|
|
2018-01-11 17:36:48 +08:00
|
|
|
while (q.next()) {
|
2018-01-15 06:12:46 +08:00
|
|
|
checked.fill(false);
|
|
|
|
|
|
2018-01-13 23:59:55 +08:00
|
|
|
int p = levels.count();
|
2018-01-15 06:12:46 +08:00
|
|
|
int n = -1;
|
|
|
|
|
|
2018-01-13 23:59:55 +08:00
|
|
|
while (p) {
|
2019-07-19 20:52:52 +08:00
|
|
|
// Q_ASSERT(p != lastP);
|
|
|
|
|
// if (p == lastP)
|
|
|
|
|
// qFatal("NULL Loop detected");
|
|
|
|
|
|
2018-10-15 22:34:50 +08:00
|
|
|
++n;
|
|
|
|
|
n = n % levels.count();
|
2018-01-15 06:12:46 +08:00
|
|
|
if (checked[n])
|
|
|
|
|
continue;
|
|
|
|
|
LevelData &data = levels[n];
|
|
|
|
|
|
|
|
|
|
// check if key value is changed
|
|
|
|
|
if (data.lastKeyValue == q.value(data.keyFiledname)) {
|
2018-01-14 04:43:51 +08:00
|
|
|
--p;
|
2019-07-19 20:52:52 +08:00
|
|
|
// qDebug() << "key os not changed for" << data.keyFiledname;
|
2018-01-15 06:12:46 +08:00
|
|
|
continue;
|
2018-01-11 17:36:48 +08:00
|
|
|
}
|
2018-01-15 06:12:46 +08:00
|
|
|
|
|
|
|
|
// check if master if current table has processed
|
|
|
|
|
foreach (int m, data.masters)
|
2018-10-15 22:34:50 +08:00
|
|
|
if (!checked[m]) {
|
2019-07-19 20:52:52 +08:00
|
|
|
// qDebug() << "row is checked";
|
2018-01-15 06:12:46 +08:00
|
|
|
continue;
|
2018-10-15 22:34:50 +08:00
|
|
|
}
|
2018-01-15 06:12:46 +08:00
|
|
|
|
|
|
|
|
checked[n] = true;
|
|
|
|
|
--p;
|
|
|
|
|
data.lastKeyValue = q.value(data.keyFiledname);
|
|
|
|
|
|
|
|
|
|
//create table row
|
2019-07-18 15:09:31 +08:00
|
|
|
Table *table;
|
2019-07-19 20:52:52 +08:00
|
|
|
Row<Table> shp;
|
2018-01-15 06:12:46 +08:00
|
|
|
if (data.table->className() == d->className) {
|
2019-07-18 15:38:16 +08:00
|
|
|
table = new T();
|
2019-06-18 21:40:40 +08:00
|
|
|
#ifdef NUT_SHARED_POINTER
|
2019-07-19 20:52:52 +08:00
|
|
|
shp = QSharedPointer<Table>(table);
|
|
|
|
|
returnList.append(shp.objectCast<T>());
|
|
|
|
|
d->tableSet->add(shp);
|
2019-06-18 21:40:40 +08:00
|
|
|
#else
|
2019-07-18 15:38:16 +08:00
|
|
|
returnList.append(dynamic_cast<T*>(table));
|
2019-06-18 21:40:40 +08:00
|
|
|
#endif
|
2019-07-18 15:38:16 +08:00
|
|
|
table->setParentTableSet(d->tableSet);
|
2018-01-15 06:12:46 +08:00
|
|
|
} else {
|
2019-07-18 15:38:16 +08:00
|
|
|
const QMetaObject *childMetaObject
|
|
|
|
|
= QMetaType::metaObjectForType(data.table->typeId());
|
2019-07-18 15:09:31 +08:00
|
|
|
table = qobject_cast<Table *>(childMetaObject->newInstance());
|
|
|
|
|
if (!table)
|
2018-02-13 23:39:21 +08:00
|
|
|
qFatal("Could not create instance of %s",
|
|
|
|
|
qPrintable(data.table->name()));
|
2019-07-19 20:52:52 +08:00
|
|
|
shp = QSharedPointer<Table>(table);
|
2018-01-15 06:12:46 +08:00
|
|
|
}
|
2019-07-20 13:22:25 +08:00
|
|
|
const char *className = table->metaObject()->className();
|
|
|
|
|
connect(table, &QObject::destroyed, [className](QObject *){
|
|
|
|
|
qDebug() << "Destroyed " << className;
|
2019-07-19 20:52:52 +08:00
|
|
|
});
|
|
|
|
|
|
2019-02-10 17:35:35 +08:00
|
|
|
QList<FieldModel*> childFields = data.table->fields();
|
|
|
|
|
foreach (FieldModel *field, childFields)
|
2019-07-18 15:38:16 +08:00
|
|
|
table->setProperty(field->name.toLatin1().data(),
|
2019-02-28 17:49:43 +08:00
|
|
|
d->database->sqlGenertor()->unescapeValue(
|
2019-02-10 17:35:35 +08:00
|
|
|
field->type,
|
|
|
|
|
q.value(data.table->name() + "." + field->name)));
|
2018-01-15 06:12:46 +08:00
|
|
|
|
2018-01-15 21:50:40 +08:00
|
|
|
for (int i = 0; i < data.masters.count(); ++i) {
|
|
|
|
|
int master = data.masters[i];
|
2019-07-21 14:46:02 +08:00
|
|
|
//#ifdef NUT_SHARED_POINTER
|
|
|
|
|
// QString mName = QString("set%1").arg(levels[master].lastRow->metaObject()->className());
|
|
|
|
|
// QString type = QString("Nut::Row<%1>").arg(levels[master].lastRow->metaObject()->className());
|
|
|
|
|
// bool ok = table->metaObject()->invokeMethod(table,
|
|
|
|
|
// mName.toLocal8Bit().data(),
|
|
|
|
|
// QGenericArgument(type.toLatin1().data(), levels[master].lastRow));
|
|
|
|
|
//// bool ok = table->setProperty(data.masterFields[i].toLocal8Bit().data(),
|
|
|
|
|
//// QVariant::fromValue(shp.data()));
|
|
|
|
|
|
|
|
|
|
//#else
|
|
|
|
|
// bool ok = table->setProperty(data.masterFields[i].toLocal8Bit().data(),
|
|
|
|
|
// QVariant::fromValue(levels[master].lastRow));
|
|
|
|
|
//#endif
|
|
|
|
|
|
|
|
|
|
// if (!ok)
|
|
|
|
|
// qWarning("Unable to set property %s::%s",
|
|
|
|
|
// table->metaObject()->className(), data.masterFields[i].toLocal8Bit().data());
|
2019-07-08 22:53:02 +08:00
|
|
|
|
|
|
|
|
auto tableset = levels[master].lastRow->childTableSet(
|
|
|
|
|
data.table->className());
|
2019-07-21 14:46:02 +08:00
|
|
|
// table->setParentTableSet(tableset);
|
2019-07-18 15:38:16 +08:00
|
|
|
#ifdef NUT_SHARED_POINTER
|
2019-07-19 20:52:52 +08:00
|
|
|
tableset->add(shp);
|
|
|
|
|
#else
|
|
|
|
|
tableset->add(table);
|
2019-07-18 15:38:16 +08:00
|
|
|
#endif
|
2018-01-15 06:12:46 +08:00
|
|
|
}
|
|
|
|
|
|
2019-07-18 15:38:16 +08:00
|
|
|
table->setStatus(Table::FeatchedFromDB);
|
|
|
|
|
table->setParent(this);
|
|
|
|
|
table->clear();
|
2018-01-15 06:12:46 +08:00
|
|
|
|
|
|
|
|
//set last created row
|
2019-07-18 15:38:16 +08:00
|
|
|
data.lastRow = /*QSharedPointer<Table>*/(table);
|
2018-01-15 06:12:46 +08:00
|
|
|
} //while
|
|
|
|
|
} // while
|
2019-06-18 21:40:40 +08:00
|
|
|
|
|
|
|
|
#ifndef NUT_SHARED_POINTER
|
2018-01-11 17:36:48 +08:00
|
|
|
if (m_autoDelete)
|
|
|
|
|
deleteLater();
|
2019-06-18 21:40:40 +08:00
|
|
|
#endif
|
2018-01-11 17:36:48 +08:00
|
|
|
return returnList;
|
2019-07-19 20:52:52 +08:00
|
|
|
|
2016-05-12 14:08:58 +08:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 16:08:12 +08:00
|
|
|
template <typename T>
|
|
|
|
|
template <typename F>
|
|
|
|
|
Q_OUTOFLINE_TEMPLATE QList<F> Query<T>::select(const FieldPhrase<F> f)
|
|
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
QList<F> ret;
|
2018-01-11 00:18:49 +08:00
|
|
|
|
|
|
|
|
d->joins.prepend(d->tableName);
|
2017-07-25 22:10:43 +08:00
|
|
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
2018-02-17 23:44:39 +08:00
|
|
|
d->tableName,
|
|
|
|
|
SqlGeneratorBase::SignleField, f.data->toString(),
|
|
|
|
|
d->wherePhrase,
|
|
|
|
|
d->relations,
|
|
|
|
|
d->skip, d->take);
|
2018-03-11 16:38:07 +08:00
|
|
|
|
2017-07-25 22:10:43 +08:00
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
2017-05-30 16:08:12 +08:00
|
|
|
|
|
|
|
|
while (q.next()) {
|
2017-08-17 00:17:12 +08:00
|
|
|
QVariant v = q.value(0);
|
2017-05-30 16:08:12 +08:00
|
|
|
ret.append(v.value<F>());
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
if (m_autoDelete)
|
2017-06-01 00:10:35 +08:00
|
|
|
deleteLater();
|
2017-05-30 16:08:12 +08:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2019-06-18 23:37:03 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE Row<T> Query<T>::first()
|
2016-05-12 14:08:58 +08:00
|
|
|
{
|
2018-01-09 17:33:54 +08:00
|
|
|
skip(0);
|
|
|
|
|
take(1);
|
2019-06-18 23:37:03 +08:00
|
|
|
RowList<T> list = toList(1);
|
2016-05-12 14:08:58 +08:00
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
if (list.count())
|
2016-05-12 14:08:58 +08:00
|
|
|
return list.first();
|
|
|
|
|
else
|
2018-10-15 22:34:50 +08:00
|
|
|
return nullptr;
|
2016-05-12 14:08:58 +08:00
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2016-05-12 14:08:58 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE int Query<T>::count()
|
|
|
|
|
{
|
2016-06-05 20:22:26 +08:00
|
|
|
Q_D(Query);
|
|
|
|
|
|
2018-01-11 00:18:49 +08:00
|
|
|
d->joins.prepend(d->tableName);
|
2016-06-05 20:22:26 +08:00
|
|
|
d->select = "COUNT(*)";
|
2018-02-17 23:44:39 +08:00
|
|
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
|
|
|
|
d->tableName,
|
|
|
|
|
SqlGeneratorBase::Count,
|
|
|
|
|
QStringLiteral("*"),
|
|
|
|
|
d->wherePhrase,
|
|
|
|
|
d->relations);
|
2017-07-25 22:10:43 +08:00
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
2016-06-05 20:22:26 +08:00
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
if (q.next())
|
2016-06-05 20:22:26 +08:00
|
|
|
return q.value(0).toInt();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2018-01-16 04:04:42 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::max(const FieldPhrase<int> &f)
|
2017-08-10 23:09:41 +08:00
|
|
|
{
|
2016-06-05 20:22:26 +08:00
|
|
|
Q_D(Query);
|
|
|
|
|
|
2018-01-11 00:18:49 +08:00
|
|
|
d->joins.prepend(d->tableName);
|
2017-08-10 23:09:41 +08:00
|
|
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
2018-02-17 23:44:39 +08:00
|
|
|
d->tableName,
|
|
|
|
|
SqlGeneratorBase::Max, f.data->toString(),
|
|
|
|
|
d->wherePhrase,
|
2018-01-13 23:59:55 +08:00
|
|
|
d->relations);
|
2017-07-25 22:10:43 +08:00
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
2016-06-05 20:22:26 +08:00
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
if (q.next())
|
2016-06-05 20:22:26 +08:00
|
|
|
return q.value(0).toInt();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2018-01-16 04:04:42 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::min(const FieldPhrase<int> &f)
|
2017-08-10 23:09:41 +08:00
|
|
|
{
|
2016-06-05 20:22:26 +08:00
|
|
|
Q_D(Query);
|
|
|
|
|
|
2018-01-11 00:18:49 +08:00
|
|
|
d->joins.prepend(d->tableName);
|
2017-08-10 23:09:41 +08:00
|
|
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
2018-02-17 23:44:39 +08:00
|
|
|
d->tableName,
|
|
|
|
|
SqlGeneratorBase::Min, f.data->toString(),
|
|
|
|
|
d->wherePhrase,
|
2018-01-13 23:59:55 +08:00
|
|
|
d->relations);
|
2017-07-25 22:10:43 +08:00
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
2016-06-05 20:22:26 +08:00
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
if (q.next())
|
2016-05-12 14:08:58 +08:00
|
|
|
return q.value(0).toInt();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2018-01-16 04:04:42 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::average(const FieldPhrase<int> &f)
|
2017-05-28 23:08:59 +08:00
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
|
2018-01-11 00:18:49 +08:00
|
|
|
d->joins.prepend(d->tableName);
|
2017-08-10 23:09:41 +08:00
|
|
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
2018-02-17 23:44:39 +08:00
|
|
|
d->tableName,
|
|
|
|
|
SqlGeneratorBase::Average, f.data->toString(),
|
|
|
|
|
d->wherePhrase,
|
2018-01-13 23:59:55 +08:00
|
|
|
d->relations);
|
2017-07-25 22:10:43 +08:00
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
2017-05-28 23:08:59 +08:00
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
if (q.next())
|
2017-05-28 23:08:59 +08:00
|
|
|
return q.value(0).toInt();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-15 22:34:50 +08:00
|
|
|
template<class T>
|
2019-03-09 23:29:24 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::insert(const AssignmentPhraseList &p)
|
2018-10-15 22:34:50 +08:00
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
d->sql = d->database->sqlGenertor()
|
|
|
|
|
->insertCommand(d->tableName, p);
|
|
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
|
|
|
|
|
|
|
|
|
return q.lastInsertId();
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2018-01-10 01:32:28 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::join(const QString &className)
|
2016-05-12 14:08:58 +08:00
|
|
|
{
|
2016-06-05 20:22:26 +08:00
|
|
|
Q_D(Query);
|
2018-01-13 23:59:55 +08:00
|
|
|
|
2018-01-15 22:18:49 +08:00
|
|
|
RelationModel *rel = d->database->model()
|
|
|
|
|
.relationByClassNames(d->className, className);
|
2018-01-13 23:59:55 +08:00
|
|
|
if (!rel)
|
2018-01-15 22:18:49 +08:00
|
|
|
rel = d->database->model()
|
|
|
|
|
.relationByClassNames(className, d->className);
|
2018-01-13 23:59:55 +08:00
|
|
|
|
2018-01-14 22:03:24 +08:00
|
|
|
if (!rel) {
|
2018-02-26 18:28:01 +08:00
|
|
|
qDebug() << "No relation between" << d->className
|
2018-02-25 23:21:42 +08:00
|
|
|
<< "and" << className;
|
2018-01-14 22:03:24 +08:00
|
|
|
return this;
|
|
|
|
|
}
|
2018-01-13 23:59:55 +08:00
|
|
|
|
|
|
|
|
d->relations.append(rel);
|
2018-01-10 01:32:28 +08:00
|
|
|
d->joins.append(className);
|
2016-05-12 14:08:58 +08:00
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-09 17:33:54 +08:00
|
|
|
template<class T>
|
|
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::join(Table *c)
|
|
|
|
|
{
|
|
|
|
|
join(c->metaObject()->className());
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2018-02-17 23:44:39 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::where(const ConditionalPhrase &ph)
|
|
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
2018-02-18 22:58:55 +08:00
|
|
|
if (d->wherePhrase.data)
|
|
|
|
|
d->wherePhrase = d->wherePhrase && ph;
|
|
|
|
|
else
|
|
|
|
|
d->wherePhrase = ph;
|
2018-02-17 23:44:39 +08:00
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::setWhere(const ConditionalPhrase &ph)
|
2016-05-12 14:08:58 +08:00
|
|
|
{
|
2016-06-05 20:22:26 +08:00
|
|
|
Q_D(Query);
|
2018-02-17 23:44:39 +08:00
|
|
|
d->wherePhrase = ph;
|
2016-05-12 14:08:58 +08:00
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-24 23:35:23 +08:00
|
|
|
template<class T>
|
2018-01-09 17:33:54 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::skip(int n)
|
2017-08-24 23:35:23 +08:00
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
d->skip = n;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class T>
|
2018-01-09 17:33:54 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::take(int n)
|
2017-08-24 23:35:23 +08:00
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
d->take = n;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 23:39:21 +08:00
|
|
|
template<class T>
|
2018-02-17 23:44:39 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::fields(const PhraseList &ph)
|
2018-02-13 23:39:21 +08:00
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
2018-02-17 23:44:39 +08:00
|
|
|
d->fieldPhrase = ph;
|
2018-02-13 23:39:21 +08:00
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
//template <class T>
|
|
|
|
|
//Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::orderBy(QString fieldName,
|
|
|
|
|
// QString type)
|
|
|
|
|
//{
|
|
|
|
|
// Q_D(Query);
|
|
|
|
|
// d->orderPhrases.append(fieldName, type);
|
|
|
|
|
// return this;
|
|
|
|
|
//}
|
2016-05-12 14:08:58 +08:00
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2018-02-17 23:44:39 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE Query<T> *Query<T>::orderBy(const PhraseList &ph)
|
2016-05-12 14:08:58 +08:00
|
|
|
{
|
2016-06-05 20:22:26 +08:00
|
|
|
Q_D(Query);
|
2018-02-17 23:44:39 +08:00
|
|
|
d->orderPhrase = ph;
|
2016-06-05 20:22:26 +08:00
|
|
|
return this;
|
2016-05-12 14:08:58 +08:00
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2018-02-17 23:44:39 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE int Query<T>::update(const AssignmentPhraseList &ph)
|
2017-05-31 00:19:37 +08:00
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
|
2018-02-17 23:44:39 +08:00
|
|
|
d->sql = d->database->sqlGenertor()->updateCommand(
|
|
|
|
|
d->tableName,
|
|
|
|
|
ph,
|
|
|
|
|
d->wherePhrase);
|
2019-04-09 15:25:19 +08:00
|
|
|
|
2017-07-25 22:10:43 +08:00
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
2018-03-11 16:38:07 +08:00
|
|
|
|
2017-06-01 00:10:35 +08:00
|
|
|
if (m_autoDelete)
|
|
|
|
|
deleteLater();
|
|
|
|
|
return q.numRowsAffected();
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2017-06-01 00:10:35 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE int Query<T>::remove()
|
|
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
|
2018-02-17 23:44:39 +08:00
|
|
|
d->sql = d->database->sqlGenertor()->deleteCommand(
|
|
|
|
|
d->tableName, d->wherePhrase);
|
2017-07-25 22:10:43 +08:00
|
|
|
QSqlQuery q = d->database->exec(d->sql);
|
|
|
|
|
|
|
|
|
|
if (m_autoDelete)
|
|
|
|
|
deleteLater();
|
2017-05-31 00:19:37 +08:00
|
|
|
return q.numRowsAffected();
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 23:39:21 +08:00
|
|
|
template <class T>
|
2018-10-15 22:34:50 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE QSqlQueryModel *Query<T>::toModel()
|
2019-03-09 23:29:24 +08:00
|
|
|
{
|
|
|
|
|
QSqlQueryModel *model = new QSqlQueryModel;
|
|
|
|
|
toModel(model);
|
|
|
|
|
return model;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
|
Q_OUTOFLINE_TEMPLATE void Query<T>::toModel(QSqlQueryModel *model)
|
2018-02-13 23:39:21 +08:00
|
|
|
{
|
2018-02-18 22:58:55 +08:00
|
|
|
Q_D(Query);
|
|
|
|
|
|
|
|
|
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
|
|
|
|
d->tableName,
|
|
|
|
|
d->fieldPhrase,
|
|
|
|
|
d->wherePhrase, d->orderPhrase, d->relations,
|
|
|
|
|
d->skip, d->take);
|
2019-02-10 17:35:35 +08:00
|
|
|
|
2018-02-18 22:58:55 +08:00
|
|
|
DatabaseModel dbModel = d->database->model();
|
|
|
|
|
model->setQuery(d->sql, d->database->database());
|
|
|
|
|
|
|
|
|
|
int fieldIndex = 0;
|
2018-10-15 22:34:50 +08:00
|
|
|
|
|
|
|
|
if (d->fieldPhrase.data.count()) {
|
|
|
|
|
foreach (const PhraseData *pd, d->fieldPhrase.data) {
|
|
|
|
|
QString displayName = dbModel.tableByClassName(pd->className)
|
|
|
|
|
->field(pd->fieldName)->displayName;
|
|
|
|
|
|
|
|
|
|
model->setHeaderData(fieldIndex++,
|
|
|
|
|
Qt::Horizontal,
|
|
|
|
|
displayName);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
TableModel *tbl = d->database->model().tableByName(d->tableName);
|
|
|
|
|
foreach (FieldModel *f, tbl->fields()) {
|
|
|
|
|
model->setHeaderData(fieldIndex++,
|
|
|
|
|
Qt::Horizontal,
|
|
|
|
|
f->displayName);
|
|
|
|
|
}
|
2018-02-18 22:58:55 +08:00
|
|
|
}
|
2018-02-13 23:39:21 +08:00
|
|
|
}
|
|
|
|
|
|
2019-06-18 21:40:40 +08:00
|
|
|
template<class T>
|
|
|
|
|
Q_OUTOFLINE_TEMPLATE void Query<T>::toModel(SqlModel *model)
|
|
|
|
|
{
|
|
|
|
|
Q_D(Query);
|
|
|
|
|
|
|
|
|
|
d->sql = d->database->sqlGenertor()->selectCommand(
|
|
|
|
|
d->tableName,
|
|
|
|
|
d->fieldPhrase,
|
|
|
|
|
d->wherePhrase, d->orderPhrase, d->relations,
|
|
|
|
|
d->skip, d->take);
|
|
|
|
|
|
|
|
|
|
model->setTable(toList());
|
|
|
|
|
/*
|
|
|
|
|
DatabaseModel dbModel = d->database->model();
|
|
|
|
|
model->setQuery(d->sql, d->database->database());
|
|
|
|
|
|
|
|
|
|
int fieldIndex = 0;
|
|
|
|
|
|
|
|
|
|
if (d->fieldPhrase.data.count()) {
|
|
|
|
|
foreach (const PhraseData *pd, d->fieldPhrase.data) {
|
|
|
|
|
QString displayName = dbModel.tableByClassName(pd->className)
|
|
|
|
|
->field(pd->fieldName)->displayName;
|
|
|
|
|
|
|
|
|
|
model->setHeaderData(fieldIndex++,
|
|
|
|
|
Qt::Horizontal,
|
|
|
|
|
displayName);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
TableModel *tbl = d->database->model().tableByName(d->tableName);
|
|
|
|
|
foreach (FieldModel *f, tbl->fields()) {
|
|
|
|
|
model->setHeaderData(fieldIndex++,
|
|
|
|
|
Qt::Horizontal,
|
|
|
|
|
f->displayName);
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-10 23:09:41 +08:00
|
|
|
template <class T>
|
2017-07-25 22:10:43 +08:00
|
|
|
Q_OUTOFLINE_TEMPLATE QString Query<T>::sqlCommand() const
|
|
|
|
|
{
|
|
|
|
|
Q_D(const Query);
|
|
|
|
|
return d->sql;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-08 20:13:13 +08:00
|
|
|
//TODO: complete this class later
|
|
|
|
|
//class RawQuery : public Query<void>
|
|
|
|
|
//{
|
|
|
|
|
//public:
|
|
|
|
|
// void setRawCommand(const QString &sql) {
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
//};
|
|
|
|
|
|
2017-02-01 18:01:21 +08:00
|
|
|
NUT_END_NAMESPACE
|
2016-05-12 14:08:58 +08:00
|
|
|
|
|
|
|
|
#endif // QUERY_H
|