Even more error handling
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Lucien Cartier-Tilet 2023-01-17 00:58:01 +01:00
parent 3220f5c005
commit a36fd740af
Signed by: phundrak
GPG Key ID: BD7789E705CB8DCA
2 changed files with 56 additions and 66 deletions

View File

@ -7,12 +7,12 @@ use self::models::words::Word;
use diesel::pg::PgConnection;
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
use diesel::result::Error;
use diesel::{insert_into, prelude::*};
use dotenvy::dotenv;
use juniper::{graphql_value, DefaultScalarValue, FieldError, IntoFieldError};
use std::env;
use std::error::Error;
use tracing::info;
#[derive(Debug)]
@ -36,7 +36,7 @@ impl DatabaseError {
}
}
impl Error for DatabaseError {}
impl std::error::Error for DatabaseError {}
impl std::fmt::Display for DatabaseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -53,23 +53,6 @@ impl IntoFieldError for DatabaseError {
}
}
macro_rules! find_element {
($conn:expr,$dsl:ident,$type:ty,$value:expr,$errmsg:expr) => {
if let Ok(val) = $conn {
$dsl.find($value).first::<$type>(val).map_or_else(
|e| {
info!("{}: {:?}", $errmsg, e);
None
},
Some,
)
} else {
info!("Failed to obtain connection for the database");
None
}
};
}
#[derive(Debug, Clone)]
pub struct Database {
conn: Pool<ConnectionManager<PgConnection>>,
@ -170,37 +153,42 @@ impl Database {
})
}
pub fn language(&self, name: &str, owner: &str) -> Option<Language> {
pub fn language(
&self,
name: &str,
owner: &str,
) -> Result<Option<Language>, DatabaseError> {
use self::schema::languages::dsl;
match &mut self.conn() {
Ok(conn) => match dsl::languages
match dsl::languages
.filter(dsl::name.eq(name))
.filter(dsl::owner.eq(owner))
.first::<Language>(conn)
.first(&mut self.conn()?)
{
Ok(val) => Some(val),
Err(e) => {
info!("Could not retrieve language {} of user {} from database: {:?}",
name, owner, e);
None
}
},
Err(e) => {
info!("Could not connect to the database: {:?}", e);
None
}
Ok(val) => Ok(Some(val)),
Err(Error::NotFound) => Ok(None),
Err(e) => Err(DatabaseError::new(
format!(
"Failed to find language {} belonging to {}: {:?}",
name, owner, e
),
"Database error",
)),
}
}
pub fn user(&self, id: &str) -> Option<User> {
pub fn user(&self, id: &str) -> Result<Option<User>, DatabaseError> {
use self::schema::users::dsl::users;
find_element!(
&mut self.conn(),
users,
User,
id.to_string(),
format!("Failed to retrieve user {} from database", id)
)
match users.find(id).first::<User>(&mut self.conn()?) {
Ok(val) => Ok(Some(val)),
Err(Error::NotFound) => Ok(None),
Err(e) => Err(DatabaseError::new(
format!(
"Failed to retrieve user {} from database: {:?}",
id, e
),
"Database Error",
)),
}
}
pub fn insert_user(
@ -239,18 +227,18 @@ impl Database {
}
}
pub fn word_id(&self, id: &str) -> Option<Word> {
pub fn word_id(&self, id: &str) -> Result<Option<Word>, DatabaseError> {
use self::schema::words::dsl;
if let Ok(conn) = &mut self.conn() {
match dsl::words.find(id).first::<Word>(conn) {
Ok(val) => Some(val),
Err(e) => {
info!("Error retrieving {}: {:?}", id, e);
None
}
}
} else {
None
match dsl::words.find(id).first::<Word>(&mut self.conn()?) {
Ok(val) => Ok(Some(val)),
Err(Error::NotFound) => Ok(None),
Err(e) => Err(DatabaseError::new(
format!(
"Failed to retrieve word {} from database: {:?}",
id, e
),
"Database Error",
)),
}
}

View File

@ -76,24 +76,27 @@ impl Query {
context: &Context,
name: String,
owner: String,
) -> Option<Language> {
context.db.language(name.as_str(), owner.as_str())
) -> FieldResult<Option<Language>> {
context
.db
.language(name.as_str(), owner.as_str())
.map_err(Into::into)
}
#[graphql(
description = "Retrieve a specific user from its id",
arguments(id(description = "Appwrite ID of a user"))
)]
fn user(context: &Context, id: String) -> Option<User> {
context.db.user(id.as_str())
fn user(context: &Context, id: String) -> FieldResult<Option<User>> {
context.db.user(id.as_str()).map_err(Into::into)
}
#[graphql(
description = "Retrieve a specific word from its id",
arguments(id(description = "Unique identifier of a word"))
)]
fn word(context: &Context, id: String) -> Option<Word> {
context.db.word_id(id.as_str())
fn word(context: &Context, id: String) -> FieldResult<Option<Word>> {
context.db.word_id(id.as_str()).map_err(Into::into)
}
#[graphql(
@ -140,10 +143,9 @@ impl Query {
word: String,
) -> FieldResult<Vec<Word>> {
match Uuid::from_str(&language) {
Ok(uuid) => context
.db
.words(uuid, word.as_str())
.map_err(Into::into),
Ok(uuid) => {
context.db.words(uuid, word.as_str()).map_err(Into::into)
}
Err(e) => Err(DatabaseError::new(
format!("Failed to convert {} to a UUID: {:?}", language, e),
"Conversion Error",