From 5b54f40ec0a9a8bc8692e280c987c824a36d56c5 Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Wed, 29 Nov 2023 17:13:15 +0100
Subject: [PATCH] Add cache option to from_db_model functions

---
 api.v1.yaml                               | 17 ----
 emgauwa-core/src/handlers/v1/schedules.rs |  2 -
 emgauwa-lib/src/models/mod.rs             | 97 +++++++++++++++++------
 3 files changed, 74 insertions(+), 42 deletions(-)

diff --git a/api.v1.yaml b/api.v1.yaml
index 1306c3a..e4a8bba 100644
--- a/api.v1.yaml
+++ b/api.v1.yaml
@@ -218,23 +218,6 @@ paths:
       operationId: get-controllers
       description: Return all controllers.
     parameters: [ ]
-  /api/v1/controllers/discover:
-    put:
-      summary: discover controllers
-      tags:
-        - controllers
-      responses:
-        '200':
-          description: OK
-          content:
-            application/json:
-              schema:
-                type: array
-                items:
-                  $ref: '#/components/schemas/controller'
-      operationId: put-controllers-discover
-      description: Start a discovery process to find controllers in the network. This operations needs multiple seconds to complete.
-    parameters: [ ]
   '/api/v1/controllers/{controller_id}':
     parameters:
       - schema:
diff --git a/emgauwa-core/src/handlers/v1/schedules.rs b/emgauwa-core/src/handlers/v1/schedules.rs
index cb58d92..babeebd 100644
--- a/emgauwa-core/src/handlers/v1/schedules.rs
+++ b/emgauwa-core/src/handlers/v1/schedules.rs
@@ -22,7 +22,6 @@ pub async fn index(pool: web::Data<Pool<Sqlite>>) -> Result<HttpResponse, ApiErr
 	let mut pool_conn = pool.acquire().await?;
 
 	let db_schedules = DbSchedule::get_all(&mut pool_conn).await?;
-
 	let schedules: Vec<Schedule> = convert_db_list(&mut pool_conn, db_schedules)?;
 
 	Ok(HttpResponse::Ok().json(schedules))
