about summary refs log tree commit diff stats
path: root/crates/rocie-server/src/api/get/product.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/rocie-server/src/api/get/product.rs')
-rw-r--r--crates/rocie-server/src/api/get/product.rs119
1 files changed, 113 insertions, 6 deletions
diff --git a/crates/rocie-server/src/api/get/product.rs b/crates/rocie-server/src/api/get/product.rs
index 55e5d91..4216f9b 100644
--- a/crates/rocie-server/src/api/get/product.rs
+++ b/crates/rocie-server/src/api/get/product.rs
@@ -4,7 +4,11 @@ use percent_encoding::percent_decode_str;
 
 use crate::{
     app::App,
-    storage::sql::product::{Product, ProductId, ProductIdStub},
+    storage::sql::{
+        product::{Product, ProductId, ProductIdStub},
+        product_amount::ProductAmount,
+        product_parent::{ProductParent, ProductParentId, ProductParentIdStub},
+    },
 };
 
 /// A String, that is not url-decoded on parse.
@@ -65,7 +69,7 @@ pub(crate) async fn product_by_name(
     req: HttpRequest,
     name: web::Path<String>,
 ) -> Result<impl Responder> {
-    let _name = name;
+    drop(name);
 
     let name = UrlEncodedString::from_str(
         req.path()
@@ -96,7 +100,7 @@ pub(crate) async fn product_suggestion_by_name(
     req: HttpRequest,
     name: web::Path<String>,
 ) -> Result<impl Responder> {
-    let _name = name;
+    drop(name);
 
     let name = UrlEncodedString::from_str(
         req.path()
@@ -118,13 +122,116 @@ pub(crate) async fn product_suggestion_by_name(
 /// Return all registered products
 #[utoipa::path(
     responses(
-        (status = OK, description = "All products founds", body = Vec<Product>),
+        (status = OK, description = "All products found", body = Vec<Product>),
         (status = INTERNAL_SERVER_ERROR, description = "Server encountered error", body = String)
     ),
 )]
-#[get("/products/")]
-pub(crate) async fn products(app: web::Data<App>) -> Result<impl Responder> {
+#[get("/products_registered/")]
+pub(crate) async fn products_registered(app: web::Data<App>) -> Result<impl Responder> {
     let all = Product::get_all(&app).await?;
 
     Ok(HttpResponse::Ok().json(all))
 }
+
+/// Return all products, which non-null amount in storage
+#[utoipa::path(
+    responses(
+        (status = OK, description = "All products found", body = Vec<Product>),
+        (status = INTERNAL_SERVER_ERROR, description = "Server encountered error", body = String)
+    ),
+)]
+#[get("/products_in_storage/")]
+pub(crate) async fn products_in_storage(app: web::Data<App>) -> Result<impl Responder> {
+    let all = Product::get_all(&app).await?;
+
+    let mut output_products = Vec::with_capacity(all.len());
+    for product in all {
+        let amount = ProductAmount::from_id(&app, product.id).await?;
+
+        if amount.is_some_and(|amount| amount.amount.value > 0) {
+            output_products.push(product);
+        }
+    }
+
+    Ok(HttpResponse::Ok().json(output_products))
+}
+
+/// Get Products by it's product parent id
+///
+/// This will also return all products below this product parent id
+#[utoipa::path(
+    responses(
+        (status = OK, description = "Products found from database", body = Vec<Product>),
+        (status = NOT_FOUND, description = "Product parent id not found in database"),
+        (status = INTERNAL_SERVER_ERROR, description = "Server encountered error", body = String)
+    ),
+    params(
+        ("id" = ProductParentId, description = "Product parent id" ),
+    )
+)]
+#[get("/product/by-product-parent-id-indirect/{id}")]
+pub(crate) async fn products_by_product_parent_id_indirect(
+    app: web::Data<App>,
+    id: web::Path<ProductParentIdStub>,
+) -> Result<impl Responder> {
+    let id = id.into_inner();
+
+    if let Some(parent) = ProductParent::from_id(&app, id.into()).await? {
+        async fn collect_products(app: &App, parent: ProductParent) -> Result<Vec<Product>> {
+            let mut all = Product::get_all(app)
+                .await?
+                .into_iter()
+                .filter(|prod| prod.parent.is_some_and(|val| val == parent.id))
+                .collect::<Vec<_>>();
+
+            if let Some(child) = ProductParent::get_all(app)
+                .await?
+                .into_iter()
+                .find(|pp| pp.parent.is_some_and(|id| id == parent.id))
+            {
+                all.extend(Box::pin(collect_products(app, child)).await?);
+            }
+
+            Ok(all)
+        }
+
+        let all = collect_products(&app, parent).await?;
+
+        Ok(HttpResponse::Ok().json(all))
+    } else {
+        Ok(HttpResponse::NotFound().finish())
+    }
+}
+
+/// Get Products by it's product parent id
+///
+/// This will only return products directly associated with this product parent id
+#[utoipa::path(
+    responses(
+        (status = OK, description = "Products found from database", body = Vec<Product>),
+        (status = NOT_FOUND, description = "Product parent id not found in database"),
+        (status = INTERNAL_SERVER_ERROR, description = "Server encountered error", body = String)
+    ),
+    params(
+        ("id" = ProductParentId, description = "Product parent id" ),
+    )
+)]
+#[get("/product/by-product-parent-id-direct/{id}")]
+pub(crate) async fn products_by_product_parent_id_direct(
+    app: web::Data<App>,
+    id: web::Path<ProductParentIdStub>,
+) -> Result<impl Responder> {
+    let id = id.into_inner();
+
+    if let Some(parent) = ProductParent::from_id(&app, id.into()).await? {
+        let all = Product::get_all(&app)
+            .await?
+            .into_iter()
+            .filter(|prod| prod.parent.is_some_and(|val| val == parent.id))
+            .collect::<Vec<_>>();
+
+        Ok(HttpResponse::Ok().json(all))
+    } else {
+        Ok(HttpResponse::NotFound().finish())
+    }
+}