diff --git a/tooling/pipeline/includes/data_model/generated_models.h b/tooling/pipeline/includes/data_model/generated_models.h index 7492d23..9d09b99 100644 --- a/tooling/pipeline/includes/data_model/generated_models.h +++ b/tooling/pipeline/includes/data_model/generated_models.h @@ -7,6 +7,7 @@ * enriched data, and complete generation results. */ +#include #include #include "data_model/models.h" @@ -92,22 +93,40 @@ struct EnrichedCity { }; /** - * @brief A brewery's street-level address, distinct from the shared `City` - * it belongs to. Mirrors the backend's `BreweryPostLocation` shape. + * @brief A brewery's address. Owns the `City` it belongs to alongside its + * street-level fields. Mirrors the `brewery_addresses` table and the + * backend's `BreweryPostLocation` shape. * - * Only `postal_code` is populated today -- street-address generation has no - * fixture data or service yet. + * Only `city` and `postal_code` are populated today -- street-address + * generation has no fixture data or service yet, so the address lines stay + * empty. */ -struct Address { +struct BreweryAddress { + City city{}; + std::optional address_line_1{}; + std::optional address_line_2{}; std::string postal_code{}; }; +/** + * @brief A user's address. Owns the `City` it belongs to alongside its + * street-level fields. Mirrors the `user_addresses` table. + * + * Only `city` is populated today; the street-level columns exist for future + * enrichment. + */ +struct UserAddress { + City city{}; + std::optional address_line_1{}; + std::optional address_line_2{}; + std::optional postal_code{}; +}; + /** * @brief Helper struct to store generated brewery data. */ struct BreweryRecord { - City location; - Address address; + BreweryAddress address; BreweryResult brewery; }; @@ -119,7 +138,7 @@ struct BreweryRecord { * consumer can register real accounts from the pipeline's SQLite export. */ struct UserRecord { - City location; + UserAddress address{}; UserResult user; std::string email{}; std::string date_of_birth{}; diff --git a/tooling/pipeline/includes/data_model/models.h b/tooling/pipeline/includes/data_model/models.h index e07a778..7b86f67 100644 --- a/tooling/pipeline/includes/data_model/models.h +++ b/tooling/pipeline/includes/data_model/models.h @@ -60,16 +60,6 @@ struct City { * @brief Local language codes in priority order. */ std::vector local_languages{}; - - /** - * @brief Latitude in decimal degrees. - */ - double latitude{}; - - /** - * @brief Longitude in decimal degrees. - */ - double longitude{}; }; // ============================================================================ diff --git a/tooling/pipeline/includes/services/database/sqlite_export_service.h b/tooling/pipeline/includes/services/database/sqlite_export_service.h index f595ebe..b0dec38 100644 --- a/tooling/pipeline/includes/services/database/sqlite_export_service.h +++ b/tooling/pipeline/includes/services/database/sqlite_export_service.h @@ -63,7 +63,9 @@ class SqliteExportService final : public IExportService { SqliteDatabaseHandle db_handle_; SqliteStatementHandle insert_city_stmt_; SqliteStatementHandle insert_brewery_stmt_; + SqliteStatementHandle insert_brewery_address_stmt_; SqliteStatementHandle insert_user_stmt_; + SqliteStatementHandle insert_user_address_stmt_; bool transaction_open_ = false; std::unordered_map city_cache_; }; diff --git a/tooling/pipeline/includes/services/database/sqlite_statement_helpers.h b/tooling/pipeline/includes/services/database/sqlite_statement_helpers.h index fb8491a..c784c95 100644 --- a/tooling/pipeline/includes/services/database/sqlite_statement_helpers.h +++ b/tooling/pipeline/includes/services/database/sqlite_statement_helpers.h @@ -27,9 +27,7 @@ CREATE TABLE IF NOT EXISTS cities ( country TEXT NOT NULL, iso3166_1 TEXT NOT NULL, local_languages_json TEXT NOT NULL, - latitude REAL NOT NULL, - longitude REAL NOT NULL, - UNIQUE(city, state_province, iso3166_2, country, latitude, longitude) + UNIQUE(city, state_province, iso3166_2, country) ); )sql"; @@ -43,19 +41,16 @@ CREATE TABLE IF NOT EXISTS breweries ( description_en TEXT NOT NULL, name_local TEXT NOT NULL, description_local TEXT NOT NULL, - postal_code TEXT NOT NULL, FOREIGN KEY(city_id) REFERENCES cities(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_breweries_city_id ON breweries(city_id); - )sql"; inline constexpr std::string_view kCreateUsersTableSql = R"sql( CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, - city_id INTEGER NOT NULL, first_name TEXT NOT NULL, last_name TEXT NOT NULL, gender TEXT NOT NULL, @@ -63,12 +58,45 @@ CREATE TABLE IF NOT EXISTS users ( bio TEXT NOT NULL, activity_weight REAL NOT NULL, email TEXT NOT NULL UNIQUE, - date_of_birth TEXT NOT NULL, + date_of_birth TEXT NOT NULL +); + +)sql"; + +inline constexpr std::string_view kCreateBreweryAddressTableSql = R"sql( +CREATE TABLE IF NOT EXISTS brewery_addresses ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + brewery_id INTEGER NOT NULL, + address_line_1 TEXT, + address_line_2 TEXT, + postal_code TEXT NOT NULL, + city_id INTEGER NOT NULL, + FOREIGN KEY(brewery_id) REFERENCES breweries(id) ON DELETE CASCADE, FOREIGN KEY(city_id) REFERENCES cities(id) ON DELETE CASCADE ); -CREATE INDEX IF NOT EXISTS idx_users_city_id ON users(city_id); +CREATE INDEX IF NOT EXISTS idx_brewery_addresses_brewery_id + ON brewery_addresses(brewery_id); +CREATE INDEX IF NOT EXISTS idx_brewery_addresses_city_id + ON brewery_addresses(city_id); +)sql"; +inline constexpr std::string_view kCreateUserAddressTableSql = R"sql( +CREATE TABLE IF NOT EXISTS user_addresses ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL, + address_line_1 TEXT, + address_line_2 TEXT, + postal_code TEXT, + city_id INTEGER NOT NULL, + FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY(city_id) REFERENCES cities(id) ON DELETE CASCADE +); + +CREATE INDEX IF NOT EXISTS idx_user_addresses_user_id + ON user_addresses(user_id); +CREATE INDEX IF NOT EXISTS idx_user_addresses_city_id + ON user_addresses(city_id); )sql"; inline constexpr std::string_view kInsertCitySql = R"sql( @@ -78,10 +106,8 @@ INSERT INTO cities ( iso3166_2, country, iso3166_1, - local_languages_json, - latitude, - longitude -) VALUES (?, ?, ?, ?, ?, ?, ?, ?); + local_languages_json +) VALUES (?, ?, ?, ?, ?, ?); )sql"; inline constexpr std::string_view kInsertBrewerySql = R"sql( @@ -90,14 +116,12 @@ INSERT INTO breweries ( name_en, description_en, name_local, - description_local, - postal_code -) VALUES (?, ?, ?, ?, ?, ?); + description_local +) VALUES (?, ?, ?, ?, ?); )sql"; inline constexpr std::string_view kInsertUserSql = R"sql( INSERT INTO users ( - city_id, first_name, last_name, gender, @@ -106,7 +130,22 @@ INSERT INTO users ( activity_weight, email, date_of_birth -) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); +) VALUES (?, ?, ?, ?, ?, ?, ?, ?); +)sql"; + +inline constexpr std::string_view kInsertBreweryAddressSql = R"sql( +INSERT INTO brewery_addresses ( + brewery_id, + postal_code, + city_id +) VALUES (?, ?, ?); +)sql"; + +inline constexpr std::string_view kInsertUserAddressSql = R"sql( +INSERT INTO user_addresses ( + user_id, + city_id +) VALUES (?, ?); )sql"; // sqlite3_bind_*() parameter indices are 1-based, matching the "?" @@ -118,8 +157,6 @@ enum CityBindIndex { kCityCountryBindIndex, kCityIso31661BindIndex, kCityLanguagesBindIndex, - kCityLatitudeBindIndex, - kCityLongitudeBindIndex, }; enum BreweryBindIndex { @@ -128,12 +165,10 @@ enum BreweryBindIndex { kBreweryEnglishDescriptionBindIndex, kBreweryLocalNameBindIndex, kBreweryLocalDescriptionBindIndex, - kBreweryPostalCodeBindIndex, }; enum UserBindIndex { - kUserCityIdBindIndex = 1, - kUserFirstNameBindIndex, + kUserFirstNameBindIndex = 1, kUserLastNameBindIndex, kUserGenderBindIndex, kUserUsernameBindIndex, @@ -143,6 +178,17 @@ enum UserBindIndex { kUserDateOfBirthBindIndex, }; +enum BreweryAddressBindIndex { + kBreweryAddressBreweryIdBindIndex = 1, + kBreweryAddressPostalCodeBindIndex, + kBreweryAddressCityIdBindIndex, +}; + +enum UserAddressBindIndex { + kUserAddressUserIdBindIndex = 1, + kUserAddressCityIdBindIndex, +}; + SqliteStatementHandle PrepareStatement(const SqliteDatabaseHandle& db_handle, std::string_view sql, const char* action); diff --git a/tooling/pipeline/src/biergarten_pipeline_orchestrator/generate_breweries.cc b/tooling/pipeline/src/biergarten_pipeline_orchestrator/generate_breweries.cc index 70d575f..93d186b 100644 --- a/tooling/pipeline/src/biergarten_pipeline_orchestrator/generate_breweries.cc +++ b/tooling/pipeline/src/biergarten_pipeline_orchestrator/generate_breweries.cc @@ -29,9 +29,10 @@ void BiergartenPipelineOrchestrator::GenerateBreweries( generator_->GenerateBrewery(location, region_context); const std::string postal_code = postal_code_service_->GeneratePostalCode(location); - return BreweryRecord{.location = location, - .address = Address{.postal_code = postal_code}, - .brewery = brewery}; + return BreweryRecord{ + .address = + BreweryAddress{.city = location, .postal_code = postal_code}, + .brewery = brewery}; } catch (const std::exception& e) { ++skipped_count; @@ -51,13 +52,13 @@ void BiergartenPipelineOrchestrator::GenerateBreweries( exporter_->ProcessRecord(record); } catch (const std::exception& export_exception) { ++export_failed_count; - logger_->Log( - {.level = LogLevel::Warn, - .phase = PipelinePhase::BreweryAndBeerGeneration, - .message = std::format("[Pipeline] Generated brewery for '{}' ({}) " - "but SQLite export failed: {}", - record.location.city, record.location.country, - export_exception.what())}); + logger_->Log({.level = LogLevel::Warn, + .phase = PipelinePhase::BreweryAndBeerGeneration, + .message = std::format( + "[Pipeline] Generated brewery for '{}' ({}) " + "but SQLite export failed: {}", + record.address.city.city, record.address.city.country, + export_exception.what())}); } }; diff --git a/tooling/pipeline/src/biergarten_pipeline_orchestrator/generate_users.cc b/tooling/pipeline/src/biergarten_pipeline_orchestrator/generate_users.cc index bbfe52d..a7dfc4b 100644 --- a/tooling/pipeline/src/biergarten_pipeline_orchestrator/generate_users.cc +++ b/tooling/pipeline/src/biergarten_pipeline_orchestrator/generate_users.cc @@ -137,7 +137,7 @@ void BiergartenPipelineOrchestrator::GenerateUsers( generator_->GenerateUser(city, persona, sampled_name); return UserRecord{ - .location = city.location, + .address = UserAddress{.city = city.location}, .user = user, .email = BuildEmail(sampled_name, used_email_local_parts), .date_of_birth = GenerateDateOfBirth(rng), @@ -161,13 +161,13 @@ void BiergartenPipelineOrchestrator::GenerateUsers( } catch (const std::exception& export_exception) { ++export_failed_count; - logger_->Log( - {.level = LogLevel::Warn, - .phase = PipelinePhase::UserGeneration, - .message = std::format("[Pipeline] Generated user for '{}' ({}) but " - "SQLite export failed: {}", - record.location.city, record.location.country, - export_exception.what())}); + logger_->Log({.level = LogLevel::Warn, + .phase = PipelinePhase::UserGeneration, + .message = std::format( + "[Pipeline] Generated user for '{}' ({}) but " + "SQLite export failed: {}", + record.address.city.city, record.address.city.country, + export_exception.what())}); } }; diff --git a/tooling/pipeline/src/biergarten_pipeline_orchestrator/log_results.cc b/tooling/pipeline/src/biergarten_pipeline_orchestrator/log_results.cc index 1ab7393..281a980 100644 --- a/tooling/pipeline/src/biergarten_pipeline_orchestrator/log_results.cc +++ b/tooling/pipeline/src/biergarten_pipeline_orchestrator/log_results.cc @@ -14,7 +14,8 @@ void BiergartenPipelineOrchestrator::LogResults() const { boost::json::array brewery_output; - for (const auto& [location, address, brewery] : generated_breweries_) { + for (const auto& [address, brewery] : generated_breweries_) { + const City& location = address.city; brewery_output.push_back(boost::json::object{ {"name_en", brewery.name_en}, {"description_en", brewery.description_en}, @@ -26,8 +27,6 @@ void BiergartenPipelineOrchestrator::LogResults() const { {"country", location.country}, {"state_province", location.state_province}, {"iso3166_2", location.iso3166_2}, - {"latitude", location.latitude}, - {"longitude", location.longitude}, }}}); } diff --git a/tooling/pipeline/src/services/curated_data/curated_json_data_service.cc b/tooling/pipeline/src/services/curated_data/curated_json_data_service.cc index 4e08a1b..e3fcb64 100644 --- a/tooling/pipeline/src/services/curated_data/curated_json_data_service.cc +++ b/tooling/pipeline/src/services/curated_data/curated_json_data_service.cc @@ -136,8 +136,7 @@ const CityList& CuratedJsonDataService::LoadCities() { const boost::json::value* postal_code = object.if_contains("postal_code"); if (postal_code == nullptr || !postal_code->is_object()) { - throw std::runtime_error( - "Missing or invalid object field: postal_code"); + throw std::runtime_error("Missing or invalid object field: postal_code"); } locations.push_back(City{ @@ -147,8 +146,6 @@ const CityList& CuratedJsonDataService::LoadCities() { .country = ReadRequiredString(object, "country"), .iso3166_1 = ReadRequiredString(object, "iso3166_1"), .local_languages = ReadRequiredStringArray(object, "local_languages"), - .latitude = ReadRequiredNumber(object, "latitude"), - .longitude = ReadRequiredNumber(object, "longitude"), .postal_regex = ReadRequiredStringArray(postal_code->as_object(), "city_regex"), .postal_code_examples = @@ -159,13 +156,21 @@ const CityList& CuratedJsonDataService::LoadCities() { for (auto location : locations) { std::cout << "Location: " << location.city << ", " << location.state_province << ", " << location.iso3166_2 << ", " - << location.country << ", " << location.iso3166_1 << ", " - << location.latitude << ", " << location.longitude << std::endl; + << location.country << ", " << location.iso3166_1 << "\n"; for (const auto& regex : location.postal_regex) { - std::cout << " Postal regex: " << regex << std::endl; + std::cout << " Postal regex: " << regex << "\n"; + } + + for (const auto& example : location.postal_code_examples) { + std::cout << " Postal example: " << example << "\n"; + } + + for (const auto& lang : location.local_languages) { + std::cout << " Local language: " << lang << "\n"; } } + cache_.locations = std::move(locations); return cache_.locations; } diff --git a/tooling/pipeline/src/services/curated_data/mock_curated_data_service.cc b/tooling/pipeline/src/services/curated_data/mock_curated_data_service.cc index 31264a7..a108281 100644 --- a/tooling/pipeline/src/services/curated_data/mock_curated_data_service.cc +++ b/tooling/pipeline/src/services/curated_data/mock_curated_data_service.cc @@ -7,46 +7,38 @@ MockCuratedDataService::MockCuratedDataService() : locations_{ - City{.city = "Portland", - .state_province = "Oregon", - .iso3166_2 = "US-OR", - .country = "United States", - .iso3166_1 = "US", - .local_languages = {"en"}, - .latitude = 45.5152, - .longitude = -122.6784, - .postal_regex = {"^972[0-9]{2}(?:-[0-9]{4})?$"}, - .postal_code_examples = {"97201", "97294"}}, - City{.city = "Munich", - .state_province = "Bavaria", - .iso3166_2 = "DE-BY", - .country = "Germany", - .iso3166_1 = "DE", - .local_languages = {"de"}, - .latitude = 48.1351, - .longitude = 11.5820, - .postal_regex = {"^8[01][0-9]{3}$"}, - .postal_code_examples = {"80331", "81929"}}, - City{.city = "Lyon", - .state_province = "Auvergne-Rhone-Alpes", - .iso3166_2 = "FR-ARA", - .country = "France", - .iso3166_1 = "FR", - .local_languages = {"fr"}, - .latitude = 45.7640, - .longitude = 4.8357, - .postal_regex = {"^6900[1-9]$"}, - .postal_code_examples = {"69001", "69009"}}, - City{.city = "Brussels", - .state_province = "Brussels-Capital", - .iso3166_2 = "BE-BRU", - .country = "Belgium", - .iso3166_1 = "BE", - .local_languages = {"nl", "fr"}, - .latitude = 50.8503, - .longitude = 4.3517, - .postal_regex = {"^1(?:0[0-9]{2}|1[0-9]{2}|20[0-9]|210)$"}, - .postal_code_examples = {"1000", "1210"}}, + {.city = "Portland", + .state_province = "Oregon", + .iso3166_2 = "US-OR", + .country = "United States", + .iso3166_1 = "US", + .local_languages = {"en"}, + .postal_regex = {"^972[0-9]{2}(?:-[0-9]{4})?$"}, + .postal_code_examples = {"97201", "97294"}}, + {.city = "Munich", + .state_province = "Bavaria", + .iso3166_2 = "DE-BY", + .country = "Germany", + .iso3166_1 = "DE", + .local_languages = {"de"}, + .postal_regex = {"^8[01][0-9]{3}$"}, + .postal_code_examples = {"80331", "81929"}}, + {.city = "Lyon", + .state_province = "Auvergne-Rhone-Alpes", + .iso3166_2 = "FR-ARA", + .country = "France", + .iso3166_1 = "FR", + .local_languages = {"fr"}, + .postal_regex = {"^6900[1-9]$"}, + .postal_code_examples = {"69001", "69009"}}, + {.city = "Brussels", + .state_province = "Brussels-Capital", + .iso3166_2 = "BE-BRU", + .country = "Belgium", + .iso3166_1 = "BE", + .local_languages = {"nl", "fr"}, + .postal_regex = {"^1(?:0[0-9]{2}|1[0-9]{2}|20[0-9]|210)$"}, + .postal_code_examples = {"1000", "1210"}}, }, personas_{ UserPersona{.name = "Hophead Explorer", @@ -91,9 +83,7 @@ MockCuratedDataService::MockCuratedDataService() {"BE", SurnameList{"Peeters", "Janssens"}}, } {} -const CityList& MockCuratedDataService::LoadCities() { - return locations_; -} +const CityList& MockCuratedDataService::LoadCities() { return locations_; } const PersonasList& MockCuratedDataService::LoadPersonas() { return personas_; } diff --git a/tooling/pipeline/src/services/sqlite/finalize.cc b/tooling/pipeline/src/services/sqlite/finalize.cc index 40fe643..b8e6457 100644 --- a/tooling/pipeline/src/services/sqlite/finalize.cc +++ b/tooling/pipeline/src/services/sqlite/finalize.cc @@ -14,7 +14,9 @@ void SqliteExportService::Finalize() { } try { + insert_user_address_stmt_.reset(); insert_user_stmt_.reset(); + insert_brewery_address_stmt_.reset(); insert_brewery_stmt_.reset(); insert_city_stmt_.reset(); if (transaction_open_) { diff --git a/tooling/pipeline/src/services/sqlite/initialize.cc b/tooling/pipeline/src/services/sqlite/initialize.cc index e23e194..28c399b 100644 --- a/tooling/pipeline/src/services/sqlite/initialize.cc +++ b/tooling/pipeline/src/services/sqlite/initialize.cc @@ -36,6 +36,12 @@ void SqliteExportService::InitializeSchema() const { sqlite_export_service_internal::ExecSql( db_handle_, sqlite_export_service_internal::kCreateUsersTableSql, "Failed to create SQLite users table"); + sqlite_export_service_internal::ExecSql( + db_handle_, sqlite_export_service_internal::kCreateBreweryAddressTableSql, + "Failed to create SQLite brewery addresses table"); + sqlite_export_service_internal::ExecSql( + db_handle_, sqlite_export_service_internal::kCreateUserAddressTableSql, + "Failed to create SQLite user addresses table"); } void SqliteExportService::PrepareStatements() { @@ -45,9 +51,16 @@ void SqliteExportService::PrepareStatements() { insert_brewery_stmt_ = sqlite_export_service_internal::PrepareStatement( db_handle_, sqlite_export_service_internal::kInsertBrewerySql, "Failed to prepare SQLite brewery insert statement"); + insert_brewery_address_stmt_ = + sqlite_export_service_internal::PrepareStatement( + db_handle_, sqlite_export_service_internal::kInsertBreweryAddressSql, + "Failed to prepare SQLite brewery address insert statement"); insert_user_stmt_ = sqlite_export_service_internal::PrepareStatement( db_handle_, sqlite_export_service_internal::kInsertUserSql, "Failed to prepare SQLite user insert statement"); + insert_user_address_stmt_ = sqlite_export_service_internal::PrepareStatement( + db_handle_, sqlite_export_service_internal::kInsertUserAddressSql, + "Failed to prepare SQLite user address insert statement"); } void SqliteExportService::RollbackAndCloseNoThrow() noexcept { @@ -60,7 +73,9 @@ void SqliteExportService::RollbackAndCloseNoThrow() noexcept { transaction_open_ = false; } + insert_user_address_stmt_.reset(); insert_user_stmt_.reset(); + insert_brewery_address_stmt_.reset(); insert_brewery_stmt_.reset(); insert_city_stmt_.reset(); db_handle_.reset(); diff --git a/tooling/pipeline/src/services/sqlite/process_record.cc b/tooling/pipeline/src/services/sqlite/process_record.cc index ac35ee3..1cf1555 100644 --- a/tooling/pipeline/src/services/sqlite/process_record.cc +++ b/tooling/pipeline/src/services/sqlite/process_record.cc @@ -4,7 +4,6 @@ * and the shared city-resolution helper. */ -#include #include #include #include @@ -12,8 +11,6 @@ #include "services/database/sqlite_export_service.h" #include "services/database/sqlite_export_service_helpers.h" -constexpr int kLocationPrecision = 17; - std::string SqliteExportService::BuildCityKey(const City& location) { std::ostringstream key_stream; key_stream << location.city << '\n' @@ -21,10 +18,6 @@ std::string SqliteExportService::BuildCityKey(const City& location) { << location.iso3166_2 << '\n' << location.country << '\n' << location.iso3166_1 << '\n' - << std::setprecision(kLocationPrecision) << location.latitude - << '\n' - << std::setprecision(kLocationPrecision) << location.longitude - << '\n' << sqlite_export_service_internal::SerializeVector( location.local_languages); return key_stream.str(); @@ -49,8 +42,7 @@ sqlite3_int64 SqliteExportService::ResolveCityId(const City& location) { sqlite_export_service_internal::Bind( insert_city_stmt_, sqlite_export_service_internal::BoundParam{ - .index = - sqlite_export_service_internal::kCityStateProvinceBindIndex, + .index = sqlite_export_service_internal::kCityStateProvinceBindIndex, .value = location.state_province, .action = "Failed to bind SQLite city state/province"}); sqlite_export_service_internal::Bind( @@ -77,22 +69,9 @@ sqlite3_int64 SqliteExportService::ResolveCityId(const City& location) { .index = sqlite_export_service_internal::kCityLanguagesBindIndex, .value = local_languages_json, .action = "Failed to bind SQLite city languages"}); - sqlite_export_service_internal::Bind( - insert_city_stmt_, - sqlite_export_service_internal::BoundParam{ - .index = sqlite_export_service_internal::kCityLatitudeBindIndex, - .value = location.latitude, - .action = "Failed to bind SQLite city latitude"}); - sqlite_export_service_internal::Bind( - insert_city_stmt_, - sqlite_export_service_internal::BoundParam{ - .index = sqlite_export_service_internal::kCityLongitudeBindIndex, - .value = location.longitude, - .action = "Failed to bind SQLite city longitude"}); sqlite_export_service_internal::StepStatement( - db_handle_, insert_city_stmt_, - "Failed to insert SQLite city row"); + db_handle_, insert_city_stmt_, "Failed to insert SQLite city row"); const sqlite3_int64 city_id = sqlite_export_service_internal::LastInsertRowId(db_handle_); @@ -107,7 +86,7 @@ uint64_t SqliteExportService::ProcessRecord(const BreweryRecord& brewery) { throw std::runtime_error("SQLite export service is not initialized"); } - const sqlite3_int64 city_id = ResolveCityId(brewery.location); + const sqlite3_int64 city_id = ResolveCityId(brewery.address.city); sqlite_export_service_internal::Bind( insert_brewery_stmt_, @@ -146,17 +125,40 @@ uint64_t SqliteExportService::ProcessRecord(const BreweryRecord& brewery) { .value = brewery.brewery.description_local, .action = "Failed to bind SQLite brewery local description"}); - sqlite_export_service_internal::Bind( - insert_brewery_stmt_, - sqlite_export_service_internal::BoundParam{ - .index = sqlite_export_service_internal::kBreweryPostalCodeBindIndex, - .value = brewery.address.postal_code, - .action = "Failed to bind SQLite brewery postal code"}); - sqlite_export_service_internal::StepStatement( db_handle_, insert_brewery_stmt_, "Failed to insert SQLite brewery row"); + const sqlite3_int64 brewery_id = + sqlite_export_service_internal::LastInsertRowId(db_handle_); sqlite_export_service_internal::ResetStatement(insert_brewery_stmt_); - return sqlite_export_service_internal::LastInsertRowId(db_handle_); + sqlite_export_service_internal::Bind( + insert_brewery_address_stmt_, + sqlite_export_service_internal::BoundParam{ + .index = + sqlite_export_service_internal::kBreweryAddressBreweryIdBindIndex, + .value = brewery_id, + .action = "Failed to bind SQLite brewery address brewery id"}); + sqlite_export_service_internal::Bind( + insert_brewery_address_stmt_, + sqlite_export_service_internal::BoundParam{ + .index = sqlite_export_service_internal:: + kBreweryAddressPostalCodeBindIndex, + .value = brewery.address.postal_code, + .action = "Failed to bind SQLite brewery address postal code"}); + sqlite_export_service_internal::Bind( + insert_brewery_address_stmt_, + sqlite_export_service_internal::BoundParam{ + .index = + sqlite_export_service_internal::kBreweryAddressCityIdBindIndex, + .value = city_id, + .action = "Failed to bind SQLite brewery address city id"}); + + sqlite_export_service_internal::StepStatement( + db_handle_, insert_brewery_address_stmt_, + "Failed to insert SQLite brewery address row"); + + sqlite_export_service_internal::ResetStatement(insert_brewery_address_stmt_); + + return brewery_id; } diff --git a/tooling/pipeline/src/services/sqlite/process_user_record.cc b/tooling/pipeline/src/services/sqlite/process_user_record.cc index 9288386..7ded49e 100644 --- a/tooling/pipeline/src/services/sqlite/process_user_record.cc +++ b/tooling/pipeline/src/services/sqlite/process_user_record.cc @@ -13,14 +13,8 @@ uint64_t SqliteExportService::ProcessRecord(const UserRecord& user) { throw std::runtime_error("SQLite export service is not initialized"); } - const sqlite3_int64 city_id = ResolveCityId(user.location); + const sqlite3_int64 city_id = ResolveCityId(user.address.city); - sqlite_export_service_internal::Bind( - insert_user_stmt_, - sqlite_export_service_internal::BoundParam{ - .index = sqlite_export_service_internal::kUserCityIdBindIndex, - .value = city_id, - .action = "Failed to bind SQLite user city id"}); sqlite_export_service_internal::Bind( insert_user_stmt_, sqlite_export_service_internal::BoundParam{ @@ -73,7 +67,28 @@ uint64_t SqliteExportService::ProcessRecord(const UserRecord& user) { sqlite_export_service_internal::StepStatement( db_handle_, insert_user_stmt_, "Failed to insert SQLite user row"); + const sqlite3_int64 user_id = + sqlite_export_service_internal::LastInsertRowId(db_handle_); sqlite_export_service_internal::ResetStatement(insert_user_stmt_); - return sqlite_export_service_internal::LastInsertRowId(db_handle_); + sqlite_export_service_internal::Bind( + insert_user_address_stmt_, + sqlite_export_service_internal::BoundParam{ + .index = sqlite_export_service_internal::kUserAddressUserIdBindIndex, + .value = user_id, + .action = "Failed to bind SQLite user address user id"}); + sqlite_export_service_internal::Bind( + insert_user_address_stmt_, + sqlite_export_service_internal::BoundParam{ + .index = sqlite_export_service_internal::kUserAddressCityIdBindIndex, + .value = city_id, + .action = "Failed to bind SQLite user address city id"}); + + sqlite_export_service_internal::StepStatement( + db_handle_, insert_user_address_stmt_, + "Failed to insert SQLite user address row"); + + sqlite_export_service_internal::ResetStatement(insert_user_address_stmt_); + + return user_id; }