Refactor API and add 'fetch_within' method

Changed `workspace_id` type to `u64` for broader compatibility. Introduced `fetch_within` to allow fetching time entries within a given date range and abstracted database update logic into `update_database`.
This commit is contained in:
Joshua Coles 2024-07-27 19:34:48 +01:00
parent 7fb0ab06e1
commit ead22776c3
2 changed files with 42 additions and 12 deletions

View File

@ -1,6 +1,7 @@
use chrono::{DateTime, TimeDelta, Utc};
use chrono::{DateTime, DurationRound, NaiveDate, TimeDelta, Utc};
use sqlx::{Connection, PgConnection};
use toggl::TogglApi;
use crate::toggl::types::{TimeEntry, TogglReportFilters};
mod toggl;
mod sensitive;
@ -55,7 +56,21 @@ impl Worker {
})
}
async fn fetch_changed_since(&mut self, look_back: TimeDelta) -> Result<(), AppError> {
pub async fn fetch_within(&mut self, start: DateTime<Utc>, end: DateTime<Utc>) -> Result<(), AppError> {
let results = self.toggl_api.search(self.toggl_api.workspace_id, TogglReportFilters {
start_date: Some(start.date_naive()),
end_date: Some(end.date_naive()),
..Default::default()
}).await?;
let time_entries = results.into_iter()
.map(|entry| entry.into_time_entry(self.toggl_api.workspace_id))
.collect::<Vec<_>>();
self.update_database(time_entries).await
}
pub async fn fetch_changed_since(&mut self, look_back: TimeDelta) -> Result<(), AppError> {
if look_back > TimeDelta::days(90) {
return Err(AppError::LookBackTooLarge)
}
@ -63,7 +78,7 @@ impl Worker {
self.update_time_entries(Utc::now() - look_back).await
}
async fn update(&mut self, default_look_back: TimeDelta) -> Result<(), AppError> {
pub async fn update(&mut self, default_look_back: TimeDelta) -> Result<(), AppError> {
let result = sqlx::query!("select max(updated_at) as last_updated_at from time_entries")
.fetch_optional(&mut self.db)
.await
@ -77,11 +92,15 @@ impl Worker {
}
async fn update_time_entries(&mut self, fetch_since: DateTime<Utc>) -> Result<(), AppError> {
let existing_ids = self.get_ids().await?;
let time_entries = self.toggl_api
.get_time_entries_for_user_modified_since(fetch_since).await?;
self.update_database(time_entries).await
}
async fn update_database(&mut self, time_entries: Vec<TimeEntry>) -> Result<(), AppError> {
let existing_ids = self.get_ids().await?;
let fetch_workspaces = time_entries.iter()
.map(|entry| entry.workspace_id)
.filter(|workspace_id| !existing_ids.workspace_ids.contains(&workspace_id))
@ -324,7 +343,18 @@ async fn main() {
toggl_api: api,
};
worker.fetch_changed_since(TimeDelta::days(90))
.await
.unwrap();
let start = NaiveDate::from_ymd_opt(2024, 2, 1)
.expect("Invalid date")
.and_hms_opt(0, 0, 0)
.expect("Invalid time")
.and_utc();
let end = NaiveDate::from_ymd_opt(2024, 5, 1)
.expect("Invalid date")
.and_hms_opt(0, 0, 0)
.expect("Invalid time")
.and_utc();
worker.fetch_within(start, end).await
.expect("Failed to fetch time entries");
}

View File

@ -39,7 +39,7 @@ impl reqwest_ratelimit::RateLimiter for ReqwestRateLimiter {
#[derive(Clone)]
pub struct TogglApi {
client: ClientWithMiddleware,
workspace_id: u32,
pub workspace_id: u64,
headers: HeaderMap,
}
@ -212,11 +212,11 @@ impl TogglApi {
}
#[tracing::instrument(skip(self))]
pub async fn search(&self, filters: types::TogglReportFilters) -> Result<Vec<types::ReportEntry>, TogglError> {
pub async fn search(&self, workspace_id: u64, filters: types::TogglReportFilters) -> Result<Vec<types::ReportEntry>, TogglError> {
let url = format!(
"{base_url}/workspace/{workspace_id}/search/time_entries",
base_url = &REPORTS_BASE_URL,
workspace_id = self.workspace_id,
workspace_id = workspace_id,
);
let mut last_row_number = Some(0);
@ -432,7 +432,7 @@ pub mod types {
}
impl ReportEntry {
fn into_time_entry(self, workspace_id: u64) -> TimeEntry {
pub fn into_time_entry(self, workspace_id: u64) -> TimeEntry {
TimeEntry {
id: self.time_entries[0].id,
workspace_id,