(toggl-portal): Cache clients in database
This commit is contained in:
parent
100ef25044
commit
84cb5f5379
@ -1,15 +1,17 @@
|
||||
pub use sea_orm_migration::prelude::*;
|
||||
|
||||
mod m20231101_172500_create_time_entry_table;
|
||||
mod m20231106_134950_create_clients;
|
||||
|
||||
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),
|
||||
Box::new(m20231106_134950_create_clients::Migration),
|
||||
]
|
||||
}
|
||||
|
||||
fn migration_table_name() -> DynIden {
|
||||
|
||||
46
migration/src/m20231106_134950_create_clients.rs
Normal file
46
migration/src/m20231106_134950_create_clients.rs
Normal file
@ -0,0 +1,46 @@
|
||||
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
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Client::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Client::Id)
|
||||
.integer()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(Client::Name).string().not_null())
|
||||
.col(ColumnDef::new(Client::Archived).boolean().not_null())
|
||||
.col(ColumnDef::new(Client::WorkspaceId).integer().not_null())
|
||||
.col(ColumnDef::new(Client::At).timestamp_with_time_zone().not_null())
|
||||
.col(ColumnDef::new(Client::ServerDeletedAt).timestamp_with_time_zone())
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Client::Table).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Client {
|
||||
Table,
|
||||
Id,
|
||||
Name,
|
||||
Archived,
|
||||
WorkspaceId,
|
||||
At,
|
||||
ServerDeletedAt
|
||||
}
|
||||
21
src/db.rs
21
src/db.rs
@ -1,10 +1,10 @@
|
||||
use sea_orm::{NotSet, Set};
|
||||
use crate::entity::time_entry::ActiveModel;
|
||||
use crate::types::ReportEntry;
|
||||
use crate::entity::{time_entry, client};
|
||||
use crate::types::{Project, ProjectClient, ReportEntry};
|
||||
|
||||
impl ReportEntry {
|
||||
pub(crate) fn as_models(&self) -> Vec<ActiveModel> {
|
||||
self.time_entries.iter().map(|inner| ActiveModel {
|
||||
pub(crate) fn as_models(&self) -> Vec<time_entry::ActiveModel> {
|
||||
self.time_entries.iter().map(|inner| time_entry::ActiveModel {
|
||||
id: NotSet,
|
||||
toggl_id: Set(inner.id as i64),
|
||||
description: Set(self.description.clone()),
|
||||
@ -15,3 +15,16 @@ impl ReportEntry {
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl ProjectClient {
|
||||
pub fn as_model(&self) -> client::ActiveModel {
|
||||
client::ActiveModel {
|
||||
id: Set(self.id),
|
||||
name: Set(self.name.clone()),
|
||||
archived: Set(self.archived.clone()),
|
||||
workspace_id: Set(self.wid),
|
||||
at: Set(self.at.clone().fixed_offset()),
|
||||
server_deleted_at: Set(self.server_deleted_at.clone().map(|dt| dt.fixed_offset())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
src/entity/client.rs
Normal file
21
src/entity/client.rs
Normal file
@ -0,0 +1,21 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "client")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub archived: bool,
|
||||
pub workspace_id: i32,
|
||||
pub at: DateTimeWithTimeZone,
|
||||
pub server_deleted_at: Option<DateTimeWithTimeZone>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
@ -2,4 +2,6 @@
|
||||
|
||||
pub mod prelude;
|
||||
|
||||
pub mod client;
|
||||
pub mod time_entry;
|
||||
pub mod toggl_portal_seaql_migrations;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
|
||||
|
||||
pub use super::client::Entity as Client;
|
||||
pub use super::time_entry::Entity as TimeEntry;
|
||||
pub use super::toggl_portal_seaql_migrations::Entity as TogglPortalSeaqlMigrations;
|
||||
|
||||
@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(unique)]
|
||||
pub toggl_id: i64,
|
||||
pub description: String,
|
||||
pub project_id: Option<i64>,
|
||||
|
||||
17
src/entity/toggl_portal_seaql_migrations.rs
Normal file
17
src/entity/toggl_portal_seaql_migrations.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.2
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "toggl_portal_seaql_migrations")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub version: String,
|
||||
pub applied_at: i64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
25
src/main.rs
25
src/main.rs
@ -86,11 +86,30 @@ pub async fn start_time_entry(
|
||||
}
|
||||
|
||||
async fn projects(Extension(toggl_client): Extension<TogglClient>) -> Result<Json<Vec<Project>>> {
|
||||
Ok(Json(toggl_client.fetch_projects().await?))
|
||||
let projects = toggl_client.fetch_projects().await?;
|
||||
Ok(Json(projects))
|
||||
}
|
||||
|
||||
async fn clients(Extension(toggl_client): Extension<TogglClient>) -> Result<Json<Vec<ProjectClient>>> {
|
||||
Ok(Json(toggl_client.fetch_clients().await?))
|
||||
async fn clients(
|
||||
Extension(db): Extension<DatabaseConnection>,
|
||||
Extension(toggl_client): Extension<TogglClient>
|
||||
) -> Result<Json<Vec<ProjectClient>>> {
|
||||
let clients = toggl_client.fetch_clients().await?;
|
||||
entity::client::Entity::insert_many(clients.iter().map(ProjectClient::as_model))
|
||||
.on_conflict(
|
||||
OnConflict::column(entity::client::Column::Id)
|
||||
.update_columns(vec![
|
||||
entity::client::Column::Name,
|
||||
entity::client::Column::Archived,
|
||||
entity::client::Column::At,
|
||||
entity::client::Column::ServerDeletedAt,
|
||||
entity::client::Column::WorkspaceId,
|
||||
])
|
||||
.to_owned(),
|
||||
)
|
||||
.exec(&db).await?;
|
||||
|
||||
Ok(Json(clients))
|
||||
}
|
||||
|
||||
async fn health(Extension(toggl_client): Extension<TogglClient>) -> Result<&'static str> {
|
||||
|
||||
12
src/types.rs
12
src/types.rs
@ -61,22 +61,22 @@ pub struct Project {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ProjectClient {
|
||||
/// Indicates whether the client is archived or not.
|
||||
archived: bool,
|
||||
pub archived: bool,
|
||||
|
||||
/// Represents the timestamp of the last update made to the client.
|
||||
at: DateTime<Utc>,
|
||||
pub at: DateTime<Utc>,
|
||||
|
||||
/// The unique identifier for the client.
|
||||
id: i32,
|
||||
pub id: i32,
|
||||
|
||||
/// The name of the client.
|
||||
name: String,
|
||||
pub name: String,
|
||||
|
||||
/// Indicates the timestamp when the client was deleted. If the client is not deleted, this property will be null.
|
||||
server_deleted_at: Option<DateTime<Utc>>,
|
||||
pub server_deleted_at: Option<DateTime<Utc>>,
|
||||
|
||||
/// The Workspace ID associated with the client.
|
||||
wid: i32,
|
||||
pub wid: i32,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user