Add SQLite profile repository and Qt SQL dependency

This commit is contained in:
Keith Smith
2026-03-01 09:06:31 -07:00
parent 6d147894c5
commit fba7336f69
4 changed files with 203 additions and 2 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build/

View File

@@ -10,18 +10,20 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
find_package(Qt6 6.2 REQUIRED COMPONENTS Widgets) find_package(Qt6 6.2 REQUIRED COMPONENTS Widgets Sql)
qt_standard_project_setup() qt_standard_project_setup()
add_executable(orbithub add_executable(orbithub
src/main.cpp src/main.cpp
src/profile_repository.cpp
src/profile_repository.h
src/profiles_window.cpp src/profiles_window.cpp
src/profiles_window.h src/profiles_window.h
src/session_window.cpp src/session_window.cpp
src/session_window.h src/session_window.h
) )
target_link_libraries(orbithub PRIVATE Qt6::Widgets) target_link_libraries(orbithub PRIVATE Qt6::Widgets Qt6::Sql)
install(TARGETS orbithub RUNTIME DESTINATION bin) install(TARGETS orbithub RUNTIME DESTINATION bin)

163
src/profile_repository.cpp Normal file
View File

@@ -0,0 +1,163 @@
#include "profile_repository.h"
#include <QDir>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QStandardPaths>
#include <QVariant>
namespace {
QString buildDatabasePath()
{
QString appDataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
if (appDataPath.isEmpty()) {
appDataPath = QDir::currentPath();
}
QDir dataDir(appDataPath);
dataDir.mkpath(QStringLiteral("."));
return dataDir.filePath(QStringLiteral("orbithub_profiles.sqlite"));
}
}
ProfileRepository::ProfileRepository() : m_connectionName(QStringLiteral("orbithub_main"))
{
if (!initializeDatabase()) {
QSqlDatabase::removeDatabase(m_connectionName);
}
}
ProfileRepository::~ProfileRepository()
{
if (QSqlDatabase::contains(m_connectionName)) {
QSqlDatabase db = QSqlDatabase::database(m_connectionName);
if (db.isOpen()) {
db.close();
}
}
QSqlDatabase::removeDatabase(m_connectionName);
}
QString ProfileRepository::initError() const
{
return m_initError;
}
std::vector<Profile> ProfileRepository::listProfiles(const QString& searchQuery) const
{
std::vector<Profile> result;
if (!QSqlDatabase::contains(m_connectionName)) {
return result;
}
QSqlQuery query(QSqlDatabase::database(m_connectionName));
if (searchQuery.trimmed().isEmpty()) {
query.prepare(QStringLiteral(
"SELECT id, name FROM profiles ORDER BY lower(name) ASC, id ASC"));
} else {
query.prepare(QStringLiteral(
"SELECT id, name FROM profiles "
"WHERE lower(name) LIKE lower(?) "
"ORDER BY lower(name) ASC, id ASC"));
query.addBindValue(QStringLiteral("%") + searchQuery.trimmed() + QStringLiteral("%"));
}
if (!query.exec()) {
return result;
}
while (query.next()) {
result.push_back(Profile{query.value(0).toLongLong(), query.value(1).toString()});
}
return result;
}
std::optional<Profile> ProfileRepository::createProfile(const QString& name) const
{
if (!QSqlDatabase::contains(m_connectionName)) {
return std::nullopt;
}
const QString trimmedName = name.trimmed();
if (trimmedName.isEmpty()) {
return std::nullopt;
}
QSqlQuery query(QSqlDatabase::database(m_connectionName));
query.prepare(QStringLiteral("INSERT INTO profiles(name) VALUES (?)"));
query.addBindValue(trimmedName);
if (!query.exec()) {
return std::nullopt;
}
return Profile{query.lastInsertId().toLongLong(), trimmedName};
}
bool ProfileRepository::updateProfile(qint64 id, const QString& name) const
{
if (!QSqlDatabase::contains(m_connectionName)) {
return false;
}
const QString trimmedName = name.trimmed();
if (trimmedName.isEmpty()) {
return false;
}
QSqlQuery query(QSqlDatabase::database(m_connectionName));
query.prepare(QStringLiteral("UPDATE profiles SET name = ? WHERE id = ?"));
query.addBindValue(trimmedName);
query.addBindValue(id);
if (!query.exec()) {
return false;
}
return query.numRowsAffected() > 0;
}
bool ProfileRepository::deleteProfile(qint64 id) const
{
if (!QSqlDatabase::contains(m_connectionName)) {
return false;
}
QSqlQuery query(QSqlDatabase::database(m_connectionName));
query.prepare(QStringLiteral("DELETE FROM profiles WHERE id = ?"));
query.addBindValue(id);
if (!query.exec()) {
return false;
}
return query.numRowsAffected() > 0;
}
bool ProfileRepository::initializeDatabase()
{
QSqlDatabase database = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), m_connectionName);
database.setDatabaseName(buildDatabasePath());
if (!database.open()) {
m_initError = database.lastError().text();
return false;
}
QSqlQuery query(database);
const bool created = query.exec(QStringLiteral(
"CREATE TABLE IF NOT EXISTS profiles ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT NOT NULL UNIQUE"
")"));
if (!created) {
m_initError = query.lastError().text();
}
return created;
}

35
src/profile_repository.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef ORBITHUB_PROFILE_REPOSITORY_H
#define ORBITHUB_PROFILE_REPOSITORY_H
#include <QString>
#include <optional>
#include <vector>
struct Profile
{
qint64 id;
QString name;
};
class ProfileRepository
{
public:
ProfileRepository();
~ProfileRepository();
QString initError() const;
std::vector<Profile> listProfiles(const QString& searchQuery = QString()) const;
std::optional<Profile> createProfile(const QString& name) const;
bool updateProfile(qint64 id, const QString& name) const;
bool deleteProfile(qint64 id) const;
private:
QString m_connectionName;
QString m_initError;
bool initializeDatabase();
};
#endif