This commit is contained in:
parent
443b52bf38
commit
91d39a4d83
7 changed files with 29 additions and 7 deletions
|
@ -35,6 +35,7 @@ pub struct Item {
|
||||||
pub variants: HashMap<String, Variant>,
|
pub variants: HashMap<String, Variant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the path of an image file in `path`
|
||||||
pub fn get_image(path: &std::path::Path) -> Option<String> {
|
pub fn get_image(path: &std::path::Path) -> Option<String> {
|
||||||
let parent = path.parent()?;
|
let parent = path.parent()?;
|
||||||
let file_name = path.file_stem()?.to_str()?;
|
let file_name = path.file_stem()?.to_str()?;
|
||||||
|
@ -120,12 +121,14 @@ impl Item {
|
||||||
self.variants.get(variant).cloned()
|
self.variants.get(variant).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all active `Transaction`s of this `Item` not yet consumed
|
||||||
pub async fn inventory(&self) -> Vec<Transaction> {
|
pub async fn inventory(&self) -> Vec<Transaction> {
|
||||||
sqlx::query_as("SELECT * FROM transactions WHERE item = $1 AND consumed_timestamp IS NULL ORDER BY created DESC")
|
sqlx::query_as("SELECT * FROM transactions WHERE item = $1 AND consumed_timestamp IS NULL ORDER BY created DESC")
|
||||||
.bind(&self.id)
|
.bind(&self.id)
|
||||||
.fetch_all(get_pg!()).await.unwrap()
|
.fetch_all(get_pg!()).await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all active `Transaction`s of this `Item` not yet consumed of `origin`
|
||||||
pub async fn inventory_by_origin(&self, origin: &str) -> Vec<Transaction> {
|
pub async fn inventory_by_origin(&self, origin: &str) -> Vec<Transaction> {
|
||||||
sqlx::query_as("SELECT * FROM transactions WHERE item = $1 AND consumed_timestamp IS NULL AND origin = $2 ORDER BY created DESC")
|
sqlx::query_as("SELECT * FROM transactions WHERE item = $1 AND consumed_timestamp IS NULL AND origin = $2 ORDER BY created DESC")
|
||||||
.bind(&self.id)
|
.bind(&self.id)
|
||||||
|
@ -133,6 +136,7 @@ impl Item {
|
||||||
.fetch_all(get_pg!()).await.unwrap()
|
.fetch_all(get_pg!()).await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all active `Transaction`s of this `Item` not yet consumed of `destination`
|
||||||
pub async fn consumed_by_destination(&self, destination: &str) -> Vec<Transaction> {
|
pub async fn consumed_by_destination(&self, destination: &str) -> Vec<Transaction> {
|
||||||
sqlx::query_as("SELECT * FROM transactions WHERE item = $1 AND consumed_timestamp IS NOT NULL AND destination = $2 ORDER BY created DESC")
|
sqlx::query_as("SELECT * FROM transactions WHERE item = $1 AND consumed_timestamp IS NOT NULL AND destination = $2 ORDER BY created DESC")
|
||||||
.bind(&self.id)
|
.bind(&self.id)
|
5
src/core/mod.rs
Normal file
5
src/core/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pub mod flow;
|
||||||
|
pub mod item;
|
||||||
|
pub mod location;
|
||||||
|
pub mod transaction;
|
||||||
|
pub mod variant;
|
|
@ -54,14 +54,17 @@ impl Transaction {
|
||||||
.fetch_one(get_pg!()).await.unwrap()
|
.fetch_one(get_pg!()).await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the `Item` of the `Transaction`
|
||||||
pub async fn item(&self) -> Option<&Item> {
|
pub async fn item(&self) -> Option<&Item> {
|
||||||
get_itemdb!().get_item(&self.item)
|
get_itemdb!().get_item(&self.item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the `Variant` of the `Item` of the `Transaction`
|
||||||
pub async fn item_variant(&self) -> Option<Variant> {
|
pub async fn item_variant(&self) -> Option<Variant> {
|
||||||
get_itemdb!().get_item(&self.item)?.variant(&self.variant)
|
get_itemdb!().get_item(&self.item)?.variant(&self.variant)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a `Transaction` via `id`
|
||||||
pub async fn get(id: &uuid::Uuid) -> Option<Self> {
|
pub async fn get(id: &uuid::Uuid) -> Option<Self> {
|
||||||
sqlx::query_as("SELECT * FROM transactions WHERE id = $1")
|
sqlx::query_as("SELECT * FROM transactions WHERE id = $1")
|
||||||
.bind(id)
|
.bind(id)
|
||||||
|
@ -203,7 +206,7 @@ impl ToAPI for Transaction {
|
||||||
"timestamp": self.created.timestamp(),
|
"timestamp": self.created.timestamp(),
|
||||||
"consumed": consumed,
|
"consumed": consumed,
|
||||||
"note": self.note,
|
"note": self.note,
|
||||||
"expired": self.is_expired().await
|
"expired": self.is_expired().await,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -104,6 +104,8 @@ impl Variant {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a API id for this Item Variant.
|
||||||
|
/// The ID has the format: `<ITEM>::<VARIANT>`
|
||||||
pub fn item_variant_id(&self) -> String {
|
pub fn item_variant_id(&self) -> String {
|
||||||
format!("{}::{}", self.item, self.variant)
|
format!("{}::{}", self.item, self.variant)
|
||||||
}
|
}
|
||||||
|
@ -189,6 +191,7 @@ impl Variant {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get Transactions within `year` and `month`
|
||||||
pub async fn get_transaction_timeslice(&self, year: i32, month: u32) -> Vec<Transaction> {
|
pub async fn get_transaction_timeslice(&self, year: i32, month: u32) -> Vec<Transaction> {
|
||||||
let (start, end) = timestamp_range(year, month);
|
let (start, end) = timestamp_range(year, month);
|
||||||
|
|
||||||
|
@ -198,6 +201,7 @@ impl Variant {
|
||||||
.fetch_all(get_pg!()).await.unwrap()
|
.fetch_all(get_pg!()).await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all unique origins
|
||||||
pub async fn get_unique_origins(&self) -> Vec<String> {
|
pub async fn get_unique_origins(&self) -> Vec<String> {
|
||||||
let res: Vec<(String,)> = sqlx::query_as("SELECT DISTINCT(origin) FROM transactions WHERE origin NOT LIKE 'flow::%' AND item = $1 AND variant = $2")
|
let res: Vec<(String,)> = sqlx::query_as("SELECT DISTINCT(origin) FROM transactions WHERE origin NOT LIKE 'flow::%' AND item = $1 AND variant = $2")
|
||||||
.bind(&self.item)
|
.bind(&self.item)
|
||||||
|
@ -206,6 +210,7 @@ impl Variant {
|
||||||
res.into_iter().map(|x| x.0).collect()
|
res.into_iter().map(|x| x.0).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all unique destinations
|
||||||
pub async fn get_unique_destinations(&self) -> Vec<String> {
|
pub async fn get_unique_destinations(&self) -> Vec<String> {
|
||||||
let res: Vec<(String,)> = sqlx::query_as("SELECT DISTINCT(destination) FROM transactions WHERE destination NOT LIKE 'flow::%' AND item = $1 AND variant = $2")
|
let res: Vec<(String,)> = sqlx::query_as("SELECT DISTINCT(destination) FROM transactions WHERE destination NOT LIKE 'flow::%' AND item = $1 AND variant = $2")
|
||||||
.bind(&self.item)
|
.bind(&self.item)
|
||||||
|
@ -214,6 +219,7 @@ impl Variant {
|
||||||
res.into_iter().map(|x| x.0).collect()
|
res.into_iter().map(|x| x.0).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the last `limit` price values for `origin`
|
||||||
pub async fn price_history_by_origin(&self, origin: &str, limit: Option<i64>) -> Vec<f64> {
|
pub async fn price_history_by_origin(&self, origin: &str, limit: Option<i64>) -> Vec<f64> {
|
||||||
let res: Vec<(f64,)> = sqlx::query_as(
|
let res: Vec<(f64,)> = sqlx::query_as(
|
||||||
&format!("SELECT price FROM transactions WHERE item = $1 AND variant = $2 AND origin = $3 ORDER BY created DESC {}", if let Some(limit) = limit {
|
&format!("SELECT price FROM transactions WHERE item = $1 AND variant = $2 AND origin = $3 ORDER BY created DESC {}", if let Some(limit) = limit {
|
||||||
|
@ -227,6 +233,7 @@ impl Variant {
|
||||||
res.into_iter().map(|x| x.0).collect()
|
res.into_iter().map(|x| x.0).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the latest price for `origin`
|
||||||
pub async fn get_latest_price(&self, origin: Option<String>) -> f64 {
|
pub async fn get_latest_price(&self, origin: Option<String>) -> f64 {
|
||||||
if let Some(origin) = origin {
|
if let Some(origin) = origin {
|
||||||
let res: (f64,) = sqlx::query_as("SELECT price FROM transactions WHERE item = $1 AND variant = $2 AND origin = $3 ORDER BY created DESC LIMIT 1")
|
let res: (f64,) = sqlx::query_as("SELECT price FROM transactions WHERE item = $1 AND variant = $2 AND origin = $3 ORDER BY created DESC LIMIT 1")
|
||||||
|
@ -257,6 +264,7 @@ impl Variant {
|
||||||
(false, 0)
|
(false, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the `Variant` satisfies `StorageConditions`
|
||||||
pub async fn satisfy_condition(&self, conditions: &StorageConditions) -> bool {
|
pub async fn satisfy_condition(&self, conditions: &StorageConditions) -> bool {
|
||||||
if let Some(needs) = &self.needs {
|
if let Some(needs) = &self.needs {
|
||||||
if let Some(room_temp) = conditions.accurate_temperature().await {
|
if let Some(room_temp) = conditions.accurate_temperature().await {
|
||||||
|
@ -346,7 +354,8 @@ impl Variant {
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"min": self.min,
|
"min": self.min,
|
||||||
"expiry": self.expiry,
|
"expiry": self.expiry,
|
||||||
"barcodes": self.barcodes
|
"barcodes": self.barcodes,
|
||||||
|
"needs": self.needs
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
11
src/main.rs
11
src/main.rs
|
@ -7,15 +7,16 @@ use rocket::{http::Method, launch};
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
mod core;
|
||||||
mod db;
|
mod db;
|
||||||
mod flow;
|
|
||||||
mod integrity;
|
mod integrity;
|
||||||
mod item;
|
|
||||||
mod json_store;
|
mod json_store;
|
||||||
mod location;
|
pub use core::flow;
|
||||||
|
pub use core::item;
|
||||||
|
pub use core::location;
|
||||||
|
pub use core::transaction;
|
||||||
|
pub use core::variant;
|
||||||
mod routes;
|
mod routes;
|
||||||
mod transaction;
|
|
||||||
mod variant;
|
|
||||||
|
|
||||||
pub static PG: OnceCell<sqlx::PgPool> = OnceCell::const_new();
|
pub static PG: OnceCell<sqlx::PgPool> = OnceCell::const_new();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue