From ce60eaf310ac4f7770027eac93d97a31b82b8db4 Mon Sep 17 00:00:00 2001 From: Joshua Coles Date: Sun, 3 Mar 2024 18:14:50 +0000 Subject: [PATCH] Add time_entry columns --- Cargo.lock | 1 + migration/Cargo.lock | 350 +++++++++++++++++- migration/Cargo.toml | 2 + migration/src/lib.rs | 2 + ...20240302_171651_update_time_entry_table.rs | 56 +++ src/db.rs | 18 +- src/entity/time_entry.rs | 4 + src/toggl_api/types.rs | 8 +- 8 files changed, 434 insertions(+), 7 deletions(-) create mode 100644 migration/src/m20240302_171651_update_time_entry_table.rs diff --git a/Cargo.lock b/Cargo.lock index 710764a..51c2b4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1630,6 +1630,7 @@ version = "0.1.0" dependencies = [ "async-std", "sea-orm-migration", + "serde_json", ] [[package]] diff --git a/migration/Cargo.lock b/migration/Cargo.lock index 4c4187f..b3d3817 100644 --- a/migration/Cargo.lock +++ b/migration/Cargo.lock @@ -355,6 +355,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" @@ -366,6 +372,9 @@ name = "bitflags" version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -437,6 +446,7 @@ dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", + "serde", "windows-targets 0.52.4", ] @@ -495,6 +505,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -550,6 +566,27 @@ dependencies = [ "typenum", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "derivative" version = "2.2.0" @@ -568,6 +605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -683,6 +721,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -722,6 +771,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-intrusive" version = "0.5.0" @@ -1020,6 +1080,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "libc" @@ -1027,6 +1090,23 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -1089,6 +1169,7 @@ version = "0.1.0" dependencies = [ "async-std", "sea-orm-migration", + "serde_json", ] [[package]] @@ -1139,6 +1220,49 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -1146,6 +1270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1241,6 +1366,15 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1270,6 +1404,33 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "polling" version = "2.8.0" @@ -1300,6 +1461,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1441,11 +1608,31 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin", + "spin 0.9.8", "untrusted", "windows-sys 0.52.0", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1552,6 +1739,7 @@ checksum = "6632f499b80cc6aaa781b302e4c9fae663e0e3dcf2640e9d80034d5b10731efe" dependencies = [ "async-stream", "async-trait", + "chrono", "futures", "log", "ouroboros", @@ -1559,11 +1747,14 @@ dependencies = [ "sea-query", "sea-query-binder", "serde", + "serde_json", "sqlx", "strum", "thiserror", + "time", "tracing", "url", + "uuid", ] [[package]] @@ -1624,6 +1815,7 @@ dependencies = [ "inherent", "ordered-float", "sea-query-derive", + "serde_json", ] [[package]] @@ -1633,6 +1825,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36bbb68df92e820e4d5aeb17b4acd5cc8b5d18b2c36a4dd6f4626aabfa7ab1b9" dependencies = [ "sea-query", + "serde_json", "sqlx", ] @@ -1734,6 +1927,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "slab" version = "0.4.9" @@ -1769,11 +1972,30 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] [[package]] name = "sqlformat" @@ -1794,7 +2016,9 @@ checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" dependencies = [ "sqlx-core", "sqlx-macros", + "sqlx-mysql", "sqlx-postgres", + "sqlx-sqlite", ] [[package]] @@ -1871,13 +2095,57 @@ dependencies = [ "serde_json", "sha2", "sqlx-core", + "sqlx-mysql", "sqlx-postgres", + "sqlx-sqlite", "syn 1.0.109", "tempfile", "tokio", "url", ] +[[package]] +name = "sqlx-mysql" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +dependencies = [ + "atoi", + "base64", + "bitflags 2.4.2", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + [[package]] name = "sqlx-postgres" version = "0.7.3" @@ -1917,6 +2185,29 @@ dependencies = [ "whoami", ] +[[package]] +name = "sqlx-sqlite" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -2016,6 +2307,36 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -2161,18 +2482,39 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "serde", +] + [[package]] name = "value-bag" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126e423afe2dd9ac52142e7e9d5ce4135d7e13776c529d27fd6bc49f19e3280b" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -2461,3 +2803,9 @@ dependencies = [ "quote", "syn 2.0.52", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/migration/Cargo.toml b/migration/Cargo.toml index 9b9195e..059df7d 100644 --- a/migration/Cargo.toml +++ b/migration/Cargo.toml @@ -10,10 +10,12 @@ path = "src/lib.rs" [dependencies] async-std = { version = "1", features = ["attributes", "tokio1"] } +serde_json = "^1.0" [dependencies.sea-orm-migration] version = "0.12.0" features = [ "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature "sqlx-postgres", # `DATABASE_DRIVER` feature + 'with-json' ] diff --git a/migration/src/lib.rs b/migration/src/lib.rs index c52530f..5b7d6ff 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -5,6 +5,7 @@ mod m20231106_134950_create_clients; mod m20231106_195401_create_projects; mod m20231106_201029_add_time_entry_project_fk; mod m20240302_102418_update_project_table; +mod m20240302_171651_update_time_entry_table; pub struct Migrator; @@ -17,6 +18,7 @@ impl MigratorTrait for Migrator { Box::new(m20231106_195401_create_projects::Migration), Box::new(m20231106_201029_add_time_entry_project_fk::Migration), Box::new(m20240302_102418_update_project_table::Migration), + Box::new(m20240302_171651_update_time_entry_table::Migration), ] } diff --git a/migration/src/m20240302_171651_update_time_entry_table.rs b/migration/src/m20240302_171651_update_time_entry_table.rs new file mode 100644 index 0000000..24513c9 --- /dev/null +++ b/migration/src/m20240302_171651_update_time_entry_table.rs @@ -0,0 +1,56 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.alter_table(TableAlterStatement::new() + .table(TimeEntry::Table) + .add_column(ColumnDef::new(TimeEntry::Tags) + .json_binary() + .default(serde_json::json!([])) + .not_null() + ) + .add_column(ColumnDef::new(TimeEntry::ServerUpdatedAt) + .timestamp_with_time_zone()) + .add_column(ColumnDef::new(TimeEntry::ServerDeletedAt) + .timestamp_with_time_zone()) + .to_owned() + ).await?; + + manager.get_connection().execute_unprepared( + r#" + update "time_entry" + set "tags" = coalesce(raw_json -> 'tags', '[]' :: jsonb), + "server_updated_at" = (raw_json ->> 'at') :: timestamptz; + "#, + ).await?; + + manager.alter_table( + TableAlterStatement::new() + .table(TimeEntry::Table) + .modify_column(ColumnDef::new(TimeEntry::ServerUpdatedAt).not_null()) + .to_owned() + ).await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.alter_table(TableAlterStatement::new() + .table(TimeEntry::Table) + .drop_column(TimeEntry::Tags) + .drop_column(TimeEntry::ServerDeletedAt) + .drop_column(TimeEntry::ServerUpdatedAt) + .to_owned() + ).await + } +} + +#[derive(DeriveIden)] +enum TimeEntry { + Table, + ServerUpdatedAt, + ServerDeletedAt, + Tags, +} diff --git a/src/db.rs b/src/db.rs index 958f4cd..4e04711 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,5 +1,5 @@ use crate::entity::{client, project, time_entry}; -use crate::toggl_api::types::{Project, Client, ReportRow}; +use crate::toggl_api::types::{Project, Client, ReportRow, TimeEntry}; use sea_orm::sea_query::OnConflict; use sea_orm::{NotSet, Set}; @@ -32,6 +32,20 @@ impl ReportRow { } } +impl TimeEntry { + pub(crate) fn as_model(&self) -> time_entry::ActiveModel { + time_entry::ActiveModel { + id: NotSet, + toggl_id: Set(self.id), + description: Set(self.description.clone()), + project_id: Set(self.project_id), + start: Set(self.start.clone().fixed_offset()), + stop: Set(self.stop.unwrap().fixed_offset()), + raw_json: Set(serde_json::to_value(self).unwrap()), + } + } +} + impl Client { pub fn as_model(&self) -> client::ActiveModel { client::ActiveModel { @@ -70,7 +84,7 @@ impl Project { color: Set(self.color.clone()), server_created_at: Set(self.created_at.clone().fixed_offset()), server_updated_at: Set(self.at.clone().fixed_offset()), - server_deleted_at: Set(self.server_deleted_at.clone().fixed_offset()), + server_deleted_at: Set(self.server_deleted_at.map(|dt| dt.fixed_offset())), } } diff --git a/src/entity/time_entry.rs b/src/entity/time_entry.rs index c3041eb..279deac 100644 --- a/src/entity/time_entry.rs +++ b/src/entity/time_entry.rs @@ -16,6 +16,10 @@ pub struct Model { pub stop: DateTimeWithTimeZone, #[sea_orm(column_type = "JsonBinary")] pub raw_json: Json, + #[sea_orm(column_type = "JsonBinary")] + pub tags: Json, + pub server_updated_at: DateTimeWithTimeZone, + pub server_deleted_at: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/toggl_api/types.rs b/src/toggl_api/types.rs index 8d89bc0..d84bbc9 100644 --- a/src/toggl_api/types.rs +++ b/src/toggl_api/types.rs @@ -37,14 +37,14 @@ pub struct TimeEntry { pub project_id: Option, pub task_id: Option, pub billable: bool, - pub start: String, - pub stop: Option, + pub start: DateTime, + pub stop: Option>, pub duration: i64, pub description: String, pub tags: Vec, pub tag_ids: Vec, - pub at: String, - pub server_deleted_at: Option, + pub at: DateTime, + pub server_deleted_at: Option>, pub user_id: i64, // Ignored fields