Add asynchronous call to database.
[recipes.git] / backend / src / data / asynchronous.rs
diff --git a/backend/src/data/asynchronous.rs b/backend/src/data/asynchronous.rs
new file mode 100644 (file)
index 0000000..4dda803
--- /dev/null
@@ -0,0 +1,104 @@
+//! Functions to be called from actix code. They are asynchonrous and won't block worker thread caller.
+
+use std::fmt;
+
+use chrono::{prelude::*, Duration};
+use actix_web::{web, error::BlockingError};
+
+use super::db::*;
+use crate::model;
+use crate::user::User;
+
+#[derive(Debug)]
+pub enum DBAsyncError {
+    DBError(DBError),
+    ActixError(BlockingError),
+    Other(String),
+}
+
+impl fmt::Display for DBAsyncError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl std::error::Error for DBAsyncError { }
+
+impl From<DBError> for DBAsyncError  {
+    fn from(error: DBError) -> Self {
+        DBAsyncError::DBError(error)
+    }
+}
+
+impl From<BlockingError> for DBAsyncError  {
+    fn from(error: BlockingError) -> Self {
+        DBAsyncError::ActixError(error)
+    }
+}
+
+impl DBAsyncError {
+    fn from_dyn_error(error: Box<dyn std::error::Error>) -> Self {
+        DBAsyncError::Other(error.to_string())
+    }
+}
+
+fn combine_errors<T>(error: std::result::Result<std::result::Result<T, DBAsyncError>, BlockingError>) -> Result<T> {
+    error?
+}
+
+type Result<T> = std::result::Result<T, DBAsyncError>;
+
+impl Connection {
+    pub async fn get_all_recipe_titles_async(&self) -> Result<Vec<(i32, String)>> {
+        let self_copy = self.clone();
+        web::block(move || { self_copy.get_all_recipe_titles().unwrap_or_default() }).await.map_err(DBAsyncError::from)
+    }
+
+    pub async fn get_recipe_async(&self, id: i32) -> Result<model::Recipe> {
+        let self_copy = self.clone();
+        combine_errors(web::block(move || { self_copy.get_recipe(id).map_err(DBAsyncError::from) }).await)
+    }
+
+    pub async fn load_user_async(&self, user_id: i32) -> Result<User> {
+        let self_copy = self.clone();
+        combine_errors(web::block(move || { self_copy.load_user(user_id).map_err(DBAsyncError::from) }).await)
+    }
+
+    pub async fn sign_up_async(&self, email: &str, password: &str) -> Result<SignUpResult> {
+        let self_copy = self.clone();
+        let email_copy = email.to_string();
+        let password_copy = password.to_string();
+        combine_errors(web::block(move || { self_copy.sign_up(&email_copy, &password_copy).map_err(DBAsyncError::from) }).await)
+    }
+
+    pub async fn validation_async(&self, token: &str, validation_time: Duration, ip: &str, user_agent: &str) -> Result<ValidationResult> {
+        let self_copy = self.clone();
+        let token_copy = token.to_string();
+        let ip_copy = ip.to_string();
+        let user_agent_copy = user_agent.to_string();
+        combine_errors(web::block(move || { self_copy.validation(&token_copy, validation_time, &ip_copy, &user_agent_copy).map_err(DBAsyncError::from) }).await)
+    }
+
+    pub async fn sign_in_async(&self, email: &str, password: &str, ip: &str, user_agent: &str) -> Result<SignInResult> {
+        let self_copy = self.clone();
+        let email_copy = email.to_string();
+        let password_copy = password.to_string();
+        let ip_copy = ip.to_string();
+        let user_agent_copy = user_agent.to_string();
+        combine_errors(web::block(move || { self_copy.sign_in(&email_copy, &password_copy, &ip_copy, &user_agent_copy).map_err(DBAsyncError::from) }).await)
+    }
+
+    pub async fn authentication_async(&self, token: &str, ip: &str, user_agent: &str) -> Result<AuthenticationResult> {
+        let self_copy = self.clone();
+        let token_copy = token.to_string();
+        let ip_copy = ip.to_string();
+        let user_agent_copy = user_agent.to_string();
+        combine_errors(web::block(move || { self_copy.authentication(&token_copy, &ip_copy, &user_agent_copy).map_err(DBAsyncError::from) }).await)
+    }
+
+    pub async fn sign_out_async(&self, token: &str) -> Result<()> {
+        let self_copy = self.clone();
+        let token_copy = token.to_string();
+        combine_errors(web::block(move || { self_copy.sign_out(&token_copy).map_err(DBAsyncError::from) }).await)
+    }
+}
\ No newline at end of file