f1 0.2.0

Get historical and live Formula 1 (F1) data
Documentation
mod api_structs;
mod convert;

use crate::ergast;
use crate::Constructor;
use crate::Driver;
use crate::F1Error;
use crate::SessionType;
use chrono::Local;
use chrono::NaiveTime;
use serde::Deserialize;

use self::api_structs::ErgastCircuit;
use self::api_structs::QualiResult;
use self::api_structs::RaceResult;

pub fn get_season(year: i32) -> Result<Vec<ErgastWeekend>, F1Error> {
    let v = ergast::get(year.to_string())?;
    let weekends = v["RaceTable"]["Races"]
        .as_array()
        .unwrap()
        .iter()
        .map(|item| {
            ErgastWeekend::new(
                item["season"].as_str().unwrap().parse().unwrap(),
                item["round"].as_str().unwrap().parse().unwrap(),
            )
            .unwrap()
        })
        .collect();

    Ok(weekends)
}

pub struct ErgastWeekend {
    pub year: i32,
    pub round: i32,
    pub name: String,
    circuit: ErgastCircuit,
}

impl ErgastWeekend {
    pub fn new(year: i32, round: i32) -> Result<Self, F1Error> {
        let url = format!("{}/{}", year, round);
        let v = ergast::get(url)?;
        let c: ErgastCircuit =
            serde_json::from_value(v["RaceTable"]["Races"][0]["Circuit"].clone())
                .map_err(|_| F1Error::JsonDeserialization)?;

        Ok(Self {
            year,
            round,
            name: v["RaceTable"]["Races"][0]["raceName"]
                .as_str()
                .unwrap_or_default()
                .parse()
                .unwrap_or_default(),
            circuit: c,
        })
    }

    fn race_results(&self) -> Result<Vec<RaceResult>, F1Error> {
        let url = format!("{}/{}/results", self.year, self.round);
        let v = ergast::get(url)?;

        let ret: Vec<RaceResult> =
            serde_json::from_value(v["RaceTable"]["Races"][0]["Results"].clone())
                .map_err(|_| F1Error::JsonDeserialization)?;

        Ok(ret)
    }

    fn qualifying_results(&self) -> Result<Vec<QualiResult>, F1Error> {
        let url = format!("{}/{}/qualifying", self.year, self.round);
        let v = ergast::get(url)?;

        let ret: Vec<QualiResult> =
            serde_json::from_value(v["RaceTable"]["Races"][0]["QualifyingResults"].clone())
                .map_err(|_| F1Error::JsonDeserialization)?;

        Ok(ret)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::*;

    #[test]
    fn test_quali_results() {
        let weekend = ErgastWeekend::new(2021, 22).unwrap();
        let results = weekend.qualifying_results().unwrap();
        let max = results[0].clone();
        assert_eq!(max.position, "1");
    }

    #[test]
    fn test_quali_results_with_from() {
        let weekend = ErgastWeekend::new(2021, 22).unwrap();
        let results: Session = weekend.qualifying_results().unwrap().into();

        assert_eq!(results.r#type, SessionType::Qualifying);

        let max = &results.standings[0];
        assert_eq!(max.position, 1);
        assert_eq!(max.lap_time, NaiveTime::from_hms_milli(0, 1, 22, 109));

        let lewis = &results.standings[1];
        assert_eq!(lewis.position, 2);
        assert_eq!(lewis.lap_time, NaiveTime::from_hms_milli(0, 1, 22, 480));

        let alonso = &results.standings[10];
        assert_eq!(alonso.position, 11);
        assert_eq!(alonso.lap_time, NaiveTime::from_hms_milli(0, 1, 23, 460));
    }

    #[test]
    fn test_race_results() {
        let weekend = ErgastWeekend::new(2021, 22).unwrap();
        let results = weekend.race_results().unwrap();
        let max = results[0].clone();
        assert_eq!(max.position, "1");
    }

    #[test]
    fn test_race_results_with_from() {
        let weekend = ErgastWeekend::new(2021, 22).unwrap();
        let results: Session = weekend.race_results().unwrap().into();

        assert_eq!(results.r#type, SessionType::Race);

        let max = &results.standings[0];
        assert_eq!(max.position, 1);
        assert_eq!(max.lap_time, NaiveTime::from_hms_milli(0, 1, 26, 103));

        let lewis = &results.standings[1];
        assert_eq!(lewis.position, 2);
        assert_eq!(lewis.lap_time, NaiveTime::from_hms_milli(0, 1, 26, 615));
    }

    #[test]
    fn test_get_weekend() {
        let weekend = ErgastWeekend::new(2021, 22).unwrap();
        assert_eq!(weekend.name, "Abu Dhabi Grand Prix");
        assert_eq!(weekend.year, 2021);
        assert_eq!(weekend.round, 22);
    }

    #[test]
    fn test_get_2021_season() {
        let weekends = get_season(2021).unwrap();
        assert_eq!(weekends.len(), 22);

        let first = weekends.first().unwrap();
        assert_eq!(first.name, "Bahrain Grand Prix");
    }
}