(toggl-portal): Database work
This commit is contained in:
parent
8f39bf7d23
commit
d47174efee
@ -28,3 +28,5 @@ sea-orm = { version = "0.12", features = [
|
|||||||
] }
|
] }
|
||||||
|
|
||||||
migration = { path = "./migration" }
|
migration = { path = "./migration" }
|
||||||
|
chrono = { version = "0.4.31", features = ["serde"] }
|
||||||
|
futures = "0.3.29"
|
||||||
|
|||||||
4
justfile
4
justfile
@ -1,5 +1,9 @@
|
|||||||
#!/usr/bin/env just --justfile
|
#!/usr/bin/env just --justfile
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sea-orm-cli migrate down
|
||||||
|
sea-orm-cli migrate up
|
||||||
|
|
||||||
migrate:
|
migrate:
|
||||||
sea-orm-cli migrate up
|
sea-orm-cli migrate up
|
||||||
|
|
||||||
|
|||||||
@ -7,8 +7,12 @@ pub struct Migrator;
|
|||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl MigratorTrait for Migrator {
|
impl MigratorTrait for Migrator {
|
||||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||||
vec![
|
vec![Box::new(
|
||||||
Box::new(m20231101_172500_create_time_entry_table::Migration),
|
m20231101_172500_create_time_entry_table::Migration,
|
||||||
]
|
)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migration_table_name() -> DynIden {
|
||||||
|
Alias::new("toggl_portal_seaql_migrations").into_iden()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,15 +13,17 @@ impl MigrationTrait for Migration {
|
|||||||
.if_not_exists()
|
.if_not_exists()
|
||||||
.col(
|
.col(
|
||||||
ColumnDef::new(TimeEntry::Id)
|
ColumnDef::new(TimeEntry::Id)
|
||||||
.big_integer()
|
.integer()
|
||||||
.not_null()
|
.not_null()
|
||||||
.auto_increment()
|
.auto_increment()
|
||||||
.primary_key(),
|
.primary_key(),
|
||||||
)
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(TimeEntry::TogglId).big_unsigned().not_null().unique_key())
|
||||||
.col(ColumnDef::new(TimeEntry::Description).string().not_null())
|
.col(ColumnDef::new(TimeEntry::Description).string().not_null())
|
||||||
.col(ColumnDef::new(TimeEntry::ProjectId).big_integer())
|
.col(ColumnDef::new(TimeEntry::ProjectId).big_unsigned())
|
||||||
.col(ColumnDef::new(TimeEntry::Start).timestamp().not_null())
|
.col(ColumnDef::new(TimeEntry::Start).timestamp_with_time_zone().not_null())
|
||||||
.col(ColumnDef::new(TimeEntry::Stop).timestamp().not_null())
|
.col(ColumnDef::new(TimeEntry::Stop).timestamp_with_time_zone().not_null())
|
||||||
.col(ColumnDef::new(TimeEntry::RawJson).json_binary().not_null())
|
.col(ColumnDef::new(TimeEntry::RawJson).json_binary().not_null())
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
@ -39,6 +41,7 @@ impl MigrationTrait for Migration {
|
|||||||
enum TimeEntry {
|
enum TimeEntry {
|
||||||
Table,
|
Table,
|
||||||
Id,
|
Id,
|
||||||
|
TogglId,
|
||||||
Description,
|
Description,
|
||||||
ProjectId,
|
ProjectId,
|
||||||
Start,
|
Start,
|
||||||
|
|||||||
17
src/db.rs
Normal file
17
src/db.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use sea_orm::{NotSet, Set};
|
||||||
|
use crate::entity::time_entry::ActiveModel;
|
||||||
|
use crate::types::ReportEntry;
|
||||||
|
|
||||||
|
impl ReportEntry {
|
||||||
|
pub(crate) fn as_models(&self) -> Vec<ActiveModel> {
|
||||||
|
self.time_entries.iter().map(|inner| ActiveModel {
|
||||||
|
id: NotSet,
|
||||||
|
toggl_id: Set(inner.id as i64),
|
||||||
|
description: Set(self.description.clone()),
|
||||||
|
project_id: Set(self.project_id.map(|id| id as i64)),
|
||||||
|
start: Set(chrono::DateTime::parse_from_rfc3339(&inner.start).unwrap()),
|
||||||
|
stop: Set(chrono::DateTime::parse_from_rfc3339(&inner.start).unwrap()),
|
||||||
|
raw_json: Set(serde_json::to_value(inner).unwrap()),
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,11 +7,12 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[sea_orm(table_name = "time_entry")]
|
#[sea_orm(table_name = "time_entry")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: i64,
|
pub id: i32,
|
||||||
|
pub toggl_id: i64,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub project_id: Option<i64>,
|
pub project_id: Option<i64>,
|
||||||
pub start: DateTime,
|
pub start: DateTimeWithTimeZone,
|
||||||
pub stop: DateTime,
|
pub stop: DateTimeWithTimeZone,
|
||||||
#[sea_orm(column_type = "JsonBinary")]
|
#[sea_orm(column_type = "JsonBinary")]
|
||||||
pub raw_json: Json,
|
pub raw_json: Json,
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/main.rs
23
src/main.rs
@ -12,11 +12,16 @@ use clap::Parser;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
use sea_orm::{DatabaseConnection, EntityTrait};
|
||||||
|
use sea_orm::sea_query::OnConflict;
|
||||||
use tower_http::trace::TraceLayer;
|
use tower_http::trace::TraceLayer;
|
||||||
use migration::{Migrator, MigratorTrait};
|
use migration::{Migrator, MigratorTrait};
|
||||||
|
use crate::entity::time_entry::{self, Entity as TimeEntry};
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
mod types;
|
mod types;
|
||||||
|
mod db;
|
||||||
|
mod entity;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Parser)]
|
#[derive(Debug, Clone, Parser)]
|
||||||
struct Config {
|
struct Config {
|
||||||
@ -35,9 +40,25 @@ struct Config {
|
|||||||
|
|
||||||
pub async fn report(
|
pub async fn report(
|
||||||
Extension(toggl_client): Extension<TogglClient>,
|
Extension(toggl_client): Extension<TogglClient>,
|
||||||
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Json(query): Json<TogglQuery>,
|
Json(query): Json<TogglQuery>,
|
||||||
) -> Result<Json<Vec<ReportEntry>>> {
|
) -> Result<Json<Vec<ReportEntry>>> {
|
||||||
Ok(toggl_client.full_report(&query).await.map(Json)?)
|
let report = toggl_client.full_report(&query).await?;
|
||||||
|
let models = report.iter().flat_map(|entry| entry.as_models());
|
||||||
|
|
||||||
|
TimeEntry::insert_many(models)
|
||||||
|
.on_conflict(
|
||||||
|
OnConflict::column(time_entry::Column::TogglId)
|
||||||
|
.update_columns(vec![
|
||||||
|
time_entry::Column::Description,
|
||||||
|
time_entry::Column::ProjectId,
|
||||||
|
time_entry::Column::Start,
|
||||||
|
time_entry::Column::Stop,
|
||||||
|
time_entry::Column::RawJson,
|
||||||
|
]).to_owned()
|
||||||
|
).exec(&db).await?;
|
||||||
|
|
||||||
|
Ok(Json(report))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn current(
|
pub async fn current(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user