mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 17:00:05 +00:00 
			
		
		
		
	Add GetCounties to county database
- Also remove mutex, as the database is only modified on initialization
This commit is contained in:
		
							parent
							
								
									7cf2121b8e
								
							
						
					
					
						commit
						bcc7391a19
					
				
					 3 changed files with 80 additions and 16 deletions
				
			
		|  | @ -1,7 +1,6 @@ | ||||||
| #include <scwx/qt/config/county_database.hpp> | #include <scwx/qt/config/county_database.hpp> | ||||||
| #include <scwx/util/logger.hpp> | #include <scwx/util/logger.hpp> | ||||||
| 
 | 
 | ||||||
| #include <shared_mutex> |  | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| 
 | 
 | ||||||
| #include <boost/uuid/uuid.hpp> | #include <boost/uuid/uuid.hpp> | ||||||
|  | @ -25,9 +24,12 @@ static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||||
| 
 | 
 | ||||||
| static const std::string countyDatabaseFilename_ = ":/res/db/counties.db"; | static const std::string countyDatabaseFilename_ = ":/res/db/counties.db"; | ||||||
| 
 | 
 | ||||||
|  | typedef std::unordered_map<std::string, std::string> CountyMap; | ||||||
|  | typedef std::unordered_map<std::string, CountyMap>   StateMap; | ||||||
|  | typedef std::unordered_map<char, StateMap>           FormatMap; | ||||||
|  | 
 | ||||||
| static bool                                         initialized_ {false}; | static bool                                         initialized_ {false}; | ||||||
| static std::unordered_map<std::string, std::string> countyMap_; | static FormatMap                                    countyDatabase_; | ||||||
| static std::shared_mutex                            countyMutex_; |  | ||||||
| static std::unordered_map<std::string, std::string> stateMap_; | static std::unordered_map<std::string, std::string> stateMap_; | ||||||
| 
 | 
 | ||||||
| void Initialize() | void Initialize() | ||||||
|  | @ -88,8 +90,8 @@ void Initialize() | ||||||
|       return; |       return; | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    // Database is open, acquire lock
 |    // Ensure counties exists
 | ||||||
|    std::unique_lock lock(countyMutex_); |    countyDatabase_.emplace('C', StateMap {}); | ||||||
| 
 | 
 | ||||||
|    // Query database for counties
 |    // Query database for counties
 | ||||||
|    rc = sqlite3_exec( |    rc = sqlite3_exec( | ||||||
|  | @ -102,17 +104,26 @@ void Initialize() | ||||||
|       { |       { | ||||||
|          int status = 0; |          int status = 0; | ||||||
| 
 | 
 | ||||||
|          if (columns == 2) |          if (columns == 2 && std::strlen(columnText[0]) == 6) | ||||||
|          { |          { | ||||||
|             countyMap_.emplace(columnText[0], columnText[1]); |             std::string fipsId = columnText[0]; | ||||||
|  |             std::string state  = fipsId.substr(0, 2); | ||||||
|  |             char        type   = fipsId.at(2); | ||||||
|  | 
 | ||||||
|  |             countyDatabase_[type][state].emplace(fipsId, columnText[1]); | ||||||
|          } |          } | ||||||
|          else |          else if (columns != 2) | ||||||
|          { |          { | ||||||
|             logger_->error( |             logger_->error( | ||||||
|                "County database format error, invalid number of columns: {}", |                "County database format error, invalid number of columns: {}", | ||||||
|                columns); |                columns); | ||||||
|             status = -1; |             status = -1; | ||||||
|          } |          } | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             logger_->error("Invalid FIPS ID: {}", columnText[0]); | ||||||
|  |             status = -1; | ||||||
|  |          } | ||||||
| 
 | 
 | ||||||
|          return status; |          return status; | ||||||
|       }, |       }, | ||||||
|  | @ -157,9 +168,6 @@ void Initialize() | ||||||
|       sqlite3_free(errorMessage); |       sqlite3_free(errorMessage); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    // Finished populating county map, release lock
 |  | ||||||
|    lock.unlock(); |  | ||||||
| 
 |  | ||||||
|    // Close database
 |    // Close database
 | ||||||
|    sqlite3_close(db); |    sqlite3_close(db); | ||||||
| 
 | 
 | ||||||
|  | @ -176,17 +184,47 @@ void Initialize() | ||||||
| 
 | 
 | ||||||
| std::string GetCountyName(const std::string& id) | std::string GetCountyName(const std::string& id) | ||||||
| { | { | ||||||
|    std::shared_lock lock(countyMutex_); |    if (id.length() > 3) | ||||||
|  |    { | ||||||
|  |       // SSFNNN
 | ||||||
|  |       char        format = id.at(2); | ||||||
|  |       std::string state  = id.substr(0, 2); | ||||||
| 
 | 
 | ||||||
|    auto it = countyMap_.find(id); |       auto stateIt = countyDatabase_.find(format); | ||||||
|    if (it != countyMap_.cend()) |       if (stateIt != countyDatabase_.cend()) | ||||||
|  |       { | ||||||
|  |          StateMap& states   = stateIt->second; | ||||||
|  |          auto      countyIt = states.find(state); | ||||||
|  |          if (countyIt != states.cend()) | ||||||
|  |          { | ||||||
|  |             CountyMap& counties = countyIt->second; | ||||||
|  |             auto       it       = counties.find(id); | ||||||
|  |             if (it != counties.cend()) | ||||||
|             { |             { | ||||||
|                return it->second; |                return it->second; | ||||||
|             } |             } | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |    } | ||||||
| 
 | 
 | ||||||
|    return id; |    return id; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | std::unordered_map<std::string, std::string> | ||||||
|  | GetCounties(const std::string& state) | ||||||
|  | { | ||||||
|  |    std::unordered_map<std::string, std::string> counties {}; | ||||||
|  | 
 | ||||||
|  |    StateMap& states = countyDatabase_.at('C'); | ||||||
|  |    auto      it     = states.find(state); | ||||||
|  |    if (it != states.cend()) | ||||||
|  |    { | ||||||
|  |       counties = it->second; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    return counties; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } // namespace CountyDatabase
 | } // namespace CountyDatabase
 | ||||||
| } // namespace config
 | } // namespace config
 | ||||||
| } // namespace qt
 | } // namespace qt
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <unordered_map> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
| namespace scwx | namespace scwx | ||||||
|  | @ -15,6 +16,8 @@ namespace CountyDatabase | ||||||
| 
 | 
 | ||||||
| void        Initialize(); | void        Initialize(); | ||||||
| std::string GetCountyName(const std::string& id); | std::string GetCountyName(const std::string& id); | ||||||
|  | std::unordered_map<std::string, std::string> | ||||||
|  | GetCounties(const std::string& state); | ||||||
| 
 | 
 | ||||||
| } // namespace CountyDatabase
 | } // namespace CountyDatabase
 | ||||||
