Initial commit

This commit is contained in:
user
2026-07-12 14:34:52 +04:00
commit 3abf6bd9c2
557 changed files with 68706 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
#include "database_manager.h"
#include "config.h"
#include "execute_sql_file.h"
#include <QFile>
#include <QSqlError>
#include <qsqldatabase.h>
DatabaseManager::~DatabaseManager() {
disconnectDefaultDatabase();
QString defaultConnectionName = QSqlDatabase::database().connectionName();
QSqlDatabase::removeDatabase(QSqlDatabase::database().connectionName());
qInfo() << "Database with default connection name:" << defaultConnectionName
<< "was removed";
}
DatabaseManager::CreateDatabaseResult
DatabaseManager::createDefaultDatabaseIfMissing(
const QString &databaseFileName) {
if (QFile::exists(databaseFileName)) {
qInfo()
<< "Database file name already exists and will not be created again:"
<< databaseFileName;
return CreateDatabaseResult::AlreadyExists;
}
if (!connectToDefaultDatabase(databaseFileName)) {
qWarning() << "Failed to create and connect to the database";
return CreateDatabaseResult::Error;
}
// Execute SQL files to initialize the database
QStringList sqlFiles = {":/sql/create_tables.sql", ":/sql/create_indexes.sql",
":/sql/create_views.sql", ":/sql/create_triggers.sql",
":/sql/insert_role.sql"};
#ifndef NDEBUG
QStringList additionalSqlFiles = {
":/sql/insert_genre.sql", ":/sql/insert_hall.sql",
":/sql/insert_movie.sql", ":/sql/insert_user.sql"};
sqlFiles.append(additionalSqlFiles);
#endif
QSqlDatabase defaultDatabase = QSqlDatabase::database();
bool success = executeSqlFiles(sqlFiles, defaultDatabase);
disconnectDefaultDatabase();
if (success) {
qInfo() << "Database created and initialized successfully";
return CreateDatabaseResult::Success;
}
qWarning() << "Failed to execute initialization SQL files";
if (QFile::remove(databaseFileName)) {
qInfo() << "Database file deleted due to initialization failure:"
<< databaseFileName;
} else {
qWarning() << "Failed to delete database file:" << databaseFileName;
}
return CreateDatabaseResult::Error;
}
bool DatabaseManager::connectToDefaultDatabase(
const QString &databaseFileName) {
QSqlDatabase defaultDatabase = QSqlDatabase::database();
defaultDatabase.setDatabaseName(databaseFileName);
if (defaultDatabase.isValid() && defaultDatabase.isOpen()) {
qInfo() << "Database is already connected";
return true;
}
// Constructor does not open/close the connection
defaultDatabase = QSqlDatabase::addDatabase(DATABASE_DRIVER);
defaultDatabase.setDatabaseName(databaseFileName);
if (!defaultDatabase.open()) {
qWarning() << "Failed to connect to the database:" << databaseFileName;
return false;
}
qDebug() << "Database was connected successfully: Connection name:"
<< defaultDatabase.connectionName();
return true;
}
void DatabaseManager::disconnectDefaultDatabase() {
QSqlDatabase defaultDatabase = QSqlDatabase::database();
if (defaultDatabase.isOpen()) {
defaultDatabase.close();
qInfo() << "Database disconnected";
}
}
bool DatabaseManager::executeSqlFiles(const QStringList &filePaths,
QSqlDatabase &database) {
ExecuteSqlFile executor(database);
for (const QString &filePath : filePaths) {
qInfo() << "Executing SQL file:" << filePath;
if (!executor(filePath)) {
qWarning() << "Failed to execute SQL file:" << filePath;
return false;
}
}
return true;
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef DATABASE_MANAGER_H
#define DATABASE_MANAGER_H
#include <QMutex>
#include <QSqlDatabase>
#include <QString>
class DatabaseManager {
public:
enum class CreateDatabaseResult { Success, AlreadyExists, Error };
private:
~DatabaseManager();
DatabaseManager(const DatabaseManager &) = delete;
DatabaseManager &operator=(const DatabaseManager &) = delete;
public:
static CreateDatabaseResult
createDefaultDatabaseIfMissing(const QString &databaseFileName);
static bool connectToDefaultDatabase(const QString &databaseFileName);
static void disconnectDefaultDatabase();
private:
static bool databaseFileExists(const QString &databaseName, QSqlDatabase &db);
static bool executeSqlFiles(const QStringList &filePaths, QSqlDatabase &db);
};
#endif // DATABASE_MANAGER_H
+108
View File
@@ -0,0 +1,108 @@
#include "execute_sql_file.h"
#include <QRegularExpression>
ExecuteSqlFile::ExecuteSqlFile(QSqlDatabase &db)
: db_(db), delimiter_(";") { // Default delimiter is ";"
// Constructor does not open/close the connection
}
bool ExecuteSqlFile::operator()(const QString &filePath) {
// Ensure the database connection is open
if (!db_.isOpen()) {
qWarning() << "Database connection is not open";
return false;
}
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "Failed to open file:" << filePath;
return false;
}
QTextStream in(&file);
QString sqlContent = in.readAll();
file.close();
QStringList statements = sqlContent.split("\n", Qt::SkipEmptyParts);
qInfo() << "Executing SQL file:" << filePath;
return processStatements(statements);
}
bool ExecuteSqlFile::processStatements(QStringList &statements) {
QString currentStatement;
for (QString &line : statements) {
qInfo() << "Processing line:" << line;
if (!processLine(line, currentStatement)) {
return false;
}
}
// Execute any remaining statement
if (!currentStatement.isEmpty() && !executeStatement(currentStatement)) {
return false;
}
return true;
}
bool ExecuteSqlFile::processLine(QString &line, QString &currentStatement) {
if (!filterLine(line)) {
qInfo() << "Line is empty after filtering";
return true; // Line was empty after filtering
}
if (processDelimiterChange(line)) {
qInfo() << "Delimiter changed to:" << delimiter_;
return true;
}
currentStatement += line + " ";
auto delimiterIndex = currentStatement.lastIndexOf(delimiter_);
if (delimiterIndex == -1) {
qInfo() << "Delimiter not found, current statement is not finished";
return true;
}
qInfo() << "Statement finished, delimiter found at index:" << delimiterIndex;
// Execute the current statement
QString completedStatement =
currentStatement.replace(delimiter_, ";").trimmed();
if (!executeStatement(completedStatement)) {
qWarning() << "Failed to execute statement:" << completedStatement;
return false; // Execution failed
}
qInfo() << "Successfully executed statement:" << completedStatement;
currentStatement.clear();
return true;
}
bool ExecuteSqlFile::processDelimiterChange(QString &line) {
QRegularExpression regex(R"(^DELIMITER\s+(\S+))");
QRegularExpressionMatch match = regex.match(line);
if (!match.hasMatch()) {
return false;
}
delimiter_ = match.captured(1); // Update the delimiter_
return true;
}
bool ExecuteSqlFile::filterLine(QString &line) {
line = line.section("--", 0, 0).trimmed(); // Remove comments and trim
return !line.isEmpty(); // Return true if line is not empty
}
bool ExecuteSqlFile::executeStatement(const QString &statement) const {
QSqlQuery query(db_);
if (!query.exec(statement)) {
qWarning() << "Error:" << query.lastError().text();
return false;
}
return true;
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef EXECUTE_SQL_FILE_H
#define EXECUTE_SQL_FILE_H
#include <QDebug>
#include <QFile>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QTextStream>
class ExecuteSqlFile {
private:
QSqlDatabase &db_; // Reference to the database handler
// Tracks if the parser is inside a trigger block
bool insideTrigger_ = false;
// Delimiter for SQL statements
QString delimiter_;
public:
// Constructor to initialize the database handler
explicit ExecuteSqlFile(QSqlDatabase &db);
// Executes the SQL commands from the given file
bool operator()(const QString &filePath);
private:
// Executes a single SQL statement
bool executeStatement(const QString &statement) const;
// Filter out comments and empty lines
bool filterLine(QString &line);
// Processes the DELIMITER command
bool processDelimiterChange(QString &line);
// Processes a single line of SQL and updates the current state
bool processLine(QString &line, QString &currentStatement);
// Processes a block of SQL statements, handling triggers separately
bool processStatements(QStringList &statements);
};
#endif // EXECUTE_SQL_FILE_H
+26
View File
@@ -0,0 +1,26 @@
#ifndef TABLE_INFO_INTERFACE_H
#define TABLE_INFO_INTERFACE_H
#include <QMetaType>
#include <QString>
class TableInfoInterface {
public:
virtual ~TableInfoInterface() {}
virtual QMetaType::Type
columnMetaType(const QString &columnName) const noexcept = 0;
virtual QString columnName(qint32 columnIndex) const noexcept = 0;
virtual QString databaseTableName() const noexcept = 0;
virtual QStringList columnNames() const noexcept = 0;
virtual qint32 columnIndex(const QString &columnName) const noexcept = 0;
virtual void
setDatabaseTableName(const QString &databaseTableName) noexcept = 0;
};
#endif