more oob experiments
This commit is contained in:
@@ -162,6 +162,24 @@
|
|||||||
},
|
},
|
||||||
"query": "SELECT\n id,\n name,\n weight,\n description,\n category_id\n FROM inventory_items AS item\n WHERE item.id = ?"
|
"query": "SELECT\n id,\n name,\n weight,\n description,\n category_id\n FROM inventory_items AS item\n WHERE item.id = ?"
|
||||||
},
|
},
|
||||||
|
"5fd2b986fcaafe93e816f9ed665b6319d120a3987dc5adca1e3c8634203f7533": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "weight",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Int"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
true
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n SELECT COALESCE(MAX(i_item.weight), 0) as weight\n FROM inventory_items_categories as category\n INNER JOIN inventory_items as i_item\n ON i_item.category_id = category.id\n WHERE category_id = ?\n "
|
||||||
|
},
|
||||||
"68304c19a0bee12c0b3ce9740d53389620b20e47973b41975678dbd13bd30c7f": {
|
"68304c19a0bee12c0b3ce9740d53389620b20e47973b41975678dbd13bd30c7f": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -386,24 +404,6 @@
|
|||||||
},
|
},
|
||||||
"query": "INSERT INTO trips\n (id, name, date_start, date_end, state)\n VALUES\n (?, ?, ?, ?, ?)"
|
"query": "INSERT INTO trips\n (id, name, date_start, date_end, state)\n VALUES\n (?, ?, ?, ?, ?)"
|
||||||
},
|
},
|
||||||
"9c4c2eb24747c3d8157ad17bacbe074d906d2891e8c68160becd8e10d045cfbc": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "weight",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Int"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
true
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "\n SELECT COALESCE(MAX(i_item.weight), 0) as weight\n FROM inventory_items_categories as category\n INNER JOIN inventory_items as i_item\n ON i_item.category_id = category.id\n WHERE category_id = (\n SELECT category_id\n FROM inventory_items\n WHERE inventory_items.id = ?\n )\n "
|
|
||||||
},
|
|
||||||
"a81bcbeb11260e3b4363e19c26b71b489e326b08bfacb6e11b4c4fc068dc7806": {
|
"a81bcbeb11260e3b4363e19c26b71b489e326b08bfacb6e11b4c4fc068dc7806": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
@@ -444,6 +444,114 @@
|
|||||||
},
|
},
|
||||||
"query": "DELETE FROM inventory_items\n WHERE id = ?"
|
"query": "DELETE FROM inventory_items\n WHERE id = ?"
|
||||||
},
|
},
|
||||||
|
"cc1ad49669cff7f89975abfab3d0a8caef2e3978c826e1877db91c05a7f9d00d": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "description",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "SELECT\n id,\n name,\n description\n FROM inventory_items_categories AS category\n WHERE category.id = ?"
|
||||||
|
},
|
||||||
|
"d0562ad92782a6ad6080c0535749c4a0a28fa78a17698933bce670db057e2628": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "category_id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "category_name",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "category_description",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "trip_id",
|
||||||
|
"ordinal": 3,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "item_id",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "item_name",
|
||||||
|
"ordinal": 5,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "item_description",
|
||||||
|
"ordinal": 6,
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "item_weight",
|
||||||
|
"ordinal": 7,
|
||||||
|
"type_info": "Int64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "item_is_picked",
|
||||||
|
"ordinal": 8,
|
||||||
|
"type_info": "Bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "item_is_packed",
|
||||||
|
"ordinal": 9,
|
||||||
|
"type_info": "Bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "item_is_new",
|
||||||
|
"ordinal": 10,
|
||||||
|
"type_info": "Bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n SELECT\n category.id as category_id,\n category.name as category_name,\n category.description AS category_description,\n inner.trip_id AS trip_id,\n inner.item_id AS item_id,\n inner.item_name AS item_name,\n inner.item_description AS item_description,\n inner.item_weight AS item_weight,\n inner.item_is_picked AS item_is_picked,\n inner.item_is_packed AS item_is_packed,\n inner.item_is_new AS item_is_new\n FROM inventory_items_categories AS category\n LEFT JOIN (\n SELECT\n trip.trip_id AS trip_id,\n category.id as category_id,\n category.name as category_name,\n category.description as category_description,\n item.id as item_id,\n item.name as item_name,\n item.description as item_description,\n item.weight as item_weight,\n trip.pick as item_is_picked,\n trip.pack as item_is_packed,\n trip.new as item_is_new\n FROM trips_items as trip\n INNER JOIN inventory_items as item\n ON item.id = trip.item_id\n INNER JOIN inventory_items_categories as category\n ON category.id = item.category_id\n WHERE trip.trip_id = ?\n ) AS inner\n ON inner.category_id = category.id\n WHERE category.id = ?\n "
|
||||||
|
},
|
||||||
"ded3be1c8894a64e3b5f749461db7261d9224abb8a54da980db8262733d08205": {
|
"ded3be1c8894a64e3b5f749461db7261d9224abb8a54da980db8262733d08205": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ impl Root {
|
|||||||
link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" {}
|
link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" {}
|
||||||
link rel="shortcut icon" type="image/svg+xml" href="/favicon.svg" {}
|
link rel="shortcut icon" type="image/svg+xml" href="/favicon.svg" {}
|
||||||
script { (PreEscaped(include_str!(concat!(env!("CARGO_MANIFEST_DIR"),"/js/app.js")))) }
|
script { (PreEscaped(include_str!(concat!(env!("CARGO_MANIFEST_DIR"),"/js/app.js")))) }
|
||||||
|
meta name="htmx-config" content=r#"{"useTemplateFragments":true}"# {}
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
hx-boost="true"
|
hx-boost="true"
|
||||||
|
|||||||
@@ -745,12 +745,14 @@ impl TripCategoryListRow {
|
|||||||
pub fn build(
|
pub fn build(
|
||||||
category: &TripCategory,
|
category: &TripCategory,
|
||||||
active: bool,
|
active: bool,
|
||||||
has_new_items: bool,
|
|
||||||
biggest_category_weight: i64,
|
biggest_category_weight: i64,
|
||||||
|
htmx_swap: bool,
|
||||||
) -> Markup {
|
) -> Markup {
|
||||||
|
let has_new_items = category.items.as_ref().unwrap().iter().any(|item| item.new);
|
||||||
html!(
|
html!(
|
||||||
tr
|
tr
|
||||||
id={"category-" (category.category.id)}
|
id={"category-" (category.category.id)}
|
||||||
|
hx-swap-oob=[htmx_swap.then_some("outerHTML")]
|
||||||
."h-10"
|
."h-10"
|
||||||
."hover:bg-purple-100"
|
."hover:bg-purple-100"
|
||||||
."m-3"
|
."m-3"
|
||||||
@@ -872,9 +874,8 @@ impl TripCategoryList {
|
|||||||
}
|
}
|
||||||
tbody {
|
tbody {
|
||||||
@for category in trip.categories() {
|
@for category in trip.categories() {
|
||||||
@let has_new_items = category.items.as_ref().unwrap().iter().any(|item| item.new);
|
|
||||||
@let active = state.active_category_id.map_or(false, |id| category.category.id == id);
|
@let active = state.active_category_id.map_or(false, |id| category.category.id == id);
|
||||||
(TripCategoryListRow::build(category, active, has_new_items, biggest_category_weight))
|
(TripCategoryListRow::build(category, active, biggest_category_weight,false))
|
||||||
}
|
}
|
||||||
tr ."h-10" ."hover:bg-purple-200" ."bg-gray-300" ."font-bold" {
|
tr ."h-10" ."hover:bg-purple-200" ."bg-gray-300" ."font-bold" {
|
||||||
td ."border" ."p-0" ."m-0" {
|
td ."border" ."p-0" ."m-0" {
|
||||||
@@ -922,8 +923,8 @@ impl TripItemList {
|
|||||||
{
|
{
|
||||||
thead ."bg-gray-200" {
|
thead ."bg-gray-200" {
|
||||||
tr ."h-10" {
|
tr ."h-10" {
|
||||||
th ."border" ."p-2" { "Take?" }
|
th ."border" ."p-2" {}
|
||||||
th ."border" ."p-2" { "Packed?" }
|
th ."border" ."p-2" {}
|
||||||
th ."border" ."p-2" ."w-1/2" { "Name" }
|
th ."border" ."p-2" ."w-1/2" { "Name" }
|
||||||
th ."border" ."p-2" ."w-1/4" { "Weight" }
|
th ."border" ."p-2" ."w-1/4" { "Weight" }
|
||||||
}
|
}
|
||||||
|
|||||||
187
rust/src/main.rs
187
rust/src/main.rs
@@ -114,54 +114,53 @@ async fn main() -> Result<(), sqlx::Error> {
|
|||||||
.route("/favicon.svg", get(icon_handler))
|
.route("/favicon.svg", get(icon_handler))
|
||||||
.route("/assets/luggage.svg", get(icon_handler))
|
.route("/assets/luggage.svg", get(icon_handler))
|
||||||
.route("/", get(root))
|
.route("/", get(root))
|
||||||
.route("/trips/", get(trips))
|
.nest(
|
||||||
.route("/trips/types/", get(trips_types).post(trip_type_create))
|
"/trips/",
|
||||||
.route(
|
Router::new()
|
||||||
"/trips/types/:id/edit/name/submit",
|
.route("/", get(trips))
|
||||||
post(trips_types_edit_name),
|
.route("/trips/types/", get(trips_types).post(trip_type_create))
|
||||||
|
.route("/types/:id/edit/name/submit", post(trips_types_edit_name))
|
||||||
|
.route("/", post(trip_create))
|
||||||
|
.route("/:id/", get(trip))
|
||||||
|
.route("/:id/comment/submit", post(trip_comment_set))
|
||||||
|
.route("/:id/state/:id", post(trip_state_set))
|
||||||
|
.route("/:id/type/:id/add", get(trip_type_add))
|
||||||
|
.route("/:id/type/:id/remove", get(trip_type_remove))
|
||||||
|
.route("/:id/edit/:attribute/submit", post(trip_edit_attribute))
|
||||||
|
.route(
|
||||||
|
"/:id/items/:id/pick",
|
||||||
|
get(trip_item_set_pick).post(trip_item_set_pick_htmx),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/:id/items/:id/unpick",
|
||||||
|
get(trip_item_set_unpick).post(trip_item_set_unpick_htmx),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/:id/items/:id/pack",
|
||||||
|
get(trip_item_set_pack).post(trip_item_set_pack_htmx),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/:id/items/:id/unpack",
|
||||||
|
get(trip_item_set_unpack).post(trip_item_set_unpack_htmx),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.route("/trips/", post(trip_create))
|
.nest(
|
||||||
.route("/trips/:id/", get(trip))
|
"/inventory/",
|
||||||
.route("/trips/:id/comment/submit", post(trip_comment_set))
|
Router::new()
|
||||||
.route("/trips/:id/state/:id", post(trip_state_set))
|
.route("/", get(inventory_inactive))
|
||||||
.route("/trips/:id/type/:id/add", get(trip_type_add))
|
.route("/category/", post(inventory_category_create))
|
||||||
.route("/trips/:id/type/:id/remove", get(trip_type_remove))
|
.route("/item/:id/", get(inventory_item))
|
||||||
.route(
|
.route("/item/", post(inventory_item_create))
|
||||||
"/trips/:id/edit/:attribute/submit",
|
.route("/item/name/validate", post(inventory_item_validate_name))
|
||||||
post(trip_edit_attribute),
|
.route("/category/:id/", get(inventory_active))
|
||||||
|
.route("/item/:id/delete", get(inventory_item_delete))
|
||||||
|
.route("/item/:id/edit", post(inventory_item_edit))
|
||||||
|
.route("/item/:id/cancel", get(inventory_item_cancel)), // .route(
|
||||||
|
// "/inventory/category/:id/items",
|
||||||
|
// post(htmx_inventory_category_items),
|
||||||
|
// );
|
||||||
)
|
)
|
||||||
.route(
|
.fallback(|| async { (StatusCode::NOT_FOUND, "not found") })
|
||||||
"/trips/:id/items/:id/pick",
|
|
||||||
get(trip_item_set_pick).post(trip_item_set_pick_htmx),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/trips/:id/items/:id/unpick",
|
|
||||||
get(trip_item_set_unpick).post(trip_item_set_unpick_htmx),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/trips/:id/items/:id/pack",
|
|
||||||
get(trip_item_set_pack).post(trip_item_set_pack_htmx),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/trips/:id/items/:id/unpack",
|
|
||||||
get(trip_item_set_unpack).post(trip_item_set_unpack_htmx),
|
|
||||||
)
|
|
||||||
.route("/inventory/", get(inventory_inactive))
|
|
||||||
.route("/inventory/category/", post(inventory_category_create))
|
|
||||||
.route("/inventory/item/:id/", get(inventory_item))
|
|
||||||
.route("/inventory/item/", post(inventory_item_create))
|
|
||||||
.route(
|
|
||||||
"/inventory/item/name/validate",
|
|
||||||
post(inventory_item_validate_name),
|
|
||||||
)
|
|
||||||
.route("/inventory/category/:id/", get(inventory_active))
|
|
||||||
.route("/inventory/item/:id/delete", get(inventory_item_delete))
|
|
||||||
.route("/inventory/item/:id/edit", post(inventory_item_edit))
|
|
||||||
.route("/inventory/item/:id/cancel", get(inventory_item_cancel))
|
|
||||||
// .route(
|
|
||||||
// "/inventory/category/:id/items",
|
|
||||||
// post(htmx_inventory_category_items),
|
|
||||||
// );
|
|
||||||
.with_state(state);
|
.with_state(state);
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
@@ -996,6 +995,65 @@ async fn trip_item_set_state(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn trip_row(
|
||||||
|
state: &AppState,
|
||||||
|
trip_id: Uuid,
|
||||||
|
item_id: Uuid,
|
||||||
|
) -> Result<Markup, (StatusCode, Markup)> {
|
||||||
|
let item: TripItem = TripItem::find(&state.database_pool, trip_id, item_id)
|
||||||
|
.await
|
||||||
|
.map_err(|error| {
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
ErrorPage::build(&error.to_string()),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.ok_or_else(|| {
|
||||||
|
(
|
||||||
|
StatusCode::NOT_FOUND,
|
||||||
|
ErrorPage::build(&format!(
|
||||||
|
"item with id {} not found for trip {}",
|
||||||
|
item_id, trip_id
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let item_row = components::trip::TripItemListRow::build(
|
||||||
|
trip_id,
|
||||||
|
&item,
|
||||||
|
Item::get_category_max_weight(&state.database_pool, item.item.category_id)
|
||||||
|
.await
|
||||||
|
.map_err(|error| {
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
ErrorPage::build(&error.to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let category = TripCategory::find(&state.database_pool, trip_id, item.item.category_id)
|
||||||
|
.map_err(|error| {
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
ErrorPage::build(&error.to_string()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| {
|
||||||
|
(
|
||||||
|
StatusCode::NOT_FOUND,
|
||||||
|
ErrorPage::build(&format!(
|
||||||
|
"category with id {} not found",
|
||||||
|
item.item.category_id
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let category_row = components::trip::TripCategoryListRow::build(&category, true, 0, true);
|
||||||
|
|
||||||
|
Ok(html!((item_row)(category_row)))
|
||||||
|
}
|
||||||
|
|
||||||
async fn trip_item_set_pick(
|
async fn trip_item_set_pick(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||||
@@ -1056,43 +1114,6 @@ async fn trip_item_set_unpick(
|
|||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn trip_row(
|
|
||||||
state: &AppState,
|
|
||||||
trip_id: Uuid,
|
|
||||||
item_id: Uuid,
|
|
||||||
) -> Result<Markup, (StatusCode, Markup)> {
|
|
||||||
let item: TripItem = TripItem::find(&state.database_pool, trip_id, item_id)
|
|
||||||
.await
|
|
||||||
.map_err(|error| {
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
ErrorPage::build(&error.to_string()),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.ok_or_else(|| {
|
|
||||||
(
|
|
||||||
StatusCode::NOT_FOUND,
|
|
||||||
ErrorPage::build(&format!(
|
|
||||||
"item with id {} not found for trip {}",
|
|
||||||
item_id, trip_id
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(components::trip::TripItemListRow::build(
|
|
||||||
trip_id,
|
|
||||||
&item,
|
|
||||||
Item::get_category_max_weight(&state.database_pool, item.item.category_id)
|
|
||||||
.await
|
|
||||||
.map_err(|error| {
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
ErrorPage::build(&error.to_string()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn trip_item_set_unpick_htmx(
|
async fn trip_item_set_unpick_htmx(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
Path((trip_id, item_id)): Path<(Uuid, Uuid)>,
|
||||||
|
|||||||
@@ -214,6 +214,114 @@ impl TripCategory {
|
|||||||
.map(|item| item.item.weight)
|
.map(|item| item.item.weight)
|
||||||
.sum()
|
.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn find(
|
||||||
|
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||||
|
trip_id: Uuid,
|
||||||
|
category_id: Uuid,
|
||||||
|
) -> Result<Option<TripCategory>, Error> {
|
||||||
|
let mut category: Option<TripCategory> = None;
|
||||||
|
|
||||||
|
let trip_id_param = trip_id.to_string();
|
||||||
|
let category_id_param = category_id.to_string();
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
SELECT
|
||||||
|
category.id as category_id,
|
||||||
|
category.name as category_name,
|
||||||
|
category.description AS category_description,
|
||||||
|
inner.trip_id AS trip_id,
|
||||||
|
inner.item_id AS item_id,
|
||||||
|
inner.item_name AS item_name,
|
||||||
|
inner.item_description AS item_description,
|
||||||
|
inner.item_weight AS item_weight,
|
||||||
|
inner.item_is_picked AS item_is_picked,
|
||||||
|
inner.item_is_packed AS item_is_packed,
|
||||||
|
inner.item_is_new AS item_is_new
|
||||||
|
FROM inventory_items_categories AS category
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
trip.trip_id AS trip_id,
|
||||||
|
category.id as category_id,
|
||||||
|
category.name as category_name,
|
||||||
|
category.description as category_description,
|
||||||
|
item.id as item_id,
|
||||||
|
item.name as item_name,
|
||||||
|
item.description as item_description,
|
||||||
|
item.weight as item_weight,
|
||||||
|
trip.pick as item_is_picked,
|
||||||
|
trip.pack as item_is_packed,
|
||||||
|
trip.new as item_is_new
|
||||||
|
FROM trips_items as trip
|
||||||
|
INNER JOIN inventory_items as item
|
||||||
|
ON item.id = trip.item_id
|
||||||
|
INNER JOIN inventory_items_categories as category
|
||||||
|
ON category.id = item.category_id
|
||||||
|
WHERE trip.trip_id = ?
|
||||||
|
) AS inner
|
||||||
|
ON inner.category_id = category.id
|
||||||
|
WHERE category.id = ?
|
||||||
|
",
|
||||||
|
trip_id_param,
|
||||||
|
category_id_param
|
||||||
|
)
|
||||||
|
.fetch(pool)
|
||||||
|
.map_ok(|row| -> Result<(), Error> {
|
||||||
|
match &category {
|
||||||
|
Some(_) => (),
|
||||||
|
None => {
|
||||||
|
category = Some(TripCategory {
|
||||||
|
category: Category {
|
||||||
|
id: Uuid::try_parse(&row.category_id)?,
|
||||||
|
name: row.category_name,
|
||||||
|
description: row.category_description,
|
||||||
|
items: None,
|
||||||
|
},
|
||||||
|
items: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match row.item_id {
|
||||||
|
None => {
|
||||||
|
// we have an empty (unused) category which has NULL values
|
||||||
|
// for the item_id column
|
||||||
|
category.as_mut().unwrap().items = Some(vec![]);
|
||||||
|
category.as_mut().unwrap().category.items = Some(vec![]);
|
||||||
|
}
|
||||||
|
Some(item_id) => {
|
||||||
|
let item = TripItem {
|
||||||
|
item: Item {
|
||||||
|
id: Uuid::try_parse(&item_id)?,
|
||||||
|
name: row.item_name.unwrap(),
|
||||||
|
description: row.item_description,
|
||||||
|
weight: row.item_weight.unwrap(),
|
||||||
|
category_id: category.as_ref().unwrap().category.id,
|
||||||
|
},
|
||||||
|
picked: row.item_is_picked.unwrap(),
|
||||||
|
packed: row.item_is_packed.unwrap(),
|
||||||
|
new: row.item_is_new.unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match &mut category.as_mut().unwrap().items {
|
||||||
|
None => category.as_mut().unwrap().items = Some(vec![item]),
|
||||||
|
Some(ref mut items) => items.push(item),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.try_collect::<Vec<Result<(), Error>>>()
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Result<(), Error>>()?;
|
||||||
|
|
||||||
|
// this may be None if there are no results (which
|
||||||
|
// means that the category was not found)
|
||||||
|
Ok(category)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -658,6 +766,34 @@ pub struct DbInventoryItemsRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Category {
|
impl<'a> Category {
|
||||||
|
// pub async fn find(
|
||||||
|
// pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||||
|
// id: Uuid,
|
||||||
|
// ) -> Result<Option<Category>, Error> {
|
||||||
|
// let id_param = id.to_string();
|
||||||
|
// let item: Result<Result<Category, Error>, sqlx::Error> = sqlx::query_as!(
|
||||||
|
// DbCategoryRow,
|
||||||
|
// "SELECT
|
||||||
|
// id,
|
||||||
|
// name,
|
||||||
|
// description
|
||||||
|
// FROM inventory_items_categories AS category
|
||||||
|
// WHERE category.id = ?",
|
||||||
|
// id_param,
|
||||||
|
// )
|
||||||
|
// .fetch_one(pool)
|
||||||
|
// .map_ok(|row| row.try_into())
|
||||||
|
// .await;
|
||||||
|
|
||||||
|
// match item {
|
||||||
|
// Err(e) => match e {
|
||||||
|
// sqlx::Error::RowNotFound => Ok(None),
|
||||||
|
// _ => Err(e.into()),
|
||||||
|
// },
|
||||||
|
// Ok(v) => Ok(Some(v?)),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn items(&'a self) -> &'a Vec<Item> {
|
pub fn items(&'a self) -> &'a Vec<Item> {
|
||||||
self.items
|
self.items
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -787,22 +923,18 @@ impl Item {
|
|||||||
|
|
||||||
pub async fn get_category_max_weight(
|
pub async fn get_category_max_weight(
|
||||||
pool: &sqlx::Pool<sqlx::Sqlite>,
|
pool: &sqlx::Pool<sqlx::Sqlite>,
|
||||||
id: Uuid,
|
category_id: Uuid,
|
||||||
) -> Result<i64, Error> {
|
) -> Result<i64, Error> {
|
||||||
let id_param = id.to_string();
|
let category_id_param = category_id.to_string();
|
||||||
let weight: Result<i64, sqlx::Error> = sqlx::query!(
|
let weight: Result<i64, sqlx::Error> = sqlx::query!(
|
||||||
"
|
"
|
||||||
SELECT COALESCE(MAX(i_item.weight), 0) as weight
|
SELECT COALESCE(MAX(i_item.weight), 0) as weight
|
||||||
FROM inventory_items_categories as category
|
FROM inventory_items_categories as category
|
||||||
INNER JOIN inventory_items as i_item
|
INNER JOIN inventory_items as i_item
|
||||||
ON i_item.category_id = category.id
|
ON i_item.category_id = category.id
|
||||||
WHERE category_id = (
|
WHERE category_id = ?
|
||||||
SELECT category_id
|
|
||||||
FROM inventory_items
|
|
||||||
WHERE inventory_items.id = ?
|
|
||||||
)
|
|
||||||
",
|
",
|
||||||
id_param
|
category_id_param
|
||||||
)
|
)
|
||||||
.fetch_one(pool)
|
.fetch_one(pool)
|
||||||
.map_ok(|row| {
|
.map_ok(|row| {
|
||||||
|
|||||||
Reference in New Issue
Block a user