Add new major transactions table + fix docker and packages #36

Merged
alban merged 4 commits from docker3 into master 3 years ago

@ -1,16 +0,0 @@
[package]
name = "fast-insiders"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace]
members = ["server", "client"]
[workspace.dependencies]
chrono = { version = "0.4.23", features = ["serde"] }
serde = { version = "1.0.152", features = ["derive"] }
dotenvy = "0.15.6"
envy = "0.4.2"
serde_json = "1.0.91"

2268
client/Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -6,9 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
chrono = { workspace = true, features = ["serde"] } chrono = { version = "0.4.23", features = ["serde"] }
serde = { workspace = true, features = ["derive"] } serde = { version = "1.0.152", features = ["derive"] }
serde_json = { workspace = true } serde_json = "1.0.91"
perseus = { version = "0.4", features = ["hydrate"] } perseus = { version = "0.4", features = ["hydrate"] }
sycamore = { version = "^0.8.1", features = [ sycamore = { version = "^0.8.1", features = [
"ssr", "ssr",

@ -21,43 +21,22 @@ RUN rustup target add wasm32-unknown-unknown;\
# retrieve the src dir # retrieve the src dir
COPY . . COPY . .
# RUN curl https://git.albv.org/alban/fast-insiders/archive/master.tar.gz | tar -xz
# go to src dir
WORKDIR /app/client
# install perseus-cli # install perseus-cli
RUN cargo install perseus-cli --version $PERSEUS_VERSION;\ RUN cargo install perseus-cli --version $PERSEUS_VERSION;\
perseus clean perseus clean
# specify deps in app config
# RUN sed -i s"/perseus = .*/perseus = \"${PERSEUS_VERSION}\"/" ./Cargo.toml \
# && sed -i s"/perseus-size-opt = .*/perseus-size-opt = \"${PERSEUS_SIZE_OPT_VERSION}\"/" ./Cargo.toml \
# && cat ./Cargo.toml
#
# # modify main.rs
# RUN sed -i s'/SizeOpts::default()/SizeOpts { wee_alloc: true, lto: true, opt_level: "z".to_string(), codegen_units: 1, enable_fluent_bundle_patch: false, }/' ./src/main.rs \
# && cat ./src/main.rs
# # run plugin(s) to adjust app
# RUN perseus tinker
# single-threaded perseus CLI mode required for low memory environments
#ENV PERSEUS_CLI_SEQUENTIAL=true
# deploy app # deploy app
RUN perseus deploy RUN perseus deploy
# go back to app dir
WORKDIR /app
# download and unpack esbuild # download and unpack esbuild
RUN curl -O https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-${ESBUILD_VERSION}.tgz \ RUN curl -O https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-${ESBUILD_VERSION}.tgz \
&& tar xf esbuild-linux-64-${ESBUILD_VERSION}.tgz \ && tar xf esbuild-linux-64-${ESBUILD_VERSION}.tgz \
&& ./package/bin/esbuild --version && ./package/bin/esbuild --version
# run esbuild against bundle.js # run esbuild against bundle.js
RUN ./package/bin/esbuild ./client/pkg/dist/pkg/perseus_engine.js --minify --target=es6 --outfile=./client/pkg/dist/pkg/perseus_engine.js --allow-overwrite \ RUN ./package/bin/esbuild ./pkg/dist/pkg/perseus_engine.js --minify --target=es6 --outfile=./pkg/dist/pkg/perseus_engine.js --allow-overwrite \
&& ls -lha ./client/pkg/dist/pkg && ls -lha ./pkg/dist/pkg
# download and unpack binaryen # download and unpack binaryen
RUN wget -nv https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_VERSION}/binaryen-version_${BINARYEN_VERSION}-x86_64-linux.tar.gz \ RUN wget -nv https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_VERSION}/binaryen-version_${BINARYEN_VERSION}-x86_64-linux.tar.gz \
@ -65,14 +44,14 @@ RUN wget -nv https://github.com/WebAssembly/binaryen/releases/download/version_$
&& ./binaryen-version_${BINARYEN_VERSION}/bin/wasm-opt --version && ./binaryen-version_${BINARYEN_VERSION}/bin/wasm-opt --version
# run wasm-opt against bundle.wasm # run wasm-opt against bundle.wasm
RUN ./binaryen-version_${BINARYEN_VERSION}/bin/wasm-opt -Os ./client/pkg/dist/pkg/perseus_engine_bg.wasm -o ./client/pkg/dist/pkg/perseus_engine_bg.wasm RUN ./binaryen-version_${BINARYEN_VERSION}/bin/wasm-opt -Os ./pkg/dist/pkg/perseus_engine_bg.wasm -o ./pkg/dist/pkg/perseus_engine_bg.wasm
# prepare deployment image # prepare deployment image
FROM debian:stable-slim FROM debian:stable-slim
WORKDIR /app WORKDIR /app
COPY --from=build /app/client/pkg /app/ COPY --from=build /app/pkg /app/
ENV HOST=0.0.0.0 ENV HOST=0.0.0.0

@ -1,7 +1,9 @@
use crate::api::{ use crate::api::{
types::{ types::{
paginated_response::PaginatedResponse, paginated_response::PaginatedResponse,
transaction::{LatestTransaction, TransactionCompany, TransactionsAggregated}, transaction::{
LatestTransaction, MajorTransactions, TransactionCompany, TransactionsAggregated,
},
}, },
FastInsidersApi, FastInsidersApi,
}; };
@ -105,4 +107,32 @@ impl FastInsidersApi {
Ok(res) Ok(res)
} }
pub async fn get_major_transactions(
&self,
_: Option<String>,
page: i64,
size: i64,
) -> Result<PaginatedResponse<MajorTransactions>, ()> {
let route = &format!("{}/transaction/major?page={}&size={}", self.url, page, size,);
#[cfg(client)]
let res = reqwasm::http::Request::get(route)
.send()
.await
.map_err(|_| ())?
.json::<PaginatedResponse<MajorTransactions>>()
.await
.map_err(|_| ())?;
#[cfg(engine)]
let res = reqwest::get(route)
.await
.map_err(|_| ())?
.json::<PaginatedResponse<MajorTransactions>>()
.await
.map_err(|_| ())?;
Ok(res)
}
} }

