You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
5.2 KiB
191 lines
5.2 KiB
use axum::extract::{Json, Path, Query, State};
|
|
use chrono::{NaiveDate, NaiveDateTime};
|
|
use sea_orm::{
|
|
prelude::*, DbBackend, FromQueryResult, ItemsAndPagesNumber, JoinType, Order, QueryOrder,
|
|
QuerySelect, Statement,
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::db::paginate::{paginate_also_related, PaginatedResponse};
|
|
use crate::error::AppError;
|
|
use crate::{model, AppState};
|
|
|
|
use super::{CompanySlug, Pagination};
|
|
|
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
|
pub struct TransactionCompany {
|
|
pub id: i32,
|
|
pub foreign_id: String,
|
|
pub date_published: NaiveDate,
|
|
pub date_executed: NaiveDate,
|
|
pub person: String,
|
|
pub exchange: String,
|
|
pub nature: String,
|
|
pub isin: Option<String>,
|
|
pub instrument: String,
|
|
pub volume: i32,
|
|
pub unit_price: f32,
|
|
pub created_at_utc: NaiveDateTime,
|
|
pub company: Option<model::company::Model>,
|
|
}
|
|
|
|
pub async fn get_all(
|
|
state: State<AppState>,
|
|
Query(CompanySlug { company_slug }): Query<CompanySlug>,
|
|
Query(Pagination { page, size }): Query<Pagination>,
|
|
) -> Result<Json<PaginatedResponse<TransactionCompany>>, AppError> {
|
|
let db = &state.db;
|
|
|
|
let mut filters = vec![];
|
|
if let Some(c) = company_slug {
|
|
filters.push(model::company::Column::Slug.eq(c))
|
|
}
|
|
|
|
let res = paginate_also_related::<
|
|
model::transaction::Entity,
|
|
model::company::Entity,
|
|
model::transaction::Model,
|
|
model::company::Model,
|
|
model::transaction::Column,
|
|
>(
|
|
db,
|
|
page,
|
|
size,
|
|
Some(model::transaction::Column::DatePublished),
|
|
Some(Order::Desc),
|
|
Some(filters),
|
|
)
|
|
.await?;
|
|
|
|
let list = res
|
|
.list
|
|
.iter()
|
|
.map(|t| TransactionCompany {
|
|
id: t.0.id,
|
|
foreign_id: t.0.foreign_id.to_owned(),
|
|
date_published: t.0.date_published,
|
|
date_executed: t.0.date_executed,
|
|
person: t.0.person.to_owned(),
|
|
exchange: t.0.exchange.to_owned(),
|
|
nature: t.0.nature.to_owned(),
|
|
isin: t.0.isin.clone(),
|
|
instrument: t.0.instrument.to_owned(),
|
|
volume: t.0.volume,
|
|
unit_price: t.0.unit_price,
|
|
created_at_utc: t.0.created_at_utc,
|
|
company: t.1.to_owned(),
|
|
})
|
|
.collect();
|
|
|
|
let res = PaginatedResponse {
|
|
count: res.count,
|
|
num_pages: res.num_pages,
|
|
list,
|
|
};
|
|
|
|
Ok(Json(res))
|
|
}
|
|
|
|
#[derive(FromQueryResult, Serialize)]
|
|
pub struct LatestTransaction {
|
|
company_name: String,
|
|
slug: String,
|
|
nature: String,
|
|
total: f32,
|
|
}
|
|
|
|
pub async fn get_latest_transactions(
|
|
state: State<AppState>,
|
|
Query(pagination): Query<Pagination>,
|
|
) -> Result<Json<PaginatedResponse<LatestTransaction>>, AppError> {
|
|
let db = &state.db;
|
|
let s = pagination.size.unwrap_or(20).min(50);
|
|
|
|
let query_raw = "SELECT
|
|
company.name as company_name,
|
|
company.slug,
|
|
transaction.nature,
|
|
SUM(transaction.volume * transaction.unit_price) as total
|
|
FROM transaction
|
|
JOIN company ON transaction.company_id = company.id
|
|
WHERE DATE(created_at_utc) IN (SELECT DATE(MAX(created_at_utc)) FROM transaction)
|
|
GROUP BY company.name, transaction.nature
|
|
ORDER BY transaction.nature, total DESC"
|
|
.to_string();
|
|
|
|
let query = model::transaction::Entity::find()
|
|
.from_raw_sql(Statement::from_string(
|
|
DbBackend::MySql,
|
|
query_raw.to_string(),
|
|
))
|
|
.into_model::<LatestTransaction>();
|
|
|
|
let pages = query.paginate(db, s);
|
|
|
|
let ItemsAndPagesNumber {
|
|
number_of_items: count,
|
|
number_of_pages: num_pages,
|
|
} = pages.num_items_and_pages().await?;
|
|
|
|
let p = pagination.page.unwrap_or(0).min(num_pages);
|
|
|
|
let list = pages.fetch_page(p).await?;
|
|
|
|
let res = PaginatedResponse {
|
|
count,
|
|
num_pages,
|
|
list,
|
|
};
|
|
|
|
Ok(Json(res))
|
|
}
|
|
|
|
pub async fn get_aggregated_transactions(
|
|
state: State<AppState>,
|
|
pagination: Query<Pagination>,
|
|
) -> Result<Json<PaginatedResponse<TransactionsAggregated>>, AppError> {
|
|
let db = &state.db;
|
|
let s = pagination.0.size.unwrap_or(20).min(50);
|
|
let query = model::company::Entity::find()
|
|
.select_only()
|
|
.join(
|
|
JoinType::InnerJoin,
|
|
model::company::Relation::Transaction.def(),
|
|
)
|
|
.column(model::company::Column::Id)
|
|
.column(model::company::Column::Name)
|
|
.column(model::company::Column::Slug)
|
|
.column_as(model::transaction::Column::Id.count(), "transaction_count");
|
|
|
|
let pages = query
|
|
.group_by(model::company::Column::Name)
|
|
.order_by(model::transaction::Column::Id.count(), Order::Desc)
|
|
.into_model::<TransactionsAggregated>()
|
|
.paginate(db, s);
|
|
|
|
let ItemsAndPagesNumber {
|
|
number_of_items: count,
|
|
number_of_pages: num_pages,
|
|
} = pages.num_items_and_pages().await?;
|
|
|
|
let p = pagination.0.page.unwrap_or(0).min(num_pages);
|
|
|
|
let list = pages.fetch_page(p).await?;
|
|
|
|
let res = PaginatedResponse {
|
|
count,
|
|
num_pages,
|
|
list,
|
|
};
|
|
|
|
Ok(Json(res))
|
|
}
|
|
|
|
#[derive(Serialize, FromQueryResult, Debug)]
|
|
pub struct TransactionsAggregated {
|
|
id: i32,
|
|
name: String,
|
|
slug: String,
|
|
transaction_count: i32,
|
|
}
|