Even more error handling
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
3220f5c005
commit
a36fd740af
100
src/db/mod.rs
100
src/db/mod.rs
@ -7,12 +7,12 @@ use self::models::words::Word;
|
|||||||
|
|
||||||
use diesel::pg::PgConnection;
|
use diesel::pg::PgConnection;
|
||||||
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
|
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
|
||||||
|
use diesel::result::Error;
|
||||||
use diesel::{insert_into, prelude::*};
|
use diesel::{insert_into, prelude::*};
|
||||||
|
|
||||||
use dotenvy::dotenv;
|
use dotenvy::dotenv;
|
||||||
use juniper::{graphql_value, DefaultScalarValue, FieldError, IntoFieldError};
|
use juniper::{graphql_value, DefaultScalarValue, FieldError, IntoFieldError};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -36,7 +36,7 @@ impl DatabaseError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for DatabaseError {}
|
impl std::error::Error for DatabaseError {}
|
||||||
|
|
||||||
impl std::fmt::Display for DatabaseError {
|
impl std::fmt::Display for DatabaseError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
conn: Pool<ConnectionManager<PgConnection>>,
|
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;
|
use self::schema::languages::dsl;
|
||||||
match &mut self.conn() {
|
match dsl::languages
|
||||||
Ok(conn) => match dsl::languages
|
.filter(dsl::name.eq(name))
|
||||||
.filter(dsl::name.eq(name))
|
.filter(dsl::owner.eq(owner))
|
||||||
.filter(dsl::owner.eq(owner))
|
.first(&mut self.conn()?)
|
||||||
.first::<Language>(conn)
|
{
|
||||||
{
|
Ok(val) => Ok(Some(val)),
|
||||||
Ok(val) => Some(val),
|
Err(Error::NotFound) => Ok(None),
|
||||||
Err(e) => {
|
Err(e) => Err(DatabaseError::new(
|
||||||
info!("Could not retrieve language {} of user {} from database: {:?}",
|
format!(
|
||||||
name, owner, e);
|
"Failed to find language {} belonging to {}: {:?}",
|
||||||
None
|
name, owner, e
|
||||||
}
|
),
|
||||||
},
|
"Database error",
|
||||||
Err(e) => {
|
)),
|
||||||
info!("Could not connect to the database: {:?}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn user(&self, id: &str) -> Option<User> {
|
pub fn user(&self, id: &str) -> Result<Option<User>, DatabaseError> {
|
||||||
use self::schema::users::dsl::users;
|
use self::schema::users::dsl::users;
|
||||||
find_element!(
|
match users.find(id).first::<User>(&mut self.conn()?) {
|
||||||
&mut self.conn(),
|
Ok(val) => Ok(Some(val)),
|
||||||
users,
|
Err(Error::NotFound) => Ok(None),
|
||||||
User,
|
Err(e) => Err(DatabaseError::new(
|
||||||
id.to_string(),
|
format!(
|
||||||
format!("Failed to retrieve user {} from database", id)
|
"Failed to retrieve user {} from database: {:?}",
|
||||||
)
|
id, e
|
||||||
|
),
|
||||||
|
"Database Error",
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_user(
|
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;
|
use self::schema::words::dsl;
|
||||||
if let Ok(conn) = &mut self.conn() {
|
match dsl::words.find(id).first::<Word>(&mut self.conn()?) {
|
||||||
match dsl::words.find(id).first::<Word>(conn) {
|
Ok(val) => Ok(Some(val)),
|
||||||
Ok(val) => Some(val),
|
Err(Error::NotFound) => Ok(None),
|
||||||
Err(e) => {
|
Err(e) => Err(DatabaseError::new(
|
||||||
info!("Error retrieving {}: {:?}", id, e);
|
format!(
|
||||||
None
|
"Failed to retrieve word {} from database: {:?}",
|
||||||
}
|
id, e
|
||||||
}
|
),
|
||||||
} else {
|
"Database Error",
|
||||||
None
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,24 +76,27 @@ impl Query {
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
name: String,
|
name: String,
|
||||||
owner: String,
|
owner: String,
|
||||||
) -> Option<Language> {
|
) -> FieldResult<Option<Language>> {
|
||||||
context.db.language(name.as_str(), owner.as_str())
|
context
|
||||||
|
.db
|
||||||
|
.language(name.as_str(), owner.as_str())
|
||||||
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[graphql(
|
#[graphql(
|
||||||
description = "Retrieve a specific user from its id",
|
description = "Retrieve a specific user from its id",
|
||||||
arguments(id(description = "Appwrite ID of a user"))
|
arguments(id(description = "Appwrite ID of a user"))
|
||||||
)]
|
)]
|
||||||
fn user(context: &Context, id: String) -> Option<User> {
|
fn user(context: &Context, id: String) -> FieldResult<Option<User>> {
|
||||||
context.db.user(id.as_str())
|
context.db.user(id.as_str()).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[graphql(
|
#[graphql(
|
||||||
description = "Retrieve a specific word from its id",
|
description = "Retrieve a specific word from its id",
|
||||||
arguments(id(description = "Unique identifier of a word"))
|
arguments(id(description = "Unique identifier of a word"))
|
||||||
)]
|
)]
|
||||||
fn word(context: &Context, id: String) -> Option<Word> {
|
fn word(context: &Context, id: String) -> FieldResult<Option<Word>> {
|
||||||
context.db.word_id(id.as_str())
|
context.db.word_id(id.as_str()).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[graphql(
|
#[graphql(
|
||||||
@ -140,10 +143,9 @@ impl Query {
|
|||||||
word: String,
|
word: String,
|
||||||
) -> FieldResult<Vec<Word>> {
|
) -> FieldResult<Vec<Word>> {
|
||||||
match Uuid::from_str(&language) {
|
match Uuid::from_str(&language) {
|
||||||
Ok(uuid) => context
|
Ok(uuid) => {
|
||||||
.db
|
context.db.words(uuid, word.as_str()).map_err(Into::into)
|
||||||
.words(uuid, word.as_str())
|
}
|
||||||
.map_err(Into::into),
|
|
||||||
Err(e) => Err(DatabaseError::new(
|
Err(e) => Err(DatabaseError::new(
|
||||||
format!("Failed to convert {} to a UUID: {:?}", language, e),
|
format!("Failed to convert {} to a UUID: {:?}", language, e),
|
||||||
"Conversion Error",
|
"Conversion Error",
|
||||||
|
Loading…
Reference in New Issue
Block a user