@ -3,7 +3,7 @@ use sycamore::prelude::*;
use crate::components::base_table::TableContent; use crate::components::base_table::TableContent;
use super::transaction::{TransactionCompany, TransactionsAggregated, LatestTransaction}; use super::transaction::{TransactionCompany, TransactionsAggregated, LatestTransaction, MajorTransactions};
pub trait IntoTableData<G> pub trait IntoTableData<G>
where where
@ -143,3 +143,50 @@ where
} }
} }
} }
impl<G> IntoTableData<G> for PaginatedResponse<MajorTransactions>
where
G: GenericNode,
{
fn into_table_data(self, cx: Scope) -> TableContent<G> {
let headers_view = vec![
view! {cx, "Company" },
view! {cx, "Date published" },
view! {cx, "Date executed" },
view! {cx, "Nature" },
view! {cx, "Instrument" },
view! {cx, "Volume" },
view! {cx, "Unit price" },
view! {cx, "Total" },
];
let data_view: Vec<Vec<View<G>>> = self
.list
.into_iter()
.map(|t| {
let mut res = vec![];
res.push(view! {cx,
a (href=format!("transactions/{}", t.slug),
class="text-indigo-800 dark:text-indigo-300 hover:text-indigo-500 hover:underline dark:hover:text-indigo-600",
) {
(t.company_name.to_owned())
}
});
res.push(view! {cx, (t.date_published.to_owned()) });
res.push(view! {cx, (t.date_executed.to_owned()) });
res.push(view! {cx, (t.nature.to_owned()) });
res.push(view! {cx, (t.instrument.to_owned()) });
res.push(view! {cx, (t.volume.to_owned()) });
res.push(view! {cx, (t.unit_price.to_owned()) });
res.push(view! {cx, (t.total.to_string()) });
res
})
.collect();
TableContent {
headers_view,
data_view,
}
}
}

@ -52,3 +52,16 @@ pub struct LatestTransaction {
pub nature: String, pub nature: String,
pub total: f32, pub total: f32,
} }
#[derive(Deserialize, Clone)]
pub struct MajorTransactions {
pub company_name: String,
pub slug: String,
pub date_published: NaiveDate,
pub date_executed: NaiveDate,
pub nature: String,
pub instrument: String,
pub volume: i32,
pub unit_price: f32,
pub total: f32,
}

@ -2,7 +2,7 @@ use perseus::prelude::*;
use sycamore::prelude::*; use sycamore::prelude::*;
use crate::{ use crate::{
api::types::transaction::{LatestTransaction, TransactionsAggregated}, api::types::transaction::{LatestTransaction, MajorTransactions, TransactionsAggregated},
components::{ components::{
main_content_container::MainContentContainer, main_content_container::MainContentContainer,
paginated_data_table::{PaginatedTable, PaginatedTableStateRx}, paginated_data_table::{PaginatedTable, PaginatedTableStateRx},
@ -42,6 +42,17 @@ fn index_page<G: Html>(cx: BoundedScope) -> View<G> {
table_class: table_classes, table_class: table_classes,
}; };
let route_ref = create_ref(cx, move |c, p, s| {
api_scope_ref.get_major_transactions(c, p, s)
});
let table_transactions_major: PaginatedTableStateRx<MajorTransactions, _, _> =
PaginatedTableStateRx {
record_label: "transactions".to_owned(),
route: route_ref,
filter: Some((24 * 30).to_string()),
table_class: table_classes,
};
let dark_mode_class = create_memo(cx, || { let dark_mode_class = create_memo(cx, || {
if *global_state.dark_mode.get() { if *global_state.dark_mode.get() {
"dark" "dark"
@ -68,6 +79,12 @@ fn index_page<G: Html>(cx: BoundedScope) -> View<G> {
} }
PaginatedTable(table_transactions_month) PaginatedTable(table_transactions_month)
} }
div (class="flex-grow") {
h1 (class="mb-1 text-center") {
"Major transactions in the past 30 days"
}
PaginatedTable(table_transactions_major)
}
} }
} }
} }

