mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-07-16 17:47:22 +00:00
refactor(pipeline): restructure config, add PromptDirectory, consolidate SQLite layer (#217)
* Refactor ApplicationOptions to separate config concerns * add prompt dir app option * readability updates: remove magic numbers, update comments * codebase formatting * Update docs * Extract argument parsing, timer out of
This commit is contained in:
85
tooling/pipeline/src/services/prompt_directory.cc
Normal file
85
tooling/pipeline/src/services/prompt_directory.cc
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @file services/prompt_directory.cc
|
||||
* @brief PromptDirectory implementation: validates the directory at
|
||||
* construction and loads named prompt files on demand with in-process caching.
|
||||
*/
|
||||
|
||||
#include "services/prompt_directory.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// PromptDirectory
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
PromptDirectory::PromptDirectory(const std::filesystem::path& prompt_dir)
|
||||
: prompt_dir_(prompt_dir) {
|
||||
std::error_code ec;
|
||||
|
||||
// Scenario 4: directory must exist.
|
||||
if (!std::filesystem::exists(prompt_dir_, ec) || ec) {
|
||||
throw std::runtime_error(
|
||||
"PromptDirectory: prompt directory does not exist: " +
|
||||
prompt_dir_.string());
|
||||
}
|
||||
|
||||
// Scenario 4: path must be a directory, not a file.
|
||||
if (!std::filesystem::is_directory(prompt_dir_, ec) || ec) {
|
||||
throw std::runtime_error(
|
||||
"PromptDirectory: prompt directory path is not a directory: " +
|
||||
prompt_dir_.string());
|
||||
}
|
||||
|
||||
// Scenario 4: directory must be readable (probe with directory_iterator).
|
||||
std::filesystem::directory_iterator probe(prompt_dir_, ec);
|
||||
if (ec) {
|
||||
throw std::runtime_error(
|
||||
"PromptDirectory: prompt directory is not readable: " +
|
||||
prompt_dir_.string() + " (" + ec.message() + ")");
|
||||
}
|
||||
|
||||
spdlog::info("[PromptDirectory] Resolved prompt directory: {}",
|
||||
prompt_dir_.string());
|
||||
}
|
||||
|
||||
std::string PromptDirectory::Load(std::string_view key) {
|
||||
const std::string key_str(key);
|
||||
|
||||
// Return cached content if already loaded during this run.
|
||||
const auto cache_it = cache_.find(key_str);
|
||||
if (cache_it != cache_.end()) {
|
||||
return cache_it->second;
|
||||
}
|
||||
|
||||
// Scenario 3: resolve <prompt_dir>/<key>.md and require it to exist.
|
||||
const std::filesystem::path file_path =
|
||||
prompt_dir_ / std::filesystem::path(key_str + ".md");
|
||||
|
||||
std::ifstream file(file_path);
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error(
|
||||
"PromptDirectory: prompt file not found for key '" + key_str +
|
||||
"': " + file_path.string());
|
||||
}
|
||||
|
||||
std::string content((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
if (content.empty()) {
|
||||
throw std::runtime_error("PromptDirectory: prompt file for key '" +
|
||||
key_str + "' is empty: " + file_path.string());
|
||||
}
|
||||
|
||||
spdlog::info("[PromptDirectory] Loaded prompt '{}' from '{}' ({} chars)",
|
||||
key_str, file_path.string(), content.size());
|
||||
|
||||
cache_.emplace(key_str, content);
|
||||
return content;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* @file services/sqlite/build_database_path.cc
|
||||
* @brief SqliteExportService::BuildDatabasePath() implementation.
|
||||
*/
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include "services/sqlite_export_service.h"
|
||||
|
||||
std::filesystem::path SqliteExportService::BuildDatabasePath() const {
|
||||
std::filesystem::path base_filename("biergarten_seed_" + run_timestamp_utc_ +
|
||||
".sqlite");
|
||||
std::filesystem::path candidate =
|
||||
std::filesystem::current_path() / base_filename;
|
||||
|
||||
for (int suffix = 1; std::filesystem::exists(candidate); ++suffix) {
|
||||
candidate = std::filesystem::current_path() /
|
||||
std::filesystem::path("biergarten_seed_" + run_timestamp_utc_ +
|
||||
"-" + std::to_string(suffix) + ".sqlite");
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "services/sqlite_export_service.h"
|
||||
#include "services/sqlite_export_service_helpers.h"
|
||||
|
||||
|
||||
void SqliteExportService::Finalize() {
|
||||
if (db_handle_ == nullptr) {
|
||||
return;
|
||||
|
||||
@@ -10,7 +10,8 @@ void SqliteDatabaseDeleter::operator()(sqlite3* handle) const noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void SqliteStatementDeleter::operator()(sqlite3_stmt* statement) const noexcept {
|
||||
void SqliteStatementDeleter::operator()(
|
||||
sqlite3_stmt* statement) const noexcept {
|
||||
if (statement != nullptr) {
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
@@ -23,7 +24,6 @@ void ThrowSqliteError(sqlite3* db_handle, std::string_view action) {
|
||||
}
|
||||
|
||||
SqliteDatabaseHandle OpenDatabase(const std::filesystem::path& path) {
|
||||
|
||||
sqlite3* raw_handle = nullptr;
|
||||
const int result = sqlite3_open(path.string().c_str(), &raw_handle);
|
||||
|
||||
@@ -54,7 +54,8 @@ void ExecSql(const SqliteDatabaseHandle& db_handle, std::string_view sql,
|
||||
}
|
||||
}
|
||||
|
||||
void RollbackTransactionNoThrow(const SqliteDatabaseHandle& db_handle) noexcept {
|
||||
void RollbackTransactionNoThrow(
|
||||
const SqliteDatabaseHandle& db_handle) noexcept {
|
||||
if (!db_handle) {
|
||||
return;
|
||||
}
|
||||
@@ -63,4 +64,3 @@ void RollbackTransactionNoThrow(const SqliteDatabaseHandle& db_handle) noexcept
|
||||
}
|
||||
|
||||
} // namespace sqlite_export_service_internal
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "services/sqlite_statement_helpers.h"
|
||||
#include "services/sqlite_connection_helpers.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <boost/json.hpp>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "services/sqlite_connection_helpers.h"
|
||||
|
||||
namespace sqlite_export_service_internal {
|
||||
|
||||
@@ -86,16 +87,6 @@ sqlite3_int64 LastInsertRowId(const SqliteDatabaseHandle& db_handle) {
|
||||
return sqlite3_last_insert_rowid(db_handle.get());
|
||||
}
|
||||
|
||||
std::string SerializeLocalLanguages(
|
||||
const std::vector<std::string>& local_languages) {
|
||||
boost::json::array array;
|
||||
array.reserve(local_languages.size());
|
||||
for (const auto& language : local_languages) {
|
||||
array.emplace_back(language);
|
||||
}
|
||||
return boost::json::serialize(array);
|
||||
}
|
||||
|
||||
std::string SerializeVector(const std::vector<std::string>& str_vec) {
|
||||
boost::json::array array(str_vec.size());
|
||||
for (const auto& s : str_vec) {
|
||||
@@ -105,4 +96,3 @@ std::string SerializeVector(const std::vector<std::string>& str_vec) {
|
||||
}
|
||||
|
||||
} // namespace sqlite_export_service_internal
|
||||
|
||||
@@ -11,6 +11,19 @@
|
||||
#include "services/sqlite_export_service.h"
|
||||
#include "services/sqlite_export_service_helpers.h"
|
||||
|
||||
std::filesystem::path SqliteExportService::BuildDatabasePath() const {
|
||||
std::filesystem::path base_filename("biergarten_seed_" + run_timestamp_utc_ +
|
||||
".sqlite");
|
||||
std::filesystem::path candidate = output_path_ / base_filename;
|
||||
|
||||
for (int suffix = 1; std::filesystem::exists(candidate); ++suffix) {
|
||||
candidate = output_path_ /
|
||||
std::filesystem::path("biergarten_seed_" + run_timestamp_utc_ +
|
||||
"-" + std::to_string(suffix) + ".sqlite");
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
void SqliteExportService::InitializeSchema() const {
|
||||
sqlite_export_service_internal::ExecSql(
|
||||
@@ -46,7 +59,6 @@ void SqliteExportService::RollbackAndCloseNoThrow() noexcept {
|
||||
location_cache_.clear();
|
||||
}
|
||||
|
||||
|
||||
void SqliteExportService::Initialize() {
|
||||
if (db_handle_ != nullptr) {
|
||||
throw std::runtime_error("SQLite export service is already initialized");
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* @brief SqliteExportService::ProcessRecord() implementation.
|
||||
*/
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
SqliteExportService::SqliteExportService()
|
||||
: date_time_provider_(std::make_unique<SystemDateTimeProvider>()) {}
|
||||
SqliteExportService::SqliteExportService(const ApplicationOptions& options)
|
||||
: date_time_provider_(std::make_unique<SystemDateTimeProvider>()),
|
||||
output_path_(options.pipeline.output_path) {}
|
||||
|
||||
SqliteExportService::~SqliteExportService() {
|
||||
if (db_handle_ != nullptr) {
|
||||
RollbackAndCloseNoThrow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user