destination/import/
fire_inspection.rs

1//! The `fire_inspections` module imports data from fire inspections into the library to facilitate
2//! address matching.
3use crate::{AddressErrorKind, Io, Nom, Parse, PartialAddress};
4
5/// The `FireInspectionRaw` struct functions as a builder for a [`FireInspection`] struct.
6/// The fields correspond to the csv of fire inspection data from the fire department.
7/// A raw inspection represents the address a String, as opposed to a [`PartialAddress`].
8#[derive(
9    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize,
10)]
11#[serde(rename_all = "PascalCase")]
12pub struct FireInspectionRaw {
13    // Business name.
14    name: String,
15    // Address blob.
16    address: String,
17    // Field used by fire dept.
18    class: Option<String>,
19    // Field used by fire dept.
20    subclass: Option<String>,
21}
22
23/// The `FireInspectionsRaw` struct is a wrapper around a vector of type [`FireInspectionRaw`]
24#[derive(
25    Debug,
26    Clone,
27    PartialEq,
28    Eq,
29    PartialOrd,
30    Ord,
31    Hash,
32    serde::Deserialize,
33    serde::Serialize,
34    derive_more::Deref,
35    derive_more::DerefMut,
36)]
37pub struct FireInspectionsRaw(Vec<FireInspectionRaw>);
38
39impl FireInspectionsRaw {
40    /// Used to read fire inspection data in from the csv source file.
41    #[tracing::instrument(skip_all)]
42    pub fn from_csv<P: AsRef<std::path::Path>>(path: P) -> Result<Self, Io> {
43        let records = crate::from_csv(path)?;
44        Ok(FireInspectionsRaw(records))
45    }
46}
47
48/// The `FireInspection` struct contains fields from a fire inspection record, with the business
49/// address mapped to a [`PartialAddress`].  Built from a [`FireInspectionRaw`].
50#[derive(
51    Debug,
52    Clone,
53    PartialEq,
54    Eq,
55    PartialOrd,
56    Ord,
57    Hash,
58    serde::Serialize,
59    serde::Deserialize,
60    derive_getters::Getters,
61    derive_setters::Setters,
62)]
63#[setters(prefix = "with_", strip_option, borrow_self)]
64pub struct FireInspection {
65    #[setters(doc = "Sets the value of the `name` field representing the business name.")]
66    name: String,
67    #[setters(doc = "Sets the value of the `address` field representing the business address.")]
68    address: PartialAddress,
69    // Field used by fire dept.
70    class: Option<String>,
71    // Field used by fire dept.
72    subclass: Option<String>,
73}
74
75impl TryFrom<FireInspectionRaw> for FireInspection {
76    type Error = Nom;
77
78    fn try_from(raw: FireInspectionRaw) -> Result<Self, Self::Error> {
79        match Parse::address(&raw.address) {
80            Ok((_, address)) => {
81                let mut upper_address = address.clone();
82                if let Some(identifier) = address.subaddress_identifier() {
83                    upper_address.set_subaddress_identifier(&identifier.to_uppercase())
84                };
85                Ok(FireInspection {
86                    name: raw.name,
87                    address: upper_address,
88                    class: raw.class,
89                    subclass: raw.subclass,
90                })
91            }
92            Err(source) => Err(Nom::new(
93                raw.address.clone(),
94                source,
95                line!(),
96                file!().to_string(),
97            )),
98        }
99    }
100}
101
102/// The `FireInspections` struct is a wrapper around a vector of type [`FireInspection`].
103#[derive(
104    Debug,
105    Clone,
106    PartialEq,
107    Eq,
108    PartialOrd,
109    Ord,
110    Hash,
111    serde::Deserialize,
112    serde::Serialize,
113    derive_more::Deref,
114    derive_more::DerefMut,
115)]
116pub struct FireInspections(Vec<FireInspection>);
117
118impl FireInspections {
119    /// Reads in the data as a raw fire inspections, attempts to parse each address, returning a
120    /// `FireInspections` if successful.
121    #[tracing::instrument(skip_all)]
122    pub fn from_csv<P: AsRef<std::path::Path>>(path: P) -> Result<Self, AddressErrorKind> {
123        // Try to read in as raw.
124        let raw = FireInspectionsRaw::from_csv(path)?;
125        let mut records = Vec::new();
126        for record in raw.iter() {
127            // Parse the raw address.
128            records.push(FireInspection::try_from(record.clone())?);
129        }
130        Ok(FireInspections(records))
131    }
132}