#include "databaseapi.h" Q_LOGGING_CATEGORY(database, "database.api"); DatabaseAPI::DatabaseAPI(serversdk::DatabaseManager *dbMan, bool dryMode) : mDryMode(dryMode), mDbMan(dbMan), utils(std::make_unique(dbMan)) { mDbMan->setDryMode(dryMode); } bool DatabaseAPI::open() { return mDbMan->openPostgres(QStringLiteral("192.168.1.94"), QStringLiteral("deloitte"), QStringLiteral("postgres"), QStringLiteral("34rjkciea12"), QStringLiteral("postgres-connection")); } void DatabaseAPI::downloadData() { auto updatedQuery = mDbMan->execPlainSql("SELECT * " "FROM colnod_token WHERE last_modified > last_update AND deleted = false"); auto deletedQuery = mDbMan->execPlainSql("SELECT id " "FROM colnod_token WHERE last_modified > last_update AND deleted = true"); emit downloadDataFinished(composeData(updatedQuery, deletedQuery)); } void DatabaseAPI::processData(const std::shared_ptr &data) { uploadTokens(data->updatedTokens); uploadSubjects(data->updatedSubjects); deleteItems(data->deletedTokens, "colnod_token"); deleteItems(data->deletedSubjects, "colnod_subject"); qInfo(database) << tab << "-> DATA PROCESSED TO DATABASE:"; qInfo(database) << tab << tab << data->updatedTokens.size() << "TOKENS ADDED/UPDATED"; qInfo(database) << tab << tab << data->deletedTokens.size() << "TOKENS DELETED"; qInfo(database) << tab << tab << data->updatedSubjects.size() << "SUBJECTS ADDED/UPDATED"; qInfo(database) << tab << tab << data->deletedSubjects.size() << "SUBJECTS DELETED"; qInfo(database) << dash; } std::shared_ptr DatabaseAPI::composeData(const QSqlQuery &updatedQuery, QSqlQuery &deletedQuery) { auto data = std::make_shared(); auto list = utils->tableFromQuery(updatedQuery); for (const auto &token : list) { data->updatedTokens.insert(token->id(), token); } while (deletedQuery.next()) { data->deletedTokens.append(deletedQuery.value(0).toString()); } qInfo(database) << tab << "-> DATABASE DATA:"; qInfo(database) << tab << tab << data->updatedTokens.size() << "TOKENS WERE ADDED/UPDATED"; qInfo(database) << tab << tab << data->deletedTokens.size() << "TOKENS MARKED FOR DELETION"; qInfo(database) << dash; return data; } qint64 DatabaseAPI::getLastSync() { auto query = mDbMan->execPlainSql("SELECT last_sync FROM config"); if (query.next()){ return query.value(0).toLongLong(); } return -1; } void DatabaseAPI::setLastSync(qint64 timestamp) { auto query = mDbMan->createQuery(); query.prepare("UPDATE config SET last_sync = :last_sync"); query.bindValue(":last_sync", timestamp); mDbMan->executeQuery(query); } void DatabaseAPI::setLastUpdate(const QHash> &tokens) { auto query = mDbMan->createQuery(); for (const auto &token : tokens){ query.prepare("UPDATE colnod_token SET last_update = :last_update WHERE id = :id"); query.bindValue(":last_update", token->lastUpdate()); query.bindValue(":id", token->id()); mDbMan->executeQuery(query); } qInfo(database) << equals; qInfo(database) << "Synchronize last update in database with colnod"; qInfo(database) << equals; } void DatabaseAPI::setLastUpdate(const QList ids) { auto query = mDbMan->createQuery(); for (const auto &id : ids){ query.prepare("UPDATE colnod_token SET last_update = :last_update WHERE id = :id"); query.bindValue(":last_update", QDateTime::fromMSecsSinceEpoch(getNow()).toString("yyyy-MM-dd hh:mm:ss.zzz")); query.bindValue(":id", id); mDbMan->executeQuery(query); } } qint64 DatabaseAPI::getNow() { auto query = mDbMan->execPlainSql("SELECT EXTRACT(EPOCH FROM NOW())*1000"); query.next(); return query.value(0).toLongLong(); } void DatabaseAPI::initNewTokens() { auto query = mDbMan->execPlainSql("SELECT * FROM colnod_token WHERE name IS NULL"); QHash> tokensToInit; auto list = utils->tableFromQuery(query); for (const auto &token : list) { qint16 num = getNumOfTokensOfSubject(token->subjectId()); token->setName(getSubjectNameByTokenId(token->id()) + "_mobile_" + QString::number(num + 1)); token->setDescription("mobile"); token->setTokenData(token->tokenData().toUpper()); tokensToInit.insert(token->id(), token); qInfo(database).noquote() << Message::massageTemplate("Inicializing new", "token", "database", token->name()); } uploadTokens(tokensToInit); } void DatabaseAPI::uploadTokens(const QHash> &tokens) { auto query = mDbMan->createQuery(); for (const auto &token : tokens) { if (exists(token->id(), "colnod_token")) { query = utils->updateTable(token.get(), "colnod_token"); qInfo(database).noquote() << Message::massageTemplate("Updating", "token", "database", token->name()); } else { query = utils->insertIntoTable(token.get(), "colnod_token"); qInfo(database).noquote() << Message::massageTemplate("Adding", "token", "database", token->name()); } } } void DatabaseAPI::uploadSubjects(const QHash> &subjects) { auto query = mDbMan->createQuery(); for (const auto &subject : subjects) { for (const auto &attribute : subject->getAttributes()) { if (exists(attribute->id(), "colnod_subject_attribute")) { query = utils->updateTable(attribute.get(), "colnod_subject_attribute"); } else { query = utils->insertIntoTable(attribute.get(), "colnod_subject_attribute"); } } // NOTE: about actions if (exists(subject->id(), "colnod_subject")) { query = utils->updateTable(subject.get(), "colnod_subject"); qInfo(database).noquote() << Message::massageTemplate("Updating", "subject", "database", subject->name()); } else { query = utils->insertIntoTable(subject.get(), "colnod_subject"); qInfo(database).noquote() << Message::massageTemplate("Adding", "subject", "database", subject->name()); } } } void DatabaseAPI::deleteItems(const QList &ids, const QString &tableName) { auto query = mDbMan->createQuery(); QString nowString = QDateTime::fromMSecsSinceEpoch(getLastSync()).toString("yyyy-MM-dd hh:mm:ss.zzz"); for (const auto &id : ids) { qInfo(database).noquote() << Message::massageTemplate("Deleting", tableName.mid(tableName.indexOf("_") + 1, tableName.length() - 1), "database", id); query.prepare(QString("UPDATE %1 SET deleted = true, last_update = :now, last_modified = :now WHERE id = :id").arg(tableName)); query.bindValue(":id", id); query.bindValue(":now", nowString); mDbMan->executeQuery(query); } } std::shared_ptr DatabaseAPI::getToken(const QString &id) { auto query = mDbMan->createQuery(); query.prepare("SELECT * FROM colnod_token WHERE id = :id"); query.bindValue(":id", id); mDbMan->executeQuery(query); auto list = utils->tableFromQuery(query); if (list.isEmpty()) return nullptr; return list.at(0); } bool DatabaseAPI::isAlreadyDeleted(const QString &id) { auto token = getToken(id); if (token->deleted()) return true; return false; } bool DatabaseAPI::exists(const QString &id, const QString &tableName) { auto query = mDbMan->createQuery(); query.prepare(QString("SELECT 1 FROM %1 WHERE id = :id").arg(tableName)); query.bindValue(":id", id); query = mDbMan->executeQuery(query); return query.next(); } qint16 DatabaseAPI::getNumOfTokensOfSubject(const QString &id) { auto query = mDbMan->createQuery(); query.prepare("SELECT 1 FROM colnod_token WHERE subject_id = :id AND deleted = false"); query.bindValue(":id", id); return static_cast(mDbMan->executeQuery(query).size()); } QString DatabaseAPI::getSubjectNameByTokenId(const QString &tokenId) { auto query = mDbMan->createQuery(); query.prepare("SELECT name FROM colnod_subject WHERE id = (SELECT subject_id FROM colnod_token WHERE id = :tokenId)"); query.bindValue(":tokenId", tokenId); if (mDbMan->executeQuery(query).next()) return query.value(0).toString(); qWarning() << "Token:" << tokenId << "is not assigned to any subject"; return "(No subject)"; }