Better error handling

This commit is contained in:
Lucien Cartier-Tilet 2023-01-16 00:22:58 +01:00
parent 425e00acc1
commit dcaa920c51
Signed by: phundrak
GPG Key ID: BD7789E705CB8DCA
3 changed files with 54 additions and 21 deletions

View File

@ -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<S, T>(long: S, short: T) -> Self
where
T: ToString,

View File

@ -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<Word> {
) -> Result<Vec<Word>, 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::<WordRelation>(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::<Word>(conn)
})
.collect::<Vec<Word>>(),
Err(e) => {
info!("Could not connect to database: {:?}", e);
Vec::new()
}
.collect::<Vec<Word>>()),
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<Word> {
fn related_words(&self, context: &Context) -> FieldResult<Vec<Word>> {
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<Word> {
fn definitions(&self, context: &Context) -> FieldResult<Vec<Word>> {
self.relationship(&context.db, WordRelationship::Definition)
.map_err(Into::into)
}
}

View File

@ -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<Language> {
context.db.all_languages().unwrap()
fn all_languages(context: &Context) -> FieldResult<Vec<Language>> {
context.db.all_languages().map_err(Into::into)
}
fn all_users(context: &Context, admin_key: String) -> FieldResult<Vec<User>> {
fn all_users(
context: &Context,
admin_key: String,
) -> FieldResult<Vec<User>> {
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<Word> {
context
.db
.words(uuid::Uuid::from_str(&language).unwrap(), word.as_str())
fn words(
context: &Context,
language: String,
word: String,
) -> FieldResult<Vec<Word>> {
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()),
}
}
}