733 lines
28 KiB
Plaintext
Executable File
733 lines
28 KiB
Plaintext
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* Template for 'real' structures including insert/update/delete functions for db
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
{% autoescape off %}
|
|
// filename: {{ namespace_abbr }}_db_impl.cpp
|
|
#include "{{ namespace_abbr }}_db_impl.h"
|
|
{% if custom_db_procs %}
|
|
#include <{{ include_prefix }}/{{ namespace_abbr }}_db_impl_custom.h>
|
|
{% endif %}
|
|
|
|
#include <ngldb/dbtransaction.h>
|
|
#include <ngldb/nsqlquery.h>
|
|
#include <ngldb/dbconnection.h>
|
|
#include <ngldb/sql_query_janitor.h>
|
|
#include <QtSql/QSqlError>
|
|
#include <QVariant>
|
|
#include <NGLLogger/INGLLogger.h>
|
|
|
|
namespace {{ namespace }}
|
|
{
|
|
|
|
QString qVariantToJsonString(const QVariant &value)
|
|
{
|
|
return value.isNull() ? QStringLiteral("{}") : value.toString();
|
|
}
|
|
|
|
QString fixupEmptyJsonString(const QString &str)
|
|
{
|
|
return str.isEmpty() ? QStringLiteral("{}") : str;
|
|
}
|
|
|
|
// DatabaseInterface
|
|
std::shared_ptr<DatabaseInterface> DatabaseInterface::create(int exerciseId)
|
|
{
|
|
{% if custom_db_procs %}
|
|
return std::make_shared<DatabaseInterfaceImplCustom>(exerciseId);
|
|
{% else %}
|
|
return std::make_shared<DatabaseInterfaceImpl>(exerciseId);
|
|
{% endif %}
|
|
}
|
|
|
|
DatabaseInterfaceImpl::DatabaseInterfaceImpl(int exerciseId)
|
|
: m_query(nullptr)
|
|
, m_exerciseId(exerciseId)
|
|
, m_bEmitMessageOnError(true)
|
|
, m_bCanHandleSchemas(true)
|
|
, m_ownDatabaseConnection(true)
|
|
, m_logger(getLogger("Db"))
|
|
{}
|
|
|
|
DatabaseInterfaceImpl::~DatabaseInterfaceImpl()
|
|
{
|
|
m_query = nullptr;
|
|
{% if has_db_notifications %}
|
|
QSqlDriver *driver = m_dbConnection.driver();
|
|
if (driver && m_dbConnection.isOpen())
|
|
{
|
|
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %}
|
|
driver->unsubscribeFromNotification(QStringLiteral("{{ db_notify }}"));{% endfor %}{% endfor %}
|
|
}
|
|
{% endif %}
|
|
if (m_ownDatabaseConnection && m_dbConnection.isOpen())
|
|
m_dbConnection.close();
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::init(const QSqlDatabase &dbConnection)
|
|
{
|
|
m_dbConnection = dbConnection;
|
|
m_ownDatabaseConnection = false;
|
|
return initInternal();
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::init(const QString &dbUser,
|
|
const QString &dbPasswd,
|
|
const QString &dbDriver,
|
|
const QString &dbHost,
|
|
const QString &dbName)
|
|
{
|
|
m_ownDatabaseConnection = true;
|
|
|
|
m_dbConnection = DBConnection::open(m_logger, dbUser, dbPasswd, dbDriver, dbHost, dbName, schemaName());
|
|
|
|
return initInternal();
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::initInternal()
|
|
{
|
|
QSqlDriver *driver = m_dbConnection.driver();
|
|
if (!driver)
|
|
{
|
|
WARNING_LOG(m_logger) << "No SQL driver loaded - no database available!";
|
|
return false;
|
|
}
|
|
const QString driverName = m_dbConnection.driverName();
|
|
DEBUG_LOG(m_logger) << "Connected to database " << m_dbConnection.databaseName() << "@" << m_dbConnection.hostName()
|
|
<< ", schema: " << schemaName() << ", used driver: " << driverName;
|
|
if (!m_dbConnection.isOpen())
|
|
{
|
|
WARNING_LOG(m_logger) << "Database connection is no open - can not initialize database interface";
|
|
return false;
|
|
}
|
|
if (driverName == QLatin1String("QSQLITE"))
|
|
m_bCanHandleSchemas = false;
|
|
|
|
{% if has_db_notifications %}
|
|
if (!driver->hasFeature(QSqlDriver::EventNotifications))
|
|
{
|
|
WARNING_LOG(m_logger) << "Can not subscribe to notifications - sqldriver does not support this feature!";
|
|
}
|
|
else
|
|
{
|
|
connect(driver, QOverload<const QString&,QSqlDriver::NotificationSource,const QVariant&>::of(&QSqlDriver::notification),
|
|
this, &DatabaseInterfaceImpl::onNotification);
|
|
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %}
|
|
driver->subscribeToNotification(QStringLiteral("{{ db_notify }}"));{% endfor %}{% endfor %}
|
|
}
|
|
{% endif %}
|
|
m_query = std::unique_ptr<NSqlQuery>(new NSqlQuery(m_dbConnection, m_logger));
|
|
return true;
|
|
}
|
|
|
|
QString DatabaseInterfaceImpl::schemaName() const
|
|
{
|
|
if (!m_bCanHandleSchemas)
|
|
return QString();
|
|
if (m_exerciseId <= 0)
|
|
return QStringLiteral("{{ namespace_abbr }}");
|
|
return DBCommon::getExerciseSchemaName(m_exerciseId);
|
|
}
|
|
|
|
QString DatabaseInterfaceImpl::dbUser() const
|
|
{
|
|
if (m_exerciseId > 0)
|
|
return QStringLiteral("ets_ex_00");
|
|
else
|
|
return QStringLiteral("ets_") + schemaName();
|
|
}
|
|
|
|
void DatabaseInterfaceImpl::setEmitMessageOnError(bool bEmit)
|
|
{
|
|
m_bEmitMessageOnError = bEmit;
|
|
}
|
|
|
|
QString DatabaseInterfaceImpl::getTableName(const QString &tableName) const
|
|
{
|
|
if (!m_bCanHandleSchemas)
|
|
return tableName;
|
|
if (m_exerciseId > 0)
|
|
return DBCommon::getExerciseTableName(tableName, m_exerciseId);
|
|
return QStringLiteral("{{ namespace_abbr }}.") + tableName;
|
|
}
|
|
|
|
QSqlError DatabaseInterfaceImpl::getLastError() const
|
|
{
|
|
return m_lastError;
|
|
}
|
|
|
|
{% if has_db_notifications %}
|
|
void DatabaseInterfaceImpl::onNotification(const QString &name, QSqlDriver::NotificationSource source, const QVariant &payload)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Notification source = " << source;
|
|
// no need to emit notification signals
|
|
if (source == QSqlDriver::SelfSource)
|
|
return;
|
|
// search coresponding signal
|
|
{% for cpp_struct in cpp_structs %}{% for db_notify in cpp_struct.dbNotifications %}
|
|
if (name == QLatin1String("{{ db_notify }}"))
|
|
{
|
|
emit {{ db_notify }}(payload);
|
|
}{% endfor %}{% endfor %}
|
|
}
|
|
{% endif %}
|
|
|
|
{% for cpp_struct in cpp_structs %}
|
|
//
|
|
// Struct: Database::{{ cpp_struct.name }}
|
|
//
|
|
bool DatabaseInterfaceImpl::insert(Database::{{ cpp_struct.name }} &data)
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
{% if cpp_struct.insertStructures|length > 1 %}
|
|
DBTransaction transaction(m_dbConnection);
|
|
{% endif %}
|
|
{% for insertStruct in cpp_struct.insertStructures %}
|
|
{
|
|
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
|
|
|
QString keyColumnInsertKey;
|
|
QString keyColumnInsertVal;
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
const bool bInsertWithKey = data.{{cpp_struct.primaryKey.cppMemberName}} != {{cpp_struct.primaryKey.cppDefault}};
|
|
if (bInsertWithKey)
|
|
{
|
|
keyColumnInsertKey = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }}, ");
|
|
keyColumnInsertVal = QStringLiteral(" :{{ insertStruct.primaryKey.dbColumnName }}, ");
|
|
}
|
|
{% endif %}
|
|
const QString stmt(QStringLiteral("INSERT INTO ") + tableName +
|
|
QStringLiteral(" (") + keyColumnInsertKey +
|
|
QStringLiteral("{% for row in insertStruct.member %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" ) VALUES (") + keyColumnInsertVal +
|
|
QStringLiteral("{% for row in insertStruct.member %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} )"));
|
|
|
|
if (!m_query->prepare(stmt))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
if (bInsertWithKey)
|
|
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
|
{% endif %}
|
|
{% for row in insertStruct.member %}
|
|
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
|
{% endfor %}
|
|
|
|
if (!m_query->exec(m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
{% if insertStruct.serialMember.cppMemberName %}
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
if (data.{{cpp_struct.primaryKey.cppMemberName}} == {{cpp_struct.primaryKey.cppDefault}})
|
|
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
|
{% else %}
|
|
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
|
{% endif %}
|
|
{% if insertStruct.baseId.cppMemberName %}
|
|
data.{{ insertStruct.baseId.cppMemberName }} = data.{{ insertStruct.serialMember.cppMemberName }};
|
|
{% endif %}
|
|
{% endif %}
|
|
}
|
|
{% endfor %}
|
|
{% if cpp_struct.insertStructures|length > 1 %}
|
|
transaction.commit();
|
|
{% endif %}
|
|
return true;
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::upsert(Database::{{ cpp_struct.name }} &data)
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
{% if cpp_struct.insertStructures|length > 1 %}
|
|
DBTransaction transaction(m_dbConnection);
|
|
{% endif %}
|
|
{% for insertStruct in cpp_struct.insertStructures %}
|
|
{
|
|
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
|
|
|
QString keyColumnInsertKey;
|
|
QString keyColumnInsertKeyConflict;
|
|
QString keyColumnInsertVal;
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
const bool bInsertWithKey = true;
|
|
keyColumnInsertVal = QStringLiteral(" :{{ insertStruct.primaryKey.dbColumnName }}, ");
|
|
keyColumnInsertKey = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }}, ");
|
|
{% endif %}
|
|
|
|
keyColumnInsertKeyConflict = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }} ");
|
|
|
|
const QString stmt(QStringLiteral("INSERT INTO ") + tableName +
|
|
QStringLiteral(" (") + keyColumnInsertKey +
|
|
QStringLiteral("{% for row in insertStruct.member %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" ) VALUES (") + keyColumnInsertVal +
|
|
QStringLiteral("{% for row in insertStruct.member %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} )") +
|
|
QStringLiteral(" ON CONFLICT (") + keyColumnInsertKeyConflict + QStringLiteral(") DO UPDATE ") +
|
|
QStringLiteral(" SET"
|
|
" {% for row in insertStruct.member %}{{ row.dbColumnName }} = :{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" WHERE excluded.{{ insertStruct.primaryKey.dbColumnName }} = :{{ insertStruct.primaryKey.dbColumnName }}"));
|
|
|
|
if (!m_query->prepare(stmt))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
if (bInsertWithKey)
|
|
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
|
{% endif %}
|
|
{% for row in insertStruct.member %}
|
|
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
|
{% endfor %}
|
|
|
|
if (!m_query->exec(m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
{% if insertStruct.serialMember.cppMemberName %}
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
if (data.{{cpp_struct.primaryKey.cppMemberName}} == {{cpp_struct.primaryKey.cppDefault}})
|
|
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
|
{% else %}
|
|
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
|
{% endif %}
|
|
{% if insertStruct.baseId.cppMemberName %}
|
|
data.{{ insertStruct.baseId.cppMemberName }} = data.{{ insertStruct.serialMember.cppMemberName }};
|
|
{% endif %}
|
|
{% endif %}
|
|
}
|
|
{% endfor %}
|
|
{% if cpp_struct.insertStructures|length > 1 %}
|
|
transaction.commit();
|
|
{% endif %}
|
|
return true;
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::update(const Database::{{ cpp_struct.name }} &data)
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
{% if cpp_struct.insertStructures|length > 1 %}
|
|
DBTransaction transaction(m_dbConnection);
|
|
{% endif %}
|
|
{% for insertStruct in cpp_struct.insertStructures %}
|
|
{
|
|
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
|
const QString stmt(QStringLiteral("UPDATE ") + tableName +
|
|
QStringLiteral(" SET"
|
|
" {% for row in insertStruct.member %}{{ row.dbColumnName }} = :{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" WHERE {{ insertStruct.primaryKey.dbColumnName }} = :{{ insertStruct.primaryKey.dbColumnName }}"));
|
|
|
|
if (!m_query->prepare(stmt))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
{% for row in insertStruct.member %}
|
|
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
|
{% endfor %}
|
|
{% if insertStruct.serialMember.cppMemberName %}
|
|
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
|
{% endif %}
|
|
|
|
if (!m_query->exec(m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
}
|
|
{% endfor %}
|
|
{% if cpp_struct.insertStructures|length > 1 %}
|
|
transaction.commit();
|
|
{% endif %}
|
|
return true;
|
|
}
|
|
|
|
{% if cpp_struct.insertStructures|length == 1 %}
|
|
// current only implemented for 'plain' structures with only one affected table
|
|
bool DatabaseInterfaceImpl::insert(std::vector<Database::{{ cpp_struct.name }}> &cont)
|
|
{
|
|
if (cont.empty())
|
|
return true;
|
|
|
|
{% for insertStruct in cpp_struct.insertStructures %}
|
|
{
|
|
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
|
|
|
QString keyColumnInsertKey;
|
|
QString keyColumnInsertVal;
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
const bool bInsertWithKey = cont[0].{{cpp_struct.primaryKey.cppMemberName}} != {{cpp_struct.primaryKey.cppDefault}};
|
|
// the first element determines the stmt to be used
|
|
if (bInsertWithKey)
|
|
{
|
|
keyColumnInsertKey = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }}, ");
|
|
keyColumnInsertVal = QStringLiteral(" :{{ insertStruct.primaryKey.dbColumnName }}, ");
|
|
}
|
|
{% endif %}
|
|
const QString stmt(QStringLiteral("INSERT INTO ") + tableName +
|
|
QStringLiteral(" (") + keyColumnInsertKey +
|
|
QStringLiteral("{% for row in insertStruct.member %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" ) VALUES (") + keyColumnInsertVal +
|
|
QStringLiteral("{% for row in insertStruct.member %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} )"));
|
|
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
if (!m_query->prepare(stmt))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
for (auto &data : cont)
|
|
{
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
if (bInsertWithKey)
|
|
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
|
{% endif %}
|
|
{% for row in insertStruct.member %}
|
|
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
|
{% endfor %}
|
|
|
|
if (!m_query->exec(m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
{% if insertStruct.serialMember.cppMemberName %}
|
|
if (data.{{cpp_struct.primaryKey.cppMemberName}} == {{cpp_struct.primaryKey.cppDefault}})
|
|
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
|
{% endif %}
|
|
}
|
|
}
|
|
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
if (bInsertWithKey)
|
|
fixUpSequence{{ cpp_struct.nameCc }}();
|
|
{% endif %}
|
|
|
|
}
|
|
{% endfor %}
|
|
return true;
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::upsert(std::vector<Database::{{ cpp_struct.name }}> &cont)
|
|
{
|
|
if (cont.empty())
|
|
return true;
|
|
|
|
{% for insertStruct in cpp_struct.insertStructures %}
|
|
{
|
|
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
|
|
|
QString keyColumnInsertKey;
|
|
QString keyColumnInsertKeyConflict;
|
|
QString keyColumnInsertVal;
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
const bool bInsertWithKey = true;
|
|
keyColumnInsertVal = QStringLiteral(" :{{ insertStruct.primaryKey.dbColumnName }}, ");
|
|
keyColumnInsertKey = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }}, ");
|
|
{% endif %}
|
|
// the first element determines the stmt to be used
|
|
keyColumnInsertKeyConflict = QStringLiteral("{{ insertStruct.primaryKey.dbColumnName }} ");
|
|
|
|
const QString stmt(QStringLiteral("INSERT INTO ") + tableName +
|
|
QStringLiteral(" (") + keyColumnInsertKey +
|
|
QStringLiteral("{% for row in insertStruct.member %} {{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" ) VALUES (") + keyColumnInsertVal +
|
|
QStringLiteral("{% for row in insertStruct.member %}:{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %} )") +
|
|
QStringLiteral(" ON CONFLICT (") + keyColumnInsertKeyConflict + QStringLiteral(") DO UPDATE ") +
|
|
QStringLiteral(" SET"
|
|
" {% for row in insertStruct.member %}{{ row.dbColumnName }} = :{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" WHERE excluded.{{ insertStruct.primaryKey.dbColumnName }} = :{{ insertStruct.primaryKey.dbColumnName }}"));
|
|
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
if (!m_query->prepare(stmt))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
for (auto &data : cont)
|
|
{
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
if (bInsertWithKey)
|
|
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
|
{% endif %}
|
|
{% for row in insertStruct.member %}
|
|
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
|
{% endfor %}
|
|
|
|
if (!m_query->exec(m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
{% if insertStruct.serialMember.cppMemberName %}
|
|
if (data.{{cpp_struct.primaryKey.cppMemberName}} == {{cpp_struct.primaryKey.cppDefault}})
|
|
data.{{ insertStruct.serialMember.cppMemberName }} = m_query->lastInsertId(){{ insertStruct.serialMember.cppFromQvPost }};
|
|
{% endif %}
|
|
}
|
|
}
|
|
|
|
{% if forloop.first and cpp_struct.primaryKey.dbHasSequence %}
|
|
if (bInsertWithKey)
|
|
fixUpSequence{{ cpp_struct.nameCc }}();
|
|
{% endif %}
|
|
|
|
}
|
|
{% endfor %}
|
|
return true;
|
|
}
|
|
|
|
// current only implemented for 'plain' structures with only one affected table
|
|
bool DatabaseInterfaceImpl::update(const std::vector<Database::{{ cpp_struct.name }}> &cont)
|
|
{
|
|
if (cont.empty())
|
|
return true;
|
|
|
|
{% for insertStruct in cpp_struct.insertStructures %}
|
|
{
|
|
const QString tableName(getTableName(QStringLiteral("{{ insertStruct.name }}")));
|
|
const QString stmt(QStringLiteral("UPDATE ") + tableName +
|
|
QStringLiteral(" SET"
|
|
" {% for row in insertStruct.member %}{{ row.dbColumnName }} = :{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" WHERE {{ insertStruct.primaryKey.dbColumnName }} = :{{ insertStruct.primaryKey.dbColumnName }}"));
|
|
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
if (!m_query->prepare(stmt))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
for (const auto &data : cont)
|
|
{
|
|
{% for row in insertStruct.member %}
|
|
m_query->bindValue(QStringLiteral(":{{ row.dbColumnName }}"), {{ row.cppToQvPre }}data.{{ row.cppMemberName }}{{ row.cppToQvPost }});
|
|
{% endfor %}
|
|
{% if insertStruct.serialMember.cppMemberName %}
|
|
m_query->bindValue(QStringLiteral(":{{ insertStruct.primaryKey.dbColumnName }}"), data.{{ insertStruct.serialMember.cppMemberName }});
|
|
{% endif %}
|
|
|
|
if (!m_query->exec(m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
{% endfor %}
|
|
return true;
|
|
}
|
|
{% endif %}
|
|
|
|
bool DatabaseInterfaceImpl::select(QVector<Database::{{ cpp_struct.name }}> &dataVec)
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
const auto cb =[&dataVec] (const Database::{{ cpp_struct.name }} &data)
|
|
{
|
|
dataVec.push_back(data);
|
|
};
|
|
return selectPrepareInternal{{ cpp_struct.name }}(QString()) && selectFetchInternal{{ cpp_struct.name }}(cb);
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::select(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb)
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
return selectPrepareInternal{{ cpp_struct.name }}(QString()) && selectFetchInternal{{ cpp_struct.name }}(cb);
|
|
}
|
|
|
|
{% for fk in cpp_struct.selectRemoveMember %}
|
|
bool DatabaseInterfaceImpl::selectBy{{ fk.cppMemberNameCc }}(QVector<Database::{{ cpp_struct.name }}> &dataVec, const {{ fk.cppType }} &{{ fk.cppMemberName }}, const QString &orderBy)
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
if (!selectPrepareInternal{{ cpp_struct.name }}(QStringLiteral(" WHERE {{ fk.dbColumnName }} = :{{ fk.dbColumnName }}") + orderBy))
|
|
{
|
|
ERROR_LOG(m_logger) << "Error preparing query: " << m_query->lastError().text();
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
m_query->bindValue(QStringLiteral(":{{ fk.dbColumnName }}"), {{ fk.cppToQvPre }}{{ fk.cppMemberName }}{{ fk.cppToQvPost }});
|
|
const auto cb =[&dataVec] (const Database::{{ cpp_struct.name }} &data)
|
|
{
|
|
dataVec.push_back(data);
|
|
};
|
|
return selectFetchInternal{{ cpp_struct.name }}(cb);
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::selectBy{{ fk.cppMemberNameCc }}(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb, const {{ fk.cppType }} &{{ fk.cppMemberName }}, const QString &orderBy)
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
if (!selectPrepareInternal{{ cpp_struct.name }}(QStringLiteral(" WHERE {{ fk.dbColumnName }} = :{{ fk.dbColumnName }}") + orderBy))
|
|
{
|
|
ERROR_LOG(m_logger) << "Error preparing query: " << m_query->lastError().text();
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
m_query->bindValue(QStringLiteral(":{{ fk.dbColumnName }}"), {{ fk.cppToQvPre }}{{ fk.cppMemberName }}{{ fk.cppToQvPost }});
|
|
return selectFetchInternal{{ cpp_struct.name }}(cb);
|
|
}
|
|
{% endfor %}
|
|
|
|
bool DatabaseInterfaceImpl::selectPrepareInternal{{ cpp_struct.name }}(const QString &where)
|
|
{
|
|
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.viewTableName }}")));
|
|
const QString stmt(QStringLiteral("SELECT {% for row in cpp_struct.viewMember %}{{ row.dbColumnNameView }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" FROM ") + tableName + where);
|
|
return m_query->prepare(stmt);
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::selectFetchInternal{{ cpp_struct.name }}(const std::function<void(const Database::{{ cpp_struct.name }} &data)> &cb)
|
|
{
|
|
if (!m_query->exec(m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
Database::{{ cpp_struct.name }} data;
|
|
while (m_query->next())
|
|
{
|
|
int i = 0;
|
|
{% for row in cpp_struct.viewMember %}
|
|
data.{{ row.cppMemberName }}{{ row.cppFromQvPre1 }} = {{ row.cppFromQvPre2 }}m_query->value(i++){{ row.cppFromQvPost }};{% endfor %}
|
|
cb(data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::select{{ cpp_struct.name }}({{ cpp_struct.primaryKey.cppType }} {{ cpp_struct.primaryKey.cppMemberName }}, Database::{{ cpp_struct.name }} &data)
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
int iCnt = 0;
|
|
const auto cb =[&data, &iCnt] (const Database::{{ cpp_struct.name }} &content)
|
|
{
|
|
data = content;
|
|
++iCnt;
|
|
};
|
|
const QString where = QStringLiteral(" WHERE {{ cpp_struct.primaryKey.dbColumnName }} = %1").arg({{ cpp_struct.primaryKey.cppMemberName }});
|
|
if (!selectPrepareInternal{{ cpp_struct.name }}(where) || !selectFetchInternal{{ cpp_struct.name }}(cb))
|
|
return false;
|
|
|
|
return (iCnt == 1);
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::remove{{ cpp_struct.name }}({{ cpp_struct.primaryKey.cppType }} {{ cpp_struct.primaryKey.cppMemberName }})
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.primaryKey.dbTableName }}")));
|
|
const QString stmt(QStringLiteral("DELETE FROM ") + tableName +
|
|
QStringLiteral(" WHERE {{ cpp_struct.primaryKey.dbColumnName }} = ") +
|
|
QString::number({{ cpp_struct.primaryKey.cppMemberName }}));
|
|
|
|
if (!m_query->exec(stmt, m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
{% if cpp_struct.deleteWithoutPkAllowed %} {% for fk in cpp_struct.selectRemoveMember %}
|
|
bool DatabaseInterfaceImpl::remove{{ cpp_struct.nameCc }}By{{ fk.cppMemberNameCc }}(const {{ fk.cppType }} &{{ fk.cppMemberName }})
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.primaryKey.dbTableName }}")));
|
|
const QString stmt(QStringLiteral("DELETE FROM ") + tableName +
|
|
QStringLiteral(" WHERE {{ fk.dbColumnName }} = :{{ fk.cppMemberName }}"));
|
|
|
|
if (!m_query->prepare(stmt))
|
|
{
|
|
ERROR_LOG(m_logger) << "Error preparing query: " << m_query->lastError().text();
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
m_query->bindValue(QStringLiteral(":{{ fk.cppMemberName }}"), {{ fk.cppToQvPre }}{{ fk.cppMemberName }}{{ fk.cppToQvPost }});
|
|
|
|
|
|
return m_query->exec(m_bEmitMessageOnError);
|
|
}
|
|
{% endfor %} {% endif %}
|
|
bool DatabaseInterfaceImpl::fixUpSequence{{ cpp_struct.nameCc }}()
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.primaryKey.dbTableName }}")));
|
|
const QString stmt(QStringLiteral("SELECT setval('") + tableName + QStringLiteral("_{{ cpp_struct.primaryKey.dbColumnName }}_seq', COALESCE((SELECT MAX({{ cpp_struct.primaryKey.dbColumnName }})+1 FROM ") +
|
|
tableName + QStringLiteral("), 1),false)"));
|
|
|
|
if (!m_query->exec(stmt, m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DatabaseInterfaceImpl::truncate{{ cpp_struct.nameCc }}()
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
const QString tableName(getTableName(QStringLiteral("{{ cpp_struct.primaryKey.dbTableName }}")));
|
|
const QString stmt(QStringLiteral("TRUNCATE TABLE ") + tableName + QStringLiteral(" CASCADE"));
|
|
|
|
if (!m_query->exec(stmt, m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
// Database::{{ cpp_struct.name }} end
|
|
{% endfor %}
|
|
|
|
{% for ds in data_structs %}
|
|
bool DatabaseInterfaceImpl::select(QVector<Database::{{ ds.name }}> &dataVec)
|
|
{
|
|
SqlQueryJanitor janitor(m_query);
|
|
const QString tableName(getTableName(QStringLiteral("{{ ds.viewTableName }}")));
|
|
const QString stmt(QStringLiteral("SELECT {% for row in ds.viewMember %}{{ row.dbColumnName }}{% if not forloop.last %}, {% endif %}{% endfor %}"
|
|
" FROM ") + tableName);
|
|
|
|
if (!m_query->exec(stmt, m_bEmitMessageOnError))
|
|
{
|
|
m_lastError = m_query->lastError();
|
|
return false;
|
|
}
|
|
|
|
Database::{{ ds.name }} data;
|
|
while (m_query->next())
|
|
{
|
|
int i = 0;
|
|
{% for row in ds.member %}
|
|
data.{{ row.cppMemberName }}{{ row.cppFromQvPre1 }} = {{ row.cppFromQvPre2 }}m_query->value(i++){{ row.cppFromQvPost }};{% endfor %}
|
|
dataVec.append(data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
{% endfor %}
|
|
} // namespace {{ namespace }}
|
|
{% endautoescape %}
|