Add asynchronous call to database.
[recipes.git] / backend / src / data / asynchronous.rs
1 //! Functions to be called from actix code. They are asynchonrous and won't block worker thread caller.
2
3 use std::fmt;
4
5 use chrono::{prelude::*, Duration};
6 use actix_web::{web, error::BlockingError};
7
8 use super::db::*;
9 use crate::model;
10 use crate::user::User;
11
12 #[derive(Debug)]
13 pub enum DBAsyncError {
14 DBError(DBError),
15 ActixError(BlockingError),
16 Other(String),
17 }
18
19 impl fmt::Display for DBAsyncError {
20 fn fmt(&self, f: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
21 write!(f, "{:?}", self)
22 }
23 }
24
25 impl std::error::Error for DBAsyncError { }
26
27 impl From<DBError> for DBAsyncError {
28 fn from(error: DBError) -> Self {
29 DBAsyncError::DBError(error)
30 }
31 }
32
33 impl From<BlockingError> for DBAsyncError {
34 fn from(error: BlockingError) -> Self {
35 DBAsyncError::ActixError(error)
36 }
37 }
38
39 impl DBAsyncError {
40 fn from_dyn_error(error: Box<dyn std::error::Error>) -> Self {
41 DBAsyncError::Other(error.to_string())
42 }
43 }
44
45 fn combine_errors<T>(error: std::result::Result<std::result::Result<T, DBAsyncError>, BlockingError>) -> Result<T> {
46 error?
47 }
48
49 type Result<T> = std::result::Result<T, DBAsyncError>;
50
51 impl Connection {
52 pub async fn get_all_recipe_titles_async(&self) -> Result<Vec<(i32, String)>> {
53 let self_copy = self.clone();
54 web::block(move || { self_copy.get_all_recipe_titles().unwrap_or_default() }).await.map_err(DBAsyncError::from)
55 }
56
57 pub async fn get_recipe_async(&self, id: i32) -> Result<model::Recipe> {
58 let self_copy = self.clone();
59 combine_errors(web::block(move || { self_copy.get_recipe(id).map_err(DBAsyncError::from) }).await)
60 }
61
62 pub async fn load_user_async(&self, user_id: i32) -> Result<User> {
63 let self_copy = self.clone();
64 combine_errors(web::block(move || { self_copy.load_user(user_id).map_err(DBAsyncError::from) }).await)
65 }
66
67 pub async fn sign_up_async(&self, email: &str, password: &str) -> Result<SignUpResult> {
68 let self_copy = self.clone();
69 let email_copy = email.to_string();
70 let password_copy = password.to_string();
71 combine_errors(web::block(move || { self_copy.sign_up(&email_copy, &password_copy).map_err(DBAsyncError::from) }).await)
72 }
73
74 pub async fn validation_async(&self, token: &str, validation_time: Duration, ip: &str, user_agent: &str) -> Result<ValidationResult> {
75 let self_copy = self.clone();
76 let token_copy = token.to_string();
77 let ip_copy = ip.to_string();
78 let user_agent_copy = user_agent.to_string();
79 combine_errors(web::block(move || { self_copy.validation(&token_copy, validation_time, &ip_copy, &user_agent_copy).map_err(DBAsyncError::from) }).await)
80 }
81
82 pub async fn sign_in_async(&self, email: &str, password: &str, ip: &str, user_agent: &str) -> Result<SignInResult> {
83 let self_copy = self.clone();
84 let email_copy = email.to_string();
85 let password_copy = password.to_string();
86 let ip_copy = ip.to_string();
87 let user_agent_copy = user_agent.to_string();
88 combine_errors(web::block(move || { self_copy.sign_in(&email_copy, &password_copy, &ip_copy, &user_agent_copy).map_err(DBAsyncError::from) }).await)
89 }
90
91 pub async fn authentication_async(&self, token: &str, ip: &str, user_agent: &str) -> Result<AuthenticationResult> {
92 let self_copy = self.clone();
93 let token_copy = token.to_string();
94 let ip_copy = ip.to_string();
95 let user_agent_copy = user_agent.to_string();
96 combine_errors(web::block(move || { self_copy.authentication(&token_copy, &ip_copy, &user_agent_copy).map_err(DBAsyncError::from) }).await)
97 }
98
99 pub async fn sign_out_async(&self, token: &str) -> Result<()> {
100 let self_copy = self.clone();
101 let token_copy = token.to_string();
102 combine_errors(web::block(move || { self_copy.sign_out(&token_copy).map_err(DBAsyncError::from) }).await)
103 }
104 }