use super::TigerResource;
use bamcensus_core::model::identifier::{Geoid, GeoidType, HasGeoidString};
use std::{collections::HashSet, fmt::Display};
pub enum TigerResourceBuilder {
Tiger2010,
Tiger2010Format { year: u64 },
Tiger2020Format { year: u64 },
}
impl Display for TigerResourceBuilder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TigerResourceBuilder::Tiger2010 => write!(f, "TIGER2010"),
TigerResourceBuilder::Tiger2010Format { year } => write!(f, "TIGER{year}"),
TigerResourceBuilder::Tiger2020Format { year } => write!(f, "TIGER{year}"),
}
}
}
impl TigerResourceBuilder {
pub const TIGER_BASE_URL: &'static str = "https://www2.census.gov/geo/tiger";
pub fn new(year: u64) -> Result<TigerResourceBuilder, String> {
match year {
2010 => Ok(TigerResourceBuilder::Tiger2010),
y if 2010 < y && y < 2020 => Ok(TigerResourceBuilder::Tiger2010Format { year }),
y if 2020 <= y => Ok(TigerResourceBuilder::Tiger2020Format { year }),
_ => Err(format!("unsupported TIGER year {year}")),
}
}
pub fn create_resources(&self, geoids: &[&Geoid]) -> Result<Vec<TigerResource>, String> {
let mut unique_uris: HashSet<TigerResource> = HashSet::new();
for geoid in geoids {
let uri = self.create_resource(geoid)?;
unique_uris.insert(uri);
}
let uris = unique_uris.into_iter().collect::<Vec<_>>();
Ok(uris)
}
pub fn create_resource(&self, geoid: &Geoid) -> Result<TigerResource, String> {
let suffix: String = match (self, geoid) {
(TigerResourceBuilder::Tiger2010, Geoid::State(state)) => {
format!("STATE/2010/tl_2010_{}_state10.zip", state.geoid_string(),)
}
(TigerResourceBuilder::Tiger2010, Geoid::County(state, _)) => {
format!("COUNTY/2010/tl_2010_{}_county10.zip", state.geoid_string(),)
}
(TigerResourceBuilder::Tiger2010, Geoid::CountySubdivision(state, county, _)) => {
format!(
"COUSUB/2010/tl_2010_{}{}_cousub10.zip",
state.geoid_string(),
county.geoid_string()
)
}
(TigerResourceBuilder::Tiger2010, Geoid::Place(state, _)) => {
format!("PLACE/2010/tl_2010_{}_place10.zip", state.geoid_string(),)
}
(TigerResourceBuilder::Tiger2010, Geoid::CensusTract(state, county, _)) => format!(
"TRACT/2010/tl_2010_{}{}_tract10.zip",
state.geoid_string(),
county.geoid_string()
),
(TigerResourceBuilder::Tiger2010, Geoid::BlockGroup(state, county, _, _)) => format!(
"BG/2010/tl_2010_{}{}_bg10.zip",
state.geoid_string(),
county.geoid_string()
),
(TigerResourceBuilder::Tiger2010, Geoid::Block(state, county, _, _)) => format!(
"TABBLOCK/2010/tl_2010_{}{}_tabblock10.zip",
state.geoid_string(),
county.geoid_string()
),
(TigerResourceBuilder::Tiger2010Format { year }, Geoid::State(_)) => {
format!("STATE/tl_{year}_us_state.zip",)
}
(TigerResourceBuilder::Tiger2010Format { year }, Geoid::County(_, _)) => {
format!("COUNTY/tl_{year}_us_county.zip")
}
(
TigerResourceBuilder::Tiger2010Format { year },
Geoid::CountySubdivision(state, _, _),
) => {
format!("COUSUB/tl_{}_{}_cousub.zip", year, state.geoid_string())
}
(TigerResourceBuilder::Tiger2010Format { year }, Geoid::Place(state, _)) => {
format!("PLACE/tl_{}_{}_place.zip", year, state.geoid_string(),)
}
(TigerResourceBuilder::Tiger2010Format { year }, Geoid::CensusTract(state, _, _)) => {
format!("TRACT/tl_{}_{}_tract.zip", year, state.geoid_string())
}
(TigerResourceBuilder::Tiger2010Format { year }, Geoid::BlockGroup(state, _, _, _)) => {
format!("BG/tl_{}_{}_bg.zip", year, state.geoid_string())
}
(TigerResourceBuilder::Tiger2010Format { year }, Geoid::Block(state, _, _, _)) => {
format!(
"TABBLOCK/tl_{}_{}_tabblock10.zip",
year,
state.geoid_string()
)
}
(TigerResourceBuilder::Tiger2020Format { year }, Geoid::State(_)) => {
format!("STATE/tl_{year}_us_state.zip",)
}
(TigerResourceBuilder::Tiger2020Format { year }, Geoid::County(_, _)) => {
format!("COUNTY/tl_{year}_us_county.zip")
}
(
TigerResourceBuilder::Tiger2020Format { year },
Geoid::CountySubdivision(state, _, _),
) => {
format!("COUSUB/tl_{}_{}_cousub.zip", year, state.geoid_string())
}
(TigerResourceBuilder::Tiger2020Format { year }, Geoid::Place(state, _)) => {
format!("PLACE/tl_{}_{}_place.zip", year, state.geoid_string(),)
}
(TigerResourceBuilder::Tiger2020Format { year }, Geoid::CensusTract(state, _, _)) => {
format!("TRACT/tl_{}_{}_tract.zip", year, state.geoid_string())
}
(TigerResourceBuilder::Tiger2020Format { year }, Geoid::BlockGroup(state, _, _, _)) => {
format!("BG/tl_{}_{}_bg.zip", year, state.geoid_string())
}
(TigerResourceBuilder::Tiger2020Format { year }, Geoid::Block(state, _, _, _)) => {
format!(
"TABBLOCK20/tl_{}_{}_tabblock20.zip",
year,
state.geoid_string()
)
}
};
let file_scope = match (self, geoid) {
(TigerResourceBuilder::Tiger2010, Geoid::State(_)) => Some(GeoidType::State),
(TigerResourceBuilder::Tiger2010, Geoid::County(_, _)) => Some(GeoidType::State),
(TigerResourceBuilder::Tiger2010, Geoid::CountySubdivision(_, _, _)) => {
Some(GeoidType::State)
}
(TigerResourceBuilder::Tiger2010, Geoid::Place(_, _)) => Some(GeoidType::State),
(TigerResourceBuilder::Tiger2010, Geoid::CensusTract(_, _, _)) => {
Some(GeoidType::County)
}
(TigerResourceBuilder::Tiger2010, Geoid::BlockGroup(_, _, _, _)) => {
Some(GeoidType::County)
}
(TigerResourceBuilder::Tiger2010, Geoid::Block(_, _, _, _)) => Some(GeoidType::County),
(TigerResourceBuilder::Tiger2010Format { year: _ }, Geoid::State(_)) => None,
(TigerResourceBuilder::Tiger2010Format { year: _ }, Geoid::County(_, _)) => None,
(
TigerResourceBuilder::Tiger2010Format { year: _ },
Geoid::CountySubdivision(_, _, _),
) => Some(GeoidType::State),
(TigerResourceBuilder::Tiger2010Format { year: _ }, Geoid::Place(_, _)) => {
Some(GeoidType::State)
}
(TigerResourceBuilder::Tiger2010Format { year: _ }, Geoid::CensusTract(_, _, _)) => {
Some(GeoidType::State)
}
(TigerResourceBuilder::Tiger2010Format { year: _ }, Geoid::BlockGroup(_, _, _, _)) => {
Some(GeoidType::State)
}
(TigerResourceBuilder::Tiger2010Format { year: _ }, Geoid::Block(_, _, _, _)) => {
Some(GeoidType::State)
}
(TigerResourceBuilder::Tiger2020Format { year: _ }, Geoid::State(_)) => None,
(TigerResourceBuilder::Tiger2020Format { year: _ }, Geoid::County(_, _)) => None,
(
TigerResourceBuilder::Tiger2020Format { year: _ },
Geoid::CountySubdivision(_, _, _),
) => Some(GeoidType::State),
(TigerResourceBuilder::Tiger2020Format { year: _ }, Geoid::Place(_, _)) => {
Some(GeoidType::State)
}
(TigerResourceBuilder::Tiger2020Format { year: _ }, Geoid::CensusTract(_, _, _)) => {
Some(GeoidType::State)
}
(TigerResourceBuilder::Tiger2020Format { year: _ }, Geoid::BlockGroup(_, _, _, _)) => {
Some(GeoidType::State)
}
(TigerResourceBuilder::Tiger2020Format { year: _ }, Geoid::Block(_, _, _, _)) => {
Some(GeoidType::State)
}
};
let prefix = self.base_url();
let uri = format!("{prefix}/{suffix}");
let geoid_type = geoid.geoid_type();
let tiger_uri = TigerResource::new(uri, geoid_type, file_scope); Ok(tiger_uri)
}
fn get_year(&self) -> u64 {
match self {
TigerResourceBuilder::Tiger2010 => 2010,
TigerResourceBuilder::Tiger2010Format { year } => *year,
TigerResourceBuilder::Tiger2020Format { year } => *year,
}
}
fn base_url(&self) -> String {
let year = self.get_year();
format!("{}/TIGER{}", TigerResourceBuilder::TIGER_BASE_URL, year)
}
}