Skip to content

Commit

Permalink
Implement Entity Wrappers
Browse files Browse the repository at this point in the history
Implements entity wrappers to be used in the API instead of using the
models directly. Each wrapper also implement the `IntoActiveModel` trait
to handle to conversion between the Wrapper and the ActiveModel.

Signed-off-by: Rémy Greinhofer <[email protected]>
  • Loading branch information
rgreinho committed Jan 7, 2024
1 parent 159b3a5 commit e19ee7e
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 34 deletions.
2 changes: 2 additions & 0 deletions entity/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
mod entities;
pub mod wrappers;

pub use entities::{prelude::*, *};
128 changes: 128 additions & 0 deletions entity/src/wrappers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use crate::entities::submission;
use sea_orm::{ActiveValue, IntoActiveModel};
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Submission {
pub first_name: String,
pub last_name: String,
pub title: Option<String>,
pub organization: Option<String>,
pub email: String,
pub country: String,
pub city: String,
pub region: Option<String>,
pub fips_code: String,
pub consent: bool,
}

impl IntoActiveModel<submission::ActiveModel> for Submission {
fn into_active_model(self) -> submission::ActiveModel {
submission::ActiveModel {
id: ActiveValue::NotSet,
first_name: ActiveValue::Set(self.first_name),
last_name: ActiveValue::Set(self.last_name),
title: self
.title
.map_or(ActiveValue::NotSet, |v| ActiveValue::Set(Some(v))),
organization: self
.organization
.map_or(ActiveValue::NotSet, |v| ActiveValue::Set(Some(v))),
email: ActiveValue::Set(self.email),
country: ActiveValue::Set(self.country),
city: ActiveValue::Set(self.city),
region: self
.region
.map_or(ActiveValue::NotSet, |v| ActiveValue::Set(Some(v))),
fips_code: ActiveValue::Set(self.fips_code),
consent: ActiveValue::Set(self.consent),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_submission_into_active_model_full() {
let first_name = "John".to_string();
let last_name = "Doe".to_string();
let title = Some("Director".to_owned());
let organization = Some("ACME".to_string());
let email = "[email protected]".to_string();
let country = "usa".to_string();
let city = "austin".to_string();
let region = Some("texas".to_string());
let fips_code = "0123456".to_string();
let consent = true;
let wrapper = Submission {
first_name: first_name.clone(),
last_name: last_name.clone(),
title: title.clone(),
organization: organization.clone(),
email: email.clone(),
country: country.clone(),
city: city.clone(),
region: region.clone(),
fips_code: fips_code.clone(),
consent,
};
let active_model = wrapper.into_active_model();
let expected = submission::ActiveModel {
id: ActiveValue::NotSet,
first_name: ActiveValue::Set(first_name),
last_name: ActiveValue::Set(last_name),
title: ActiveValue::Set(title),
organization: ActiveValue::Set(organization),
email: ActiveValue::Set(email),
country: ActiveValue::Set(country),
city: ActiveValue::Set(city),
region: ActiveValue::Set(region),
fips_code: ActiveValue::Set(fips_code),
consent: ActiveValue::Set(consent),
};
assert_eq!(active_model, expected);
}

#[test]
fn test_submission_into_active_model_required_only() {
let first_name = "John".to_string();
let last_name = "Doe".to_string();
let title = None;
let organization = None;
let email = "[email protected]".to_string();
let country = "usa".to_string();
let city = "austin".to_string();
let region = None;
let fips_code = "0123456".to_string();
let consent = true;
let wrapper = Submission {
first_name: first_name.clone(),
last_name: last_name.clone(),
title: title.clone(),
organization: organization.clone(),
email: email.clone(),
country: country.clone(),
city: city.clone(),
region: region.clone(),
fips_code: fips_code.clone(),
consent,
};
let active_model = wrapper.into_active_model();
let expected = submission::ActiveModel {
id: ActiveValue::NotSet,
first_name: ActiveValue::Set(first_name),
last_name: ActiveValue::Set(last_name),
title: ActiveValue::NotSet,
organization: ActiveValue::NotSet,
email: ActiveValue::Set(email),
country: ActiveValue::Set(country),
city: ActiveValue::Set(city),
region: ActiveValue::NotSet,
fips_code: ActiveValue::Set(fips_code),
consent: ActiveValue::Set(consent),
};
assert_eq!(active_model, expected);
}
}
39 changes: 5 additions & 34 deletions lambdas/src/submissions/post-submissions-city.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,13 @@
use dotenv::dotenv;
use entity::submission;
use entity::{prelude::*, wrappers};
use lambda_http::{
http::StatusCode, run, service_fn, Body, Error, IntoResponse, Request, Response,
};
use lambdas::{database_connect, get_apigw_request_id, APIError, APIErrorSource, APIErrors};
use sea_orm::{ActiveValue, EntityTrait};
use serde::{Deserialize, Serialize};
use sea_orm::{EntityTrait, IntoActiveModel};
use serde_json::json;
use tracing::info;

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct SubmissionWrapper {
pub first_name: String,
pub last_name: String,
pub title: Option<String>,
pub organization: Option<String>,
pub email: String,
pub country: String,
pub city: String,
pub region: Option<String>,
pub fips_code: String,
pub consent: bool,
}

async fn function_handler(event: Request) -> Result<Response<Body>, Error> {
dotenv().ok();

Expand All @@ -34,7 +19,7 @@ async fn function_handler(event: Request) -> Result<Response<Body>, Error> {
let body = event.body();
let body_str = std::str::from_utf8(body).expect("invalid utf-8 sequence");
info!(body_str);
let wrapper = match serde_json::from_str::<SubmissionWrapper>(body_str) {
let wrapper = match serde_json::from_str::<wrappers::Submission>(body_str) {
Ok(model) => model,
Err(e) => {
let api_error = APIError::new(
Expand All @@ -49,28 +34,14 @@ async fn function_handler(event: Request) -> Result<Response<Body>, Error> {
};

// Turn the model wrapper into an active model and unset the primary key.
let active_submission = submission::ActiveModel {
id: ActiveValue::NotSet,
first_name: ActiveValue::Set(wrapper.first_name),
last_name: ActiveValue::Set(wrapper.last_name),
title: ActiveValue::Set(wrapper.title),
organization: ActiveValue::Set(wrapper.organization),
email: ActiveValue::Set(wrapper.email),
country: ActiveValue::Set(wrapper.country),
city: ActiveValue::Set(wrapper.city),
region: ActiveValue::Set(wrapper.region),
fips_code: ActiveValue::Set(wrapper.fips_code),
consent: ActiveValue::Set(wrapper.consent),
};
let active_submission = wrapper.into_active_model();
info!(
"inserting Submission into database: {:?}",
active_submission
);

// Insert the submission into the database.
let res = submission::Entity::insert(active_submission)
.exec(&db)
.await?;
let res = Submission::insert(active_submission).exec(&db).await?;
Ok(json!(res.last_insert_id).into_response().await)
}

Expand Down

0 comments on commit e19ee7e

Please sign in to comment.