From 271b24b70d95ccdb299affdbeb7cf859037fdfdf Mon Sep 17 00:00:00 2001 From: Tobias Reisinger Date: Tue, 21 Nov 2023 03:42:33 +0100 Subject: [PATCH] Make use of pool.acquire to prevent out-of-order db-actions --- src/db.rs | 44 +++++----- src/db/errors.rs | 2 +- src/db/model_utils.rs | 5 +- src/db/schedules.rs | 104 +++++++++++++++--------- src/db/tag.rs | 59 +++++++++----- src/handlers/v1/schedules.rs | 152 ++++++++++++++++++++++++----------- src/return_models.rs | 11 ++- src/types/emgauwa_uid.rs | 2 +- 8 files changed, 248 insertions(+), 131 deletions(-) diff --git a/src/db.rs b/src/db.rs index 7960693..ef01994 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,11 +1,11 @@ use log::{info, trace}; use sqlx::migrate::Migrator; -use sqlx::{Pool, Sqlite}; use sqlx::sqlite::SqlitePoolOptions; +use sqlx::{Pool, Sqlite}; use crate::db::errors::DatabaseError; use crate::db::model_utils::Period; -use crate::db::models::{Schedule, Periods}; +use crate::db::models::{Periods, Schedule}; use crate::types::EmgauwaUid; pub mod errors; @@ -19,35 +19,38 @@ static MIGRATOR: Migrator = sqlx::migrate!(); // defaults to "./migrations" pub async fn run_migrations(pool: &Pool) { info!("Running migrations"); - MIGRATOR - .run(pool) - .await - .expect("Failed to run migrations."); + MIGRATOR.run(pool).await.expect("Failed to run migrations."); } -async fn init_schedule(pool: &Pool, uid: &EmgauwaUid, name: &str, periods: Periods) -> Result<(), DatabaseError> { +async fn init_schedule( + pool: &Pool, + uid: &EmgauwaUid, + name: &str, + periods: Periods, +) -> Result<(), DatabaseError> { trace!("Initializing schedule {:?}", name); - match schedules::get_schedule_by_uid(pool, uid).await { + match schedules::get_schedule_by_uid(&mut pool.acquire().await.unwrap(), uid).await { Ok(_) => Ok(()), Err(err) => match err { DatabaseError::NotFound => { trace!("Schedule {:?} not found, inserting", name); - sqlx::query_as!(Schedule, "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", + sqlx::query_as!( + Schedule, + "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", uid, name, periods, ) - .fetch_optional(pool) - .await? - .ok_or(DatabaseError::InsertGetError) - .map(|_| ()) + .fetch_optional(pool) + .await? + .ok_or(DatabaseError::InsertGetError) + .map(|_| ()) } _ => Err(err), }, } } - pub async fn init(db: &str) -> Pool { let pool: Pool = SqlitePoolOptions::new() .acquire_timeout(std::time::Duration::from_secs(1)) @@ -58,12 +61,7 @@ pub async fn init(db: &str) -> Pool { run_migrations(&pool).await; - init_schedule( - &pool, - &EmgauwaUid::Off, - "Off", - Periods(vec![]) - ) + init_schedule(&pool, &EmgauwaUid::Off, "Off", Periods(vec![])) .await .expect("Error initializing schedule Off"); @@ -71,10 +69,10 @@ pub async fn init(db: &str) -> Pool { &pool, &EmgauwaUid::On, "On", - Periods(vec![Period::new_on()]) + Periods(vec![Period::new_on()]), ) - .await - .expect("Error initializing schedule On"); + .await + .expect("Error initializing schedule On"); pool } diff --git a/src/db/errors.rs b/src/db/errors.rs index 8ba2fc7..37c3d4d 100644 --- a/src/db/errors.rs +++ b/src/db/errors.rs @@ -67,4 +67,4 @@ impl From for DatabaseError { _ => DatabaseError::Unknown, } } -} \ No newline at end of file +} diff --git a/src/db/model_utils.rs b/src/db/model_utils.rs index 28679d1..998025f 100644 --- a/src/db/model_utils.rs +++ b/src/db/model_utils.rs @@ -1,11 +1,11 @@ use crate::db::models::Periods; use chrono::{NaiveTime, Timelike}; use serde::{Deserialize, Serialize}; -use sqlx::{Decode, Encode, Sqlite, Type}; use sqlx::database::HasArguments; use sqlx::encode::IsNull; use sqlx::error::BoxDynError; use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef}; +use sqlx::{Decode, Encode, Sqlite, Type}; #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct Period { @@ -125,7 +125,8 @@ impl<'r> Decode<'r, Sqlite> for Periods { impl From<&Periods> for Vec { fn from(periods: &Periods) -> Vec { - periods.0 + periods + .0 .iter() .flat_map(|period| { let vec = vec![ diff --git a/src/db/schedules.rs b/src/db/schedules.rs index 89431fe..9951ccc 100644 --- a/src/db/schedules.rs +++ b/src/db/schedules.rs @@ -1,38 +1,58 @@ use std::borrow::Borrow; -use sqlx::{Pool, Sqlite}; +use std::ops::DerefMut; -use crate::types::EmgauwaUid; +use sqlx::pool::PoolConnection; +use sqlx::Sqlite; use crate::db::errors::DatabaseError; use crate::db::models::*; use crate::db::tag::{create_junction_tag_schedule, create_tag}; +use crate::types::EmgauwaUid; -pub async fn get_schedule_tags(pool: &Pool, schedule: &Schedule) -> Result, DatabaseError> { +pub async fn get_schedule_tags( + conn: &mut PoolConnection, + schedule: &Schedule, +) -> Result, DatabaseError> { Ok(sqlx::query_scalar!("SELECT tag FROM tags INNER JOIN junction_tag ON junction_tag.tag_id = tags.id WHERE junction_tag.schedule_id = ?", schedule.id) - .fetch_all(pool) - .await?) + .fetch_all(conn.deref_mut()) + .await?) } -pub async fn get_schedules(pool: &Pool) -> Result, DatabaseError> { +pub async fn get_schedules( + conn: &mut PoolConnection, +) -> Result, DatabaseError> { Ok(sqlx::query_as!(Schedule, "SELECT * FROM schedules") - .fetch_all(pool) + .fetch_all(conn.deref_mut()) .await?) } -pub async fn get_schedule_by_uid(pool: &Pool, filter_uid: &EmgauwaUid) -> Result { - sqlx::query_as!(Schedule, "SELECT * FROM schedules WHERE uid = ?", filter_uid) - .fetch_optional(pool) - .await - .map(|s| s.ok_or(DatabaseError::NotFound))? +pub async fn get_schedule_by_uid( + conn: &mut PoolConnection, + filter_uid: &EmgauwaUid, +) -> Result { + sqlx::query_as!( + Schedule, + "SELECT * FROM schedules WHERE uid = ?", + filter_uid + ) + .fetch_optional(conn.deref_mut()) + .await + .map(|s| s.ok_or(DatabaseError::NotFound))? } -pub async fn get_schedules_by_tag(pool: &Pool, tag: &Tag) -> Result, DatabaseError> { +pub async fn get_schedules_by_tag( + conn: &mut PoolConnection, + tag: &Tag, +) -> Result, DatabaseError> { Ok(sqlx::query_as!(Schedule, "SELECT schedule.* FROM schedules AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id) - .fetch_all(pool) - .await?) + .fetch_all(conn.deref_mut()) + .await?) } -pub async fn delete_schedule_by_uid(pool: &Pool, filter_uid: EmgauwaUid) -> Result<(), DatabaseError> { +pub async fn delete_schedule_by_uid( + conn: &mut PoolConnection, + filter_uid: EmgauwaUid, +) -> Result<(), DatabaseError> { let filter_uid = match filter_uid { EmgauwaUid::Off => Err(DatabaseError::Protected), EmgauwaUid::On => Err(DatabaseError::Protected), @@ -40,7 +60,7 @@ pub async fn delete_schedule_by_uid(pool: &Pool, filter_uid: EmgauwaUid) }?; sqlx::query!("DELETE FROM schedules WHERE uid = ?", filter_uid) - .execute(pool) + .execute(conn.deref_mut()) .await .map(|res| match res.rows_affected() { 0 => Err(DatabaseError::DeleteError), @@ -48,20 +68,26 @@ pub async fn delete_schedule_by_uid(pool: &Pool, filter_uid: EmgauwaUid) })? } -pub async fn create_schedule(pool: &Pool, new_name: &str, new_periods: &Periods) -> Result { +pub async fn create_schedule( + conn: &mut PoolConnection, + new_name: &str, + new_periods: &Periods, +) -> Result { let uid = EmgauwaUid::default(); - sqlx::query_as!(Schedule, "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", + sqlx::query_as!( + Schedule, + "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", uid, new_name, new_periods, ) - .fetch_optional(pool) - .await? - .ok_or(DatabaseError::InsertGetError) + .fetch_optional(conn.deref_mut()) + .await? + .ok_or(DatabaseError::InsertGetError) } pub async fn update_schedule( - pool: &Pool, + conn: &mut PoolConnection, schedule: &Schedule, new_name: &str, new_periods: &Periods, @@ -72,35 +98,41 @@ pub async fn update_schedule( EmgauwaUid::Any(_) => new_periods, }; - sqlx::query!("UPDATE schedules SET name = ?, periods = ? WHERE id = ?", + sqlx::query!( + "UPDATE schedules SET name = ?, periods = ? WHERE id = ?", new_name, new_periods, schedule.id, ) - .execute(pool) - .await?; + .execute(conn.deref_mut()) + .await?; - get_schedule_by_uid(pool, &schedule.uid).await + get_schedule_by_uid(conn, &schedule.uid).await } -pub async fn set_schedule_tags(pool: &Pool, schedule: &Schedule, new_tags: &[String]) -> Result<(), DatabaseError> { - sqlx::query!("DELETE FROM junction_tag WHERE schedule_id = ?", schedule.id) - .execute(pool) - .await?; +pub async fn set_schedule_tags( + conn: &mut PoolConnection, + schedule: &Schedule, + new_tags: &[String], +) -> Result<(), DatabaseError> { + sqlx::query!( + "DELETE FROM junction_tag WHERE schedule_id = ?", + schedule.id + ) + .execute(conn.deref_mut()) + .await?; for new_tag in new_tags { let tag: Option = sqlx::query_as!(Tag, "SELECT * FROM tags WHERE tag = ?", new_tag) - .fetch_optional(pool) + .fetch_optional(conn.deref_mut()) .await?; let tag = match tag { Some(id) => id, - None => { - create_tag(pool, new_tag).await? - } + None => create_tag(conn, new_tag).await?, }; - create_junction_tag_schedule(pool, tag, schedule).await?; + create_junction_tag_schedule(conn, tag, schedule).await?; } Ok(()) } diff --git a/src/db/tag.rs b/src/db/tag.rs index 881b2c0..556eb0c 100644 --- a/src/db/tag.rs +++ b/src/db/tag.rs @@ -1,41 +1,62 @@ -use sqlx::{Pool, Sqlite}; use crate::db::errors::DatabaseError; use crate::db::models::*; +use sqlx::pool::PoolConnection; +use sqlx::Sqlite; +use std::ops::DerefMut; -pub async fn create_tag(pool: &Pool, new_tag: &str) -> Result { - sqlx::query_as!(Tag, "INSERT INTO tags (tag) VALUES (?) RETURNING *", new_tag) - .fetch_optional(pool) - .await? - .ok_or(DatabaseError::InsertGetError) +pub async fn create_tag( + conn: &mut PoolConnection, + new_tag: &str, +) -> Result { + sqlx::query_as!( + Tag, + "INSERT INTO tags (tag) VALUES (?) RETURNING *", + new_tag + ) + .fetch_optional(conn.deref_mut()) + .await? + .ok_or(DatabaseError::InsertGetError) } -pub async fn get_tag(pool: &Pool, target_tag: &str) -> Result { +pub async fn get_tag( + conn: &mut PoolConnection, + target_tag: &str, +) -> Result { sqlx::query_as!(Tag, "SELECT * FROM tags WHERE tag = ?", target_tag) - .fetch_optional(pool) + .fetch_optional(conn.deref_mut()) .await .map(|t| t.ok_or(DatabaseError::NotFound))? } #[allow(dead_code)] pub async fn create_junction_tag_relay( - pool: &Pool, + conn: &mut PoolConnection, target_tag: Tag, target_relay: &Relay, ) -> Result { - - sqlx::query_as!(JunctionTag, "INSERT INTO junction_tag (tag_id, relay_id) VALUES (?, ?) RETURNING *", target_tag.id, target_relay.id) - .fetch_optional(pool) - .await? - .ok_or(DatabaseError::InsertGetError) + sqlx::query_as!( + JunctionTag, + "INSERT INTO junction_tag (tag_id, relay_id) VALUES (?, ?) RETURNING *", + target_tag.id, + target_relay.id + ) + .fetch_optional(conn.deref_mut()) + .await? + .ok_or(DatabaseError::InsertGetError) } pub async fn create_junction_tag_schedule( - pool: &Pool, + conn: &mut PoolConnection, target_tag: Tag, target_schedule: &Schedule, ) -> Result { - sqlx::query_as!(JunctionTag, "INSERT INTO junction_tag (tag_id, schedule_id) VALUES (?, ?) RETURNING *", target_tag.id, target_schedule.id) - .fetch_optional(pool) - .await? - .ok_or(DatabaseError::InsertGetError) + sqlx::query_as!( + JunctionTag, + "INSERT INTO junction_tag (tag_id, schedule_id) VALUES (?, ?) RETURNING *", + target_tag.id, + target_schedule.id + ) + .fetch_optional(conn.deref_mut()) + .await? + .ok_or(DatabaseError::InsertGetError) } diff --git a/src/handlers/v1/schedules.rs b/src/handlers/v1/schedules.rs index 21ce7cc..fc054d6 100644 --- a/src/handlers/v1/schedules.rs +++ b/src/handlers/v1/schedules.rs @@ -1,10 +1,10 @@ use crate::db::errors::DatabaseError; use actix_web::{delete, get, post, put, web, HttpResponse, Responder}; use serde::{Deserialize, Serialize}; +use sqlx::pool::PoolConnection; +use sqlx::{Pool, Sqlite}; use std::borrow::Borrow; use std::convert::TryFrom; -use futures::future; -use sqlx::{Pool, Sqlite}; use crate::db::models::{Periods, Schedule}; use crate::db::schedules::*; @@ -23,31 +23,14 @@ pub struct RequestSchedule { #[get("/api/v1/schedules")] pub async fn index(pool: web::Data>) -> impl Responder { - let schedules = get_schedules(&pool).await; - - if let Err(err) = schedules { - return HttpResponse::from(err); + let pool_conn = pool.acquire().await; + if let Err(err) = pool_conn { + return HttpResponse::from(DatabaseError::from(err)); } - let schedules = schedules.unwrap(); + let mut pool_conn = pool_conn.unwrap(); - let mut return_schedules: Vec = schedules.iter().map(ReturnSchedule::from).collect(); - for schedule in return_schedules.iter_mut() { - schedule.load_tags(&pool); - } + let schedules = get_schedules(&mut pool_conn).await; - HttpResponse::Ok().json(return_schedules) -} - -#[get("/api/v1/schedules/tag/{tag}")] -pub async fn tagged(pool: web::Data>, path: web::Path<(String,)>) -> impl Responder { - let (tag,) = path.into_inner(); - let tag_db = get_tag(&pool, &tag).await; - if let Err(err) = tag_db { - return HttpResponse::from(err); - } - let tag_db = tag_db.unwrap(); - - let schedules = get_schedules_by_tag(&pool, &tag_db).await; if let Err(err) = schedules { return HttpResponse::from(err); } @@ -56,25 +39,61 @@ pub async fn tagged(pool: web::Data>, path: web::Path<(String,)>) - let mut return_schedules: Vec = schedules.iter().map(ReturnSchedule::from).collect(); for schedule in return_schedules.iter_mut() { - schedule.load_tags(&pool); + schedule.load_tags(&mut pool_conn); + } + + HttpResponse::Ok().json(return_schedules) +} + +#[get("/api/v1/schedules/tag/{tag}")] +pub async fn tagged(pool: web::Data>, path: web::Path<(String,)>) -> impl Responder { + let pool_conn = pool.acquire().await; + if let Err(err) = pool_conn { + return HttpResponse::from(DatabaseError::from(err)); + } + let mut pool_conn = pool_conn.unwrap(); + + let (tag,) = path.into_inner(); + let tag_db = get_tag(&mut pool_conn, &tag).await; + if let Err(err) = tag_db { + return HttpResponse::from(err); + } + let tag_db = tag_db.unwrap(); + + let schedules = get_schedules_by_tag(&mut pool_conn, &tag_db).await; + if let Err(err) = schedules { + return HttpResponse::from(err); + } + let schedules = schedules.unwrap(); + + let mut return_schedules: Vec = + schedules.iter().map(ReturnSchedule::from).collect(); + for schedule in return_schedules.iter_mut() { + schedule.load_tags(&mut pool_conn); } HttpResponse::Ok().json(return_schedules) } #[get("/api/v1/schedules/{schedule_id}")] pub async fn show(pool: web::Data>, path: web::Path<(String,)>) -> impl Responder { + let pool_conn = pool.acquire().await; + if let Err(err) = pool_conn { + return HttpResponse::from(DatabaseError::from(err)); + } + let mut pool_conn = pool_conn.unwrap(); + let (schedule_uid,) = path.into_inner(); let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(HandlerError::BadUid)); match emgauwa_uid { Ok(uid) => { - let schedule = get_schedule_by_uid(&pool, &uid).await; + let schedule = get_schedule_by_uid(&mut pool_conn, &uid).await; match schedule { Ok(ok) => { let mut return_schedule = ReturnSchedule::from(ok); - return_schedule.load_tags(&pool); + return_schedule.load_tags(&mut pool_conn); HttpResponse::Ok().json(return_schedule) - }, + } Err(err) => HttpResponse::from(err), } } @@ -83,40 +102,63 @@ pub async fn show(pool: web::Data>, path: web::Path<(String,)>) -> } #[post("/api/v1/schedules")] -pub async fn add(pool: web::Data>, data: web::Json) -> impl Responder { - let new_schedule = create_schedule(&pool, &data.name, &data.periods).await; +pub async fn add( + pool: web::Data>, + data: web::Json, +) -> impl Responder { + let pool_conn = pool.acquire().await; + if let Err(err) = pool_conn { + return HttpResponse::from(DatabaseError::from(err)); + } + let mut pool_conn = pool_conn.unwrap(); + + let new_schedule = create_schedule(&mut pool_conn, &data.name, &data.periods).await; if let Err(err) = new_schedule { return HttpResponse::from(err); } let new_schedule = new_schedule.unwrap(); - let result = set_schedule_tags(&pool, &new_schedule, data.tags.as_slice()).await; + let result = set_schedule_tags(&mut pool_conn, &new_schedule, data.tags.as_slice()).await; if let Err(err) = result { return HttpResponse::from(err); } let mut return_schedule = ReturnSchedule::from(new_schedule); - return_schedule.load_tags(&pool); + return_schedule.load_tags(&mut pool_conn); HttpResponse::Created().json(return_schedule) } -async fn add_list_single(pool: &Pool, request_schedule: &RequestSchedule) -> Result { - let new_schedule = create_schedule(pool, &request_schedule.name, &request_schedule.periods).await?; +async fn add_list_single( + conn: &mut PoolConnection, + request_schedule: &RequestSchedule, +) -> Result { + let new_schedule = + create_schedule(conn, &request_schedule.name, &request_schedule.periods).await?; - set_schedule_tags(pool, &new_schedule, request_schedule.tags.as_slice()).await?; + set_schedule_tags(conn, &new_schedule, request_schedule.tags.as_slice()).await?; Ok(new_schedule) } #[post("/api/v1/schedules/list")] -pub async fn add_list(pool: web::Data>, data: web::Json>) -> impl Responder { - let result: Vec> = future::join_all( - data +pub async fn add_list( + pool: web::Data>, + data: web::Json>, +) -> impl Responder { + let pool_conn = pool.acquire().await; + if let Err(err) = pool_conn { + return HttpResponse::from(DatabaseError::from(err)); + } + let mut pool_conn = pool_conn.unwrap(); + + let result: Vec> = data .as_slice() .iter() - .map(|request_schedule| add_list_single(&pool, request_schedule)) - ).await; + .map(|request_schedule| { + futures::executor::block_on(add_list_single(&mut pool_conn, request_schedule)) + }) + .collect(); match vec_has_error(&result) { true => HttpResponse::from( @@ -133,7 +175,7 @@ pub async fn add_list(pool: web::Data>, data: web::Json, data: web::Json, ) -> impl Responder { + let pool_conn = pool.acquire().await; + if let Err(err) = pool_conn { + return HttpResponse::from(DatabaseError::from(err)); + } + let mut pool_conn = pool_conn.unwrap(); + let (schedule_uid,) = path.into_inner(); let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(HandlerError::BadUid)); if let Err(err) = emgauwa_uid { @@ -153,30 +201,42 @@ pub async fn update( } let emgauwa_uid = emgauwa_uid.unwrap(); - let schedule = get_schedule_by_uid(&pool, &emgauwa_uid, ).await; + let schedule = get_schedule_by_uid(&mut pool_conn, &emgauwa_uid).await; if let Err(err) = schedule { return HttpResponse::from(err); } let schedule = schedule.unwrap(); - let schedule = update_schedule(&pool, &schedule, data.name.as_str(), data.periods.borrow()).await; + let schedule = update_schedule( + &mut pool_conn, + &schedule, + data.name.as_str(), + data.periods.borrow(), + ) + .await; if let Err(err) = schedule { return HttpResponse::from(err); } let schedule = schedule.unwrap(); - let result = set_schedule_tags(&pool, &schedule, data.tags.as_slice()).await; + let result = set_schedule_tags(&mut pool_conn, &schedule, data.tags.as_slice()).await; if let Err(err) = result { return HttpResponse::from(err); } let mut return_schedule = ReturnSchedule::from(schedule); - return_schedule.load_tags(&pool); + return_schedule.load_tags(&mut pool_conn); HttpResponse::Ok().json(return_schedule) } #[delete("/api/v1/schedules/{schedule_id}")] pub async fn delete(pool: web::Data>, path: web::Path<(String,)>) -> impl Responder { + let pool_conn = pool.acquire().await; + if let Err(err) = pool_conn { + return HttpResponse::from(DatabaseError::from(err)); + } + let mut pool_conn = pool_conn.unwrap(); + let (schedule_uid,) = path.into_inner(); let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(HandlerError::BadUid)); @@ -184,7 +244,7 @@ pub async fn delete(pool: web::Data>, path: web::Path<(String,)>) - Ok(uid) => match uid { EmgauwaUid::Off => HttpResponse::from(HandlerError::ProtectedSchedule), EmgauwaUid::On => HttpResponse::from(HandlerError::ProtectedSchedule), - EmgauwaUid::Any(_) => match delete_schedule_by_uid(&pool, uid).await { + EmgauwaUid::Any(_) => match delete_schedule_by_uid(&mut pool_conn, uid).await { Ok(_) => HttpResponse::Ok().json("schedule got deleted"), Err(err) => HttpResponse::from(err), }, diff --git a/src/return_models.rs b/src/return_models.rs index 49e7212..2b2edbe 100644 --- a/src/return_models.rs +++ b/src/return_models.rs @@ -1,5 +1,7 @@ use futures::executor; use serde::Serialize; +use sqlx::pool::PoolConnection; +use sqlx::Sqlite; use crate::db::models::Schedule; use crate::db::schedules::get_schedule_tags; @@ -12,14 +14,17 @@ pub struct ReturnSchedule { } impl ReturnSchedule { - pub fn load_tags(&mut self, pool: &sqlx::Pool) { - self.tags = executor::block_on(get_schedule_tags(pool, &self.schedule)).unwrap(); + pub fn load_tags(&mut self, conn: &mut PoolConnection) { + self.tags = executor::block_on(get_schedule_tags(conn, &self.schedule)).unwrap(); } } impl From for ReturnSchedule { fn from(schedule: Schedule) -> Self { - ReturnSchedule { schedule, tags: vec![]} + ReturnSchedule { + schedule, + tags: vec![], + } } } diff --git a/src/types/emgauwa_uid.rs b/src/types/emgauwa_uid.rs index 84f0503..ca96fe4 100644 --- a/src/types/emgauwa_uid.rs +++ b/src/types/emgauwa_uid.rs @@ -4,11 +4,11 @@ use std::str::FromStr; use crate::types::EmgauwaUid; use serde::{Serialize, Serializer}; -use sqlx::{Decode, Encode, Sqlite, Type}; use sqlx::database::HasArguments; use sqlx::encode::IsNull; use sqlx::error::BoxDynError; use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef}; +use sqlx::{Decode, Encode, Sqlite, Type}; use uuid::Uuid; impl EmgauwaUid {