///Get one person
impl Handler<GetPerson> for DbExecutor {
type Result = Result<Vec<models::Person>, ServiceError>;
fn handle(&mut self, msg: GetPerson, _: &mut Self::Context) -> Self::Result {
use self::schema::people::dsl::*;
let person_name = &msg.name;
let conn: &PgConnection = &self.0.get().expect("Error to connect to database");
let items = people
.filter(name.eq(person_name))
.load::<models::Person>(conn)
.map_err(|error| ServiceError::InternalServerError(format!("{:#?}", error)))?;
let person = if !items.is_empty() {
items
} else {
ServiceError::NotFound("{} not found in database", person_name)
}
};
Ok(person)
}
}
I try to return ServiceError if the vector is empty and the vector is not however I don't know how can I do it because to use the if Pattern I need to return always the same type if not the compiler will throw the error if and else have incompatible types. Also I would like to know how can I check if items return ServiceError instead of the vector when it loads from the database
I can't test the code but I think this should work:
///Get one person
impl Handler<GetPerson> for DbExecutor {
type Result = Result<Vec<models::Person>, ServiceError>;
fn handle(&mut self, msg: GetPerson, _: &mut Self::Context) -> Self::Result {
use self::schema::people::dsl::*;
let person_name = &msg.name;
let conn: &PgConnection = &self.0.get().expect("Error to connect to database");
let items = people
.filter(name.eq(person_name))
.load::<models::Person>(conn)
.map_err(|error| ServiceError::InternalServerError(format!("{:#?}", error)))?;
if !items.is_empty() {
Ok(items)
} else {
Err(ServiceError::NotFound("{} not found in database", person_name))
}
}
}
By wrapping items in Ok() both cases will return the same type.
Thank you a lot @stefan-k and the rest who answer me this post, it works. Another question, if I get error from the database for example that the table exist, how could I check it? Because I don't think that people will return me a Vec in that case, I think it would return me the type SeviceError::InternalServerError.
let items = people
.filter(name.eq(person_name))
.load::<models::Person>(conn)
.map_err(|error| ServiceError::InternalServerError(format!("{:#?}", error)))?;
You have the underlying error in the error arg given to the map_err combinator you're using - you can inspect it inside the closure. Alternatively, you can match on it:
match people.filter(name.eq(person_name)).load::<models::Person>(conn) {
Ok(items) => ...
Err(e) => // inspect the error `e` here, depending on its type, it may expose the root problem, like table missing
If you provide a bit more detail on what exactly you'd like to do, we can give more specific advice.
Hello @vitalyd thank you for your answer. If I write to try to handler two different kind of errors the compiler fail:
match people
.filter(name.eq(person_name))
.load::<models::Person>(conn) {
Ok(items) => {
if !items.is_empty() {
Ok(items)
} else {
Err(ServiceError::NotFound(format!("{} not found in database", person_name)))
}
},
Err(e) => ServiceError::InternalServerError(format!("{:#?}", error))
}
error:
note: expected type `std::result::Result<std::vec::Vec<models::Person>, error::ServiceError>`
found type `error::ServiceError`
label: expected enum `std::result::Result`, found enum `error::ServiceError`
match people
.filter(name.eq(person_name))
.load::<models::Person>(conn) {
Ok(items) => {
if !items.is_empty() {
Ok(items)
} else {
Err(ServiceError::NotFound(format!("{} not found in database", person_name)))
}
},
Err(error) => Err(ServiceError::InternalServerError(format!("{:#?}", error)))
}