diff --git a/src/db/mod.rs b/src/db/mod.rs index 490af96..2c01450 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -18,10 +18,12 @@ use tracing::info; #[derive(Debug)] pub struct DatabaseError { long: String, + #[allow(dead_code)] short: String, } impl DatabaseError { + #[allow(clippy::needless_pass_by_value)] pub fn new(long: S, short: T) -> Self where T: ToString, diff --git a/src/db/models/words.rs b/src/db/models/words.rs index 7db77b4..114a028 100644 --- a/src/db/models/words.rs +++ b/src/db/models/words.rs @@ -1,10 +1,15 @@ use super::super::schema; -use crate::{db::Database, graphql::Context}; +use crate::{ + db::{Database, DatabaseError}, + graphql::Context, +}; use diesel::prelude::*; -use juniper::GraphQLEnum; +use juniper::{FieldResult, GraphQLEnum}; use schema::{wordrelation, words}; use tracing::info; +use std::convert::Into; + use super::languages::Language; #[derive(diesel_derive_enum::DbEnum, Debug, Clone, PartialEq, Eq)] @@ -62,24 +67,29 @@ impl Word { &self, db: &Database, relationship: WordRelationship, - ) -> Vec { + ) -> Result, DatabaseError> { use schema::wordrelation::dsl; match &mut db.conn() { - Ok(conn) => dsl::wordrelation + Ok(conn) => Ok(dsl::wordrelation .filter(dsl::wordsource.eq(self.norm.clone())) .filter(dsl::relationship.eq(relationship)) .load::(conn) - .unwrap() + .map_err(|e| { + DatabaseError::new( + format!("Failed to retrieve word relations: {:?}", e), + "Database reading failed", + ) + })? .into_iter() .flat_map(|w| { use schema::words::dsl; dsl::words.find(w.wordtarget).first::(conn) }) - .collect::>(), - Err(e) => { - info!("Could not connect to database: {:?}", e); - Vec::new() - } + .collect::>()), + Err(e) => Err(DatabaseError::new( + format!("Failed to connect to the database: {:?}", e), + "Database connection error", + )), } } } @@ -185,16 +195,18 @@ impl Word { name = "related", description = "Words related to the current word" )] - fn related_words(&self, context: &Context) -> Vec { + fn related_words(&self, context: &Context) -> FieldResult> { self.relationship(&context.db, WordRelationship::Related) + .map_err(Into::into) } #[graphql( name = "definitions", description = "Words that define the current word" )] - fn definitions(&self, context: &Context) -> Vec { + fn definitions(&self, context: &Context) -> FieldResult> { self.relationship(&context.db, WordRelationship::Definition) + .map_err(Into::into) } } diff --git a/src/graphql/query.rs b/src/graphql/query.rs index f5bf48e..3ef31fc 100644 --- a/src/graphql/query.rs +++ b/src/graphql/query.rs @@ -1,7 +1,10 @@ use juniper::FieldResult; use super::Context; -use crate::db::{models::{languages::Language, users::User, words::Word}, DatabaseError}; +use crate::db::{ + models::{languages::Language, users::User, words::Word}, + DatabaseError, +}; use std::str::FromStr; @@ -16,15 +19,19 @@ impl Query { name = "allLanguages", description = "Retrieve all languages defined in the database" )] - fn all_languages(context: &Context) -> Vec { - context.db.all_languages().unwrap() + fn all_languages(context: &Context) -> FieldResult> { + context.db.all_languages().map_err(Into::into) } - fn all_users(context: &Context, admin_key: String) -> FieldResult> { + fn all_users( + context: &Context, + admin_key: String, + ) -> FieldResult> { if admin_key == context.other_vars.admin_key { context.db.all_users().map_err(Into::into) } else { - Err(DatabaseError::new("Invalid admin key", "Invalid admin key").into()) + Err(DatabaseError::new("Invalid admin key", "Invalid admin key") + .into()) } } @@ -69,9 +76,21 @@ impl Query { word(description = "Word to search") ) )] - fn words(context: &Context, language: String, word: String) -> Vec { - context - .db - .words(uuid::Uuid::from_str(&language).unwrap(), word.as_str()) + fn words( + context: &Context, + language: String, + word: String, + ) -> FieldResult> { + match uuid::Uuid::from_str(&language) { + Ok(uuid) => Ok(context.db.words(uuid, word.as_str())), + Err(e) => Err(DatabaseError::new( + format!( + "Failed to convert {} to a proper UUID: {:?}", + language, e + ), + "Conversion Error", + ) + .into()), + } } }