chicago_project_zero_fatalities_parser 0.1.1

A parser for json data found at 'Vision Zero Chicago Traffic Fatalities | Chicago Data Portal' into GeoJson without unecessary properties.
Documentation
use anyhow::{Context, Result};
use geojson::{Feature, FeatureCollection, GeoJson, Geometry, JsonObject, JsonValue};
use serde::{Deserialize, Serialize};
use serde_json::{from_str, to_string};

#[derive(Debug, Deserialize, Serialize)]
pub struct InputJson<'a> {
    #[serde(rename = "geocoded_column")]
    geometry: Geometry,
    crash_circumstances: Option<String>,
    crash_date: &'a str,
    crash_location: &'a str,
    latitude: &'a str,
    longitude: &'a str,
    victim: &'a str,
}

pub fn parse_file(filename: String) -> Result<String, anyhow::Error> {
    let json = std::fs::read_to_string(&filename)
        .with_context(|| format!("could not read file `{}`", filename))?;
    let input_vec = from_str::<Vec<InputJson>>(&json)
        .with_context(|| format!("could not json from `{}`", json))?;
    let feature_vec = transform_to_geojson_feature_vec(input_vec);
    let geojson = make_feature_collection(feature_vec);

    to_string(&geojson).with_context(|| format!("Failed to parse JSON from: {}", geojson))
}

fn transform_to_geojson_feature_vec(input_vec: Vec<InputJson>) -> Vec<Feature> {
    let mut feature_vec: Vec<Feature> = Vec::new();

    for input_entry in &input_vec {
        let geojson = GeoJson::Feature(Feature {
            bbox: None,
            geometry: Some(input_entry.geometry.clone()),
            id: None,
            properties: Some(geo_properties_from_input_json(input_entry)),
            foreign_members: None,
        });

        let feature = Feature::try_from(geojson).expect("Failed to parse Feature from GeoJSON");

        feature_vec.push(feature);
    }

    feature_vec
}

fn make_feature_collection(input_features: Vec<Feature>) -> GeoJson {
    let feature_collection = FeatureCollection {
        bbox: None,
        features: input_features,
        foreign_members: None,
    };

    GeoJson::from(feature_collection)
}

fn geo_properties_from_input_json(input_json: &InputJson) -> JsonObject {
    let mut properties = JsonObject::new();

    properties.insert(
        "crash_circumstances".to_string(),
        JsonValue::from(input_json.crash_circumstances.as_deref()),
    );
    properties.insert(
        "crash_date".to_string(),
        JsonValue::from(input_json.crash_date),
    );
    properties.insert(
        "crash_location".to_string(),
        JsonValue::from(input_json.crash_location),
    );
    properties.insert("latitude".to_string(), JsonValue::from(input_json.latitude));

    properties.insert(
        "longitude".to_string(),
        JsonValue::from(input_json.longitude),
    );
    properties.insert("victim".to_string(), JsonValue::from(input_json.victim));

    properties
}