(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" }
|
||||
chrono = { version = "0.4.31", features = ["serde"] }
|
||||
futures = "0.3.29"
|
||||
|
||||
4
justfile
4
justfile
@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env just --justfile
|
||||
|
||||
reset:
|
||||
sea-orm-cli migrate down
|
||||
sea-orm-cli migrate up
|
||||
|
||||
migrate:
|
||||
sea-orm-cli migrate up
|
||||
|
||||
|
||||
@ -7,8 +7,12 @@ pub struct Migrator;
|
||||
#[async_trait::async_trait]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![
|
||||
Box::new(m20231101_172500_create_time_entry_table::Migration),
|
||||
]
|
||||
vec![Box::new(
|
||||
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()
|
||||
.col(
|
||||
ColumnDef::new(TimeEntry::Id)
|
||||
.big_integer()
|
||||
.integer()
|
||||
.not_null()
|
||||
.auto_increment()
|
||||
.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::ProjectId).big_integer())
|
||||
.col(ColumnDef::new(TimeEntry::Start).timestamp().not_null())
|
||||
.col(ColumnDef::new(TimeEntry::Stop).timestamp().not_null())
|
||||
.col(ColumnDef::new(TimeEntry::ProjectId).big_unsigned())
|
||||
.col(ColumnDef::new(TimeEntry::Start).timestamp_with_time_zone().not_null())
|
||||
.col(ColumnDef::new(TimeEntry::Stop).timestamp_with_time_zone().not_null())
|
||||
.col(ColumnDef::new(TimeEntry::RawJson).json_binary().not_null())
|
||||
.to_owned(),
|
||||
)
|
||||
@ -39,6 +41,7 @@ impl MigrationTrait for Migration {
|
||||
enum TimeEntry {
|
||||
Table,
|
||||
Id,
|
||||
TogglId,
|
||||
Description,
|
||||
ProjectId,
|
||||
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")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i64,
|
||||
pub id: i32,
|
||||
pub toggl_id: i64,
|
||||
pub description: String,
|
||||
pub project_id: Option<i64>,
|
||||
pub start: DateTime,
|
||||
pub stop: DateTime,
|
||||
pub start: DateTimeWithTimeZone,
|
||||
pub stop: DateTimeWithTimeZone,
|
||||
#[sea_orm(column_type = "JsonBinary")]
|
||||
pub raw_json: Json,
|
||||
}
|
||||
|
||||
23
src/main.rs
23
src/main.rs
@ -12,11 +12,16 @@ use clap::Parser;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
use sea_orm::{DatabaseConnection, EntityTrait};
|
||||
use sea_orm::sea_query::OnConflict;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use migration::{Migrator, MigratorTrait};
|
||||
use crate::entity::time_entry::{self, Entity as TimeEntry};
|
||||
|
||||
mod client;
|
||||
mod types;
|
||||
mod db;
|
||||
mod entity;
|
||||
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
struct Config {
|
||||
@ -35,9 +40,25 @@ struct Config {
|
||||
|
||||
pub async fn report(
|
||||
Extension(toggl_client): Extension<TogglClient>,
|
||||
Extension(db): Extension<DatabaseConnection>,
|
||||
Json(query): Json<TogglQuery>,
|
||||
) -> 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(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user