refactor
This commit is contained in:
parent
b8caa43972
commit
4295bdcb8d
7 changed files with 109 additions and 36 deletions
|
@ -1,6 +1,6 @@
|
|||
use mongodb::bson::doc;
|
||||
|
||||
use crate::get_mongo;
|
||||
use crate::{get_mongo, id_of};
|
||||
|
||||
pub struct InventoryCache {}
|
||||
|
||||
|
@ -18,7 +18,7 @@ impl InventoryCache {
|
|||
|
||||
db.database("cdb")
|
||||
.collection::<mongodb::bson::Document>("cache")
|
||||
.find_one_and_update(doc! { "_id": "inventory"}, update, options)
|
||||
.find_one_and_update(id_of!("inventory"), update, options)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ impl InventoryCache {
|
|||
let inventorycache = db
|
||||
.database("cdb")
|
||||
.collection::<mongodb::bson::Document>("cache")
|
||||
.find_one(doc! {"_id": "inventory"}, None)
|
||||
.find_one(id_of!("inventory"), None)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
@ -52,7 +52,7 @@ impl InventoryCache {
|
|||
|
||||
db.database("cdb")
|
||||
.collection::<mongodb::bson::Document>("cache")
|
||||
.find_one_and_update(doc! { "_id": "inventory"}, update, options)
|
||||
.find_one_and_update(id_of!("inventory"), update, options)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
|
20
src/db.rs
20
src/db.rs
|
@ -1,5 +1,6 @@
|
|||
use crate::item::{Item, ItemEntry};
|
||||
use crate::item::Item;
|
||||
|
||||
/// Collect database results into a `Vec<_>`
|
||||
#[macro_export]
|
||||
macro_rules! collect_results {
|
||||
($res:expr) => {{
|
||||
|
@ -14,6 +15,7 @@ macro_rules! collect_results {
|
|||
}};
|
||||
}
|
||||
|
||||
/// Get a database collection
|
||||
#[macro_export]
|
||||
macro_rules! cdb_col {
|
||||
($db:expr, $col:expr) => {
|
||||
|
@ -22,6 +24,7 @@ macro_rules! cdb_col {
|
|||
};
|
||||
}
|
||||
|
||||
/// Get a MongoDB Client from the environment
|
||||
#[macro_export]
|
||||
macro_rules! get_mongo {
|
||||
() => {
|
||||
|
@ -31,6 +34,7 @@ macro_rules! get_mongo {
|
|||
};
|
||||
}
|
||||
|
||||
/// MongoDB filter for the `_id` field.
|
||||
#[macro_export]
|
||||
macro_rules! id_of {
|
||||
($id:expr) => {
|
||||
|
@ -38,18 +42,22 @@ macro_rules! id_of {
|
|||
};
|
||||
}
|
||||
|
||||
/// Item database
|
||||
pub struct ItemDB {
|
||||
index: mdq::Index,
|
||||
}
|
||||
|
||||
impl ItemDB {
|
||||
/// Create a new item database using `dir` as the base.
|
||||
///
|
||||
/// The directory should contain markdown documents with valid frontmatter to be parsed into `Item`s
|
||||
pub async fn new(dir: &str) -> Self {
|
||||
// scan for markdown item entries
|
||||
let index = mdq::Index::new(dir, true);
|
||||
let mongodb = get_mongo!();
|
||||
|
||||
for item in &index.documents {
|
||||
let item = ItemEntry::new(item);
|
||||
let item = Item::new(item);
|
||||
item.init_db(&mongodb).await;
|
||||
}
|
||||
|
||||
|
@ -58,20 +66,20 @@ impl ItemDB {
|
|||
|
||||
/// Retrieves an item by name
|
||||
pub fn get_item(&self, item: &str) -> Option<Item> {
|
||||
Some(Item::new(
|
||||
Some(
|
||||
self.index
|
||||
.documents
|
||||
.iter()
|
||||
.map(ItemEntry::new)
|
||||
.map(Item::new) // <-- todo : performance?
|
||||
.find(|x| x.name == item)?,
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
/// Get all items
|
||||
pub fn items(&self) -> Vec<String> {
|
||||
let mut ret = vec![];
|
||||
for item in &self.index.documents {
|
||||
let item = ItemEntry::new(item);
|
||||
let item = Item::new(item);
|
||||
ret.push(item.name);
|
||||
}
|
||||
ret
|
||||
|
|
49
src/item.rs
49
src/item.rs
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
|||
|
||||
use crate::id_of;
|
||||
use mongodb::{bson::doc, Collection};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::variant::Variant;
|
||||
|
||||
|
@ -25,13 +26,23 @@ fn hashmap_to_bson_document(
|
|||
document
|
||||
}
|
||||
|
||||
pub struct ItemEntry {
|
||||
/// Represents a single item in a collection of physical goods.
|
||||
///
|
||||
/// This struct serves as a blueprint for describing individual items within
|
||||
/// a larger inventory or database of physical goods. It includes fields for
|
||||
/// the name of the item and its category.
|
||||
pub struct Item {
|
||||
/// The name of the Item
|
||||
pub name: String,
|
||||
/// Category of the Item
|
||||
pub category: String,
|
||||
/// The variants of an Item.
|
||||
/// Each key of the `HashMap<_>` is the name of a variant and contains a `Variant`
|
||||
pub variants: HashMap<String, Variant>,
|
||||
}
|
||||
|
||||
impl ItemEntry {
|
||||
impl Item {
|
||||
/// Creates a new `Item` from a parsed markdown document
|
||||
pub fn new(doc: &mdq::Document) -> Self {
|
||||
let name = std::path::Path::new(&doc.path)
|
||||
.file_stem()
|
||||
|
@ -72,6 +83,7 @@ impl ItemEntry {
|
|||
}
|
||||
}
|
||||
|
||||
/// Adds the `Item` to the database
|
||||
pub async fn init_db(&self, mongodb: &mongodb::Client) {
|
||||
log::info!("Adding item {} to DB", self.name);
|
||||
let items: Collection<mongodb::bson::Document> =
|
||||
|
@ -100,25 +112,28 @@ impl ItemEntry {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a single item in a collection of physical goods.
|
||||
///
|
||||
/// This struct serves as a blueprint for describing individual items within
|
||||
/// a larger inventory or database of physical goods. It includes fields for
|
||||
/// the name of the item and its category.
|
||||
pub struct Item {
|
||||
pub item: ItemEntry,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub const fn new(item: ItemEntry) -> Self {
|
||||
Self { item }
|
||||
}
|
||||
|
||||
/// Get this items variant names
|
||||
pub fn get_variants(&self) -> Vec<String> {
|
||||
self.item.variants.keys().cloned().collect()
|
||||
self.variants.keys().cloned().collect()
|
||||
}
|
||||
|
||||
/// Get a `Variant` of an `Item`
|
||||
pub fn variant(&self, variant: &str) -> Option<Variant> {
|
||||
self.item.variants.get(variant).cloned()
|
||||
self.variants.get(variant).cloned()
|
||||
}
|
||||
|
||||
pub fn api_json(&self) -> serde_json::Value {
|
||||
let variants: HashMap<String, serde_json::Value> = self
|
||||
.variants
|
||||
.iter()
|
||||
.map(|(key, value)| (key.clone(), value.api_json()))
|
||||
.collect();
|
||||
|
||||
json!({
|
||||
"item": self.name,
|
||||
"category": self.category,
|
||||
"variants": variants
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,11 +45,13 @@ async fn rocket() -> _ {
|
|||
"/",
|
||||
route![
|
||||
routes::item::get_items_route,
|
||||
routes::item::item_route,
|
||||
routes::item::item_variants_page,
|
||||
routes::item::supply_log_route,
|
||||
routes::item::demand_log_route,
|
||||
routes::item::supply_route,
|
||||
routes::item::demand_route,
|
||||
routes::item::transaction_route
|
||||
],
|
||||
)
|
||||
.manage(itemdb)
|
||||
|
|
|
@ -5,6 +5,7 @@ use serde::Deserialize;
|
|||
use serde_json::json;
|
||||
|
||||
use crate::db::ItemDB;
|
||||
use crate::transaction::Transaction;
|
||||
use crate::variant::Variant;
|
||||
|
||||
use super::{api_error, ApiError, FallibleApiResponse};
|
||||
|
@ -77,6 +78,14 @@ pub fn get_items_route(itemdb: &State<ItemDB>) -> serde_json::Value {
|
|||
json!({"items": items})
|
||||
}
|
||||
|
||||
#[get("/item/<item_id>")]
|
||||
pub fn item_route(item_id: &str, itemdb: &State<ItemDB>) -> FallibleApiResponse {
|
||||
let item = itemdb
|
||||
.get_item(item_id)
|
||||
.ok_or_else(item_does_not_exist_error)?;
|
||||
Ok(item.api_json())
|
||||
}
|
||||
|
||||
#[get("/item/<item_id>/variants")]
|
||||
pub fn item_variants_page(item_id: &str, itemdb: &State<ItemDB>) -> FallibleApiResponse {
|
||||
let item = itemdb
|
||||
|
@ -123,3 +132,11 @@ pub async fn demand_log_route(
|
|||
|
||||
Ok(json!(transactions))
|
||||
}
|
||||
|
||||
#[get("/transaction/<transaction>")]
|
||||
pub async fn transaction_route(transaction: &str) -> FallibleApiResponse {
|
||||
let t = Transaction::get(transaction)
|
||||
.await
|
||||
.ok_or_else(|| api_error("No transaction with this UUID"))?;
|
||||
Ok(t.api_json())
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
use mongodb::bson::doc;
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{cdb_col, get_mongo, id_of};
|
||||
|
||||
pub enum TransactionType {
|
||||
Batch(BatchTransaction),
|
||||
Normal(Transaction),
|
||||
|
@ -35,6 +41,24 @@ impl Transaction {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn get(uuid: &str) -> Option<Self> {
|
||||
let db = get_mongo!();
|
||||
let transactions = cdb_col!(db, "transactions");
|
||||
let doc = transactions.find_one(id_of!(uuid), None).await.ok()??;
|
||||
Some(doc.into())
|
||||
}
|
||||
|
||||
pub fn api_json(&self) -> serde_json::Value {
|
||||
json!({
|
||||
"uuid": self.uuid,
|
||||
"item": self.item,
|
||||
"variant": self.variant,
|
||||
"price": self.price,
|
||||
"origin": self.origin,
|
||||
"timestamp": self.timestamp
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_doc(&self) -> mongodb::bson::Document {
|
||||
mongodb::bson::doc! {
|
||||
"_id": &self.uuid,
|
||||
|
@ -49,12 +73,12 @@ impl Transaction {
|
|||
|
||||
impl From<mongodb::bson::Document> for Transaction {
|
||||
fn from(b: mongodb::bson::Document) -> Self {
|
||||
let uuid = b.get_str("oid").unwrap().to_string();
|
||||
let uuid = b.get_str("_id").unwrap().to_string();
|
||||
let item = b.get_str("item").unwrap().to_string();
|
||||
let variant = b.get_str("variant").unwrap().to_string();
|
||||
let origin = b.get_str("origin").unwrap().to_string();
|
||||
let timestamp = b.get_i64("timestamp").unwrap();
|
||||
let price = Price::from(b);
|
||||
let price = b.get_document("price").unwrap().clone().into();
|
||||
Self {
|
||||
uuid,
|
||||
item,
|
||||
|
@ -117,7 +141,7 @@ impl From<BatchTransaction> for mongodb::bson::Document {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct Price {
|
||||
pub value: f64,
|
||||
pub currency: String,
|
||||
|
@ -153,7 +177,7 @@ impl From<Price> for mongodb::bson::Bson {
|
|||
impl From<mongodb::bson::Document> for Price {
|
||||
fn from(value: mongodb::bson::Document) -> Self {
|
||||
Self {
|
||||
value: value.get_f64("value").unwrap(),
|
||||
value: value.get_f64("value").unwrap_or(0.0),
|
||||
currency: value.get_str("currency").unwrap().to_string(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use mongodb::bson::doc;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
cache::InventoryCache,
|
||||
cdb_col, collect_results, get_mongo,
|
||||
cdb_col, collect_results, get_mongo, id_of,
|
||||
transaction::{BatchTransaction, Price, Transaction},
|
||||
};
|
||||
|
||||
|
@ -103,10 +104,7 @@ impl Variant {
|
|||
|
||||
// check if supply transaction exists
|
||||
let supply_t = cdb_col!(db, "supply");
|
||||
supply_t
|
||||
.find_one(doc! { "_id": uuid}, None)
|
||||
.await
|
||||
.unwrap()?;
|
||||
supply_t.find_one(id_of!(uuid), None).await.unwrap()?;
|
||||
|
||||
// todo : demand batch
|
||||
|
||||
|
@ -183,6 +181,15 @@ impl Variant {
|
|||
ret_uuid
|
||||
}
|
||||
|
||||
pub fn api_json(&self) -> serde_json::Value {
|
||||
json!({
|
||||
"item": self.item,
|
||||
"variant": self.variant,
|
||||
"amount": self.amount as u32,
|
||||
"depends": self.depends
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_bson(&self) -> mongodb::bson::Document {
|
||||
mongodb::bson::doc! {
|
||||
"item": &self.item,
|
||||
|
|
Loading…
Reference in a new issue