@@ -41,7 +40,6 @@ pub async fn tagged(
 		.ok_or(DatabaseError::NotFound)?;
 
 	let db_schedules = DbSchedule::get_by_tag(&mut pool_conn, &tag_db).await?;
-
 	let schedules: Vec<Schedule> = convert_db_list(&mut pool_conn, db_schedules)?;
 
 	Ok(HttpResponse::Ok().json(schedules))
diff --git a/emgauwa-lib/src/models/mod.rs b/emgauwa-lib/src/models/mod.rs
index 1c3f8e1..1846470 100644
--- a/emgauwa-lib/src/models/mod.rs
+++ b/emgauwa-lib/src/models/mod.rs
@@ -9,6 +9,7 @@ use crate::types::ControllerUid;
 
 pub trait FromDbModel {
 	type DbModel: Clone;
+	type DbModelCache: Clone;
 
 	fn from_db_model(
 		conn: &mut PoolConnection<Sqlite>,
@@ -16,6 +17,14 @@ pub trait FromDbModel {
 	) -> Result<Self, DatabaseError>
 	where
 		Self: Sized;
+
+	fn from_db_model_cache(
+		conn: &mut PoolConnection<Sqlite>,
+		db_model: Self::DbModel,
+		cache: Self::DbModelCache,
+	) -> Result<Self, DatabaseError>
+	where
+		Self: Sized;
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -43,33 +52,53 @@ pub struct Controller {
 
 impl FromDbModel for Schedule {
 	type DbModel = DbSchedule;
+	type DbModelCache = Vec<String>;
 
 	fn from_db_model(
 		conn: &mut PoolConnection<Sqlite>,
 		db_model: Self::DbModel,
 	) -> Result<Self, DatabaseError> {
-		let schedule = db_model.clone();
-		let tags = executor::block_on(schedule.get_tags(conn))?;
+		let cache = executor::block_on(db_model.get_tags(conn))?;
+		Self::from_db_model_cache(conn, db_model, cache)
+	}
 
-		Ok(Schedule { s: schedule, tags })
+	fn from_db_model_cache(
+		_conn: &mut PoolConnection<Sqlite>,
+		db_model: Self::DbModel,
+		cache: Self::DbModelCache,
+	) -> Result<Self, DatabaseError> {
+		let schedule = db_model.clone();
+
+		Ok(Schedule {
+			s: schedule,
+			tags: cache,
+		})
 	}
 }
 
 impl FromDbModel for Relay {
 	type DbModel = DbRelay;
+	type DbModelCache = DbController;
 
 	fn from_db_model(
 		conn: &mut PoolConnection<Sqlite>,
 		db_model: Self::DbModel,
 	) -> Result<Self, DatabaseError> {
-		let relay = db_model.clone();
-		let controller = executor::block_on(relay.get_controller(conn))?;
-		let controller_id = controller.uid.clone();
-		let tags = executor::block_on(relay.get_tags(conn))?;
+		let cache = executor::block_on(db_model.get_controller(conn))?;
+		Self::from_db_model_cache(conn, db_model, cache)
+	}
+
+	fn from_db_model_cache(
+		conn: &mut PoolConnection<Sqlite>,
+		db_model: Self::DbModel,
+		cache: Self::DbModelCache,
+	) -> Result<Self, DatabaseError> {
+		let tags = executor::block_on(db_model.get_tags(conn))?;
+		let controller_id = cache.uid.clone();
 
 		Ok(Relay {
-			r: relay,
-			controller,
+			r: db_model,
+			controller: cache,
 			controller_id,
 			tags,
 		})
@@ -78,34 +107,56 @@ impl FromDbModel for Relay {
 
 impl FromDbModel for Controller {
 	type DbModel = DbController;
+	type DbModelCache = Vec<Relay>;
 
 	fn from_db_model(
 		conn: &mut PoolConnection<Sqlite>,
 		db_model: Self::DbModel,
 	) -> Result<Self, DatabaseError> {
 		let relays_db = executor::block_on(db_model.get_relays(conn))?;
-		let relays = convert_db_list(conn, relays_db)?;
+		let cache = convert_db_list_cache(conn, relays_db, db_model.clone())?;
+		Self::from_db_model_cache(conn, db_model, cache)
+	}
+
+	fn from_db_model_cache(
+		_conn: &mut PoolConnection<Sqlite>,
+		db_model: Self::DbModel,
+		cache: Self::DbModelCache,
+	) -> Result<Self, DatabaseError> {
 		Ok(Controller {
 			c: db_model,
-			relays,
+			relays: cache,
 		})
 	}
 }
 
+fn convert_db_list_generic<T: FromDbModel>(
+	conn: &mut PoolConnection<Sqlite>,
+	db_models: Vec<T::DbModel>,
+	cache: Option<T::DbModelCache>,
+) -> Result<Vec<T>, DatabaseError> {
+	let mut result: Vec<T> = Vec::new();
+	for db_model in db_models {
+		let new = match &cache {
+			Some(c) => T::from_db_model_cache(conn, db_model, c.clone()),
+			None => T::from_db_model(conn, db_model),
+		}?;
+		result.push(new);
+	}
+	Ok(result)
+}
+
 pub fn convert_db_list<T: FromDbModel>(
 	conn: &mut PoolConnection<Sqlite>,
 	db_models: Vec<T::DbModel>,
 ) -> Result<Vec<T>, DatabaseError> {
-	let mut result: Vec<T> = Vec::new();
-	db_models.into_iter().try_for_each(|s| {
-		let new = T::from_db_model(conn, s);
-		match new {
-			Ok(new) => {
-				result.push(new);
-				Ok(())
-			}
-			Err(e) => Err(e),
-		}
-	})?;
-	Ok(result)
+	convert_db_list_generic(conn, db_models, None)
+}
+
+pub fn convert_db_list_cache<T: FromDbModel>(
+	conn: &mut PoolConnection<Sqlite>,
+	db_models: Vec<T::DbModel>,
+	cache: T::DbModelCache,
+) -> Result<Vec<T>, DatabaseError> {
+	convert_db_list_generic(conn, db_models, Some(cache))
 }