Herunterladen als
root/src/schema.cpp @ 77dbed04
c22391b2 | Christian Ehringfeld | /*
|
|
* Copyright (C) 2015 Christian Ehringfeld <c.ehringfeld@t-online.de>
|
|||
*
|
|||
* This program 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.
|
|||
*
|
|||
* 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 Lesser General Public License
|
|||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|||
*/
|
|||
#include "schema.h"
|
|||
9cf4747e | Christian Ehringfeld | #include <QRegularExpression>
|
|
#include <QSqlRecord>
|
|||
#include <QSqlQuery>
|
|||
14f9beed | Christian Ehringfeld | #include "database.h"
|
|
4d58ef6a | Christian Ehringfeld | using namespace CuteEntityManager;
|
|
aa44e7d1 | Christian Ehringfeld | ||
d2c13492 | Christian Ehringfeld | Schema::Schema(QSharedPointer<Database> database,
|
|
QSharedPointer<QueryBuilder> builder) {
|
|||
9cf4747e | Christian Ehringfeld | this->database = database;
|
|
e0e1ead8 | Christian Ehringfeld | this->abstractTypeMap = QSharedPointer<QHash<QString, QString>>
|
|
(new QHash<QString, QString>());
|
|||
696666eb | Christian Ehringfeld | this->queryBuilder = builder;
|
|
e0e1ead8 | Christian Ehringfeld | this->typeMap = QSharedPointer<QHash<QString, QString>>(new
|
|
QHash<QString, QString>());
|
|||
24425325 | Christian Ehringfeld | this->initAbstractDatabaseTypes();
|
|
aa44e7d1 | Christian Ehringfeld | }
|
|
4d58ef6a | Christian Ehringfeld | Schema::~Schema() {
|
|
aa44e7d1 | Christian Ehringfeld | }
|
|
3b5d8beb | Christian Ehringfeld | QString Schema::primaryKey(int length) const {
|
|
return this->buildColumnSchema(TYPE_PK, this->lengthToString(length));
|
|||
}
|
|||
QString Schema::bigPrimaryKey(int length) const {
|
|||
return this->buildColumnSchema(TYPE_BIGPK, this->lengthToString(length));
|
|||
}
|
|||
QString Schema::string(int length, bool notNull, QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_STRING, this->lengthToString(length),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
QString Schema::text(bool notNull, QString defaultValue, bool unique,
|
|||
QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_TEXT, "", notNull, defaultValue, unique,
|
|||
checkConstraint);
|
|||
}
|
|||
QString Schema::smallInteger(int length, bool notNull, QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_SMALLINT, this->lengthToString(length),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
QString Schema::integer(int length, bool notNull, QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_INTEGER, this->lengthToString(length),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
QString Schema::bigInteger(int length, bool notNull, QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_BIGINT, this->lengthToString(length),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
QString Schema::floatColumn(int precision, bool notNull, QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_FLOAT, this->lengthToString(precision),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
QString Schema::doubleColumn(int precision, bool notNull, QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_DOUBLE, this->lengthToString(precision),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
QString Schema::decimal(int precision, int scale, bool notNull,
|
|||
QString defaultValue, bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_DECIMAL,
|
|||
this->combineScaleAndPrecision(precision, scale), notNull, defaultValue,
|
|||
unique, checkConstraint);
|
|||
}
|
|||
QString Schema::dateTime(int precision, bool notNull, QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_DATETIME, this->lengthToString(precision),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
QString Schema::timestamp(int precision, bool notNull, QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_TIMESTAMP, this->lengthToString(precision),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
QString Schema::time(int precision, bool notNull, QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_TIME, this->lengthToString(precision),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
QString Schema::binary(int length, bool notNull, bool unique,
|
|||
QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_BINARY, this->lengthToString(length),
|
|||
notNull, "", unique, checkConstraint);
|
|||
}
|
|||
QString Schema::boolean(QString defaultValue, bool notNull) const {
|
|||
return this->buildColumnSchema(TYPE_DOUBLE, "", notNull, defaultValue);
|
|||
}
|
|||
QString Schema::money(int precision, int scale, bool notNull,
|
|||
QString defaultValue, bool unique, QString checkConstraint) const {
|
|||
return this->buildColumnSchema(TYPE_MONEY,
|
|||
this->combineScaleAndPrecision(precision, scale),
|
|||
notNull, defaultValue, unique, checkConstraint);
|
|||
}
|
|||
24425325 | Christian Ehringfeld | void Schema::initAbstractDatabaseTypes() {
|
|
abb9e8c5 | Christian Ehringfeld | this->abstractTypeMap->insert("bool", TYPE_SMALLINT);
|
|
this->abstractTypeMap->insert("short", TYPE_SMALLINT);
|
|||
this->abstractTypeMap->insert("int", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("long", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("long long", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("qlonglong", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("float", TYPE_FLOAT);
|
|||
this->abstractTypeMap->insert("double", TYPE_FLOAT);
|
|||
this->abstractTypeMap->insert("long double", TYPE_FLOAT);
|
|||
this->abstractTypeMap->insert("qint", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("quint", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("quuid", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("qfloat", TYPE_FLOAT);
|
|||
this->abstractTypeMap->insert("unsigned short", TYPE_SMALLINT);
|
|||
this->abstractTypeMap->insert("unsigned int", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("unsigned long", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("unsigned long long", TYPE_INTEGER);
|
|||
this->abstractTypeMap->insert("char", TYPE_CHAR);
|
|||
this->abstractTypeMap->insert("std::string", TYPE_TEXT);
|
|||
this->abstractTypeMap->insert("std::wstring", TYPE_TEXT);
|
|||
this->abstractTypeMap->insert("QString", TYPE_TEXT);
|
|||
this->abstractTypeMap->insert("QVariant", TYPE_TEXT);
|
|||
this->abstractTypeMap->insert("QUuid", TYPE_TEXT);
|
|||
this->abstractTypeMap->insert("QDate", TYPE_DATE);
|
|||
this->abstractTypeMap->insert("QTime", TYPE_TIME);
|
|||
this->abstractTypeMap->insert("QDateTime", TYPE_DATETIME);
|
|||
this->abstractTypeMap->insert("QByteArray", TYPE_BINARY);
|
|||
this->abstractTypeMap->insert("QBitArray", TYPE_BINARY);
|
|||
b0bf458e | Christian Ehringfeld | }
|
|
a604a5a2 | Christian Ehringfeld | QString Schema::quoteSimpleTableName(QString name) {
|
|
c9f21778 | Christian Ehringfeld | return name.indexOf("`") != -1 ? name : ("`" + name + "`");
|
|
a604a5a2 | Christian Ehringfeld | }
|
|
426974c6 | Christian Ehringfeld | QString Schema::quoteTableName(QString name) {
|
|
5b49a450 | Christian Ehringfeld | if (name.indexOf("(") != -1 || name.indexOf("{{") != -1) {
|
|
9cf4747e | Christian Ehringfeld | return name;
|
|
}
|
|||
if (name.indexOf(".") == -1) {
|
|||
return this->quoteSimpleTableName(name);
|
|||
}
|
|||
QStringList parts = name.split(".");
|
|||
for (int i = 0; i < parts.size(); ++i) {
|
|||
parts.replace(i, this->quoteSimpleTableName(parts.at(i)));
|
|||
}
|
|||
return parts.join(".");
|
|||
426974c6 | Christian Ehringfeld | }
|
|
QString Schema::quoteColumnName(QString name) {
|
|||
b7446f4c | Christian Ehringfeld | if (name.indexOf("(") != -1 || name.indexOf("[[") != -1
|
|
|| name.indexOf("{{") != -1) {
|
|||
9cf4747e | Christian Ehringfeld | return name;
|
|
}
|
|||
int pos = name.indexOf(".");
|
|||
QString prefix = "";
|
|||
5b49a450 | Christian Ehringfeld | if (pos != -1 ) {
|
|
9cf4747e | Christian Ehringfeld | prefix = this->quoteTableName(name.mid(0, pos)) + ".";
|
|
name = name.mid(pos + 1);
|
|||
}
|
|||
return prefix + this->quoteSimpleColumnName(name);
|
|||
426974c6 | Christian Ehringfeld | }
|
|
QString Schema::quoteSimpleColumnName(QString name) {
|
|||
c9f21778 | Christian Ehringfeld | return name.indexOf("`") != -1 || name == "*" ? name : ("`" + name + "`");
|
|
426974c6 | Christian Ehringfeld | }
|
|
e0e1ead8 | Christian Ehringfeld | QHash<QString, QSharedPointer<TableSchema> > Schema::getTableSchemas(
|
|
QString schema, bool refresh) {
|
|||
9cf4747e | Christian Ehringfeld | QStringList names = this->getTableNames();
|
|
for (int i = 0; i < names.size(); ++i) {
|
|||
b7446f4c | Christian Ehringfeld | QString name = names.at(i);
|
|
9cf4747e | Christian Ehringfeld | if (schema != "") {
|
|
b7446f4c | Christian Ehringfeld | name = schema + "." + name;
|
|
9cf4747e | Christian Ehringfeld | }
|
|
b0bf458e | Christian Ehringfeld | this->getTableSchema(name, refresh);
|
|
9cf4747e | Christian Ehringfeld | }
|
|
return this->tables;
|
|||
426974c6 | Christian Ehringfeld | }
|
|
caea9141 | Christian Ehringfeld | QStringList Schema::getTableNames(QString schema) {
|
|
abb9e8c5 | Christian Ehringfeld | Q_UNUSED(schema)
|
|
return this->database->getDatabase().tables();
|
|||
426974c6 | Christian Ehringfeld | }
|
|
9cf4747e | Christian Ehringfeld | QVariant Schema::getLastInsertID() {
|
|
abb9e8c5 | Christian Ehringfeld | QSqlQuery q(this->database->getDatabase());
|
|
6d91d381 | Christian Ehringfeld | auto lastId = q.lastInsertId();
|
|
return lastId;
|
|||
426974c6 | Christian Ehringfeld | }
|
|
void Schema::refresh() {
|
|||
9cf4747e | Christian Ehringfeld | this->tables.clear();
|
|
426974c6 | Christian Ehringfeld | }
|
|
QString Schema::getRawTable(QString name) {
|
|||
9cf4747e | Christian Ehringfeld | if (name.indexOf("{{")) {
|
|
66704054 | Christian Ehringfeld | QRegularExpression re(QRegularExpression::escape("/\\{\\{(.*?)\\}\\}/"));
|
|
9c2f773f | Christian Ehringfeld | return name.replace(re, QRegularExpression::escape("\\1"));
|
|
9cf4747e | Christian Ehringfeld | }
|
|
return name;
|
|||
}
|
|||
14f9beed | Christian Ehringfeld | bool Schema::containsTable(QString tblname) {
|
|
0d155b40 | Christian Ehringfeld | if (this->tables.size() != this->getTableNames().size()) {
|
|
b7446f4c | Christian Ehringfeld | this->setTables(this->getTableSchemas());
|
|
}
|
|||
abb9e8c5 | Christian Ehringfeld | return this->database->getDatabase().tables().contains(tblname);
|
|
14f9beed | Christian Ehringfeld | }
|
|
b0bf458e | Christian Ehringfeld | QSharedPointer<TableSchema> Schema::getTableSchema(QString name, bool refresh) {
|
|
b7446f4c | Christian Ehringfeld | if (this->tables.contains(name) && !refresh) {
|
|
b0bf458e | Christian Ehringfeld | return this->tables.value(name);
|
|
9cf4747e | Christian Ehringfeld | }
|
|
QString realName = this->getRawTable(name);
|
|||
14f9beed | Christian Ehringfeld | auto ts = this->loadTableSchema(realName);
|
|
9cf4747e | Christian Ehringfeld | if (ts.data()) {
|
|
this->tables.insert(name, ts);
|
|||
}
|
|||
b0bf458e | Christian Ehringfeld | return ts;
|
|
14f9beed | Christian Ehringfeld | }
|
|
QSharedPointer<Database> Schema::getDatabase() const {
|
|||
return database;
|
|||
}
|
|||
9cf4747e | Christian Ehringfeld | ||
14f9beed | Christian Ehringfeld | void Schema::setDatabase(const QSharedPointer<Database> &value) {
|
|
database = value;
|
|||
9cf4747e | Christian Ehringfeld | }
|
|
b0bf458e | Christian Ehringfeld | QSharedPointer<QueryBuilder> Schema::getQueryBuilder() const {
|
|
return queryBuilder;
|
|||
}
|
|||
14f9beed | Christian Ehringfeld | ||
24425325 | Christian Ehringfeld | QSharedPointer<QHash<QString, QString> > Schema::getAbstractTypeMap() const {
|
|
return abstractTypeMap;
|
|||
}
|
|||
e0e1ead8 | Christian Ehringfeld | void Schema::setAbstractTypeMap(const QSharedPointer<QHash<QString, QString> >
|
|
&value) {
|
|||
24425325 | Christian Ehringfeld | abstractTypeMap = value;
|
|
}
|
|||
12c34ebc | Christian Ehringfeld | QString Schema::buildColumnSchema(QString type, QString length, bool notNull,
|
|
QString defaultValue,
|
|||
bool unique, QString checkConstraint) const {
|
|||
return type + this->buildLengthString(length) + this->buildNotNullString(
|
|||
notNull) + this->buildUniqueString(unique) + this->buildDefaultString(
|
|||
defaultValue) + this->buildCheckString(checkConstraint);
|
|||
}
|
|||
QString Schema::buildLengthString(QString length) const {
|
|||
return length.isEmpty() ? "" : "(" + length + ")";
|
|||
}
|
|||
QString Schema::buildNotNullString(bool notNull) const {
|
|||
return notNull ? " NOT NULL" : "";
|
|||
}
|
|||
QString Schema::buildUniqueString(bool unique) const {
|
|||
return unique ? " UNIQUE" : "";
|
|||
}
|
|||
QString Schema::buildDefaultString(QString def) const {
|
|||
3b5d8beb | Christian Ehringfeld | if (def.isEmpty()) {
|
|
return "";
|
|||
}
|
|||
QString defaultValue = " DEFAULT ";
|
|||
bool ok;
|
|||
def.toInt(&ok);
|
|||
if (ok) {
|
|||
return (defaultValue + def);
|
|||
}
|
|||
if (def == "true" || def == "false") {
|
|||
return (defaultValue + def.toUpper());
|
|||
}
|
|||
QString copy = def.replace(",", ".");
|
|||
copy.toDouble(&ok);
|
|||
if (ok) {
|
|||
return (defaultValue + copy);
|
|||
}
|
|||
return ("\'" + defaultValue + def + "\'");
|
|||
12c34ebc | Christian Ehringfeld | }
|
|
QString Schema::buildCheckString(QString check) const {
|
|||
return check.isEmpty() ? "" : (" CHECK (" + check + ")");
|
|||
}
|
|||
3b5d8beb | Christian Ehringfeld | QString Schema::lengthToString(int length) const {
|
|
return length != 0 ? QString::number(length) : "";
|
|||
}
|
|||
QString Schema::combineScaleAndPrecision(int precision, int scale) const {
|
|||
QString length = "";
|
|||
if (precision != 0) {
|
|||
length += QString::number(precision);
|
|||
}
|
|||
if (scale != 0) {
|
|||
if (precision != 0) {
|
|||
length += ", ";
|
|||
}
|
|||
length += QString::number(scale);
|
|||
}
|
|||
return length;
|
|||
}
|
|||
829c3e69 | Christian Ehringfeld | bool Schema::findColumns(const QSharedPointer<TableSchema> &ts) {
|
|
QSqlQuery q = this->database->getQuery();
|
|||
q.setForwardOnly(true);
|
|||
q.exec("SELECT * FROM " + this->quoteSimpleTableName(ts->getName()) +
|
|||
" LIMIT 0");
|
|||
QHash<QString, QSharedPointer<QSqlField>> columns =
|
|||
QHash<QString, QSharedPointer<QSqlField>>();
|
|||
auto rec = q.record();
|
|||
int count = rec.count();
|
|||
if (count == 0) {
|
|||
return false;
|
|||
}
|
|||
for (int var = 0; var < count; ++var) {
|
|||
QSqlField f = rec.field(var);
|
|||
columns.insert(f.name(), QSharedPointer<QSqlField>(new QSqlField(f)));
|
|||
}
|
|||
ts->setColumns(columns);
|
|||
return true;
|
|||
}
|
|||
24425325 | Christian Ehringfeld | ||
0d155b40 | Christian Ehringfeld | QHash<QString, QSharedPointer<TableSchema> > Schema::getTables() {
|
|
if (this->tables.size() != this->getTableNames().size()) {
|
|||
this->setTables(this->getTableSchemas());
|
|||
}
|
|||
9cf4747e | Christian Ehringfeld | return this->tables;
|
|
}
|
|||
e0e1ead8 | Christian Ehringfeld | void Schema::setTables(const QHash<QString, QSharedPointer<TableSchema> >
|
|
&value) {
|
|||
9cf4747e | Christian Ehringfeld | tables = value;
|
|
a604a5a2 | Christian Ehringfeld | }
|