diff --git a/rust/sqlx-data.json b/rust/sqlx-data.json index 89808fc..fc06534 100644 --- a/rust/sqlx-data.json +++ b/rust/sqlx-data.json @@ -18,6 +18,16 @@ }, "query": "UPDATE inventory_items AS item\n SET\n name = ?,\n weight = ?\n WHERE item.id = ?\n RETURNING inventory_items.category_id AS id\n " }, + "0e8a12e168d8ff41005b2b5a1356ef5dc39339291572005e2a9278fb28113a2b": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 2 + } + }, + "query": "INSERT INTO trips_to_trips_types\n (trip_id, trip_type_id)\n VALUES\n (?, ?)\n " + }, "1320943d04e921a8e5f409737e466838b4ecf7e73ad0ade59ccd7664459a9c80": { "describe": { "columns": [], @@ -28,16 +38,6 @@ }, "query": "\n INSERT INTO trips_items\n (\n item_id,\n trip_id,\n pick,\n pack,\n new\n )\n VALUES (?, ?, ?, ?, ?)\n " }, - "18cbb2893df033f5f81f42097fcae7ee036405749a5d93f2ea1d79ba280dfd20": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Right": 2 - } - }, - "query": "DELETE FROM trips_to_trips_types AS ttt\n WHERE ttt.trip_id = ?\n AND ttt.trip_type_id = ?\n " - }, "1994305e1521fe1f5f927ad28e21c9cab8a25598b19e1c9038dae9092fe18f1f": { "describe": { "columns": [ @@ -140,16 +140,6 @@ }, "query": "DELETE FROM inventory_items\n WHERE id = ?" }, - "4d377bb01af6bbbca637d8c61326c84e8b05b1e570199c464b593bdc81b3dba6": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Right": 2 - } - }, - "query": "INSERT INTO trips_to_trips_types\n (trip_id, trip_type_id) VALUES (?, ?)" - }, "53c45b9447118c8b448df6836e68a38ff78d0b7f4d5344a1e5064d31e70396b3": { "describe": { "columns": [ @@ -288,6 +278,16 @@ }, "query": "SELECT\n item.id AS id,\n item.name AS name,\n item.description AS description,\n weight,\n category.id AS category_id,\n category.name AS category_name,\n category.description AS category_description,\n product.id AS product_id,\n product.name AS product_name,\n product.description AS product_description,\n product.comment AS product_comment\n FROM inventory_items AS item\n INNER JOIN inventory_items_categories as category\n ON item.category_id = category.id\n LEFT JOIN inventory_products AS product\n ON item.product_id = product.id\n WHERE item.id = ?" }, + "68f936e138283635c5e7bde3313f036aae4167143200ea20fb89e1e99ada9ad1": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 2 + } + }, + "query": "INSERT INTO inventory_items_categories\n (id, name)\n VALUES\n (?, ?)" + }, "6973cceeb5499216475136b320b25e1355974e1213829d931abdd6b7a1448a87": { "describe": { "columns": [ @@ -396,7 +396,7 @@ }, "query": "SELECT\n id,\n name,\n CAST (date_start AS TEXT) date_start,\n CAST (date_end AS TEXT) date_end,\n state,\n location,\n temp_min,\n temp_max,\n comment\n FROM trips" }, - "6e2928c8c2e66b15fc3f6f0ae4e8e0d4616b714fccbf273306d5135df31f4c19": { + "82395724cd85d8b57ce50a64f49386435fbebc83f18db53ab8650b29414e40fb": { "describe": { "columns": [], "nullable": [], @@ -404,17 +404,7 @@ "Right": 2 } }, - "query": "INSERT INTO inventory_items_categories\n (id, name)\n VALUES\n (?, ?)" - }, - "88293d85c61e1eeaf9e46ada4154736b127c3bf305e92130de87b89ce7c6edab": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Right": 2 - } - }, - "query": "UPDATE trips\n SET comment = ?\n WHERE id = ?" + "query": "DELETE FROM trips_to_trips_types AS ttt\n WHERE ttt.trip_id = ?\n AND ttt.trip_type_id = ?\n " }, "918fc9cf50097d4210b212255ef49335ebedbe81002ce9a418b4dab4fbb29aa3": { "describe": { @@ -510,6 +500,16 @@ }, "query": "SELECT\n id,\n name,\n CAST (date_start AS TEXT) date_start,\n CAST (date_end AS TEXT) date_end,\n state,\n location,\n temp_min,\n temp_max,\n comment\n FROM trips\n WHERE id = ?" }, + "a5cdb8a6d5850326815efd460c0b42dda02a4ea32713ec89beceb38cd24321d5": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 2 + } + }, + "query": "UPDATE trips\n SET comment = ?\n WHERE id = ?" + }, "a81bcbeb11260e3b4363e19c26b71b489e326b08bfacb6e11b4c4fc068dc7806": { "describe": { "columns": [ diff --git a/rust/src/main.rs b/rust/src/main.rs index 2c5df4b..dae51b5 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -710,26 +710,16 @@ async fn trip_type_remove( State(state): State, Path((trip_id, type_id)): Path<(Uuid, Uuid)>, ) -> Result { - let trip_id = trip_id.to_string(); - let type_id = type_id.to_string(); - let results = query!( - "DELETE FROM trips_to_trips_types AS ttt - WHERE ttt.trip_id = ? - AND ttt.trip_type_id = ? - ", - trip_id, - type_id - ) - .execute(&state.database_pool) - .await - .map_err(|e| { - ( - StatusCode::BAD_REQUEST, - components::ErrorPage::build(&e.to_string()), - ) - })?; + let found = models::Trip::trip_type_remove(&state.database_pool, trip_id, type_id) + .map_err(|error| { + ( + StatusCode::INTERNAL_SERVER_ERROR, + components::ErrorPage::build(&error.to_string()), + ) + }) + .await?; - if results.rows_affected() == 0 { + if !found { Err(( StatusCode::NOT_FOUND, components::ErrorPage::build(&format!( @@ -745,66 +735,22 @@ async fn trip_type_add( State(state): State, Path((trip_id, type_id)): Path<(Uuid, Uuid)>, ) -> Result { - let trip_id = trip_id.to_string(); - let type_id = type_id.to_string(); - query!( - "INSERT INTO trips_to_trips_types - (trip_id, trip_type_id) VALUES (?, ?)", - trip_id, - type_id - ) - .execute(&state.database_pool) - .await - .map_err(|e| match e { - sqlx::Error::Database(ref error) => { - let sqlite_error = error.downcast_ref::(); - if let Some(code) = sqlite_error.code() { - match &*code { - "787" => { - // SQLITE_CONSTRAINT_FOREIGNKEY - ( - StatusCode::BAD_REQUEST, - // TODO: this is not perfect, as both foreign keys - // may be responsible for the error. how can we tell - // which one? - components::ErrorPage::build(&format!( - "invalid id: {}", - code.to_string() - )), - ) - } - "2067" => { - // SQLITE_CONSTRAINT_UNIQUE - ( - StatusCode::BAD_REQUEST, - components::ErrorPage::build(&format!( - "type {type_id} is already active for trip {trip_id}" - )), - ) - } - _ => ( - StatusCode::INTERNAL_SERVER_ERROR, - components::ErrorPage::build(&format!( - "got error with unknown code: {}", - sqlite_error.to_string() - )), - ), - } - } else { - ( - StatusCode::INTERNAL_SERVER_ERROR, - components::ErrorPage::build(&format!( - "got error without code: {}", - sqlite_error.to_string() - )), - ) - } - } - _ => ( - StatusCode::INTERNAL_SERVER_ERROR, - components::ErrorPage::build(&format!("got unknown error: {}", e.to_string())), - ), - })?; + models::Trip::trip_type_add(&state.database_pool, trip_id, type_id) + .map_err(|error| match error { + models::Error::ReferenceNotFound { description } => ( + StatusCode::BAD_REQUEST, + components::ErrorPage::build(&description), + ), + models::Error::Duplicate { description } => ( + StatusCode::BAD_REQUEST, + components::ErrorPage::build(&description), + ), + _ => ( + StatusCode::INTERNAL_SERVER_ERROR, + components::ErrorPage::build(&error.to_string()), + ), + }) + .await?; Ok(Redirect::to(&format!("/trips/{trip_id}/"))) } @@ -820,24 +766,17 @@ async fn trip_comment_set( Path(trip_id): Path, Form(comment_update): Form, ) -> Result { - let trip_id = trip_id.to_string(); - let result = query!( - "UPDATE trips - SET comment = ? - WHERE id = ?", - comment_update.new_comment, - trip_id, - ) - .execute(&state.database_pool) - .await - .map_err(|e| { - ( - StatusCode::BAD_REQUEST, - components::ErrorPage::build(&e.to_string()), - ) - })?; + let found = + models::Trip::set_comment(&state.database_pool, trip_id, &comment_update.new_comment) + .map_err(|error| { + ( + StatusCode::BAD_REQUEST, + components::ErrorPage::build(&error.to_string()), + ) + }) + .await?; - if result.rows_affected() == 0 { + if !found { Err(( StatusCode::NOT_FOUND, components::ErrorPage::build(&format!("trip with id {id} not found", id = trip_id)), @@ -866,31 +805,25 @@ async fn trip_edit_attribute( )); } } - let result = query(&format!( - "UPDATE trips - SET {attribute} = ? - WHERE id = ?", - attribute = to_variant_name(&attribute).unwrap() - )) - .bind(trip_update.new_value) - .bind(trip_id.to_string()) - .execute(&state.database_pool) - .await - .map_err(|e| { - ( - StatusCode::BAD_REQUEST, - components::ErrorPage::build(&e.to_string()), - ) - })?; - - if result.rows_affected() == 0 { - Err(( + models::Trip::set_attribute( + &state.database_pool, + trip_id, + attribute, + &trip_update.new_value, + ) + .map_err(|error| match error { + models::Error::NotFound { description } => ( StatusCode::NOT_FOUND, - components::ErrorPage::build(&format!("trip with id {id} not found", id = trip_id)), - )) - } else { - Ok(Redirect::to(&format!("/trips/{trip_id}/"))) - } + components::ErrorPage::build(&description), + ), + _ => ( + StatusCode::BAD_REQUEST, + components::ErrorPage::build(&error.to_string()), + ), + }) + .await?; + + Ok(Redirect::to(&format!("/trips/{trip_id}/"))) } async fn trip_item_set_state( @@ -900,35 +833,20 @@ async fn trip_item_set_state( key: models::TripItemStateKey, value: bool, ) -> Result<(), (StatusCode, Markup)> { - let result = query(&format!( - "UPDATE trips_items - SET {key} = ? - WHERE trip_id = ? - AND item_id = ?", - key = to_variant_name(&key).unwrap() - )) - .bind(value) - .bind(trip_id.to_string()) - .bind(item_id.to_string()) - .execute(&state.database_pool) - .await - .map_err(|e| { - ( - StatusCode::BAD_REQUEST, - components::ErrorPage::build(&e.to_string()), - ) - })?; + models::TripItem::set_state(&state.database_pool, trip_id, item_id, key, value) + .map_err(|error| match error { + models::Error::NotFound { description } => ( + StatusCode::NOT_FOUND, + components::ErrorPage::build(&description), + ), + _ => ( + StatusCode::INTERNAL_SERVER_ERROR, + components::ErrorPage::build(&error.to_string()), + ), + }) + .await?; - if result.rows_affected() == 0 { - Err(( - StatusCode::NOT_FOUND, - components::ErrorPage::build(&format!( - "trip with id {trip_id} or item with id {item_id} not found" - )), - )) - } else { - Ok(()) - } + Ok(()) } async fn trip_row( @@ -1267,56 +1185,18 @@ async fn inventory_category_create( )); } - let id = Uuid::new_v4(); - let id_param = id.to_string(); - query!( - "INSERT INTO inventory_items_categories - (id, name) - VALUES - (?, ?)", - id_param, - new_category.name - ) - .execute(&state.database_pool) - .map_err(|e| match e { - sqlx::Error::Database(ref error) => { - let sqlite_error = error.downcast_ref::(); - if let Some(code) = sqlite_error.code() { - match &*code { - "2067" => { - // SQLITE_CONSTRAINT_UNIQUE - ( - StatusCode::BAD_REQUEST, - components::ErrorPage::build(&format!( - "category with name \"{name}\" already exists", - name = new_category.name - )), - ) - } - _ => ( - StatusCode::INTERNAL_SERVER_ERROR, - components::ErrorPage::build(&format!( - "got error with unknown code: {}", - sqlite_error.to_string() - )), - ), - } - } else { - ( - StatusCode::INTERNAL_SERVER_ERROR, - components::ErrorPage::build(&format!( - "got error without code: {}", - sqlite_error.to_string() - )), - ) - } - } - _ => ( - StatusCode::INTERNAL_SERVER_ERROR, - components::ErrorPage::build(&format!("got unknown error: {}", e.to_string())), - ), - }) - .await?; + let _new_id = models::Category::save(&state.database_pool, &new_category.name) + .map_err(|error| match error { + models::Error::Duplicate { description } => ( + StatusCode::BAD_REQUEST, + components::ErrorPage::build(&description), + ), + _ => ( + StatusCode::INTERNAL_SERVER_ERROR, + components::ErrorPage::build(&error.to_string()), + ), + }) + .await?; Ok(Redirect::to("/inventory/")) } @@ -1398,58 +1278,26 @@ struct NewTripType { async fn trip_type_create( State(state): State, Form(new_trip_type): Form, -) -> Result { +) -> Result { if new_trip_type.name.is_empty() { return Err(( StatusCode::UNPROCESSABLE_ENTITY, - "name cannot be empty".to_string(), + components::ErrorPage::build("name cannot be empty"), )); } - let id = Uuid::new_v4(); - let id_param = id.to_string(); - query!( - "INSERT INTO trips_types - (id, name) - VALUES - (?, ?)", - id_param, - new_trip_type.name, - ) - .execute(&state.database_pool) - .await - .map_err(|e| match e { - sqlx::Error::Database(ref error) => { - let sqlite_error = error.downcast_ref::(); - if let Some(code) = sqlite_error.code() { - match &*code { - "2067" => { - // SQLITE_CONSTRAINT_UNIQUE - ( - StatusCode::BAD_REQUEST, - format!( - "trip type with name \"{name}\" already exists", - name = new_trip_type.name, - ), - ) - } - _ => ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("got error with unknown code: {}", sqlite_error.to_string()), - ), - } - } else { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("got error without code: {}", sqlite_error.to_string()), - ) - } - } - _ => ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("got unknown error: {}", e.to_string()), - ), - })?; + let _new_id = models::TripsType::save(&state.database_pool, &new_trip_type.name) + .map_err(|error| match error { + models::Error::Duplicate { description } => ( + StatusCode::BAD_REQUEST, + components::ErrorPage::build(&description), + ), + _ => ( + StatusCode::INTERNAL_SERVER_ERROR, + components::ErrorPage::build(&error.to_string()), + ), + }) + .await?; Ok(Redirect::to("/trips/types/")) } @@ -1644,7 +1492,7 @@ async fn trip_packagelist( StatusCode::OK, components::Root::build( &components::trip::packagelist::TripPackageList::build(&trip), - &components::TopLevelPage::None, + &components::TopLevelPage::Trips, ), )) } diff --git a/rust/src/models.rs b/rust/src/models.rs index 3236c26..4b5a203 100644 --- a/rust/src/models.rs +++ b/rust/src/models.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use serde_variant::to_variant_name; use sqlx::{ database::Database, database::HasValueRef, @@ -28,6 +29,9 @@ pub enum Error { Int { description: String }, Constraint { description: String }, TimeParse { description: String }, + Duplicate { description: String }, + NotFound { description: String }, + ReferenceNotFound { description: String }, } impl fmt::Display for Error { @@ -51,6 +55,15 @@ impl fmt::Display for Error { Self::Constraint { description } => { write!(f, "SQL constraint error: {description}") } + Self::Duplicate { description } => { + write!(f, "Duplicate data entry: {description}") + } + Self::NotFound { description } => { + write!(f, "not found: {description}") + } + Self::ReferenceNotFound { description } => { + write!(f, "SQL foreign key reference was not found: {description}") + } } } } @@ -395,6 +408,36 @@ impl TripItem { Ok(v) => Ok(Some(v?)), } } + + pub async fn set_state( + pool: &sqlx::Pool, + trip_id: Uuid, + item_id: Uuid, + key: TripItemStateKey, + value: bool, + ) -> Result<(), Error> { + let result = sqlx::query(&format!( + "UPDATE trips_items + SET {key} = ? + WHERE trip_id = ? + AND item_id = ?", + key = to_variant_name(&key).unwrap() + )) + .bind(value) + .bind(trip_id.to_string()) + .bind(item_id.to_string()) + .execute(pool) + .map_err(|error| Error::Sql { + description: error.to_string(), + }) + .await?; + + (result.rows_affected() != 0) + .then_some(()) + .ok_or_else(|| Error::NotFound { + description: format!("item {item_id} not found for trip {trip_id}"), + }) + } } struct DbTripRow { @@ -463,7 +506,7 @@ struct DbTripWeightRow { pub total_weight: Option, } -impl<'a> Trip { +impl Trip { pub async fn all(pool: &sqlx::Pool) -> Result, Error> { sqlx::query_as!( DbTripRow, @@ -521,6 +564,89 @@ impl<'a> Trip { } } + pub async fn trip_type_remove( + pool: &sqlx::Pool, + id: Uuid, + type_id: Uuid, + ) -> Result { + let id_param = id.to_string(); + let type_id_param = type_id.to_string(); + + let results = sqlx::query!( + "DELETE FROM trips_to_trips_types AS ttt + WHERE ttt.trip_id = ? + AND ttt.trip_type_id = ? + ", + id_param, + type_id_param, + ) + .execute(pool) + .await?; + + Ok(results.rows_affected() != 0) + } + + pub async fn trip_type_add( + pool: &sqlx::Pool, + id: Uuid, + type_id: Uuid, + ) -> Result<(), Error> { + let trip_id_param = id.to_string(); + let type_id_param = type_id.to_string(); + sqlx::query!( + "INSERT INTO trips_to_trips_types + (trip_id, trip_type_id) + VALUES + (?, ?) + ", + trip_id_param, + type_id_param, + ) + .execute(pool) + .map_err(|error| match error { + sqlx::Error::Database(ref error) => { + let sqlite_error = error.downcast_ref::(); + if let Some(code) = sqlite_error.code() { + match &*code { + "787" => { + // SQLITE_CONSTRAINT_FOREIGNKEY + Error::ReferenceNotFound { + description: format!("invalid id: {}", code.to_string()), + } + } + "2067" => { + // SQLITE_CONSTRAINT_UNIQUE + Error::Duplicate { + description: format!( + "type {type_id} is already active for trip {id}" + ), + } + } + _ => Error::Sql { + description: format!( + "got error with unknown code: {}", + sqlite_error.to_string() + ), + }, + } + } else { + Error::Sql { + description: format!( + "got error without code: {}", + sqlite_error.to_string() + ), + } + } + } + _ => Error::Sql { + description: format!("got unknown error: {}", error.to_string()), + }, + }) + .await?; + + Ok(()) + } + pub async fn set_state( pool: &sqlx::Pool, id: Uuid, @@ -540,6 +666,52 @@ impl<'a> Trip { Ok(result.rows_affected() != 0) } + pub async fn set_comment( + pool: &sqlx::Pool, + id: Uuid, + new_comment: &str, + ) -> Result { + let trip_id_param = id.to_string(); + let result = sqlx::query!( + "UPDATE trips + SET comment = ? + WHERE id = ?", + new_comment, + trip_id_param, + ) + .execute(pool) + .await?; + + Ok(result.rows_affected() != 0) + } + + pub async fn set_attribute( + pool: &sqlx::Pool, + trip_id: Uuid, + attribute: TripAttribute, + value: &str, + ) -> Result<(), Error> { + let result = sqlx::query(&format!( + "UPDATE trips + SET {attribute} = ? + WHERE id = ?", + attribute = to_variant_name(&attribute).unwrap() + )) + .bind(value) + .bind(trip_id.to_string()) + .execute(pool) + .map_err(|error| Error::Sql { + description: error.to_string(), + }) + .await?; + + (result.rows_affected() != 0) + .then_some(()) + .ok_or_else(|| Error::NotFound { + description: format!("trip {trip_id} not found"), + }) + } + pub async fn save( pool: &sqlx::Pool, name: &str, @@ -645,13 +817,13 @@ impl<'a> Trip { } } - pub fn types(&'a self) -> &Vec { + pub fn types(&self) -> &Vec { self.types .as_ref() .expect("you need to call load_trips_types()") } - pub fn categories(&'a self) -> &Vec { + pub fn categories(&self) -> &Vec { self.categories .as_ref() .expect("you need to call load_trips_types()") @@ -672,10 +844,7 @@ impl<'a> Trip { .sum::() } - pub async fn load_trips_types( - &'a mut self, - pool: &sqlx::Pool, - ) -> Result<(), Error> { + pub async fn load_trips_types(&mut self, pool: &sqlx::Pool) -> Result<(), Error> { let id = self.id.to_string(); let types = sqlx::query!( " @@ -719,7 +888,7 @@ impl<'a> Trip { } pub async fn sync_trip_items_with_inventory( - &'a mut self, + &mut self, pool: &sqlx::Pool, ) -> Result<(), Error> { // we need to get all items that are part of the inventory but not @@ -791,10 +960,7 @@ impl<'a> Trip { Ok(()) } - pub async fn load_categories( - &'a mut self, - pool: &sqlx::Pool, - ) -> Result<(), Error> { + pub async fn load_categories(&mut self, pool: &sqlx::Pool) -> Result<(), Error> { let mut categories: Vec = vec![]; // we can ignore the return type as we collect into `categories` // in the `map_ok()` closure @@ -922,6 +1088,56 @@ impl TripsType { .collect::, Error>>() } + pub async fn save(pool: &sqlx::Pool, name: &str) -> Result { + let id = Uuid::new_v4(); + let id_param = id.to_string(); + sqlx::query!( + "INSERT INTO trips_types + (id, name) + VALUES + (?, ?)", + id_param, + name, + ) + .execute(pool) + .map_err(|error| match error { + sqlx::Error::Database(ref error) => { + let sqlite_error = error.downcast_ref::(); + if let Some(code) = sqlite_error.code() { + match &*code { + "2067" => { + // SQLITE_CONSTRAINT_UNIQUE + Error::Duplicate { + description: format!( + "trip type with name \"{name}\" already exists" + ), + } + } + _ => Error::Sql { + description: format!( + "got error with unknown code: {}", + sqlite_error.to_string() + ), + }, + } + } else { + Error::Sql { + description: format!( + "got error without code: {}", + sqlite_error.to_string() + ), + } + } + } + _ => Error::Sql { + description: format!("got unknown error: {}", error.to_string()), + }, + }) + .await?; + + Ok(id) + } + pub async fn set_name( pool: &sqlx::Pool, id: Uuid, @@ -978,7 +1194,7 @@ struct DbInventoryItemsRow { category_id: String, } -impl<'a> Category { +impl Category { pub async fn _find( pool: &sqlx::Pool, id: Uuid, @@ -1007,7 +1223,57 @@ impl<'a> Category { } } - pub fn items(&'a self) -> &'a Vec { + pub async fn save(pool: &sqlx::Pool, name: &str) -> Result { + let id = Uuid::new_v4(); + let id_param = id.to_string(); + sqlx::query!( + "INSERT INTO inventory_items_categories + (id, name) + VALUES + (?, ?)", + id_param, + name, + ) + .execute(pool) + .map_err(|error| match error { + sqlx::Error::Database(ref error) => { + let sqlite_error = error.downcast_ref::(); + if let Some(code) = sqlite_error.code() { + match &*code { + "2067" => { + // SQLITE_CONSTRAINT_UNIQUE + Error::Duplicate { + description: format!( + "inventory item category with name \"{name}\" already exists" + ), + } + } + _ => Error::Sql { + description: format!( + "got error with unknown code: {}", + sqlite_error.to_string() + ), + }, + } + } else { + Error::Sql { + description: format!( + "got error without code: {}", + sqlite_error.to_string() + ), + } + } + } + _ => Error::Sql { + description: format!("got unknown error: {}", error.to_string()), + }, + }) + .await?; + + Ok(id) + } + + pub fn items(&self) -> &Vec { self.items .as_ref() .expect("you need to call populate_items()") @@ -1017,10 +1283,7 @@ impl<'a> Category { self.items().iter().map(|item| item.weight).sum() } - pub async fn populate_items( - &'a mut self, - pool: &sqlx::Pool, - ) -> Result<(), Error> { + pub async fn populate_items(&mut self, pool: &sqlx::Pool) -> Result<(), Error> { let id = self.id.to_string(); let items = sqlx::query_as!( DbInventoryItemsRow,