@ -3,8 +3,7 @@ services:
client: client:
container_name: fast-insiders-client container_name: fast-insiders-client
image: docker.albv.org/root/fast-insiders-client:latest image: docker.albv.org/root/fast-insiders-client:latest
build: build: ./client
dockerfile: ./client/Dockerfile
restart: always restart: always
ports: ports:
- 8080:8080 - 8080:8080
@ -14,8 +13,7 @@ services:
server: server:
container_name: fast-insiders-server container_name: fast-insiders-server
image: docker.albv.org/root/fast-insiders-server:latest image: docker.albv.org/root/fast-insiders-server:latest
build: build: ./server
dockerfile: ./server/Dockerfile
restart: always restart: always
ports: ports:
- 8000:8000 - 8000:8000

File diff suppressed because it is too large Load Diff

@ -6,12 +6,12 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
chrono = { version = "0.4.23", features = ["serde"] }
serde = { version = "1.0.152", features = ["derive"] }
dotenvy = "0.15.6"
envy = "0.4.2"
serde_json = "1.0.91"
migration = { version = "0.1.0", path = "./migration" } migration = { version = "0.1.0", path = "./migration" }
chrono = { workspace = true, features = ["serde"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
dotenvy = { workspace = true }
envy = { workspace = true }
tokio = { version = "^1.20.1", features = ["full"] } tokio = { version = "^1.20.1", features = ["full"] }
reqwest = { version = "0.11", features = ["json", "rustls-tls"] } reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
axum = "0.6.12" axum = "0.6.12"

@ -12,13 +12,7 @@ WORKDIR /app
COPY . . COPY . .
# Build failed when not using nightly though I don't know which crate is responsible # Build failed when not using nightly though I don't know which crate is responsible
RUN rustup default nightly RUN rustup default nightly; cargo build --release
# go to src dir
WORKDIR /app/server
# Build the final binary
RUN cargo build --release
# prepare deployment image # prepare deployment image
FROM debian:stable-slim FROM debian:stable-slim

@ -10,7 +10,6 @@ path = "src/lib.rs"
[dependencies] [dependencies]
async-std = { version = "^1", features = ["attributes", "tokio1"] } async-std = { version = "^1", features = ["attributes", "tokio1"] }
chrono.workspace = true
[dependencies.sea-orm-migration] [dependencies.sea-orm-migration]
version = "0.11.0" version = "0.11.0"

@ -80,6 +80,10 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
"/transaction/aggregated", "/transaction/aggregated",
get(transaction::get_aggregated_transactions), get(transaction::get_aggregated_transactions),
) )
.route(
"/transaction/major",
get(transaction::get_recent_major_transactions),
)
.route( .route(
"/in_process_transaction", "/in_process_transaction",
get(in_process_transaction::get_all), get(in_process_transaction::get_all),

@ -181,6 +181,71 @@ pub async fn get_aggregated_transactions(
Ok(Json(res)) Ok(Json(res))
} }
#[derive(FromQueryResult, Serialize)]
pub struct MajorTransactions {
company_name: String,
slug: String,
date_published: NaiveDate,
date_executed: NaiveDate,
nature: String,
instrument: String,
volume: i32,
unit_price: f32,
total: f32,
}
pub async fn get_recent_major_transactions(
state: State<AppState>,
pagination: Query<Pagination>,
) -> Result<Json<PaginatedResponse<MajorTransactions>>, AppError> {
let db = &state.db;
let s = pagination.size.unwrap_or(20).min(50);
let query_raw = "SELECT
b.name as company_name,
b.slug,
date_published,
date_executed,
nature,
instrument,
volume,
unit_price,
volume * unit_price as total
FROM transaction a
JOIN company b
ON a.company_id = b.id
WHERE unit_price*volume > 1000000
AND created_at_utc > DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
ORDER BY a.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::<MajorTransactions>();
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))
}
#[derive(Serialize, FromQueryResult, Debug)] #[derive(Serialize, FromQueryResult, Debug)]
pub struct TransactionsAggregated { pub struct TransactionsAggregated {
id: i32, id: i32,

Loading…
Cancel
Save