QodeAssist/context/RAGStorage.cpp
2025-02-09 00:04:44 +01:00

166 lines
4.5 KiB
C++

/*
* Copyright (C) 2024 Petr Mironychev
*
* This file is part of QodeAssist.
*
* QodeAssist is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QodeAssist is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
*/
#include "RAGStorage.hpp"
#include <QDir>
#include <QFileInfo>
#include <QSqlError>
#include <QSqlQuery>
namespace QodeAssist::Context {
RAGStorage::RAGStorage(const QString &dbPath, QObject *parent)
: QObject(parent)
, m_dbPath(dbPath)
{}
RAGStorage::~RAGStorage()
{
if (m_db.isOpen()) {
m_db.close();
}
}
bool RAGStorage::init()
{
if (!openDatabase()) {
return false;
}
return createTables();
}
bool RAGStorage::openDatabase()
{
QDir dir(QFileInfo(m_dbPath).absolutePath());
if (!dir.exists()) {
dir.mkpath(".");
}
m_db = QSqlDatabase::addDatabase("QSQLITE", "rag_storage");
m_db.setDatabaseName(m_dbPath);
return m_db.open();
}
bool RAGStorage::createTables()
{
QSqlQuery query(m_db);
return query.exec("CREATE TABLE IF NOT EXISTS file_vectors ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"file_path TEXT UNIQUE NOT NULL,"
"vector_data BLOB NOT NULL,"
"last_modified DATETIME NOT NULL,"
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
"updated_at DATETIME DEFAULT CURRENT_TIMESTAMP"
")");
}
bool RAGStorage::storeVector(const QString &filePath, const RAGVector &vector)
{
QSqlQuery query(m_db);
query.prepare("INSERT INTO file_vectors (file_path, vector_data, last_modified) "
"VALUES (:path, :vector, :modified)");
query.bindValue(":path", filePath);
query.bindValue(":vector", vectorToBlob(vector));
query.bindValue(":modified", getFileLastModified(filePath));
return query.exec();
}
bool RAGStorage::updateVector(const QString &filePath, const RAGVector &vector)
{
QSqlQuery query(m_db);
query.prepare("UPDATE file_vectors "
"SET vector_data = :vector, last_modified = :modified, "
"updated_at = CURRENT_TIMESTAMP "
"WHERE file_path = :path");
query.bindValue(":vector", vectorToBlob(vector));
query.bindValue(":modified", getFileLastModified(filePath));
query.bindValue(":path", filePath);
return query.exec();
}
std::optional<RAGVector> RAGStorage::getVector(const QString &filePath)
{
QSqlQuery query(m_db);
query.prepare("SELECT vector_data FROM file_vectors WHERE file_path = :path");
query.bindValue(":path", filePath);
if (query.exec() && query.next()) {
return blobToVector(query.value(0).toByteArray());
}
return std::nullopt;
}
bool RAGStorage::needsUpdate(const QString &filePath)
{
QSqlQuery query(m_db);
query.prepare("SELECT last_modified FROM file_vectors WHERE file_path = :path");
query.bindValue(":path", filePath);
if (query.exec() && query.next()) {
QDateTime storedTime = query.value(0).toDateTime();
return storedTime < getFileLastModified(filePath);
}
return true;
}
QStringList RAGStorage::getAllFiles()
{
QStringList files;
QSqlQuery query(m_db);
if (query.exec("SELECT file_path FROM file_vectors")) {
while (query.next()) {
files << query.value(0).toString();
}
}
return files;
}
QDateTime RAGStorage::getFileLastModified(const QString &filePath)
{
return QFileInfo(filePath).lastModified();
}
RAGVector RAGStorage::blobToVector(const QByteArray &blob)
{
RAGVector vector;
const float *data = reinterpret_cast<const float *>(blob.constData());
size_t size = blob.size() / sizeof(float);
vector.assign(data, data + size);
return vector;
}
QByteArray RAGStorage::vectorToBlob(const RAGVector &vector)
{
return QByteArray(reinterpret_cast<const char *>(vector.data()), vector.size() * sizeof(float));
}
QString RAGStorage::dbPath() const
{
return m_dbPath;
}
} // namespace QodeAssist::Context