| } // namespace config
 | } // namespace config
 | ||||||
|  |  | ||||||
|  | @ -15,6 +15,12 @@ class CountyDatabaseTest : | ||||||
|    virtual void SetUp() { scwx::qt::config::CountyDatabase::Initialize(); } |    virtual void SetUp() { scwx::qt::config::CountyDatabase::Initialize(); } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | class CountyCountTest : | ||||||
|  |     public testing::TestWithParam<std::pair<std::string, std::size_t>> | ||||||
|  | { | ||||||
|  |    virtual void SetUp() { scwx::qt::config::CountyDatabase::Initialize(); } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| TEST_P(CountyDatabaseTest, CountyName) | TEST_P(CountyDatabaseTest, CountyName) | ||||||
| { | { | ||||||
|    auto& [id, name] = GetParam(); |    auto& [id, name] = GetParam(); | ||||||
|  | @ -24,6 +30,15 @@ TEST_P(CountyDatabaseTest, CountyName) | ||||||
|    EXPECT_EQ(actualName, name); |    EXPECT_EQ(actualName, name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | TEST_P(CountyCountTest, State) | ||||||
|  | { | ||||||
|  |    auto& [state, size] = GetParam(); | ||||||
|  | 
 | ||||||
|  |    auto counties = CountyDatabase::GetCounties(state); | ||||||
|  | 
 | ||||||
|  |    EXPECT_EQ(counties.size(), size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| INSTANTIATE_TEST_SUITE_P( | INSTANTIATE_TEST_SUITE_P( | ||||||
|    CountyDatabase, |    CountyDatabase, | ||||||
|    CountyDatabaseTest, |    CountyDatabaseTest, | ||||||
|  | @ -33,6 +48,14 @@ INSTANTIATE_TEST_SUITE_P( | ||||||
|                    std::make_pair("GMZ335", "Galveston Bay"), |                    std::make_pair("GMZ335", "Galveston Bay"), | ||||||
|                    std::make_pair("ANZ338", "New York Harbor"))); |                    std::make_pair("ANZ338", "New York Harbor"))); | ||||||
| 
 | 
 | ||||||
|  | INSTANTIATE_TEST_SUITE_P(CountyDatabase, | ||||||
|  |                          CountyCountTest, | ||||||
|  |                          testing::Values(std::make_pair("AZ", 15), | ||||||
|  |                                          std::make_pair("MO", 115), | ||||||
|  |                                          std::make_pair("TX", 254), | ||||||
|  |                                          std::make_pair("GM", 0), | ||||||
|  |                                          std::make_pair("AN", 0))); | ||||||
|  | 
 | ||||||
| } // namespace config
 | } // namespace config
 | ||||||
| } // namespace qt
 | } // namespace qt
 | ||||||
| } // namespace scwx
 | } // namespace scwx
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat