#include "databaseutils.h" #include "databasemanager.h" #include "databasetable.h" #include "logger.h" #include #include namespace serversdk { /** * @brief DatabaseUtils::createTableSQL * @param table * @return * * @code{sql} * "CREATE TABLE colsunod_bject (" "id character(36) primary key NOT NULL," "description character varying(255)," "last_update timestamp NOT NULL," "name character varying(255)," "pin character varying(255)," "last_modified timestamp," "deleted BOOLEAN)" * @endcode * * Default types: * * * */ DatabaseUtils::DatabaseUtils(DatabaseManager *manager, QString type) : mDatabaseManager(manager), mSqlType(std::move(type)) { Q_ASSERT(mDatabaseManager); } QString DatabaseUtils::createTableText(const DatabaseTable *table, const QString &table_name) const { QString userData; if (table_name.isEmpty()) { return QString(); } // out: "CREATE TABLE colnod_subject ( " QString sql = QString("CREATE TABLE %1 ( ").arg(table_name); const QMetaObject *metaObj = table->metaObject(); int total = metaObj->propertyCount(); int first = true; for (int i = metaObj->propertyOffset(); i < total; ++i) { QMetaProperty prop = metaObj->property(i); // Skip non USER so -> ( Q_PROPERTY( ...... USER false ) only if (!prop.isUser()) continue; QString name = fromCamelCase(prop.name()); QVariant::Type type = prop.type(); QString textType; // Getting correct type based on QVariant if (sqlType() == "SQLITE") { textType = table->textSQLIteType(type); } else if (sqlType() == "PSQL") { textType = table->textSQLIteType(type); //return QString(); } else { qCDebug(sdkdb) << "Implemented only for SQLITE"; return QString(); } // in: id TEXT // out: "CREATE TABLE colnod_subject ( id TEXT " sql += QString("%1 %2").arg(name,textType); // in: PRIMARY KEY // out: "CREATE TABLE colnod_subject ( id TEXT PRIMARY KEY" if (first) { // first row sql += " PRIMARY KEY NOT NULL"; first = false; } // in: NOT NULL // out: "CREATE TABLE colnod_subject ( id TEXT PRIMARY KEY NOT NULL" if (!userData.isEmpty()) { sql += " " + userData; } // out: "CREATE TABLE colnod_subject ( id TEXT PRIMARY KEY NOT NULL," if (i < (total-1)) { // second last sql += ", "; } } // out: ".. subject_id TEXT)" sql+= " )"; return sql; } QSqlQuery DatabaseUtils::createTable(const DatabaseTable *table, const QString &table_name) const { // CREATE TABLE ... QString sql = createTableText(table, table_name); qCDebug(sdkdb) << "SQL:" << sql; return mDatabaseManager->execPlainSql(sql); } /** * @brief DatabaseUtils::insertIntoTable * @param table * @param table_name * @return * * @todo Loop VariantMap change to Loop over propertiess */ QSqlQuery DatabaseUtils::insertIntoTable(const DatabaseTable *table, const QString &table_name) const { QString columns; QString values; QVariantMap valueMap = table->toVariantMap(); // in: id / 23233 // out: columns: id // out: values: :id auto keys = valueMap.keys(); for (const auto& _key : keys) { QString key = fromCamelCase(_key); if (!columns.isEmpty()) { columns += ", "; values += ", "; } columns += key; values += ":" + key; } QSqlQuery query(mDatabaseManager->database()); QString queryText = QString("INSERT INTO %1 ( %2 ) VALUES ( %3 );").arg(table_name).arg(columns).arg(values); query.prepare(queryText); for (const auto& _key : keys ) { QString key = fromCamelCase(_key); auto value = valueMap.value(_key); query.bindValue(":"+key, value); } QSqlQuery res = mDatabaseManager->executeQuery(query); return res; } QSqlQuery DatabaseUtils::updateTable(const DatabaseTable *table, const QString &table_name, const QSet &filters) const { QString columnsAndValues; QString primaryKeyCondition; QVariantMap valueMap = table->toVariantMap(filters); auto keys = valueMap.keys(); Q_ASSERT(!keys.isEmpty()); // Primary key is first user property ( first VariantMap item ) // in ( primary key ): id // out: id = :id const QString primaryKey = table->primaryKey(); primaryKeyCondition = primaryKey + " = :" + primaryKey; for (const auto& _key : keys) { QString key = fromCamelCase(_key); if (!columnsAndValues.isEmpty()) { columnsAndValues += ", "; } columnsAndValues += key + " = :" + key; } QSqlQuery query(mDatabaseManager->database()); QString queryText = QString("UPDATE %1 SET %2 WHERE %3;").arg(table_name).arg(columnsAndValues).arg(primaryKeyCondition); query.prepare(queryText); for (const auto& _key : keys ) { QString key = fromCamelCase(_key); auto value = valueMap.value(_key); query.bindValue(":"+key, value); } QSqlQuery res = mDatabaseManager->executeQuery(query); return res; } QString DatabaseUtils::sqlType() const { return mSqlType; } void DatabaseUtils::setSqlType(const QString &sqlType) { mSqlType = sqlType; } QString DatabaseUtils::fromCamelCase(const QString &s) { static QRegularExpression regExp1 {"(.)([A-Z][a-z]+)"}; static QRegularExpression regExp2 {"([a-z0-9])([A-Z])"}; QString result = s; result.replace(regExp1, "\\1_\\2"); result.replace(regExp2, "\\1_\\2"); return result.toLower(); } QString serversdk::DatabaseUtils::toCamelCase(const QString &s) { QStringList parts = s.split('_', QString::SkipEmptyParts); for (int i=1; i