Begin work on biergarten data generator pipeline

This commit is contained in:
Aaron Po
2026-04-01 19:33:50 -04:00
parent 581863d69b
commit 23e2199b6b
12 changed files with 1323 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
#pragma once
#include <mutex>
#include <sqlite3.h>
#include <string>
#include <vector>
/// @struct Country
/// @brief Represents a country with geographic identifiers
struct Country {
int id;
std::string name;
std::string iso2; ///< 2-letter ISO code (e.g., "US", "CA")
std::string iso3; ///< 3-letter ISO code (e.g., "USA", "CAN")
};
/// @struct State
/// @brief Represents a state or province with geographic identifiers
struct State {
int id;
std::string name;
std::string iso2; ///< 2-letter state code (e.g., "CA", "ON")
int countryId;
};
/**
* @class SqliteDatabase
* @brief Thread-safe in-memory SQLite database wrapper for geographic data
*
* Manages a local in-memory SQLite database with countries, states, and cities.
* All write operations are serialized via mutex to enable safe concurrent
* access from multiple threads. Uses INSERT OR IGNORE for idempotent
* operations.
*
* Schema Relationships:
* countries (id, name, iso2, iso3)
* ↓ (one-to-many)
* states (id, country_id, name, iso2)
* ↓ (one-to-many)
* cities (id, state_id, country_id, name, latitude, longitude)
*/
class SqliteDatabase {
private:
sqlite3 *db = nullptr; ///< SQLite database connection handle
std::mutex dbMutex; ///< Protects all database operations from race conditions
/// @brief Creates the schema with three related tables and foreign keys
void InitializeSchema();
public:
/// @brief Destructor: safely closes the database connection
~SqliteDatabase();
/// @brief Opens an in-memory SQLite database and initializes the schema
void Initialize();
/// @brief Inserts a country record
/// @param id Unique country identifier
/// @param name Country name
/// @param iso2 2-letter ISO country code
/// @param iso3 3-letter ISO country code
/// @note Thread-safe: uses mutex lock. Idempotent: INSERT OR IGNORE prevents
/// duplicates
void InsertCountry(int id, const std::string &name, const std::string &iso2,
const std::string &iso3);
/// @brief Inserts a state/province record
/// @param id Unique state identifier
/// @param countryId Foreign key reference to parent country
/// @param name State/province name
/// @param iso2 2-letter state code (e.g., "CA", "ON")
/// @note Thread-safe and idempotent via mutex and INSERT OR IGNORE
void InsertState(int id, int countryId, const std::string &name,
const std::string &iso2);
/// @brief Inserts a city record with geographic coordinates
/// @param id Unique city identifier
/// @param stateId Foreign key reference to parent state
/// @param countryId Foreign key reference to parent country
/// @param name City name
/// @param latitude Geographic latitude coordinate (WGS84)
/// @param longitude Geographic longitude coordinate (WGS84)
/// @note Thread-safe and idempotent. Called by multithreaded JSON loader.
void InsertCity(int id, int stateId, int countryId, const std::string &name,
double latitude, double longitude);
/// @brief Queries all cities from the database
/// @return Vector of (city_id, city_name) pairs sorted alphabetically
std::vector<std::pair<int, std::string>> QueryCities();
/// @brief Queries all countries from the database with ISO codes
/// @param limit Maximum number of records to return (0 = all)
/// @return Vector of Country structs (includes id, name, iso2, iso3) sorted
/// alphabetically
std::vector<Country> QueryCountries(int limit = 0);
/// @brief Queries all states from the database with ISO codes
/// @param limit Maximum number of records to return (0 = all)
/// @return Vector of State structs (includes id, name, iso2, countryId)
/// sorted alphabetically
std::vector<State> QueryStates(int limit = 0);
};