From 04a559f4fd287b267f0fdb00b6c063689e6cb8dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20K=C3=B6rber?= Date: Tue, 29 Aug 2023 21:34:01 +0200 Subject: [PATCH] refactor trips queries --- ...6c380f42202c5cd9b09d9a3e05a749a55a910.json | 12 + ...7309bc5a881d2a2fc5364d9b666f6b53a8778.json | 12 + ...8b5ea4f49773f2de3c3e10e718a09d6816cb0.json | 12 + ...ec187d7ad3742cb85371550bdaed2b780d7f5.json | 12 - ...ac57eecfe176d49fc60f88d10244fbdd2e23c.json | 12 + ...4fe18ed0b89bb926cfa26d86cce19f20b3f4a.json | 12 + ...8e429d65c85242b6b9cd1201cc8d9cfc48ab1.json | 12 + ...4b1602b82fb350668102d496683374556d830.json | 12 + ...791bfa1f16f1e0bae709122c15d26b26e3263.json | 12 + ...0ef6d338e290460d4cebc4c580e7614ebabc7.json | 12 + ...2d9ec2f56bb7170d173f834ac766e4d3026f.json} | 4 +- ...4a6a61e94394846e84315fbe10a9956960dd7.json | 12 + rust/src/models/inventory.rs | 50 ++- rust/src/models/trips.rs | 402 +++++++++++++----- rust/src/models/user.rs | 15 +- rust/src/sqlite.rs | 245 +++++++---- 16 files changed, 646 insertions(+), 202 deletions(-) create mode 100644 rust/.sqlx/query-003e3585cc798a04c3bad7e74e16c380f42202c5cd9b09d9a3e05a749a55a910.json create mode 100644 rust/.sqlx/query-0c1f320c3cd7b9a777c558836307309bc5a881d2a2fc5364d9b666f6b53a8778.json create mode 100644 rust/.sqlx/query-41f96460749516db0bb510c01cf8b5ea4f49773f2de3c3e10e718a09d6816cb0.json delete mode 100644 rust/.sqlx/query-4e24e535cc7c0dc0de572be4295ec187d7ad3742cb85371550bdaed2b780d7f5.json create mode 100644 rust/.sqlx/query-6183a38d7587836b782e9e44b8fac57eecfe176d49fc60f88d10244fbdd2e23c.json create mode 100644 rust/.sqlx/query-72ed37defff5cacbdf0a733cdec4fe18ed0b89bb926cfa26d86cce19f20b3f4a.json create mode 100644 rust/.sqlx/query-7a70ba0bac63bef015f36a56aab8e429d65c85242b6b9cd1201cc8d9cfc48ab1.json create mode 100644 rust/.sqlx/query-c3da65d50b22628d03eeaaf8c5e4b1602b82fb350668102d496683374556d830.json create mode 100644 rust/.sqlx/query-cf1d82ba7f12a1bc315a2361599791bfa1f16f1e0bae709122c15d26b26e3263.json create mode 100644 rust/.sqlx/query-d891f3002e38de15f1361e1f7db0ef6d338e290460d4cebc4c580e7614ebabc7.json rename rust/.sqlx/{query-cd180dd379d3d7602b05173863939becee61c78da0914836a74943a46b0d3099.json => query-f361f939fd66d550cdfb2f75833d2d9ec2f56bb7170d173f834ac766e4d3026f.json} (62%) create mode 100644 rust/.sqlx/query-fcf7bcb784f0271e2e4c87cde754a6a61e94394846e84315fbe10a9956960dd7.json diff --git a/rust/.sqlx/query-003e3585cc798a04c3bad7e74e16c380f42202c5cd9b09d9a3e05a749a55a910.json b/rust/.sqlx/query-003e3585cc798a04c3bad7e74e16c380f42202c5cd9b09d9a3e05a749a55a910.json new file mode 100644 index 0000000..a339012 --- /dev/null +++ b/rust/.sqlx/query-003e3585cc798a04c3bad7e74e16c380f42202c5cd9b09d9a3e05a749a55a910.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE trips\n SET location = ?\n WHERE id = ? AND user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "003e3585cc798a04c3bad7e74e16c380f42202c5cd9b09d9a3e05a749a55a910" +} diff --git a/rust/.sqlx/query-0c1f320c3cd7b9a777c558836307309bc5a881d2a2fc5364d9b666f6b53a8778.json b/rust/.sqlx/query-0c1f320c3cd7b9a777c558836307309bc5a881d2a2fc5364d9b666f6b53a8778.json new file mode 100644 index 0000000..e26bf94 --- /dev/null +++ b/rust/.sqlx/query-0c1f320c3cd7b9a777c558836307309bc5a881d2a2fc5364d9b666f6b53a8778.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE trips\n SET date_start = ?\n WHERE id = ? AND user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "0c1f320c3cd7b9a777c558836307309bc5a881d2a2fc5364d9b666f6b53a8778" +} diff --git a/rust/.sqlx/query-41f96460749516db0bb510c01cf8b5ea4f49773f2de3c3e10e718a09d6816cb0.json b/rust/.sqlx/query-41f96460749516db0bb510c01cf8b5ea4f49773f2de3c3e10e718a09d6816cb0.json new file mode 100644 index 0000000..e2c6648 --- /dev/null +++ b/rust/.sqlx/query-41f96460749516db0bb510c01cf8b5ea4f49773f2de3c3e10e718a09d6816cb0.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE trips_items\n SET pack = ?\n WHERE trip_id = ?\n AND item_id = ?\n AND user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 4 + }, + "nullable": [] + }, + "hash": "41f96460749516db0bb510c01cf8b5ea4f49773f2de3c3e10e718a09d6816cb0" +} diff --git a/rust/.sqlx/query-4e24e535cc7c0dc0de572be4295ec187d7ad3742cb85371550bdaed2b780d7f5.json b/rust/.sqlx/query-4e24e535cc7c0dc0de572be4295ec187d7ad3742cb85371550bdaed2b780d7f5.json deleted file mode 100644 index 15746f5..0000000 --- a/rust/.sqlx/query-4e24e535cc7c0dc0de572be4295ec187d7ad3742cb85371550bdaed2b780d7f5.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO trips_types\n (id, name, user_id)\n VALUES\n (?, ?, ?)", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "4e24e535cc7c0dc0de572be4295ec187d7ad3742cb85371550bdaed2b780d7f5" -} diff --git a/rust/.sqlx/query-6183a38d7587836b782e9e44b8fac57eecfe176d49fc60f88d10244fbdd2e23c.json b/rust/.sqlx/query-6183a38d7587836b782e9e44b8fac57eecfe176d49fc60f88d10244fbdd2e23c.json new file mode 100644 index 0000000..8bbedbf --- /dev/null +++ b/rust/.sqlx/query-6183a38d7587836b782e9e44b8fac57eecfe176d49fc60f88d10244fbdd2e23c.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE trips\n SET temp_min = ?\n WHERE id = ? AND user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "6183a38d7587836b782e9e44b8fac57eecfe176d49fc60f88d10244fbdd2e23c" +} diff --git a/rust/.sqlx/query-72ed37defff5cacbdf0a733cdec4fe18ed0b89bb926cfa26d86cce19f20b3f4a.json b/rust/.sqlx/query-72ed37defff5cacbdf0a733cdec4fe18ed0b89bb926cfa26d86cce19f20b3f4a.json new file mode 100644 index 0000000..d0c1284 --- /dev/null +++ b/rust/.sqlx/query-72ed37defff5cacbdf0a733cdec4fe18ed0b89bb926cfa26d86cce19f20b3f4a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE trips\n SET temp_max = ?\n WHERE id = ? AND user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "72ed37defff5cacbdf0a733cdec4fe18ed0b89bb926cfa26d86cce19f20b3f4a" +} diff --git a/rust/.sqlx/query-7a70ba0bac63bef015f36a56aab8e429d65c85242b6b9cd1201cc8d9cfc48ab1.json b/rust/.sqlx/query-7a70ba0bac63bef015f36a56aab8e429d65c85242b6b9cd1201cc8d9cfc48ab1.json new file mode 100644 index 0000000..5ed7689 --- /dev/null +++ b/rust/.sqlx/query-7a70ba0bac63bef015f36a56aab8e429d65c85242b6b9cd1201cc8d9cfc48ab1.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE trips\n SET date_end = ?\n WHERE id = ? AND user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "7a70ba0bac63bef015f36a56aab8e429d65c85242b6b9cd1201cc8d9cfc48ab1" +} diff --git a/rust/.sqlx/query-c3da65d50b22628d03eeaaf8c5e4b1602b82fb350668102d496683374556d830.json b/rust/.sqlx/query-c3da65d50b22628d03eeaaf8c5e4b1602b82fb350668102d496683374556d830.json new file mode 100644 index 0000000..1b014f0 --- /dev/null +++ b/rust/.sqlx/query-c3da65d50b22628d03eeaaf8c5e4b1602b82fb350668102d496683374556d830.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE trips_items\n SET pick = ?\n WHERE trip_id = ?\n AND item_id = ?\n AND user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 4 + }, + "nullable": [] + }, + "hash": "c3da65d50b22628d03eeaaf8c5e4b1602b82fb350668102d496683374556d830" +} diff --git a/rust/.sqlx/query-cf1d82ba7f12a1bc315a2361599791bfa1f16f1e0bae709122c15d26b26e3263.json b/rust/.sqlx/query-cf1d82ba7f12a1bc315a2361599791bfa1f16f1e0bae709122c15d26b26e3263.json new file mode 100644 index 0000000..9c1f925 --- /dev/null +++ b/rust/.sqlx/query-cf1d82ba7f12a1bc315a2361599791bfa1f16f1e0bae709122c15d26b26e3263.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO trips_types\n (id, name, user_id)\n VALUES\n (?, ?, ?)", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "cf1d82ba7f12a1bc315a2361599791bfa1f16f1e0bae709122c15d26b26e3263" +} diff --git a/rust/.sqlx/query-d891f3002e38de15f1361e1f7db0ef6d338e290460d4cebc4c580e7614ebabc7.json b/rust/.sqlx/query-d891f3002e38de15f1361e1f7db0ef6d338e290460d4cebc4c580e7614ebabc7.json new file mode 100644 index 0000000..e35ae23 --- /dev/null +++ b/rust/.sqlx/query-d891f3002e38de15f1361e1f7db0ef6d338e290460d4cebc4c580e7614ebabc7.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE trips\n SET name = ?\n WHERE id = ? AND user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "d891f3002e38de15f1361e1f7db0ef6d338e290460d4cebc4c580e7614ebabc7" +} diff --git a/rust/.sqlx/query-cd180dd379d3d7602b05173863939becee61c78da0914836a74943a46b0d3099.json b/rust/.sqlx/query-f361f939fd66d550cdfb2f75833d2d9ec2f56bb7170d173f834ac766e4d3026f.json similarity index 62% rename from rust/.sqlx/query-cd180dd379d3d7602b05173863939becee61c78da0914836a74943a46b0d3099.json rename to rust/.sqlx/query-f361f939fd66d550cdfb2f75833d2d9ec2f56bb7170d173f834ac766e4d3026f.json index 714df43..a5ed895 100644 --- a/rust/.sqlx/query-cd180dd379d3d7602b05173863939becee61c78da0914836a74943a46b0d3099.json +++ b/rust/.sqlx/query-f361f939fd66d550cdfb2f75833d2d9ec2f56bb7170d173f834ac766e4d3026f.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT \n id,\n name,\n description \n FROM inventory_items_categories \n WHERE user_id = ?", + "query": "SELECT\n id,\n name,\n description \n FROM inventory_items_categories \n WHERE user_id = ?", "describe": { "columns": [ { @@ -28,5 +28,5 @@ true ] }, - "hash": "cd180dd379d3d7602b05173863939becee61c78da0914836a74943a46b0d3099" + "hash": "f361f939fd66d550cdfb2f75833d2d9ec2f56bb7170d173f834ac766e4d3026f" } diff --git a/rust/.sqlx/query-fcf7bcb784f0271e2e4c87cde754a6a61e94394846e84315fbe10a9956960dd7.json b/rust/.sqlx/query-fcf7bcb784f0271e2e4c87cde754a6a61e94394846e84315fbe10a9956960dd7.json new file mode 100644 index 0000000..63c5cfa --- /dev/null +++ b/rust/.sqlx/query-fcf7bcb784f0271e2e4c87cde754a6a61e94394846e84315fbe10a9956960dd7.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "UPDATE trips_items\n SET ready = ?\n WHERE trip_id = ?\n AND item_id = ?\n AND user_id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 4 + }, + "nullable": [] + }, + "hash": "fcf7bcb784f0271e2e4c87cde754a6a61e94394846e84315fbe10a9956960dd7" +} diff --git a/rust/src/models/inventory.rs b/rust/src/models/inventory.rs index ba615d6..7d5add7 100644 --- a/rust/src/models/inventory.rs +++ b/rust/src/models/inventory.rs @@ -1,11 +1,9 @@ use super::Error; -use crate::Context; +use crate::{sqlite, Context}; use futures::{TryFutureExt, TryStreamExt}; use uuid::Uuid; -use tracing::Instrument; - pub struct Inventory { pub categories: Vec, } @@ -16,10 +14,14 @@ impl Inventory { let user_id = ctx.user.id.to_string(); let mut categories = crate::query_all!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Inventory, + }, pool, DbCategoryRow, Category, - "SELECT + "SELECT id, name, description @@ -74,6 +76,10 @@ impl Category { let id_param = id.to_string(); let user_id = ctx.user.id.to_string(); crate::query_one!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Inventory, + }, pool, DbCategoryRow, Category, @@ -101,6 +107,10 @@ impl Category { let id_param = id.to_string(); let user_id = ctx.user.id.to_string(); crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Insert, + component: sqlite::Component::Inventory, + }, pool, "INSERT INTO inventory_items_categories (id, name, user_id) @@ -136,6 +146,10 @@ impl Category { let id = self.id.to_string(); let user_id = ctx.user.id.to_string(); let items = crate::query_all!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Inventory, + }, pool, DbInventoryItemsRow, Item, @@ -232,6 +246,10 @@ impl InventoryItem { let user_id = ctx.user.id.to_string(); crate::query_one!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Inventory, + }, pool, DbInventoryItemRow, Self, @@ -269,6 +287,10 @@ impl InventoryItem { ) -> Result { let user_id = ctx.user.id.to_string(); crate::query_exists!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Inventory, + }, pool, "SELECT id FROM inventory_items @@ -290,6 +312,10 @@ impl InventoryItem { let id_param = id.to_string(); let user_id = ctx.user.id.to_string(); let results = crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Delete, + component: sqlite::Component::Inventory, + }, pool, "DELETE FROM inventory_items WHERE @@ -316,6 +342,10 @@ impl InventoryItem { let id_param = id.to_string(); crate::execute_returning_uuid!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Inventory, + }, pool, "UPDATE inventory_items AS item SET @@ -348,6 +378,10 @@ impl InventoryItem { let category_id_param = category_id.to_string(); crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Insert, + component: sqlite::Component::Inventory, + }, pool, "INSERT INTO inventory_items (id, name, description, weight, category_id, user_id) @@ -374,6 +408,10 @@ impl InventoryItem { let user_id = ctx.user.id.to_string(); let category_id_param = category_id.to_string(); let weight = crate::execute_returning!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Inventory, + }, pool, " SELECT COALESCE(MAX(i_item.weight), 0) as weight @@ -436,6 +474,10 @@ impl Item { let user_id = ctx.user.id.to_string(); let category_id_param = category_id.to_string(); crate::execute_returning!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Inventory, + }, pool, " SELECT COALESCE(SUM(i_item.weight), 0) as weight diff --git a/rust/src/models/trips.rs b/rust/src/models/trips.rs index 2e206be..93e1319 100644 --- a/rust/src/models/trips.rs +++ b/rust/src/models/trips.rs @@ -6,11 +6,10 @@ use super::{ inventory, }; -use crate::Context; +use crate::{sqlite, Context}; use futures::{TryFutureExt, TryStreamExt}; use serde::{Deserialize, Serialize}; -use serde_variant::to_variant_name; use time; use uuid::Uuid; @@ -300,8 +299,14 @@ impl TripItem { let user_id = ctx.user.id.to_string(); let item_id_param = item_id.to_string(); let trip_id_param = trip_id.to_string(); - sqlx::query_as!( + crate::query_one!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Trips, + }, + pool, DbTripsItemsRow, + Self, " SELECT t_item.item_id AS id, @@ -324,10 +329,7 @@ impl TripItem { trip_id_param, user_id, ) - .fetch_optional(pool) - .await? - .map(|row| row.try_into()) - .transpose() + .await } #[tracing::instrument] @@ -340,20 +342,67 @@ impl TripItem { value: bool, ) -> Result<(), Error> { let user_id = ctx.user.id.to_string(); - let result = sqlx::query(&format!( - "UPDATE trips_items - SET {key} = ? + let trip_id_param = trip_id.to_string(); + let item_id_param = item_id.to_string(); + let result = match key { + TripItemStateKey::Pick => { + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Inventory, + }, + pool, + "UPDATE trips_items + SET pick = ? WHERE trip_id = ? AND item_id = ? AND user_id = ?", - key = to_variant_name(&key).unwrap() - )) - .bind(value) - .bind(trip_id.to_string()) - .bind(item_id.to_string()) - .bind(user_id) - .execute(pool) - .await?; + value, + trip_id_param, + item_id_param, + user_id + ) + .await + } + TripItemStateKey::Pack => { + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Inventory, + }, + pool, + "UPDATE trips_items + SET pack = ? + WHERE trip_id = ? + AND item_id = ? + AND user_id = ?", + value, + trip_id_param, + item_id_param, + user_id + ) + .await + } + TripItemStateKey::Ready => { + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Inventory, + }, + pool, + "UPDATE trips_items + SET ready = ? + WHERE trip_id = ? + AND item_id = ? + AND user_id = ?", + value, + trip_id_param, + item_id_param, + user_id + ) + .await + } + }?; (result.rows_affected() != 0).then_some(()).ok_or_else(|| { Error::Query(QueryError::NotFound { @@ -426,16 +475,18 @@ pub enum TripAttribute { TempMax, } -pub(crate) struct DbTripWeightRow { - pub total_weight: Option, -} - impl Trip { #[tracing::instrument] pub async fn all(ctx: &Context, pool: &sqlx::Pool) -> Result, Error> { let user_id = ctx.user.id.to_string(); - sqlx::query_as!( + crate::query_all!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Trips, + }, + pool, DbTripRow, + Self, "SELECT id, name, @@ -450,12 +501,7 @@ impl Trip { WHERE user_id = ?", user_id ) - .fetch(pool) - .map_ok(|row| row.try_into()) - .try_collect::>>() - .await? - .into_iter() - .collect::, Error>>() + .await } #[tracing::instrument] @@ -466,8 +512,14 @@ impl Trip { ) -> Result, Error> { let trip_id_param = trip_id.to_string(); let user_id = ctx.user.id.to_string(); - sqlx::query_as!( + crate::query_one!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Trips, + }, + pool, DbTripRow, + Self, "SELECT id, name, @@ -483,10 +535,7 @@ impl Trip { trip_id_param, user_id, ) - .fetch_optional(pool) - .await? - .map(|row| row.try_into()) - .transpose() + .await } #[tracing::instrument] @@ -500,7 +549,12 @@ impl Trip { let id_param = id.to_string(); let type_id_param = type_id.to_string(); - let results = sqlx::query!( + let results = crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Delete, + component: sqlite::Component::Trips, + }, + pool, "DELETE FROM trips_to_trips_types AS ttt WHERE ttt.trip_id = ? AND ttt.trip_type_id = ? @@ -514,7 +568,6 @@ impl Trip { type_id_param, user_id, ) - .execute(pool) .await?; Ok(results.rows_affected() != 0) @@ -532,7 +585,12 @@ impl Trip { let trip_id_param = id.to_string(); let type_id_param = type_id.to_string(); - sqlx::query!( + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Insert, + component: sqlite::Component::Trips, + }, + pool, "INSERT INTO trips_to_trips_types (trip_id, trip_type_id) SELECT trips.id as trip_id, trips_types.id as trip_type_id @@ -548,7 +606,6 @@ impl Trip { type_id_param, user_id, ) - .execute(pool) .await?; Ok(()) @@ -563,7 +620,12 @@ impl Trip { ) -> Result { let user_id = ctx.user.id.to_string(); let trip_id_param = id.to_string(); - let result = sqlx::query!( + let result = crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Trips, + }, + pool, "UPDATE trips SET state = ? WHERE id = ? and user_id = ?", @@ -571,7 +633,6 @@ impl Trip { trip_id_param, user_id, ) - .execute(pool) .await?; Ok(result.rows_affected() != 0) @@ -586,7 +647,12 @@ impl Trip { ) -> Result { let user_id = ctx.user.id.to_string(); let trip_id_param = id.to_string(); - let result = sqlx::query!( + let result = crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Trips, + }, + pool, "UPDATE trips SET comment = ? WHERE id = ? AND user_id = ?", @@ -594,7 +660,6 @@ impl Trip { trip_id_param, user_id, ) - .execute(pool) .await?; Ok(result.rows_affected() != 0) @@ -609,17 +674,106 @@ impl Trip { value: &str, ) -> Result<(), Error> { let user_id = ctx.user.id.to_string(); - let result = sqlx::query(&format!( - "UPDATE trips - SET {attribute} = ? - WHERE id = ? AND user_id = ?", - attribute = to_variant_name(&attribute).unwrap() - )) - .bind(value) - .bind(trip_id.to_string()) - .bind(user_id) - .execute(pool) - .await?; + let trip_id_param = trip_id.to_string(); + let result = match attribute { + TripAttribute::Name => { + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Trips, + }, + pool, + "UPDATE trips + SET name = ? + WHERE id = ? AND user_id = ?", + value, + trip_id_param, + user_id + ) + .await + } + + TripAttribute::DateStart => { + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Trips, + }, + pool, + "UPDATE trips + SET date_start = ? + WHERE id = ? AND user_id = ?", + value, + trip_id_param, + user_id + ) + .await + } + TripAttribute::DateEnd => { + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Trips, + }, + pool, + "UPDATE trips + SET date_end = ? + WHERE id = ? AND user_id = ?", + value, + trip_id_param, + user_id + ) + .await + } + TripAttribute::Location => { + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Trips, + }, + pool, + "UPDATE trips + SET location = ? + WHERE id = ? AND user_id = ?", + value, + trip_id_param, + user_id + ) + .await + } + TripAttribute::TempMin => { + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Trips, + }, + pool, + "UPDATE trips + SET temp_min = ? + WHERE id = ? AND user_id = ?", + value, + trip_id_param, + user_id + ) + .await + } + TripAttribute::TempMax => { + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Trips, + }, + pool, + "UPDATE trips + SET temp_max = ? + WHERE id = ? AND user_id = ?", + value, + trip_id_param, + user_id + ) + .await + } + }?; (result.rows_affected() != 0).then_some(()).ok_or_else(|| { Error::Query(QueryError::NotFound { @@ -644,7 +798,12 @@ impl Trip { let trip_state = TripState::new(); - sqlx::query!( + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Insert, + component: sqlite::Component::Trips, + }, + pool, "INSERT INTO trips (id, name, date_start, date_end, state, user_id) VALUES @@ -656,7 +815,6 @@ impl Trip { trip_state, user_id, ) - .execute(pool) .await?; Ok(id) @@ -670,8 +828,12 @@ impl Trip { ) -> Result { let user_id = ctx.user.id.to_string(); let trip_id_param = trip_id.to_string(); - let weight = sqlx::query_as!( - DbTripWeightRow, + let weight = crate::execute_returning!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Trips, + }, + pool, " SELECT CAST(IFNULL(SUM(i_item.weight), 0) AS INTEGER) AS total_weight @@ -684,11 +846,11 @@ impl Trip { trip.id = ? AND trip.user_id = ? AND t_item.pick = true ", + i64, + |row| i64::from(row.total_weight), trip_id_param, user_id, ) - .fetch_one(pool) - .map_ok(|row| i64::from(row.total_weight.unwrap())) .await?; Ok(weight) @@ -730,9 +892,38 @@ impl Trip { ctx: &Context, pool: &sqlx::Pool, ) -> Result<(), Error> { + struct Row { + id: String, + name: String, + active: i32, + } + + impl TryFrom for TripType { + type Error = Error; + + fn try_from(row: Row) -> Result { + Ok(TripType { + id: Uuid::try_parse(&row.id)?, + name: row.name, + active: match row.active { + 0 => false, + 1 => true, + _ => unreachable!(), + }, + }) + } + } + let user_id = ctx.user.id.to_string(); let id = self.id.to_string(); - let types = sqlx::query!( + let types = crate::query_all!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Trips, + }, + pool, + Row, + TripType, " SELECT type.id as id, @@ -755,22 +946,7 @@ impl Trip { user_id, user_id, ) - .fetch(pool) - .map_ok(|row| -> Result { - Ok(TripType { - id: Uuid::try_parse(&row.id)?, - name: row.name, - active: match row.active { - 0 => false, - 1 => true, - _ => unreachable!(), - }, - }) - }) - .try_collect::>>() - .await? - .into_iter() - .collect::, Error>>()?; + .await?; self.types = Some(types); Ok(()) @@ -795,7 +971,27 @@ impl Trip { // consider let user_id = ctx.user.id.to_string(); let trip_id = self.id.to_string(); - let unsynced_items: Vec = sqlx::query!( + + struct Row { + item_id: String, + } + + impl TryFrom for Uuid { + type Error = Error; + + fn try_from(value: Row) -> Result { + Uuid::try_parse(&value.item_id).map_err(Into::into) + } + } + + let unsynced_items: Vec = crate::query_all!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Trips, + }, + pool, + Row, + Uuid, " SELECT i_item.id AS item_id @@ -811,12 +1007,7 @@ impl Trip { user_id, user_id, ) - .fetch(pool) - .map_ok(|row| -> Result { Ok(Uuid::try_parse(&row.item_id)?) }) - .try_collect::>>() - .await? - .into_iter() - .collect::, Error>>()?; + .await?; // looks like there is currently no nice way to do multiple inserts // with sqlx. whatever, this won't matter @@ -826,7 +1017,12 @@ impl Trip { for unsynced_item in &unsynced_items { let item_id = unsynced_item.to_string(); - sqlx::query!( + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Insert, + component: sqlite::Component::Trips, + }, + pool, " INSERT INTO trips_items ( @@ -848,7 +1044,6 @@ impl Trip { mark_as_new, user_id, ) - .execute(pool) .await?; } @@ -986,8 +1181,14 @@ impl TripsType { #[tracing::instrument] pub async fn all(ctx: &Context, pool: &sqlx::Pool) -> Result, Error> { let user_id = ctx.user.id.to_string(); - sqlx::query_as!( + crate::query_all!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::Trips, + }, + pool, DbTripsTypesRow, + Self, "SELECT id, name @@ -995,12 +1196,7 @@ impl TripsType { WHERE user_id = ?", user_id, ) - .fetch(pool) - .map_ok(|row| row.try_into()) - .try_collect::>>() - .await? - .into_iter() - .collect::, Error>>() + .await } #[tracing::instrument] @@ -1012,16 +1208,20 @@ impl TripsType { let user_id = ctx.user.id.to_string(); let id = Uuid::new_v4(); let id_param = id.to_string(); - sqlx::query!( + crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Insert, + component: sqlite::Component::Trips, + }, + pool, "INSERT INTO trips_types - (id, name, user_id) - VALUES - (?, ?, ?)", + (id, name, user_id) + VALUES + (?, ?, ?)", id_param, name, user_id, ) - .execute(pool) .await?; Ok(id) @@ -1037,7 +1237,12 @@ impl TripsType { let user_id = ctx.user.id.to_string(); let id_param = id.to_string(); - let result = sqlx::query!( + let result = crate::execute!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Update, + component: sqlite::Component::Trips, + }, + pool, "UPDATE trips_types SET name = ? WHERE id = ? and user_id = ?", @@ -1045,7 +1250,6 @@ impl TripsType { id_param, user_id, ) - .execute(pool) .await?; Ok(result.rows_affected() != 0) diff --git a/rust/src/models/user.rs b/rust/src/models/user.rs index 5c81a1a..47138bd 100644 --- a/rust/src/models/user.rs +++ b/rust/src/models/user.rs @@ -1,6 +1,8 @@ use super::Error; use uuid::Uuid; +use crate::sqlite; + #[derive(Debug, Clone)] pub struct User { pub id: Uuid, @@ -39,15 +41,18 @@ impl User { pool: &sqlx::Pool, name: &str, ) -> Result, Error> { - sqlx::query_as!( + crate::query_one!( + sqlite::QueryClassification { + query_type: sqlite::QueryType::Select, + component: sqlite::Component::User, + }, + pool, DbUserRow, + Self, "SELECT id,username,fullname FROM users WHERE username = ?", name ) - .fetch_optional(pool) - .await? - .map(|row: DbUserRow| row.try_into()) - .transpose() + .await } } diff --git a/rust/src/sqlite.rs b/rust/src/sqlite.rs index 4d54455..4106705 100644 --- a/rust/src/sqlite.rs +++ b/rust/src/sqlite.rs @@ -1,3 +1,4 @@ +use std::fmt; use std::time; use base64::Engine as _; @@ -50,134 +51,218 @@ pub async fn migrate(url: &str) -> Result<(), StartError> { Ok(()) } -pub fn sqlx_query(query: &str, labels: &[(&'static str, String)]) { +pub enum QueryType { + Insert, + Update, + Select, + Delete, +} + +impl fmt::Display for QueryType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Insert => "insert", + Self::Update => "update", + Self::Select => "select", + Self::Delete => "delete", + } + ) + } +} + +pub enum Component { + Inventory, + User, + Trips, +} + +impl fmt::Display for Component { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Inventory => "inventory", + Self::User => "user", + Self::Trips => "trips", + } + ) + } +} + +pub struct QueryClassification { + pub query_type: QueryType, + pub component: Component, +} + +pub fn sqlx_query( + classification: QueryClassification, + query: &str, + labels: &[(&'static str, String)], +) { let query_id = { let mut hasher = Sha256::new(); hasher.update(query); hasher.finalize() }; + + // 9 bytes is enough to be unique + // If this is divisible by 3, it means that we can base64-encode it without + // any "=" padding + // + // cannot panic, as the output for sha256 will always be bit + let query_id = &query_id[..9]; + let query_id = base64::engine::general_purpose::STANDARD.encode(query_id); let mut labels = Vec::from(labels); - labels.push(("query_id", query_id)); - metrics::counter!("packager_database_queries_total", 1, &labels) + labels.extend_from_slice(&[ + ("query_id", query_id), + ("query_type", classification.query_type.to_string()), + ("query_component", classification.component.to_string()), + ]); + metrics::counter!("packager_database_queries_total", 1, &labels); } #[macro_export] macro_rules! query_all { - ( $pool:expr, $struct_row:path, $struct_into:path, $query:expr, $( $args:tt )* ) => { - async { - crate::sqlite::sqlx_query($query, &[]); - let result: Result, Error> = sqlx::query_as!( - $struct_row, - $query, - $( $args )* - ) - .fetch($pool) - .map_ok(|row: $struct_row| row.try_into()) - .try_collect::>>() - .await? - .into_iter() - .collect::, Error>>(); + ( $class:expr, $pool:expr, $struct_row:path, $struct_into:path, $query:expr, $( $args:tt )* ) => { + { + use tracing::Instrument as _; + async { + crate::sqlite::sqlx_query($class, $query, &[]); + let result: Result, Error> = sqlx::query_as!( + $struct_row, + $query, + $( $args )* + ) + .fetch($pool) + .map_ok(|row: $struct_row| row.try_into()) + .try_collect::>>() + .await? + .into_iter() + .collect::, Error>>(); - result + result - }.instrument(tracing::info_span!("packager::sql::query", "query")) + }.instrument(tracing::info_span!("packager::sql::query", "query")) + } }; } #[macro_export] macro_rules! query_one { - ( $pool:expr, $struct_row:path, $struct_into:path, $query:expr, $( $args:tt )*) => { - async { - let result: Result, Error> = sqlx::query_as!( - $struct_row, - $query, - $( $args )* - ) - .fetch_optional($pool) - .await? - .map(|row: $struct_row| row.try_into()) - .transpose(); + ( $class:expr, $pool:expr, $struct_row:path, $struct_into:path, $query:expr, $( $args:tt )*) => { + { + use tracing::Instrument as _; + async { + crate::sqlite::sqlx_query($class, $query, &[]); + let result: Result, Error> = sqlx::query_as!( + $struct_row, + $query, + $( $args )* + ) + .fetch_optional($pool) + .await? + .map(|row: $struct_row| row.try_into()) + .transpose(); - result + result - }.instrument(tracing::info_span!("packager::sql::query", "query")) + }.instrument(tracing::info_span!("packager::sql::query", "query")) + } }; } #[macro_export] macro_rules! query_exists { - ( $pool:expr, $query:expr, $( $args:tt )*) => { - async { - let result: bool = sqlx::query!( - $query, - $( $args )* - ) - .fetch_optional($pool) - .await? - .is_some(); + ( $class:expr, $pool:expr, $query:expr, $( $args:tt )*) => { + { + use tracing::Instrument as _; + async { + crate::sqlite::sqlx_query($class, $query, &[]); + let result: bool = sqlx::query!( + $query, + $( $args )* + ) + .fetch_optional($pool) + .await? + .is_some(); - Ok(result) + Ok(result) - }.instrument(tracing::info_span!("packager::sql::query", "query")) + }.instrument(tracing::info_span!("packager::sql::query", "query")) + } }; } #[macro_export] macro_rules! execute { - ( $pool:expr, $query:expr, $( $args:tt )*) => { - async { - let result: Result = sqlx::query!( - $query, - $( $args )* - ) - .execute($pool) - .await - .map_err(|e| e.into()); + ( $class:expr, $pool:expr, $query:expr, $( $args:tt )*) => { + { + use tracing::Instrument as _; + async { + crate::sqlite::sqlx_query($class, $query, &[]); + let result: Result = sqlx::query!( + $query, + $( $args )* + ) + .execute($pool) + .await + .map_err(|e| e.into()); - result - - - }.instrument(tracing::info_span!("packager::sql::query", "query")) + result + }.instrument(tracing::info_span!("packager::sql::query", "query")) + } }; } #[macro_export] macro_rules! execute_returning { - ( $pool:expr, $query:expr, $t:path, $fn:expr, $( $args:tt )*) => { - async { - let result: Result<$t, Error> = sqlx::query!( - $query, - $( $args )* - ) - .fetch_one($pool) - .map_ok($fn) - .await - .map_err(Into::into); + ( $class:expr, $pool:expr, $query:expr, $t:path, $fn:expr, $( $args:tt )*) => { + { + use tracing::Instrument as _; + async { + crate::sqlite::sqlx_query($class, $query, &[]); + let result: Result<$t, Error> = sqlx::query!( + $query, + $( $args )* + ) + .fetch_one($pool) + .map_ok($fn) + .await + .map_err(Into::into); - result + result - }.instrument(tracing::info_span!("packager::sql::query", "query")) + }.instrument(tracing::info_span!("packager::sql::query", "query")) + } }; } #[macro_export] macro_rules! execute_returning_uuid { - ( $pool:expr, $query:expr, $( $args:tt )*) => { - async { - let result: Result = sqlx::query!( - $query, - $( $args )* - ) - .fetch_one($pool) - .map_ok(|row| Uuid::try_parse(&row.id)) - .await? - .map_err(Into::into); + ( $class:expr, $pool:expr, $query:expr, $( $args:tt )*) => { + { + use tracing::Instrument as _; + async { + crate::sqlite::sqlx_query($class, $query, &[]); + let result: Result = sqlx::query!( + $query, + $( $args )* + ) + .fetch_one($pool) + .map_ok(|row| Uuid::try_parse(&row.id)) + .await? + .map_err(Into::into); - result + result - }.instrument(tracing::info_span!("packager::sql::query", "query")) + }.instrument(tracing::info_span!("packager::sql::query", "query")) + } }; }