mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
- The first part
- Added CodeDocs config file for customization - Fixing LGTM alerts - LGTM bug fixed again - added token option to hyperion-remote - fix DBManager::getDB() - next bugfix - correct broken signal from SettingManager to Hyperion - Token list is created after the schema is fetched Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
18
libsrc/db/CMakeLists.txt
Normal file
18
libsrc/db/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
find_package(Qt5 COMPONENTS Sql REQUIRED)
|
||||
|
||||
# Define the current source locations
|
||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/db)
|
||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/db)
|
||||
|
||||
FILE ( GLOB DB_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" )
|
||||
|
||||
add_library(database
|
||||
${DB_SOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries(database
|
||||
hyperion
|
||||
hyperion-utils
|
||||
Qt5::Core
|
||||
Qt5::Sql
|
||||
)
|
408
libsrc/db/DBManager.cpp
Normal file
408
libsrc/db/DBManager.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
#include <db/DBManager.h>
|
||||
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlRecord>
|
||||
#include <QDir>
|
||||
|
||||
// not in header because of linking
|
||||
static QString _rootPath;
|
||||
|
||||
DBManager::DBManager(QObject* parent)
|
||||
: QObject(parent)
|
||||
, _log(Logger::getInstance("DB"))
|
||||
{
|
||||
}
|
||||
|
||||
DBManager::~DBManager()
|
||||
{
|
||||
}
|
||||
|
||||
void DBManager::setRootPath(const QString& rootPath)
|
||||
{
|
||||
_rootPath = rootPath;
|
||||
// create directory
|
||||
QDir().mkpath(_rootPath+"/db");
|
||||
}
|
||||
|
||||
void DBManager::setDB(const QString& dbn)
|
||||
{
|
||||
_dbn = dbn;
|
||||
// new database connection if not found
|
||||
if(!QSqlDatabase::contains(dbn))
|
||||
{
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE",dbn);
|
||||
db.setDatabaseName(_rootPath+"/db/"+dbn+".db");
|
||||
if(!db.open())
|
||||
{
|
||||
Error(_log, QSTRING_CSTR(db.lastError().text()));
|
||||
throw std::runtime_error("Failed to open database connection!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DBManager::setTable(const QString& table)
|
||||
{
|
||||
_table = table;
|
||||
}
|
||||
|
||||
QSqlDatabase DBManager::getDB() const
|
||||
{
|
||||
QSqlDatabase db = QSqlDatabase::database(_dbn);
|
||||
|
||||
if (db.isOpen() && db.isValid())
|
||||
{
|
||||
return db;
|
||||
}
|
||||
else
|
||||
{
|
||||
db = QSqlDatabase::addDatabase("QSQLITE", _dbn);
|
||||
db.setDatabaseName(_rootPath+"/db/"+_dbn+".db");
|
||||
}
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
bool DBManager::createRecord(const VectorPair& conditions, const QVariantMap& columns) const
|
||||
{
|
||||
if(recordExists(conditions))
|
||||
{
|
||||
// if there is no column data, return
|
||||
if(columns.isEmpty())
|
||||
return true;
|
||||
|
||||
if(!updateRecord(conditions, columns))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QSqlDatabase idb = getDB();
|
||||
QSqlQuery query(idb);
|
||||
query.setForwardOnly(true);
|
||||
|
||||
QVariantList cValues;
|
||||
QStringList prep;
|
||||
QStringList placeh;
|
||||
// prep merge columns & condition
|
||||
QVariantMap::const_iterator i = columns.constBegin();
|
||||
while (i != columns.constEnd()) {
|
||||
prep.append(i.key());
|
||||
cValues += i.value();
|
||||
placeh.append("?");
|
||||
|
||||
++i;
|
||||
}
|
||||
for(const auto& pair : conditions)
|
||||
{
|
||||
// remove the condition statements
|
||||
QString tmp = pair.first;
|
||||
prep << tmp.remove("AND");
|
||||
cValues << pair.second;
|
||||
placeh.append("?");
|
||||
}
|
||||
query.prepare(QString("INSERT INTO %1 ( %2 ) VALUES ( %3 )").arg(_table,prep.join(", ")).arg(placeh.join(", ")));
|
||||
// add column & condition values
|
||||
doAddBindValue(query, cValues);
|
||||
if(!query.exec())
|
||||
{
|
||||
Error(_log, "Failed to create record: '%s' in table: '%s' Error: %s", QSTRING_CSTR(prep.join(", ")), QSTRING_CSTR(_table), QSTRING_CSTR(idb.lastError().text()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBManager::recordExists(const VectorPair& conditions) const
|
||||
{
|
||||
if(conditions.isEmpty())
|
||||
return false;
|
||||
|
||||
QSqlDatabase idb = getDB();
|
||||
QSqlQuery query(idb);
|
||||
query.setForwardOnly(true);
|
||||
|
||||
QStringList prepCond;
|
||||
QVariantList bindVal;
|
||||
prepCond << "WHERE";
|
||||
|
||||
for(const auto& pair : conditions)
|
||||
{
|
||||
prepCond << pair.first+"=?";
|
||||
bindVal << pair.second;
|
||||
}
|
||||
query.prepare(QString("SELECT * FROM %1 %2").arg(_table,prepCond.join(" ")));
|
||||
doAddBindValue(query, bindVal);
|
||||
if(!query.exec())
|
||||
{
|
||||
Error(_log, "Failed recordExists(): '%s' in table: '%s' Error: %s", QSTRING_CSTR(prepCond.join(" ")), QSTRING_CSTR(_table), QSTRING_CSTR(idb.lastError().text()));
|
||||
return false;
|
||||
}
|
||||
|
||||
int entry = 0;
|
||||
while (query.next()) {
|
||||
entry++;
|
||||
}
|
||||
|
||||
if(entry)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DBManager::updateRecord(const VectorPair& conditions, const QVariantMap& columns) const
|
||||
{
|
||||
QSqlDatabase idb = getDB();
|
||||
QSqlQuery query(idb);
|
||||
query.setForwardOnly(true);
|
||||
|
||||
QVariantList values;
|
||||
QStringList prep;
|
||||
|
||||
// prepare columns valus
|
||||
QVariantMap::const_iterator i = columns.constBegin();
|
||||
while (i != columns.constEnd()) {
|
||||
prep += i.key()+"=?";
|
||||
values += i.value();
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
// prepare condition values
|
||||
QStringList prepCond;
|
||||
QVariantList prepBindVal;
|
||||
if(!conditions.isEmpty())
|
||||
prepCond << "WHERE";
|
||||
|
||||
for(const auto& pair : conditions)
|
||||
{
|
||||
prepCond << pair.first+"=?";
|
||||
prepBindVal << pair.second;
|
||||
}
|
||||
|
||||
query.prepare(QString("UPDATE %1 SET %2 %3").arg(_table,prep.join(", ")).arg(prepCond.join(" ")));
|
||||
// add column values
|
||||
doAddBindValue(query, values);
|
||||
// add condition values
|
||||
doAddBindValue(query, prepBindVal);
|
||||
if(!query.exec())
|
||||
{
|
||||
Error(_log, "Failed to update record: '%s' in table: '%s' Error: %s", QSTRING_CSTR(prepCond.join(" ")), QSTRING_CSTR(_table), QSTRING_CSTR(idb.lastError().text()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBManager::getRecord(const VectorPair& conditions, QVariantMap& results, const QStringList& tColumns) const
|
||||
{
|
||||
QSqlDatabase idb = getDB();
|
||||
QSqlQuery query(idb);
|
||||
query.setForwardOnly(true);
|
||||
|
||||
QString sColumns("*");
|
||||
if(!tColumns.isEmpty())
|
||||
sColumns = tColumns.join(", ");
|
||||
|
||||
// prep conditions
|
||||
QStringList prepCond;
|
||||
QVariantList bindVal;
|
||||
if(!conditions.isEmpty())
|
||||
prepCond << "WHERE";
|
||||
|
||||
for(const auto& pair : conditions)
|
||||
{
|
||||
prepCond << pair.first+"=?";
|
||||
bindVal << pair.second;
|
||||
}
|
||||
query.prepare(QString("SELECT %1 FROM %2 %3").arg(sColumns,_table).arg(prepCond.join(" ")));
|
||||
doAddBindValue(query, bindVal);
|
||||
|
||||
if(!query.exec())
|
||||
{
|
||||
Error(_log, "Failed to get record: '%s' in table: '%s' Error: %s", QSTRING_CSTR(prepCond.join(" ")), QSTRING_CSTR(_table), QSTRING_CSTR(idb.lastError().text()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// go to first row
|
||||
query.next();
|
||||
|
||||
QSqlRecord rec = query.record();
|
||||
for(int i = 0; i<rec.count(); i++)
|
||||
{
|
||||
results[rec.fieldName(i)] = rec.value(i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBManager::getRecords(QVector<QVariantMap>& results, const QStringList& tColumns) const
|
||||
{
|
||||
QSqlDatabase idb = getDB();
|
||||
QSqlQuery query(idb);
|
||||
query.setForwardOnly(true);
|
||||
|
||||
QString sColumns("*");
|
||||
if(!tColumns.isEmpty())
|
||||
sColumns = tColumns.join(", ");
|
||||
|
||||
query.prepare(QString("SELECT %1 FROM %2").arg(sColumns,_table));
|
||||
|
||||
if(!query.exec())
|
||||
{
|
||||
Error(_log, "Failed to get records: '%s' in table: '%s' Error: %s", QSTRING_CSTR(sColumns), QSTRING_CSTR(_table), QSTRING_CSTR(idb.lastError().text()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// iterate through all found records
|
||||
while(query.next())
|
||||
{
|
||||
QVariantMap entry;
|
||||
QSqlRecord rec = query.record();
|
||||
for(int i = 0; i<rec.count(); i++)
|
||||
{
|
||||
entry[rec.fieldName(i)] = rec.value(i);
|
||||
}
|
||||
results.append(entry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool DBManager::deleteRecord(const VectorPair& conditions) const
|
||||
{
|
||||
if(conditions.isEmpty())
|
||||
{
|
||||
Error(_log, "Oops, a deleteRecord() call wants to delete the entire table (%s)! Denied it", QSTRING_CSTR(_table));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(recordExists(conditions))
|
||||
{
|
||||
QSqlDatabase idb = getDB();
|
||||
QSqlQuery query(idb);
|
||||
|
||||
// prep conditions
|
||||
QStringList prepCond("WHERE");
|
||||
QVariantList bindValues;
|
||||
|
||||
for(const auto& pair : conditions)
|
||||
{
|
||||
prepCond << pair.first+"=?";
|
||||
bindValues << pair.second;
|
||||
}
|
||||
|
||||
query.prepare(QString("DELETE FROM %1 %2").arg(_table,prepCond.join(" ")));
|
||||
doAddBindValue(query, bindValues);
|
||||
if(!query.exec())
|
||||
{
|
||||
Error(_log, "Failed to delete record: '%s' in table: '%s' Error: %s", QSTRING_CSTR(prepCond.join(" ")), QSTRING_CSTR(_table), QSTRING_CSTR(idb.lastError().text()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DBManager::createTable(QStringList& columns) const
|
||||
{
|
||||
if(columns.isEmpty())
|
||||
{
|
||||
Error(_log,"Empty tables aren't supported!");
|
||||
return false;
|
||||
}
|
||||
|
||||
QSqlDatabase idb = getDB();
|
||||
// create table if required
|
||||
QSqlQuery query(idb);
|
||||
if(!tableExists(_table))
|
||||
{
|
||||
// empty tables aren't supported by sqlite, add one column
|
||||
QString tcolumn = columns.takeFirst();
|
||||
// default CURRENT_TIMESTAMP is not supported by ALTER TABLE
|
||||
if(!query.exec(QString("CREATE TABLE %1 ( %2 )").arg(_table,tcolumn)))
|
||||
{
|
||||
Error(_log, "Failed to create table: '%s' Error: %s", QSTRING_CSTR(_table), QSTRING_CSTR(idb.lastError().text()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// create columns if required
|
||||
QSqlRecord rec = idb.record(_table);
|
||||
int err = 0;
|
||||
for(const auto& column : columns)
|
||||
{
|
||||
QStringList id = column.split(' ');
|
||||
if(rec.indexOf(id.at(0)) == -1)
|
||||
{
|
||||
if(!createColumn(column))
|
||||
{
|
||||
err++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(err)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBManager::createColumn(const QString& column) const
|
||||
{
|
||||
QSqlDatabase idb = getDB();
|
||||
QSqlQuery query(idb);
|
||||
if(!query.exec(QString("ALTER TABLE %1 ADD COLUMN %2").arg(_table,column)))
|
||||
{
|
||||
Error(_log, "Failed to create column: '%s' in table: '%s' Error: %s", QSTRING_CSTR(column), QSTRING_CSTR(_table), QSTRING_CSTR(idb.lastError().text()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DBManager::tableExists(const QString& table) const
|
||||
{
|
||||
QSqlDatabase idb = getDB();
|
||||
QStringList tables = idb.tables();
|
||||
if(tables.contains(table))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DBManager::deleteTable(const QString& table) const
|
||||
{
|
||||
if(tableExists(table))
|
||||
{
|
||||
QSqlDatabase idb = getDB();
|
||||
QSqlQuery query(idb);
|
||||
if(!query.exec(QString("DROP TABLE %1").arg(table)))
|
||||
{
|
||||
Error(_log, "Failed to delete table: '%s' Error: %s", QSTRING_CSTR(table), QSTRING_CSTR(idb.lastError().text()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DBManager::doAddBindValue(QSqlQuery& query, const QVariantList& variants) const
|
||||
{
|
||||
for(const auto& variant : variants)
|
||||
{
|
||||
QVariant::Type t = variant.type();
|
||||
switch(t)
|
||||
{
|
||||
case QVariant::UInt:
|
||||
case QVariant::Int:
|
||||
case QVariant::Bool:
|
||||
query.addBindValue(variant.toInt());
|
||||
break;
|
||||
case QVariant::Double:
|
||||
query.addBindValue(variant.toFloat());
|
||||
break;
|
||||
case QVariant::ByteArray:
|
||||
query.addBindValue(variant.toByteArray());
|
||||
break;
|
||||
default:
|
||||
query.addBindValue(variant.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user