diff --git a/src/cache.rs b/src/cache/cache.rs similarity index 66% rename from src/cache.rs rename to src/cache/cache.rs index 36326d0..34959f2 100644 --- a/src/cache.rs +++ b/src/cache/cache.rs @@ -3,22 +3,20 @@ use std::io::{BufReader, BufWriter}; use std::path::Path; use anyhow::Context; -use chrono::serde::ts_seconds; -use chrono::{DateTime, Local, Utc}; use serde::{Deserialize, Serialize}; -use crate::models::ExchangeRateResult; +use crate::cli::Resolution; use crate::os::Os; +use super::CacheLine; + const FILE_NAME: &'static str = "cache.json"; #[derive(Serialize, Deserialize, Debug)] pub struct Cache { - #[serde(with = "ts_seconds")] - date: DateTime, - - #[serde(rename = "camelCase")] - pub exchange_rate_results: Vec, + day: Option, + hist_90: Option, + hist_day: Option, } impl Cache { @@ -37,7 +35,11 @@ impl Cache { } config_path.push(FILE_NAME); if !config_path.try_exists().unwrap_or_default() { - return None; + return Some(Self { + day: None, + hist_90: None, + hist_day: None, + }); } match Self::read_config(&config_path) { @@ -49,11 +51,20 @@ impl Cache { } } - pub fn new(exchange_rate_results: Vec) -> Self { - let date = Local::now().to_utc(); - Self { - exchange_rate_results, - date, + pub fn get_cache_line(&self, resolution: Resolution) -> Option<&CacheLine> { + match resolution { + Resolution::TODAY => self.day.as_ref(), + Resolution::HistDays90 => self.hist_90.as_ref(), + Resolution::HistDay => self.hist_day.as_ref(), + } + } + + pub fn set_cache_line(&mut self, resolution: Resolution, cache_line: CacheLine) { + let cache_line_opt = Some(cache_line); + match resolution { + Resolution::TODAY => self.day = cache_line_opt, + Resolution::HistDays90 => self.hist_90 = cache_line_opt, + Resolution::HistDay => self.hist_day = cache_line_opt, } } @@ -77,12 +88,6 @@ impl Cache { Ok(()) } - pub fn validate(&self) -> bool { - let today = Local::now().naive_local().date(); - let saved = self.date.naive_local().date(); - saved == today - } - fn read_config(path: &Path) -> anyhow::Result { let file = fs::File::open(path)?; let reader = BufReader::new(file); diff --git a/src/cache/cache_line.rs b/src/cache/cache_line.rs new file mode 100644 index 0000000..33422cc --- /dev/null +++ b/src/cache/cache_line.rs @@ -0,0 +1,30 @@ +use chrono::serde::ts_seconds; +use chrono::{DateTime, Local, Utc}; +use serde::{Deserialize, Serialize}; + +use crate::models::ExchangeRateResult; + +#[derive(Serialize, Deserialize, Debug)] +pub struct CacheLine { + #[serde(with = "ts_seconds")] + date: DateTime, + + #[serde(rename = "camelCase")] + pub exchange_rate_results: Vec, +} + +impl CacheLine { + pub fn validate(&self) -> bool { + let today = Local::now().naive_local().date(); + let saved = self.date.naive_local().date(); + saved == today + } + + pub fn new(exchange_rate_results: Vec) -> Self { + let date = Local::now().to_utc(); + Self { + exchange_rate_results, + date, + } + } +} diff --git a/src/cache/mod.rs b/src/cache/mod.rs new file mode 100644 index 0000000..94b6469 --- /dev/null +++ b/src/cache/mod.rs @@ -0,0 +1,5 @@ +mod cache; +mod cache_line; + +pub use cache::Cache; +pub use cache_line::CacheLine; diff --git a/src/main.rs b/src/main.rs index 8f4b220..f70d1ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,12 @@ use clap::Parser as _; -use ecb_rates::cache::Cache; +use ecb_rates::cache::{Cache, CacheLine}; use reqwest::{Client, IntoUrl}; use std::{borrow::BorrowMut, collections::HashMap, process::ExitCode}; use ecb_rates::cli::{Cli, FormatOption}; use ecb_rates::models::ExchangeRateResult; use ecb_rates::parsing::parse; -use ecb_rates::table::{TableRef, TableTrait}; +use ecb_rates::table::{TableRef, TableTrait as _}; async fn get_and_parse(url: impl IntoUrl) -> anyhow::Result> { let client = Client::new(); @@ -40,10 +40,23 @@ async fn main() -> ExitCode { } let use_cache = !cli.no_cache; - let cache = if use_cache { Cache::load() } else { None }; - let cache_ok = cache.as_ref().map_or_else(|| false, |c| c.validate()); + let mut cache = if use_cache { Cache::load() } else { None }; + let cache_ok = cache.as_ref().map_or_else( + || false, + |c| { + c.get_cache_line(cli.resolution) + .map_or_else(|| false, |cl| cl.validate()) + }, + ); let mut parsed = if cache_ok { - cache.as_ref().unwrap().exchange_rate_results.clone() + // These are safe unwraps + cache + .as_ref() + .unwrap() + .get_cache_line(cli.resolution) + .unwrap() + .exchange_rate_results + .clone() } else { let parsed = match get_and_parse(cli.resolution.to_ecb_url()).await { Ok(k) => k, @@ -53,8 +66,12 @@ async fn main() -> ExitCode { } }; if !cache_ok { - if let Err(e) = Cache::new(parsed.clone()).save() { - eprintln!("Failed to save to cache with: {:?}", e); + if let Some(cache_safe) = cache.as_mut() { + let cache_line = CacheLine::new(parsed.clone()); + cache_safe.set_cache_line(cli.resolution, cache_line); + if let Err(e) = cache_safe.save() { + eprintln!("Failed to save to cache with: {:?}", e); + } } } parsed