Files
ORC-Gallery-Linux/src/databasemanager.cpp
T
2025-11-15 21:49:04 -05:00

223 lines
6.4 KiB
C++

#include "databasemanager.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QVariant>
#include <QFileInfo>
DatabaseManager::DatabaseManager(QObject *parent)
: QObject(parent)
, m_initialized(false)
{
// Initialize search cache
m_searchCache.clear();
// Create index on ocr_text if it doesn't exist
// This will be executed once the database is initialized
}
DatabaseManager::~DatabaseManager()
{
if (m_db.isOpen()) {
m_db.close();
}
}
bool DatabaseManager::initialize(const QString &dbPath)
{
// Check if database is already initialized
if (m_initialized) {
return true;
}
// Check if file exists
QFileInfo fileInfo(dbPath);
if (!fileInfo.exists() || !fileInfo.isFile()) {
qDebug() << "Database file does not exist:" << dbPath;
return false;
}
// Set up database connection
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setDatabaseName(dbPath);
// Open database
if (!m_db.open()) {
qDebug() << "Failed to open database:" << m_db.lastError().text();
return false;
}
// Verify required table exists
QSqlQuery query;
if (!query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='ocr_results'")) {
qDebug() << "Failed to execute query:" << query.lastError().text();
m_db.close();
return false;
}
if (!query.next()) {
qDebug() << "The required table 'ocr_results' does not exist in the database.";
m_db.close();
return false;
}
// Verify the table has the required columns
if (!query.exec("PRAGMA table_info(ocr_results)")) {
qDebug() << "Failed to get table info:" << query.lastError().text();
m_db.close();
return false;
}
bool hasFullPath = false;
bool hasOcrText = false;
while (query.next()) {
QString columnName = query.value(1).toString();
if (columnName == "full_path") hasFullPath = true;
if (columnName == "ocr_text") hasOcrText = true;
}
if (!hasFullPath || !hasOcrText) {
qDebug() << "Missing required columns in ocr_results table. Need 'full_path' and 'ocr_text'";
m_db.close();
return false;
}
// Create an index on the ocr_text column if it doesn't exist
// This will speed up text searches dramatically
query.exec("CREATE INDEX IF NOT EXISTS idx_ocr_text ON ocr_results(ocr_text)");
m_initialized = true;
qDebug() << "Database initialized successfully.";
return true;
}
QList<DatabaseManager::ImageItem> DatabaseManager::getAllImages()
{
QList<ImageItem> images;
if (!m_initialized) {
qDebug() << "Database not initialized.";
return images;
}
// Verify database is still connected
if (!m_db.isOpen() && !m_db.open()) {
qDebug() << "Database connection lost and cannot be reopened:" << m_db.lastError().text();
m_initialized = false;
return images;
}
// Start transaction to speed up query
m_db.transaction();
QSqlQuery query;
query.prepare("SELECT full_path, ocr_text FROM ocr_results");
if (!query.exec()) {
qDebug() << "Failed to fetch images:" << query.lastError().text();
return images;
}
// Check if files exist as we add them
// Reserve space for results to avoid reallocations
images.reserve(query.size() > 0 ? query.size() : 100);
while (query.next()) {
ImageItem item;
item.filePath = query.value(0).toString();
item.ocrText = query.value(1).toString();
// Only add images that have a non-empty path
if (!item.filePath.isEmpty()) {
images.append(item);
}
}
m_db.commit();
return images;
}
QList<DatabaseManager::ImageItem> DatabaseManager::searchImages(const QString &searchText)
{
QList<ImageItem> images;
if (!m_initialized) {
qDebug() << "Database not initialized.";
return images;
}
// Verify database is still connected
if (!m_db.isOpen() && !m_db.open()) {
qDebug() << "Database connection lost and cannot be reopened:" << m_db.lastError().text();
m_initialized = false;
return images;
}
// If search text is empty, return all images
if (searchText.isEmpty()) {
// Clear the search cache when empty search is performed
m_searchCache.clear();
return getAllImages();
}
// Check if we have a cached result for this search query
if (m_searchCache.contains(searchText)) {
return m_searchCache[searchText];
}
// Start transaction to speed up queries
m_db.transaction();
QSqlQuery query;
// Optimize the query based on length of search text
if (searchText.length() <= 3) {
// For short search terms, use a more targeted approach
query.prepare("SELECT full_path, ocr_text FROM ocr_results WHERE ocr_text LIKE :search");
query.bindValue(":search", "%" + searchText + "%");
} else {
// For longer search terms, use LIKE with a more specific pattern at start
// which can utilize indexes better if they exist
query.prepare("SELECT full_path, ocr_text FROM ocr_results WHERE ocr_text LIKE :search OR ocr_text LIKE :wordstart");
query.bindValue(":search", "%" + searchText + "%");
query.bindValue(":wordstart", "% " + searchText + "%");
}
if (!query.exec()) {
qDebug() << "Failed to search images:" << query.lastError().text();
m_db.rollback();
return images;
}
// Reserve space for results to avoid reallocations
images.reserve(query.size() > 0 ? query.size() : 100);
while (query.next()) {
ImageItem item;
item.filePath = query.value(0).toString();
item.ocrText = query.value(1).toString();
// Only add images that have a non-empty path
if (!item.filePath.isEmpty()) {
images.append(item);
}
}
m_db.commit();
// Cache the result for future queries
if (images.size() > 0) {
m_searchCache.insert(searchText, images);
// Limit cache size to avoid memory issues
if (m_searchCache.size() > MAX_CACHE_SIZE) {
// Remove the first key (oldest entry)
if (!m_searchCache.isEmpty()) {
m_searchCache.remove(m_searchCache.firstKey());
}
}
}
return images;
}