li7y/src/manage/item.rs

156 lines
4.4 KiB
Rust

// SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::collections::HashMap;
use sqlx::{query, query_as, query_scalar, PgPool};
use uuid::Uuid;
use crate::models::{Item, NewItem};
pub async fn add(pool: &PgPool, new_item: NewItem) -> Result<Item, sqlx::Error> {
query_as!(
Item,
"INSERT INTO items (name, parent, class, original_packaging, description) VALUES ($1, $2, $3, $4, $5) RETURNING *",
new_item.name,
new_item.parent,
new_item.class,
new_item.original_packaging,
new_item.description
)
.fetch_one(pool)
.await
}
pub async fn add_multiple(
pool: &PgPool,
new_item: NewItem,
quantity: usize,
) -> Result<Vec<Item>, sqlx::Error> {
query_as!(
Item,
r#"INSERT INTO items (name, parent, class, original_packaging, description)
SELECT * FROM UNNEST($1::VARCHAR[], $2::UUID[], $3::UUID[], $4::UUID[], $5::VARCHAR[])
RETURNING *"#,
&vec![new_item.name; quantity] as &[Option<String>],
&vec![new_item.parent; quantity] as &[Option<Uuid>],
&vec![new_item.class; quantity],
&vec![new_item.original_packaging; quantity] as &[Option<Uuid>],
&vec![new_item.description; quantity]
)
.fetch_all(pool)
.await
}
pub async fn get(pool: &PgPool, id: Uuid) -> Result<Item, sqlx::Error> {
query_as!(Item, "SELECT * FROM items WHERE id = $1", id)
.fetch_one(pool)
.await
}
pub async fn get_by_short_id(pool: &PgPool, short_id: i32) -> Result<Item, sqlx::Error> {
query_as!(Item, "SELECT * FROM items WHERE short_id = $1", short_id)
.fetch_one(pool)
.await
}
pub async fn get_all(pool: &PgPool) -> Result<Vec<Item>, sqlx::Error> {
query_as!(Item, "SELECT * FROM items ORDER BY created_at")
.fetch_all(pool)
.await
}
pub async fn get_multiple(pool: &PgPool, ids: &[Uuid]) -> Result<Vec<Item>, sqlx::Error> {
query_as!(Item, "SELECT * FROM items WHERE id = ANY ($1)", ids)
.fetch_all(pool)
.await
}
pub async fn get_all_as_map(pool: &PgPool) -> Result<HashMap<Uuid, Item>, sqlx::Error> {
Ok(get_all(pool)
.await?
.into_iter()
.map(|i| (i.id, i))
.collect())
}
pub async fn update(pool: &PgPool, id: Uuid, modified_item: NewItem) -> Result<Item, sqlx::Error> {
query_as!(
Item,
"UPDATE items SET name = $2, parent = $3, class = $4, original_packaging = $5, description = $6 WHERE id = $1 RETURNING *",
id,
modified_item.name,
modified_item.parent,
modified_item.class,
modified_item.original_packaging,
modified_item.description
)
.fetch_one(pool)
.await
}
pub async fn delete(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> {
let res = query!("DELETE FROM items WHERE id = $1", id)
.execute(pool)
.await?;
assert_eq!(res.rows_affected(), 1);
Ok(())
}
pub async fn get_parents(pool: &PgPool, id: Uuid) -> Result<Vec<Uuid>, sqlx::Error> {
// force nullable is required for all columns in views
query_scalar!(
r#"SELECT unnest(parents) as "parents!" FROM item_tree WHERE id = $1"#,
id
)
.fetch_all(pool)
.await
}
pub async fn get_all_parents(pool: &PgPool) -> Result<HashMap<Uuid, Vec<Uuid>>, sqlx::Error> {
let mut parents = HashMap::new();
for row in query!(r#"SELECT id as "id!", parents as "parents!" FROM item_tree"#)
.fetch_all(pool)
.await?
{
parents.insert(row.id, row.parents);
}
Ok(parents)
}
pub async fn get_parents_details(pool: &PgPool, id: Uuid) -> Result<Vec<Item>, sqlx::Error> {
query_as!(
Item,
"SELECT items.*
FROM items
INNER JOIN
unnest((SELECT parents FROM item_tree WHERE id = $1))
WITH ORDINALITY AS parents(id, n)
ON items.id = parents.id
ORDER BY parents.n;",
id
)
.fetch_all(pool)
.await
}
pub async fn get_children(pool: &PgPool, id: Uuid) -> Result<Vec<Item>, sqlx::Error> {
query_as!(Item, "SELECT * FROM items WHERE parent = $1", id)
.fetch_all(pool)
.await
}
pub async fn original_packaging_contents(
pool: &PgPool,
id: Uuid,
) -> Result<Vec<Item>, sqlx::Error> {
query_as!(
Item,
"SELECT * FROM items WHERE original_packaging = $1",
id
)
.fetch_all(pool)
.await
}