SOA for batch inserts using UNNEST as per docs
This commit is contained in:
parent
ce46739f30
commit
4efbb95204
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -1912,6 +1912,26 @@ version = "1.13.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "soa-rs"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c76685dff09a60d416b82a23e192e14cd47d147858b9aca2ce5ca05877acd93"
|
||||||
|
dependencies = [
|
||||||
|
"soa-rs-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "soa-rs-derive"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4281fd25ca7e6cc6e84cadaf296ffabac12719e830e1af160cd243dca831577"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.71",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.7"
|
version = "0.5.7"
|
||||||
@ -2343,6 +2363,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_json_path_to_error",
|
"serde_json_path_to_error",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
|
"soa-rs",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|||||||
@ -25,3 +25,4 @@ futures = "0.3.30"
|
|||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = "0.3.18"
|
tracing-subscriber = "0.3.18"
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
|
soa-rs = "0.6.1"
|
||||||
|
|||||||
26
src/main.rs
26
src/main.rs
@ -1,8 +1,9 @@
|
|||||||
use chrono::{DateTime, DurationRound, NaiveDate, TimeDelta, Utc};
|
use chrono::{DateTime, DurationRound, NaiveDate, TimeDelta, Utc};
|
||||||
use sqlx::{Connection, PgConnection, Postgres, QueryBuilder};
|
use sqlx::{Connection, PgConnection, Postgres, QueryBuilder};
|
||||||
use toggl::TogglApi;
|
use toggl::TogglApi;
|
||||||
use crate::toggl::types::{TimeEntry, TogglReportFilters};
|
use crate::toggl::types::{Tag, TimeEntry, TogglReportFilters};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use soa_rs::Soa;
|
||||||
|
|
||||||
mod toggl;
|
mod toggl;
|
||||||
mod sensitive;
|
mod sensitive;
|
||||||
@ -256,12 +257,12 @@ impl Worker {
|
|||||||
|
|
||||||
async fn update_tags(&mut self) -> Result<(), AppError> {
|
async fn update_tags(&mut self) -> Result<(), AppError> {
|
||||||
let tags = self.toggl_api.get_tags().await?;
|
let tags = self.toggl_api.get_tags().await?;
|
||||||
|
let tags: Soa<Tag> = Soa::from(tags.as_slice());
|
||||||
|
|
||||||
for tag in tags {
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO tags (id, name, workspace_id, creator_id, updated_at, deleted_at, permissions)
|
INSERT INTO tags (id, name, workspace_id, creator_id, updated_at, deleted_at, permissions)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
SELECT * FROM UNNEST($1::bigint[], $2::text[], $3::bigint[], $4::bigint[], $5::timestamptz[], $6::timestamptz[], $7::text[])
|
||||||
ON CONFLICT (id) DO UPDATE SET
|
ON CONFLICT (id) DO UPDATE SET
|
||||||
name = excluded.name,
|
name = excluded.name,
|
||||||
workspace_id = excluded.workspace_id,
|
workspace_id = excluded.workspace_id,
|
||||||
@ -270,17 +271,18 @@ impl Worker {
|
|||||||
deleted_at = excluded.deleted_at,
|
deleted_at = excluded.deleted_at,
|
||||||
permissions = excluded.permissions
|
permissions = excluded.permissions
|
||||||
"#,
|
"#,
|
||||||
tag.id as i64,
|
&tags.id().iter().map(|id| *id as i64).collect::<Vec<_>>()[..],
|
||||||
tag.name,
|
tags.name(),
|
||||||
tag.workspace_id as i64,
|
&tags.workspace_id().iter().map(|id| *id as i64).collect::<Vec<_>>()[..],
|
||||||
tag.creator_id as i64,
|
&tags.creator_id().iter().map(|id| *id as i64).collect::<Vec<_>>()[..],
|
||||||
tag.updated_at,
|
tags.updated_at(),
|
||||||
tag.deleted_at,
|
// Nullable fields fail to type check with UNNEST batch inserts so we silence the
|
||||||
tag.permissions,
|
// errors using `: _`.
|
||||||
|
tags.deleted_at(): _,
|
||||||
|
tags.permissions(): _,
|
||||||
)
|
)
|
||||||
.execute(&mut self.db)
|
.execute(&mut self.db)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -349,7 +351,7 @@ async fn main() {
|
|||||||
toggl_api: api,
|
toggl_api: api,
|
||||||
};
|
};
|
||||||
|
|
||||||
worker.update_clients()
|
worker.update_tags()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@ -349,7 +349,7 @@ pub mod types {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Soars, Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct TrackingClient {
|
pub struct TrackingClient {
|
||||||
/// The unique identifier for the client.
|
/// The unique identifier for the client.
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
@ -378,7 +378,7 @@ pub mod types {
|
|||||||
pub permissions: Option<String>,
|
pub permissions: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Soars, Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -493,6 +493,7 @@ pub mod types {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use soa_rs::Soars;
|
||||||
|
|
||||||
impl fmt::Debug for TogglReportFilters {
|
impl fmt::Debug for TogglReportFilters {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user