This commit is contained in:
2023-08-29 21:34:01 +02:00
parent f0e7bea5c8
commit e491636701
3 changed files with 170 additions and 73 deletions

View File

@@ -1,6 +1,6 @@
{ {
"db_name": "SQLite", "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": { "describe": {
"columns": [ "columns": [
{ {
@@ -28,5 +28,5 @@
true true
] ]
}, },
"hash": "6e8fbd5a7269c6a2021b688b58f74f8235554a414f77af5c2524d51920f0e33c" "hash": "cd180dd379d3d7602b05173863939becee61c78da0914836a74943a46b0d3099"
} }

View File

@@ -14,33 +14,25 @@ impl Inventory {
#[tracing::instrument] #[tracing::instrument]
pub async fn load(ctx: &Context, pool: &sqlx::Pool<sqlx::Sqlite>) -> Result<Self, Error> { pub async fn load(ctx: &Context, pool: &sqlx::Pool<sqlx::Sqlite>) -> Result<Self, Error> {
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
let categories = async {
let mut categories = sqlx::query_as!(
DbCategoryRow,
"SELECT
id,
name,
description
FROM inventory_items_categories
WHERE user_id = ?",
user_id,
)
.fetch(pool)
.map_ok(|row: DbCategoryRow| row.try_into())
.try_collect::<Vec<Result<Category, Error>>>()
.await?
.into_iter()
.collect::<Result<Vec<Category>, Error>>()?;
for category in &mut categories { let mut categories = crate::query_all!(
category.populate_items(ctx, pool).await?; pool,
} DbCategoryRow,
Category,
Ok::<_, Error>(categories) "SELECT
} id,
.instrument(tracing::info_span!("packager::sql::query", "query")) name,
description
FROM inventory_items_categories
WHERE user_id = ?",
user_id
)
.await?; .await?;
for category in &mut categories {
category.populate_items(ctx, pool).await?;
}
Ok(Self { categories }) Ok(Self { categories })
} }
} }
@@ -81,8 +73,10 @@ impl Category {
) -> Result<Option<Category>, Error> { ) -> Result<Option<Category>, Error> {
let id_param = id.to_string(); let id_param = id.to_string();
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
sqlx::query_as!( crate::query_one!(
pool,
DbCategoryRow, DbCategoryRow,
Category,
"SELECT "SELECT
id, id,
name, name,
@@ -94,10 +88,7 @@ impl Category {
id_param, id_param,
user_id, user_id,
) )
.fetch_optional(pool) .await
.await?
.map(|row| row.try_into())
.transpose()
} }
#[tracing::instrument] #[tracing::instrument]
@@ -109,7 +100,8 @@ impl Category {
let id = Uuid::new_v4(); let id = Uuid::new_v4();
let id_param = id.to_string(); let id_param = id.to_string();
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
sqlx::query!( crate::execute!(
pool,
"INSERT INTO inventory_items_categories "INSERT INTO inventory_items_categories
(id, name, user_id) (id, name, user_id)
VALUES VALUES
@@ -118,7 +110,6 @@ impl Category {
name, name,
user_id, user_id,
) )
.execute(pool)
.await?; .await?;
Ok(id) Ok(id)
@@ -144,8 +135,10 @@ impl Category {
) -> Result<(), Error> { ) -> Result<(), Error> {
let id = self.id.to_string(); let id = self.id.to_string();
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
let items = sqlx::query_as!( let items = crate::query_all!(
pool,
DbInventoryItemsRow, DbInventoryItemsRow,
Item,
"SELECT "SELECT
id, id,
name, name,
@@ -159,12 +152,7 @@ impl Category {
id, id,
user_id, user_id,
) )
.fetch(pool) .await?;
.map_ok(|row| row.try_into())
.try_collect::<Vec<Result<Item, Error>>>()
.await?
.into_iter()
.collect::<Result<Vec<Item>, Error>>()?;
self.items = Some(items); self.items = Some(items);
Ok(()) Ok(())
@@ -243,8 +231,10 @@ impl InventoryItem {
let id_param = id.to_string(); let id_param = id.to_string();
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
sqlx::query_as!( crate::query_one!(
pool,
DbInventoryItemRow, DbInventoryItemRow,
Self,
"SELECT "SELECT
item.id AS id, item.id AS id,
item.name AS name, item.name AS name,
@@ -268,10 +258,7 @@ impl InventoryItem {
id_param, id_param,
user_id, user_id,
) )
.fetch_optional(pool) .await
.await?
.map(|row| row.try_into())
.transpose()
} }
#[tracing::instrument] #[tracing::instrument]
@@ -281,7 +268,8 @@ impl InventoryItem {
name: &str, name: &str,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
Ok(sqlx::query!( crate::query_exists!(
pool,
"SELECT id "SELECT id
FROM inventory_items FROM inventory_items
WHERE WHERE
@@ -290,10 +278,7 @@ impl InventoryItem {
name, name,
user_id user_id
) )
.fetch_optional(pool) .await
.await?
.map(|_row| ())
.is_some())
} }
#[tracing::instrument] #[tracing::instrument]
@@ -304,7 +289,8 @@ impl InventoryItem {
) -> Result<bool, Error> { ) -> Result<bool, Error> {
let id_param = id.to_string(); let id_param = id.to_string();
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
let results = sqlx::query!( let results = crate::execute!(
pool,
"DELETE FROM inventory_items "DELETE FROM inventory_items
WHERE WHERE
id = ? id = ?
@@ -312,7 +298,6 @@ impl InventoryItem {
id_param, id_param,
user_id, user_id,
) )
.execute(pool)
.await?; .await?;
Ok(results.rows_affected() != 0) Ok(results.rows_affected() != 0)
@@ -330,7 +315,8 @@ impl InventoryItem {
let weight = i64::try_from(weight).unwrap(); let weight = i64::try_from(weight).unwrap();
let id_param = id.to_string(); let id_param = id.to_string();
Ok(sqlx::query!( crate::execute_returning_uuid!(
pool,
"UPDATE inventory_items AS item "UPDATE inventory_items AS item
SET SET
name = ?, name = ?,
@@ -345,9 +331,7 @@ impl InventoryItem {
id_param, id_param,
user_id, user_id,
) )
.fetch_one(pool) .await
.map_ok(|row| Uuid::try_parse(&row.id))
.await??)
} }
#[tracing::instrument] #[tracing::instrument]
@@ -363,7 +347,8 @@ impl InventoryItem {
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
let category_id_param = category_id.to_string(); let category_id_param = category_id.to_string();
sqlx::query!( crate::execute!(
pool,
"INSERT INTO inventory_items "INSERT INTO inventory_items
(id, name, description, weight, category_id, user_id) (id, name, description, weight, category_id, user_id)
VALUES VALUES
@@ -375,7 +360,6 @@ impl InventoryItem {
category_id_param, category_id_param,
user_id, user_id,
) )
.execute(pool)
.await?; .await?;
Ok(id) Ok(id)
@@ -389,7 +373,8 @@ impl InventoryItem {
) -> Result<i64, Error> { ) -> Result<i64, Error> {
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
let category_id_param = category_id.to_string(); let category_id_param = category_id.to_string();
let weight = sqlx::query!( let weight = crate::execute_returning!(
pool,
" "
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
@@ -399,15 +384,11 @@ impl InventoryItem {
category_id = ? category_id = ?
AND category.user_id = ? AND category.user_id = ?
", ",
i64,
|row| i64::from(row.weight),
category_id_param, category_id_param,
user_id, user_id,
) )
.fetch_one(pool)
.map_ok(|row| {
// convert to i64 because that the default integer type, but looks
// like COALESCE return i32?
i64::from(row.weight)
})
.await?; .await?;
Ok(weight) Ok(weight)
@@ -454,7 +435,8 @@ impl Item {
) -> Result<i64, Error> { ) -> Result<i64, Error> {
let user_id = ctx.user.id.to_string(); let user_id = ctx.user.id.to_string();
let category_id_param = category_id.to_string(); let category_id_param = category_id.to_string();
Ok(sqlx::query!( crate::execute_returning!(
pool,
" "
SELECT COALESCE(SUM(i_item.weight), 0) as weight SELECT COALESCE(SUM(i_item.weight), 0) as weight
FROM inventory_items_categories as category FROM inventory_items_categories as category
@@ -467,15 +449,11 @@ impl Item {
AND category.user_id = ? AND category.user_id = ?
AND t_item.pick = 1 AND t_item.pick = 1
", ",
i64,
|row| i64::from(row.weight),
category_id_param, category_id_param,
user_id, user_id,
) )
.fetch_one(pool) .await
.map_ok(|row| {
// convert to i64 because that the default integer type, but looks
// like COALESCE return i32?
i64::from(row.weight)
})
.await?)
} }
} }

View File

@@ -47,3 +47,122 @@ pub async fn migrate(url: &str) -> Result<(), StartError> {
Ok(()) Ok(())
} }
#[macro_export]
macro_rules! query_all {
( $pool:expr, $struct_row:path, $struct_into:path, $query:expr, $( $args:tt )* ) => {
async {
let result: Result<Vec<$struct_into>, Error> = sqlx::query_as!(
$struct_row,
$query,
$( $args )*
)
.fetch($pool)
.map_ok(|row: $struct_row| row.try_into())
.try_collect::<Vec<Result<$struct_into, Error>>>()
.await?
.into_iter()
.collect::<Result<Vec<$struct_into>, Error>>();
result
}.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<Option<$struct_into>, Error> = sqlx::query_as!(
$struct_row,
$query,
$( $args )*
)
.fetch_optional($pool)
.await?
.map(|row: $struct_row| row.try_into())
.transpose();
result
}.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();
Ok(result)
}.instrument(tracing::info_span!("packager::sql::query", "query"))
};
}
#[macro_export]
macro_rules! execute {
( $pool:expr, $query:expr, $( $args:tt )*) => {
async {
let result: Result<sqlx::sqlite::SqliteQueryResult, Error> = sqlx::query!(
$query,
$( $args )*
)
.execute($pool)
.await
.map_err(|e| e.into());
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);
result
}.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<Uuid, Error> = sqlx::query!(
$query,
$( $args )*
)
.fetch_one($pool)
.map_ok(|row| Uuid::try_parse(&row.id))
.await?
.map_err(Into::into);
result
}.instrument(tracing::info_span!("packager::sql::query", "query"))
};
}