From 71f9ed33121ea7ea67df92c2e25b5a83350d94c4 Mon Sep 17 00:00:00 2001 From: Joshua Coles Date: Sat, 27 Jul 2024 20:51:14 +0100 Subject: [PATCH] Move all to SOA and tag time entries to join table as this should be how it works and also UNNEST doesn't support nested arrays --- ...20240727194157_move_tags_to_join_table.sql | 16 ++++ src/main.rs | 82 +++++++++---------- src/toggl/mod.rs | 2 +- 3 files changed, 58 insertions(+), 42 deletions(-) create mode 100644 migrations/20240727194157_move_tags_to_join_table.sql diff --git a/migrations/20240727194157_move_tags_to_join_table.sql b/migrations/20240727194157_move_tags_to_join_table.sql new file mode 100644 index 0000000..c18b3d6 --- /dev/null +++ b/migrations/20240727194157_move_tags_to_join_table.sql @@ -0,0 +1,16 @@ +-- Create a new join table to associate time_entries with tags +CREATE TABLE public.time_entry_tags ( + time_entry_id bigint not null references public.time_entries(id) on delete cascade, + tag_id bigint not null references public.tags(id) on delete cascade, + primary key (time_entry_id, tag_id) +); + +-- Insert data into the new join table based on the existing time_entries and tags data +INSERT INTO public.time_entry_tags (time_entry_id, tag_id) +SELECT time_entries.id, UNNEST(time_entries.tag_ids) AS tag_id +FROM public.time_entries +WHERE time_entries.tag_ids IS NOT NULL; + +-- Remove the tag_ids array column from the time_entries table +ALTER TABLE public.time_entries +DROP COLUMN tag_ids; diff --git a/src/main.rs b/src/main.rs index b194136..a77334b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use chrono::{DateTime, DurationRound, NaiveDate, TimeDelta, Utc}; use sqlx::{Connection, PgConnection, Postgres, QueryBuilder}; use toggl::TogglApi; -use crate::toggl::types::{Tag, TimeEntry, TogglReportFilters, TrackingClient}; +use crate::toggl::types::{Project, Tag, TimeEntry, TogglReportFilters, TrackingClient}; use itertools::Itertools; use soa_rs::Soa; use tracing_subscriber::fmt::time; @@ -218,46 +218,46 @@ impl Worker { self.update_clients().await?; } - for project in projects { - sqlx::query!( - r#" - INSERT INTO projects (id, workspace_id, client_id, name, color, status, active, updated_at, start_date, created_at, server_deleted_at, actual_hours, actual_seconds, can_track_time, permissions) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) - ON CONFLICT (id) DO UPDATE SET - workspace_id = excluded.workspace_id, - client_id = excluded.client_id, - name = excluded.name, - color = excluded.color, - status = excluded.status, - active = excluded.active, - updated_at = excluded.updated_at, - start_date = excluded.start_date, - created_at = excluded.created_at, - server_deleted_at = excluded.server_deleted_at, - actual_hours = excluded.actual_hours, - actual_seconds = excluded.actual_seconds, - can_track_time = excluded.can_track_time, - permissions = excluded.permissions - "#, - project.id, - project.workspace_id, - project.client_id, - project.name, - project.color, - project.status.to_string(), - project.active, - project.updated_at, - project.start_date, - project.created_at, - project.server_deleted_at, - project.actual_hours, - project.actual_seconds, - project.can_track_time, - project.permissions, - ) - .execute(&mut self.db) - .await?; - } + let projects: Soa = Soa::from(projects.as_slice()); + + sqlx::query!( + r#" + INSERT INTO projects (id, workspace_id, client_id, name, color, status, active, updated_at, start_date, created_at, server_deleted_at, actual_hours, actual_seconds, can_track_time, permissions) + SELECT * FROM UNNEST($1::bigint[], $2::bigint[], $3::bigint[], $4::text[], $5::text[], $6::text[], $7::bool[], $8::timestamptz[], $9::date[], $10::timestamptz[], $11::timestamptz[], $12::int[], $13::int[], $14::bool[], $15::text[]) + ON CONFLICT (id) DO UPDATE SET + workspace_id = excluded.workspace_id, + client_id = excluded.client_id, + name = excluded.name, + color = excluded.color, + status = excluded.status, + active = excluded.active, + updated_at = excluded.updated_at, + start_date = excluded.start_date, + created_at = excluded.created_at, + server_deleted_at = excluded.server_deleted_at, + actual_hours = excluded.actual_hours, + actual_seconds = excluded.actual_seconds, + can_track_time = excluded.can_track_time, + permissions = excluded.permissions + "#, + &projects.id().iter().map(|id| *id as i64).collect_vec()[..], + &projects.workspace_id().iter().map(|id| *id as i64).collect_vec()[..], + projects.client_id().iter().map(|opt| opt.map(|id| id as i64)).collect_vec() as _, + projects.name(), + projects.color(), + &projects.status().iter().map(|s| s.to_string()).collect::>()[..], + projects.active(), + projects.updated_at(), + projects.start_date() as _, + projects.created_at(), + projects.server_deleted_at() as _, + &projects.actual_hours().iter().map(|opt| opt.map(|id| id as i64)).collect_vec() as _, + &projects.actual_seconds().iter().map(|opt| opt.map(|id| id as i64)).collect_vec() as _, + projects.can_track_time(), + projects.permissions() as _, + ) + .execute(&mut self.db) + .await?; Ok(()) } diff --git a/src/toggl/mod.rs b/src/toggl/mod.rs index 1de4ee1..530ea74 100644 --- a/src/toggl/mod.rs +++ b/src/toggl/mod.rs @@ -304,7 +304,7 @@ pub mod types { } } - #[derive(Serialize, Deserialize, Debug, Clone)] + #[derive(Serialize, Deserialize, Debug, Clone, Soars)] pub struct Project { pub id: i64, pub workspace_id: i64,