Add states and territories to county database

This commit is contained in:
Dan Paulat 2023-12-03 07:16:12 -06:00
parent ffd2fa83ad
commit a56b7400a4
4 changed files with 79 additions and 11 deletions

2
data

@ -1 +1 @@
Subproject commit 9b6c72f847193bc29d3ff183b206f26a9b5c007e Subproject commit db52049ea651fea92b06e5024cbff3a3d3d26bc8

View file

@ -323,6 +323,7 @@ set(ZONE_DBF_FILES ${SCWX_DIR}/data/db/fz19se23.dbf
${SCWX_DIR}/data/db/mz19se23.dbf ${SCWX_DIR}/data/db/mz19se23.dbf
${SCWX_DIR}/data/db/oz08mr23.dbf ${SCWX_DIR}/data/db/oz08mr23.dbf
${SCWX_DIR}/data/db/z_19se23.dbf) ${SCWX_DIR}/data/db/z_19se23.dbf)
set(STATE_DBF_FILES ${SCWX_DIR}/data/db/s_08mr23.dbf)
set(COUNTIES_SQLITE_DB ${scwx-qt_BINARY_DIR}/res/db/counties.db) set(COUNTIES_SQLITE_DB ${scwx-qt_BINARY_DIR}/res/db/counties.db)
set(VERSIONS_INPUT ${scwx-qt_SOURCE_DIR}/source/scwx/qt/main/versions.hpp.in) set(VERSIONS_INPUT ${scwx-qt_SOURCE_DIR}/source/scwx/qt/main/versions.hpp.in)
@ -411,8 +412,12 @@ add_custom_command(OUTPUT ${COUNTIES_SQLITE_DB}
${scwx-qt_SOURCE_DIR}/tools/generate_counties_db.py ${scwx-qt_SOURCE_DIR}/tools/generate_counties_db.py
-c ${COUNTY_DBF_FILES} -c ${COUNTY_DBF_FILES}
-z ${ZONE_DBF_FILES} -z ${ZONE_DBF_FILES}
-s ${STATE_DBF_FILES}
-o ${COUNTIES_SQLITE_DB} -o ${COUNTIES_SQLITE_DB}
DEPENDS ${COUNTY_DB_FILES} ${ZONE_DBF_FILES}) DEPENDS ${scwx-qt_SOURCE_DIR}/tools/generate_counties_db.py
${COUNTY_DB_FILES}
${STATE_DBF_FILES}
${ZONE_DBF_FILES})
add_custom_target(scwx-qt_generate_counties_db ALL add_custom_target(scwx-qt_generate_counties_db ALL
DEPENDS ${COUNTIES_SQLITE_DB}) DEPENDS ${COUNTIES_SQLITE_DB})

View file

@ -28,6 +28,7 @@ static const std::string countyDatabaseFilename_ = ":/res/db/counties.db";
static bool initialized_ {false}; static bool initialized_ {false};
static std::unordered_map<std::string, std::string> countyMap_; static std::unordered_map<std::string, std::string> countyMap_;
static std::shared_mutex countyMutex_; static std::shared_mutex countyMutex_;
static std::unordered_map<std::string, std::string> stateMap_;
void Initialize() void Initialize()
{ {
@ -108,7 +109,41 @@ void Initialize()
else else
{ {
logger_->error( logger_->error(
"Database format error, invalid number of columns: {}", columns); "County database format error, invalid number of columns: {}",
columns);
status = -1;
}
return status;
},
nullptr,
&errorMessage);
if (rc != SQLITE_OK)
{
logger_->error("SQL error: {}", errorMessage);
sqlite3_free(errorMessage);
}
// Query database for states
rc = sqlite3_exec(
db,
"SELECT * FROM states",
[](void* /* param */,
int columns,
char** columnText,
char** /* columnName */) -> int
{
int status = 0;
if (columns == 2)
{
stateMap_.emplace(columnText[0], columnText[1]);
}
else
{
logger_->error(
"State database format error, invalid number of columns: {}",
columns);
status = -1; status = -1;
} }
@ -129,13 +164,11 @@ void Initialize()
sqlite3_close(db); sqlite3_close(db);
// Remove temporary file // Remove temporary file
std::error_code err; std::error_code error;
if (!std::filesystem::remove(countyDatabaseCache, error))
if (!std::filesystem::remove(countyDatabaseCache, err)) { {
logger_->warn( logger_->warn("Unable to remove cached copy of database: {}",
"Unable to remove cached copy of database, error code: {} error category: {}", error.message());
err.value(),
err.category().name());
} }
initialized_ = true; initialized_ = true;

View file

@ -26,6 +26,14 @@ def ParseArguments():
nargs = "+", nargs = "+",
default = [], default = [],
type = pathlib.Path) type = pathlib.Path)
parser.add_argument("-s", "--state_dbf",
metavar = "filename",
help = "input state database",
dest = "inputStateDbs_",
action = "extend",
nargs = "+",
default = [],
type = pathlib.Path)
parser.add_argument("-o", "--output_db", parser.add_argument("-o", "--output_db",
metavar = "filename", metavar = "filename",
help = "output sqlite database", help = "output sqlite database",
@ -47,10 +55,13 @@ def Prepare(dbInfo, outputDb):
dbInfo.sqlCursor_ = dbInfo.sqlConnection_.cursor() dbInfo.sqlCursor_ = dbInfo.sqlConnection_.cursor()
# Create database table # Create database tables
dbInfo.sqlCursor_.execute("""CREATE TABLE counties( dbInfo.sqlCursor_.execute("""CREATE TABLE counties(
id TEXT NOT NULL PRIMARY KEY, id TEXT NOT NULL PRIMARY KEY,
name TEXT)""") name TEXT)""")
dbInfo.sqlCursor_.execute("""CREATE TABLE states(
state TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL)""")
def ProcessCountiesDbf(dbInfo, dbfFilename): def ProcessCountiesDbf(dbInfo, dbfFilename):
# County area type # County area type
@ -72,6 +83,22 @@ def ProcessCountiesDbf(dbInfo, dbfFilename):
except: except:
print("Skipping duplicate county:", fipsId, row.COUNTYNAME) print("Skipping duplicate county:", fipsId, row.COUNTYNAME)
def ProcessStateDbf(dbInfo, dbfFilename):
print("Processing states and territories file:", dbfFilename)
# Read dataframe
dbfTable = gpd.read_file(filename = dbfFilename,
include_fields = ["STATE", "NAME"],
ignore_geometry = True)
dbfTable.drop_duplicates(inplace=True)
for row in dbfTable.itertuples():
# Insert data into database
try:
dbInfo.sqlCursor_.execute("INSERT INTO states VALUES (?, ?)", (row.STATE, row.NAME))
except:
print("Error inserting row:", row.STATE, row.NAME)
def ProcessZoneDbf(dbInfo, dbfFilename): def ProcessZoneDbf(dbInfo, dbfFilename):
print("Processing zone file:", dbfFilename) print("Processing zone file:", dbfFilename)
# Zone area type # Zone area type
@ -118,4 +145,7 @@ for countyDb in args.inputCountyDbs_:
for zoneDb in args.inputZoneDbs_: for zoneDb in args.inputZoneDbs_:
ProcessZoneDbf(dbInfo, zoneDb) ProcessZoneDbf(dbInfo, zoneDb)
for stateDb in args.inputStateDbs_:
ProcessStateDbf(dbInfo, stateDb)
PostProcess(dbInfo) PostProcess(dbInfo)