Skip to content

Commit

Permalink
add entity_api implementation of find_by_id
Browse files Browse the repository at this point in the history
Also starts to consider error handling patterns. Not sure if this is ultimately where we will go as the usage does not feel quite right but will continue to play with it.
  • Loading branch information
calebbourg committed Nov 21, 2023
1 parent 4e25708 commit 820a507
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions entity_api/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use std::error::Error as StdError;
use std::fmt;

use sea_orm::error::DbErr;

/// Errors while executing operations related to entities.
/// The intent is to categorize errors into two major types:
/// * Errors related to data. Ex DbError::RecordNotFound
/// * Errors related to interactions with the database itself. Ex DbError::Conn
#[derive(Debug)]
pub struct Error {
// Underlying error emitted from seaORM internals
pub inner: DbErr,
// Enum representing which category of error
pub error_type: EntityApiErrorType,
}

#[derive(Debug)]
pub enum EntityApiErrorType {
// Record not found
RecordNotFound,
// Record not updated
RecordNotUpdated,
// Errors related to interactions with the database itself. Ex DbError::Conn
SystemError,
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Entity API Error: {:?}", self)
}
}

impl StdError for Error {}

impl From<DbErr> for Error {
fn from(err: DbErr) -> Self {
match err {
DbErr::RecordNotFound(_) => Error {
inner: err,
error_type: EntityApiErrorType::RecordNotFound,
},
DbErr::RecordNotUpdated => Error {
inner: err,
error_type: EntityApiErrorType::RecordNotUpdated,
},
DbErr::ConnectionAcquire(_) => Error {
inner: err,
error_type: EntityApiErrorType::SystemError,
},
DbErr::Conn(_) => Error {
inner: err,
error_type: EntityApiErrorType::SystemError,
},
DbErr::Exec(_) => Error {
inner: err,
error_type: EntityApiErrorType::SystemError,
},
_ => Error {
inner: err,
error_type: EntityApiErrorType::SystemError,
},
}
}
}
1 change: 1 addition & 0 deletions entity_api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use sea_orm::DatabaseConnection;

pub mod error;
pub mod organization;

pub async fn seed_database(db: &DatabaseConnection) {
Expand Down
10 changes: 9 additions & 1 deletion entity_api/src/organization.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
use super::error::Error;
use entity::organization;
use organization::{Entity, Model};
use sea_orm::{entity::prelude::*, ActiveValue, DatabaseConnection};
use serde_json::json;

pub async fn find_all(db: &DatabaseConnection) -> Vec<Model> {
Entity::find().all(db).await.unwrap_or(vec![])
Entity::find().all(db).await.unwrap_or(vec![])
}

pub async fn find_by_id(db: &DatabaseConnection, id: i32) -> Result<Option<Model>, Error> {
match Entity::find_by_id(id).one(db).await {
Ok(result) => Ok(result),
Err(error) => Err(error.into()),
}
}

pub(crate) async fn seed_database(db: &DatabaseConnection) {
Expand Down
1 change: 1 addition & 0 deletions web/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ axum = "0.6.20"
log = "0.4"
tower-http = { version = "0.4.4", features = ["fs"] }
serde_json = "1.0.107"
serde = { version = "1.0", features = ["derive"] }

[dependencies.sea-orm]
version = "0.12.3" # sea-orm version
Expand Down
14 changes: 8 additions & 6 deletions web/src/controller/organization_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use axum::response::IntoResponse;
use axum::Json;
use entity::organization;
use entity::organization::Entity as Organization;
use entity_api::organization as OrganizationApi;
use sea_orm::entity::EntityTrait;
use sea_orm::ActiveModelTrait;
use sea_orm::ActiveValue::{NotSet, Set};
use sea_orm::DeleteResult;
use serde_json::json;
use entity_api::organization as OrganizationApi;

extern crate log;
use log::*;
Expand All @@ -22,7 +22,8 @@ impl OrganizationController {
/// --request GET \
/// http://localhost:3000/organizations
pub async fn index(State(app_state): State<AppState>) -> impl IntoResponse {
let organizations = OrganizationApi::find_all(&app_state.database_connection.unwrap()).await;
let organizations =
OrganizationApi::find_all(&app_state.database_connection.unwrap()).await;

Json(organizations)
}
Expand All @@ -34,10 +35,11 @@ impl OrganizationController {
pub async fn read(State(app_state): State<AppState>, Path(id): Path<i32>) -> impl IntoResponse {
debug!("GET Organization by id: {}", id);

let organization: Option<organization::Model> = organization::Entity::find_by_id(id)
.one(&app_state.database_connection.unwrap())
.await
.unwrap_or_default();
let organization: Result<Option<organization::Model>, Error> =
match OrganizationApi::find_by_id(&app_state.database_connection.unwrap(), id).await {
Ok(result) => Ok(result),
Err(error) => Err(error.into()),
};

Json(organization)
}
Expand Down
31 changes: 27 additions & 4 deletions web/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
use std::error::Error as StdError;

use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use serde::Serialize;

use entity_api::error::EntityApiErrorType;
use entity_api::error::Error as EntityApiError;

pub type Result<T> = core::result::Result<T, Error>;

#[derive(Debug)]
#[derive(Debug, Serialize)]

pub enum Error {
InternalServer,
EntityNotFound,
UnprocessableEntity,
}

impl StdError for Error {}

impl std::fmt::Display for Error {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> core::result::Result<(), std::fmt::Error> {
write!(fmt, "{self:?}")
}
}

impl IntoResponse for Error {
Expand All @@ -16,12 +32,19 @@ impl IntoResponse for Error {
(StatusCode::INTERNAL_SERVER_ERROR, "INTERNAL SERVER ERROR").into_response()
}
Error::EntityNotFound => (StatusCode::NOT_FOUND, "ENTITY NOT FOUND").into_response(),
Error::UnprocessableEntity => {
(StatusCode::UNPROCESSABLE_ENTITY, "UNPROCESSABLE ENTITY").into_response()
}
}
}
}

impl std::fmt::Display for Error {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> core::result::Result<(), std::fmt::Error> {
write!(fmt, "{self:?}")
impl From<EntityApiError> for Error {
fn from(err: EntityApiError) -> Self {
match err.error_type {
EntityApiErrorType::RecordNotFound => Error::EntityNotFound,
EntityApiErrorType::RecordNotUpdated => Error::UnprocessableEntity,
EntityApiErrorType::SystemError => Error::InternalServer,
}
}
}

0 comments on commit 820a507

Please sign in to comment.