diff --git a/src/db/models/languages.rs b/src/db/models/languages.rs index defd686..27fb11f 100644 --- a/src/db/models/languages.rs +++ b/src/db/models/languages.rs @@ -1,6 +1,9 @@ -use crate::{db::Database, graphql::Context}; +use crate::{ + db::{Database, DatabaseError}, + graphql::Context, +}; use diesel::prelude::*; -use juniper::GraphQLEnum; +use juniper::{FieldResult, GraphQLEnum}; use tracing::info; use uuid::Uuid; @@ -8,6 +11,8 @@ use uuid::Uuid; use super::super::schema; use super::users::User; +use std::convert::Into; + use schema::{langandagents, langtranslatesto, languages}; #[derive( @@ -65,14 +70,22 @@ impl Language { &self, db: &Database, relationship: AgentLanguageRelation, - ) -> Vec { + ) -> Result, DatabaseError> { use schema::langandagents::dsl; match &mut db.conn() { - Ok(conn) => dsl::langandagents + Ok(conn) => Ok(dsl::langandagents .filter(dsl::language.eq(self.id)) .filter(dsl::relationship.eq(relationship)) .load::(conn) - .unwrap() + .map_err(|e| { + DatabaseError::new( + format!( + "Failed to retrieve language relationship: {:?}", + e + ), + "Database reading error", + ) + })? .iter() .map(|v| { use schema::users::dsl; @@ -89,7 +102,7 @@ impl Language { None } }) - .collect::>(), + .collect::>()), Err(e) => { panic!("Could not connect to the database: {:?}", e); } @@ -125,23 +138,32 @@ impl Language { name = "targetLanguage", description = "Languages in which the current language is translated" )] - fn target_language(&self, context: &Context) -> Vec { + fn target_language(&self, context: &Context) -> FieldResult> { use schema::langtranslatesto::dsl; match &mut context.db.conn() { - Ok(conn) => dsl::langtranslatesto + Ok(conn) => Ok(dsl::langtranslatesto .filter(dsl::langfrom.eq(self.id)) .load::(conn) - .unwrap() + .map_err(|e| { + DatabaseError::new( + format!( + "Failed to retrieve language translations: {:?}", + e + ), + "Database reading failure", + ) + })? .into_iter() .flat_map(|l| { use schema::languages::dsl; dsl::languages.find(l.langto).first::(conn) }) - .collect::>(), - Err(e) => { - info!("Failed to connect to the database: {:?}", e); - Vec::new() - } + .collect::>()), + Err(e) => Err(DatabaseError::new( + format!("Failed to connect to the database: {:?}", e), + "Database connection failure", + ) + .into()), } } @@ -187,34 +209,43 @@ impl Language { #[graphql( description = "User with administrative rights over the language" )] - fn owner(&self, context: &Context) -> User { + fn owner(&self, context: &Context) -> FieldResult { use schema::users::dsl; match &mut context.db.conn() { - Ok(conn) => dsl::users + Ok(conn) => Ok(dsl::users .find(self.owner.clone()) .first::(conn) - .unwrap_or_else(|e| { - panic!( - "Failed to retrieve owner {} of language {}: {:?}", - self.owner, self.name, e + .map_err(|e| { + DatabaseError::new( + format!( + "Failed to retrieve owner {} of language {}: {:?}", + self.owner, self.name, e + ), + "Database reading error", ) - }), - Err(e) => panic!("Failed to connect to the database: {:?}", e), + })?), + Err(e) => Err(DatabaseError::new( + format!("Failed to connect to the database: {:?}", e), + "Database connection failure", + ) + .into()), } } #[graphql( description = "People who participate in the elaboration of the language's dictionary" )] - fn authors(&self, context: &Context) -> Vec { + fn authors(&self, context: &Context) -> FieldResult> { self.relationship(&context.db, AgentLanguageRelation::Author) + .map_err(Into::into) } #[graphql( description = "People who can and do redistribute the language's dictionary" )] - fn publishers(&self, context: &Context) -> Vec { + fn publishers(&self, context: &Context) -> FieldResult> { self.relationship(&context.db, AgentLanguageRelation::Publisher) + .map_err(Into::into) } } diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs index 44b7e11..5c67b82 100644 --- a/src/db/models/mod.rs +++ b/src/db/models/mod.rs @@ -1,3 +1,3 @@ -pub mod users; pub mod languages; +pub mod users; pub mod words; diff --git a/src/db/models/users.rs b/src/db/models/users.rs index 8a6e425..0d0c08a 100644 --- a/src/db/models/users.rs +++ b/src/db/models/users.rs @@ -1,7 +1,9 @@ use super::super::schema::{userfollows, users}; use diesel::prelude::*; +use juniper::FieldResult; +use tracing::debug; -use crate::graphql::Context; +use crate::{db::DatabaseError, graphql::Context}; #[derive(Queryable, Insertable, Debug, Clone, PartialEq, Eq)] pub struct User { @@ -22,21 +24,45 @@ impl User { } #[graphql(description = "Who the user follows")] - pub fn following(&self, context: &Context) -> Vec { + pub fn following(&self, context: &Context) -> FieldResult> { use super::super::schema::{userfollows, users}; - let conn = &mut context.db.conn().unwrap(); - userfollows::dsl::userfollows + let conn = &mut context.db.conn().map_err(|e| { + DatabaseError::new( + format!("Failed to connect to database: {:?}", e), + "Database connection error", + ) + })?; + Ok(userfollows::dsl::userfollows .filter(userfollows::dsl::follower.eq(self.id.clone())) .load::(conn) - .unwrap() - .iter() - .map(|f| { - users::dsl::users - .find(f.following.clone()) - .first::(conn) - .unwrap() - }) - .collect::>() + .map_err(|e| { + DatabaseError::new( + format!( + "Failed to retrieve user follows from database: {:?}", + e + ), + "Database reading error", + ) + })? + .iter() + .filter_map(|f| { + match users::dsl::users + .find(f.following.clone()) + .first::(conn) { + Ok(val) => Some(val), + Err(e) => { + let err = DatabaseError::new( + format!("Failed to retrieve user {} from database: {:?}", + f.following.clone(), + e), + "Database reading error"); + debug!("{}", err); + None + } + } + + }) + .collect::>()) } } diff --git a/src/graphql/context.rs b/src/graphql/context.rs index 8882a0e..51b60e9 100644 --- a/src/graphql/context.rs +++ b/src/graphql/context.rs @@ -18,7 +18,7 @@ pub struct OtherEnvVar { impl Default for OtherEnvVar { fn default() -> Self { Self { - admin_key: from_env!("ADMIN_KEY") + admin_key: from_env!("ADMIN_KEY"), } } } @@ -28,7 +28,7 @@ pub struct Context { pub db: Database, pub appwrite: APVariables, pub user_auth: bool, - pub other_vars: OtherEnvVar + pub other_vars: OtherEnvVar, } impl Context { @@ -64,7 +64,6 @@ impl Context { res.user_auth = self.user_auth(auth_token).await; res } - } impl juniper::Context for Context {}