Nut/src/sqlgeneratorbase.cpp

557 lines
15 KiB
C++
Raw Normal View History

2016-05-21 16:09:03 +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/>.
**
**************************************************************************/
#include <QDate>
#include <QDateTime>
#include <QTime>
#include <QVariant>
2016-05-24 14:47:37 +08:00
#include "database.h"
2016-05-12 14:08:58 +08:00
#include "databasemodel.h"
#include "sqlgeneratorbase_p.h"
#include "table.h"
2016-05-21 16:09:03 +08:00
#include "tablemodel.h"
2016-06-05 20:22:26 +08:00
#include "wherephrase.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
2016-05-24 14:47:37 +08:00
SqlGeneratorBase::SqlGeneratorBase(Database *parent) : QObject((QObject*)parent)
2016-05-12 14:08:58 +08:00
{
2016-05-24 14:47:37 +08:00
if(parent)
_database = parent;
2016-05-12 14:08:58 +08:00
}
SqlGeneratorBase::~SqlGeneratorBase()
{
}
2016-05-21 16:09:03 +08:00
QString SqlGeneratorBase::masterDatabaseName(QString databaseName)
{
Q_UNUSED(databaseName);
return "";
}
QString SqlGeneratorBase::saveRecord(Table *t, QString tableName)
2016-05-12 14:08:58 +08:00
{
switch(t->status()){
case Table::Added:
2016-05-21 16:09:03 +08:00
return insertRecord(t, tableName);
2016-05-12 14:08:58 +08:00
case Table::Deleted:
2016-05-21 16:09:03 +08:00
return deleteRecord(t, tableName);
2016-05-12 14:08:58 +08:00
case Table::Modified:
2016-05-21 16:09:03 +08:00
return updateRecord(t, tableName);
2016-05-12 14:08:58 +08:00
case Table::NewCreated:
case Table::FeatchedFromDB:
// disable compiler warning
2016-05-21 16:09:03 +08:00
return "";
2016-05-12 14:08:58 +08:00
}
2016-05-21 16:09:03 +08:00
return "";
2016-05-12 14:08:58 +08:00
}
2016-05-21 16:09:03 +08:00
QString SqlGeneratorBase::fieldDeclare(FieldModel *field)
{
return field->name + " " + fieldType(field);
}
QStringList SqlGeneratorBase::diff(DatabaseModel lastModel, DatabaseModel newModel)
2016-05-12 14:08:58 +08:00
{
QStringList ret;
QSet<QString> tableNames;
2016-05-21 16:09:03 +08:00
foreach (TableModel *table, lastModel)
2016-05-12 14:08:58 +08:00
tableNames.insert(table->name());
2016-05-21 16:09:03 +08:00
foreach (TableModel *table, newModel)
2016-05-12 14:08:58 +08:00
tableNames.insert(table->name());
foreach (QString tableName, tableNames) {
2016-05-21 16:09:03 +08:00
TableModel *oldTable = lastModel.model(tableName);
TableModel *newTable = newModel.model(tableName);
ret << diff(oldTable, newTable);
2016-05-12 14:08:58 +08:00
}
return ret;
}
2016-05-21 16:09:03 +08:00
QString SqlGeneratorBase::diff(FieldModel *oldField, FieldModel *newField)
2016-05-12 14:08:58 +08:00
{
QString sql = "";
if(oldField && newField)
if(*oldField == *newField)
return QString::null;
if(!newField){
sql = "DROP COLUMN " + oldField->name;
}else{
if(oldField)
sql = "ALTER COLUMN ";
else
sql = "ADD COLUMN ";
2016-05-21 16:09:03 +08:00
sql.append(fieldDeclare(newField));
2016-05-12 14:08:58 +08:00
}
return sql;
}
2016-05-21 16:09:03 +08:00
QString SqlGeneratorBase::diff(TableModel *oldTable, TableModel *newTable)
2016-05-12 14:08:58 +08:00
{
if(oldTable && newTable)
if(*oldTable == *newTable)
return "";
if(!newTable)
return "DROP TABLE " + oldTable->name();
QSet<QString> fieldNames;
if(oldTable)
2016-05-21 16:09:03 +08:00
foreach (FieldModel *f, oldTable->fields())
2016-05-12 14:08:58 +08:00
fieldNames.insert(f->name);
2016-05-21 16:09:03 +08:00
foreach (FieldModel *f, newTable->fields())
2016-05-12 14:08:58 +08:00
fieldNames.insert(f->name);
QStringList columnSql;
foreach (QString fieldName, fieldNames) {
2016-05-21 16:09:03 +08:00
FieldModel *newField = newTable->field(fieldName);
2016-05-12 14:08:58 +08:00
if(oldTable){
2016-05-21 16:09:03 +08:00
FieldModel *oldField = oldTable->field(fieldName);
2016-05-12 14:08:58 +08:00
2016-05-21 16:09:03 +08:00
QString buffer = diff(oldField, newField);
2016-05-12 14:08:58 +08:00
if(!buffer.isNull())
columnSql << buffer;
}else{
2016-05-21 16:09:03 +08:00
columnSql << fieldDeclare(newField);
2016-05-12 14:08:58 +08:00
}
}
QString sql;
if(oldTable){
sql = QString("ALTER TABLE %1 \n%2")
.arg(newTable->name())
.arg(columnSql.join(",\n"));
}else{
if(!newTable->primaryKey().isNull())
columnSql << QString("CONSTRAINT pk_%1 PRIMARY KEY (%2)")
.arg(newTable->name())
.arg(newTable->primaryKey());
sql = QString("CREATE TABLE %1 \n(%2)")
.arg(newTable->name())
.arg(columnSql.join(",\n"));
}
return sql;
}
2016-05-21 16:09:03 +08:00
QString SqlGeneratorBase::insertRecord(Table *t, QString tableName)
2016-05-12 14:08:58 +08:00
{
QString sql = "";
QString key = t->primaryKey();
QStringList values;
foreach (QString f, t->changedProperties())
if(f != key)
values.append("'" + t->property(f.toLatin1().data()).toString() + "'");
2016-06-05 20:22:26 +08:00
QString changedPropertiesText = "";
QSet<QString> props = t->changedProperties();
foreach (QString s, props) {
if(changedPropertiesText != "")
changedPropertiesText.append(", ");
changedPropertiesText.append(s);
}
2016-05-12 14:08:58 +08:00
sql = QString("INSERT INTO %1 (%2) VALUES (%3)")
.arg(tableName)
2016-06-05 20:22:26 +08:00
.arg(changedPropertiesText)
2016-05-12 14:08:58 +08:00
.arg(values.join(", "));
return sql;
}
2016-05-21 16:09:03 +08:00
QString SqlGeneratorBase::updateRecord(Table *t, QString tableName)
2016-05-12 14:08:58 +08:00
{
QString sql = "";
QString key = t->primaryKey();
QStringList values;
foreach (QString f, t->changedProperties())
if(f != key)
values.append(f + "='" + t->property(f.toLatin1().data()).toString() + "'");
sql = QString("UPDATE %1 SET %2 WHERE %3=%4")
.arg(tableName)
.arg(values.join(", "))
.arg(key)
.arg(t->primaryValue().toString());
return sql;
}
2016-05-21 16:09:03 +08:00
QString SqlGeneratorBase::deleteRecord(Table *t, QString tableName)
2016-05-12 14:08:58 +08:00
{
return QString("DELETE FROM %1 WHERE %2='%3'")
.arg(tableName)
.arg(t->primaryKey())
.arg(t->primaryValue().toString());
}
2016-06-05 20:22:26 +08:00
QString SqlGeneratorBase::agregateText(const AgregateType &t, const QString &arg) const
{
switch (t) {
case SelectALl:
return "*";
break;
case Min:
return "MIN(" + arg + ")";
break;
case Max:
return "MAX(" + arg + ")";
break;
case Average:
return "AVERAGE(" + arg + ")";
break;
case Count:
return "COUNT(" + arg + ")";
break;
default:
return QString::null;
}
}
QString SqlGeneratorBase::fromTableText(const QString &tableName, QString &joinClassName, QString &orderBy) const
{
QString tableNameText = tableName;
if(!joinClassName.isNull()){
QString joinTableName = _database->tableName(joinClassName);
RelationModel *rel = _database->model().relationByTableNames(tableName, joinTableName);
if(rel){
QString pk = _database->model().model(tableName)->primaryKey();
tableNameText = QString("%1 INNER JOIN %2 ON (%1.%3 = %2.%4)")
.arg(tableName)
.arg(joinTableName)
.arg(pk)
.arg(rel->localColumn);
orderBy = tableName + "." + pk;
}else{
qWarning(QString("Relation between table %1 and class %2 (%3) not exists!")
.arg(tableName)
.arg(joinClassName)
.arg(joinTableName.isNull() ? "NULL" : joinTableName)
.toLatin1().data());
joinClassName = QString::null;
}
}
return tableNameText;
}
2016-05-21 16:09:03 +08:00
QString SqlGeneratorBase::deleteRecords(QString tableName, QString where)
2016-05-12 14:08:58 +08:00
{
QString sql = "";
if(where.isEmpty() || where.isNull())
sql = "DELETE FROM " + tableName;
else
sql = "DELETE FROM " + tableName + " WHERE " + where;
return sql;
}
2016-06-05 20:22:26 +08:00
QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t, QString agregateArg, QList<WherePhrase> &wheres, QList<WherePhrase> &orders, QString tableName, QString joinClassName)
2016-05-21 16:09:03 +08:00
{
2016-06-05 20:22:26 +08:00
QString select = agregateText(t, agregateArg);
QString where = createWhere(wheres);
QString order = "";
QString from = fromTableText(tableName, joinClassName, order);
foreach(WherePhrase p, orders){
if(order != "")
order.append(", ");
order.append(phraseOrder(p.data()));
}
2016-05-21 16:09:03 +08:00
2016-06-05 20:22:26 +08:00
QString sql = "SELECT " + select + " FROM " + from;
2016-05-21 16:09:03 +08:00
2016-06-05 20:22:26 +08:00
if(where != "")
sql.append(" WHERE " + where);
2016-05-21 16:09:03 +08:00
2016-06-05 20:22:26 +08:00
if(order != "")
sql.append(" ORDER BY " + order);
2016-05-21 16:09:03 +08:00
2016-06-05 20:22:26 +08:00
for(int i = 0; i < _database->model().count(); i++)
sql = sql.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + ".");
2016-05-21 16:09:03 +08:00
2016-06-05 20:22:26 +08:00
return sql;
}
2016-05-21 16:09:03 +08:00
2016-06-05 20:22:26 +08:00
QString SqlGeneratorBase::selectCommand(QList<WherePhrase> &wheres, QHash<QString, QString> &orders, QString tableName, QString joinClassName)
{
return selectCommand("*", wheres, orders, tableName, joinClassName);
2016-05-21 16:09:03 +08:00
}
2016-05-24 14:47:37 +08:00
QString SqlGeneratorBase::createWhere(QList<WherePhrase> &wheres)
{
QString whereText = "";
2016-06-05 20:22:26 +08:00
// for (int i = 0; i < wheres.count(); i++) {
// if(whereText != "")
// whereText.append(" AND ");
// whereText.append(phrase(wheres[i].data()));
// }
foreach (WherePhrase w, wheres) {
2016-05-24 14:47:37 +08:00
if(whereText != "")
whereText.append(" AND ");
2016-06-05 20:22:26 +08:00
whereText.append(phrase(w.data()));
2016-05-24 14:47:37 +08:00
}
2016-06-05 20:22:26 +08:00
// if(whereText != "")
// whereText.prepend(" WHERE ");
2016-05-24 14:47:37 +08:00
return whereText;
}
2016-06-05 20:22:26 +08:00
QString SqlGeneratorBase::selectCommand(QString selectPhrase, QList<WherePhrase> &wheres, QHash<QString, QString> &orders, QString tableName, QString joinClassName)
2016-05-24 14:47:37 +08:00
{
QString orderText = "";
QStringList orderby;
QString whereText = createWhere(wheres);
2016-06-05 20:22:26 +08:00
if(whereText != "")
whereText.prepend(" WHERE ");
2016-05-24 14:47:37 +08:00
QString tableNameText = tableName;
if(!joinClassName.isNull()){
QString joinTableName = _database->tableName(joinClassName);
RelationModel *rel = _database->model().relationByTableNames(tableName, joinTableName);
if(rel){
QString pk = _database->model().model(tableName)->primaryKey();
tableNameText = QString("%1 INNER JOIN %2 ON (%1.%3 = %2.%4)")
.arg(tableName)
.arg(joinTableName)
.arg(pk)
.arg(rel->localColumn);
orderby.append(tableName + "." + pk);
}else{
2017-02-01 18:01:21 +08:00
qWarning("Relation between table %s and class %s (%s) not exists!",
qPrintable(tableName),
qPrintable(joinClassName),
qPrintable(joinTableName.isNull() ? "NULL" : joinTableName));
2016-05-24 14:47:37 +08:00
joinClassName = QString::null;
}
}
if(orders.count())
foreach (QString o, orders.keys())
// orderby.append(o + (orders.value(o) ? " ASC" : " DESC"));
orderby.append(o + " " + orders.value(o));
if(orderby.count())
orderText = " ORDER BY " + orderby.join(", ");
2016-06-05 20:22:26 +08:00
QString command = "SELECT "
+selectPhrase
+ " FROM "
2016-05-24 14:47:37 +08:00
+ tableNameText
+ whereText
+ orderText;
foreach (TableModel *m, TableModel::allModels())
command = command.replace(m->className() + "." , m->name() + ".");
2016-06-05 20:22:26 +08:00
2016-05-24 14:47:37 +08:00
return command;
}
QString SqlGeneratorBase::deleteCommand(QList<WherePhrase> &wheres, QString tableName)
{
2016-06-05 20:22:26 +08:00
QString command = "DELETE FROM " + tableName;
QString where = createWhere(wheres);
if(where != "")
command.append(" WHERE " + where);
2016-05-24 14:47:37 +08:00
for(int i = 0; i < _database->model().count(); i++)
command = command.replace(_database->model().at(i)->className() + "." , _database->model().at(i)->name() + ".");
return command;
}
2016-06-05 20:22:26 +08:00
QString SqlGeneratorBase::escapeValue(const QVariant &v)const
{
switch (v.type()) {
2017-02-01 18:01:21 +08:00
case QVariant::Bool:
return v.toBool() ? "1" : "0";
break;
2016-06-05 20:22:26 +08:00
case QVariant::Int:
case QVariant::UInt:
case QVariant::ULongLong:
case QVariant::LongLong:
case QVariant::Double:
return v.toString();
break;
case QVariant::Char:
case QVariant::String:
return "'" + v.toString() + "'";
case QVariant::DateTime:
return "'" + v.toDateTime().toString() + "'";
case QVariant::Date:
return "'" + v.toDate().toString() + "'";
case QVariant::Time:
return "'" + v.toTime().toString() + "'";
case QVariant::StringList:
case QVariant::List:
return "['" + v.toStringList().join("', '") + "']";
case QVariant::Invalid:
qFatal("Invalud field value");
return "<FAIL>";
}
return "";
}
QString SqlGeneratorBase::phraseOrder(const PhraseData *d) const
{
QString ret = "";
switch(d->type){
case PhraseData::Field:
if(d->operatorCond == PhraseData::Not)
ret = d->text + " DESC";
else
ret = d->text;
break;
case PhraseData::WithOther:
if(d->operatorCond != PhraseData::Append)
qFatal("Order phease can only have & operator");
ret = phraseOrder(d->left) + ", " + phraseOrder(d->right);
break;
case PhraseData::WithoutOperand:
case PhraseData::WithVariant:
break;
}
return ret;
}
QString SqlGeneratorBase::phrase(const PhraseData *d) const
{
QString ret = "";
switch(d->type){
case PhraseData::Field:
ret = d->text;
break;
case PhraseData::WithVariant:
ret = phrase(d->left) + " " + operatorString(d->operatorCond) + " " + escapeValue(d->operand);
break;
case PhraseData::WithOther:
ret = phrase(d->left) + " " + operatorString(d->operatorCond) + " " + phrase(d->right);
break;
case PhraseData::WithoutOperand:
ret = phrase(d->left) + " " + operatorString(d->operatorCond);
break;
default:
ret = "<FAIL>";
}
if(d->operatorCond == PhraseData::And || d->operatorCond == PhraseData::Or)
ret = "(" + ret + ")";
return ret;
}
QString SqlGeneratorBase::operatorString(const PhraseData::Condition &cond) const
{
switch (cond){
case PhraseData::Equal:
return "=";
case PhraseData::NotEqual:
return "<>";
case PhraseData::Less:
return "<";
case PhraseData::Greater:
return ">";
case PhraseData::LessEqual:
return "<=";
case PhraseData::GreaterEqual:
return ">=";
case PhraseData::Null:
return "IS NULL";
case PhraseData::NotNull:
return "IS NOT NULL";
case PhraseData::In:
return "IN";
case PhraseData::NotIn:
return "NOT IN";
case PhraseData::And:
return "AND";
case PhraseData::Or:
return "OR";
case PhraseData::Like:
return "LIKE";
case PhraseData::NotLike:
return "NOT LIKE";
case PhraseData::Add:
return "+";
case PhraseData::Minus:
return "-";
case PhraseData::Multiple:
return "*";
case PhraseData::Divide:
return "/";
case PhraseData::Set:
return "=";
case PhraseData::Append:
return ",";
}
return QString("<FAIL>");
}
2016-05-12 14:08:58 +08:00
2017-02-01 18:01:21 +08:00
NUT_END_NAMESPACE