From c600f7a081f0db2471926ef28c53a8bf3f80fbe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Greinhofer?= Date: Sat, 16 Nov 2024 17:14:48 -0600 Subject: [PATCH] Implement endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Greinhofer --- entity/src/wrappers/census.rs | 21 +++++++++++++ lambdas/src/core/resource/cities/adaptor.rs | 32 ++++++++++++++++++++ lambdas/src/core/resource/cities/db.rs | 18 +++++------ lambdas/src/core/resource/cities/endpoint.rs | 16 ++++++++-- 4 files changed, 76 insertions(+), 11 deletions(-) diff --git a/entity/src/wrappers/census.rs b/entity/src/wrappers/census.rs index c3a6117..4da7958 100644 --- a/entity/src/wrappers/census.rs +++ b/entity/src/wrappers/census.rs @@ -1,5 +1,6 @@ use crate::census; use sea_orm::{prelude::Uuid, ActiveValue, IntoActiveModel}; +use serde::Deserialize; pub struct CensusPost { pub city_id: Uuid, @@ -21,6 +22,26 @@ impl IntoActiveModel for CensusPost { } } +#[derive(Deserialize)] +pub struct CensusFromCityPost { + pub fips_code: String, + pub pop_size: i32, + pub population: i32, +} + +impl IntoActiveModel for CensusFromCityPost { + fn into_active_model(self) -> census::ActiveModel { + census::ActiveModel { + id: ActiveValue::NotSet, + city_id: ActiveValue::NotSet, + created_at: ActiveValue::NotSet, + fips_code: ActiveValue::Set(self.fips_code), + pop_size: ActiveValue::Set(self.pop_size), + population: ActiveValue::Set(self.population), + } + } +} + pub struct CensusPatch { pub city_id: Option, pub fips_code: Option, diff --git a/lambdas/src/core/resource/cities/adaptor.rs b/lambdas/src/core/resource/cities/adaptor.rs index 5e9cddf..76d7273 100644 --- a/lambdas/src/core/resource/cities/adaptor.rs +++ b/lambdas/src/core/resource/cities/adaptor.rs @@ -4,6 +4,7 @@ use super::db::{ }; use crate::{database_connect, Context, ExecutionError, PageFlow, Paginatron}; use entity::wrappers::{ + census::CensusFromCityPost, city::CityPost, submission::{SubmissionPatch, SubmissionPost}, }; @@ -74,6 +75,37 @@ pub async fn get_cities_censuses_adaptor( )) } +pub async fn post_cities_census_adaptor( + country: &str, + region: &str, + name: &str, + census: CensusFromCityPost, +) -> Result { + // Set the database connection. + let db = database_connect(Some("DATABASE_URL_SECRET_ID")).await?; + + // Fetch the city. + let city = fetch_city(&db, country, region, name).await?; + if let Some(city) = city { + // Turn the post model into an active model. + let mut active_model: entity::census::ActiveModel = census.into_active_model(); + + // Update the active model. + active_model.city_id = ActiveValue::Set(city.id); + + // And insert a new entry. + let model = active_model.insert(&db).await?; + let value = json!(model); + Ok(value) + } else { + Err(ExecutionError::NotFound( + Some(country.to_string()), + region.to_string(), + name.to_string(), + )) + } +} + pub async fn get_cities_ratings_adaptor( country: &str, region: &str, diff --git a/lambdas/src/core/resource/cities/db.rs b/lambdas/src/core/resource/cities/db.rs index 045036e..5f77873 100644 --- a/lambdas/src/core/resource/cities/db.rs +++ b/lambdas/src/core/resource/cities/db.rs @@ -1,6 +1,6 @@ use entity::{census, city, country, state_region_crosswalk, submission, summary}; use sea_orm::{ - ColumnTrait, Condition, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter, + ColumnTrait, Condition, DatabaseConnection, DbErr, EntityTrait, PaginatorTrait, QueryFilter, QuerySelect, }; @@ -9,7 +9,7 @@ pub async fn fetch_city( country: &str, region: &str, name: &str, -) -> Result, sea_orm::DbErr> { +) -> Result, DbErr> { city::Entity::find_by_id((country.to_string(), region.to_string(), name.to_string())) .one(db) .await @@ -19,7 +19,7 @@ pub async fn fetch_cities( db: &DatabaseConnection, page: u64, page_size: u64, -) -> Result<(u64, Vec), sea_orm::DbErr> { +) -> Result<(u64, Vec), DbErr> { let select = city::Entity::find(); let count = select .clone() @@ -38,7 +38,7 @@ pub async fn fetch_cities_censuses( name: &str, page: u64, page_size: u64, -) -> Result<(u64, Vec<(city::Model, Option)>), sea_orm::DbErr> { +) -> Result<(u64, Vec<(city::Model, Option)>), DbErr> { let select = city::Entity::find_by_id((country.to_string(), region.to_string(), name.to_string())) .find_also_related(census::Entity); @@ -58,7 +58,7 @@ pub async fn fetch_cities_ratings( name: &str, page: u64, page_size: u64, -) -> Result<(u64, Vec<(city::Model, Option)>), sea_orm::DbErr> { +) -> Result<(u64, Vec<(city::Model, Option)>), DbErr> { let select = city::Entity::find_by_id((country.to_string(), region.to_string(), name.to_string())) .find_also_related(summary::Entity); @@ -74,7 +74,7 @@ pub async fn fetch_cities_ratings( pub async fn fetch_country( db: &DatabaseConnection, country: &str, -) -> Result, sea_orm::DbErr> { +) -> Result, DbErr> { country::Entity::find() .filter(country::Column::Name.eq(country)) .one(db) @@ -84,7 +84,7 @@ pub async fn fetch_country( pub async fn fetch_state_region_crosswalk( db: &DatabaseConnection, state: &str, -) -> Result, sea_orm::DbErr> { +) -> Result, DbErr> { state_region_crosswalk::Entity::find() .filter(state_region_crosswalk::Column::State.eq(state)) .one(db) @@ -95,7 +95,7 @@ pub async fn fetch_cities_submission( db: &DatabaseConnection, submission_id: i32, status: Option, -) -> Result, sea_orm::DbErr> { +) -> Result, DbErr> { // Filter the query if needed. let mut conditions = Condition::all(); if let Some(status) = status { @@ -114,7 +114,7 @@ pub async fn fetch_cities_submissions( status: Option, page: u64, page_size: u64, -) -> Result<(u64, Vec), sea_orm::DbErr> { +) -> Result<(u64, Vec), DbErr> { // Filter the query if needed. let mut conditions = Condition::all(); if let Some(status) = status { diff --git a/lambdas/src/core/resource/cities/endpoint.rs b/lambdas/src/core/resource/cities/endpoint.rs index f1d5d17..620f24d 100644 --- a/lambdas/src/core/resource/cities/endpoint.rs +++ b/lambdas/src/core/resource/cities/endpoint.rs @@ -1,7 +1,8 @@ use super::adaptor::{ get_cities_adaptor, get_cities_censuses_adaptor, get_cities_ratings_adaptor, get_cities_submission_adaptor, get_cities_submissions_adaptor, get_city_adaptor, - patch_cities_submission_adaptor, post_cities_adaptor, post_cities_submission_adaptor, + patch_cities_submission_adaptor, post_cities_adaptor, post_cities_census_adaptor, + post_cities_submission_adaptor, }; use crate::{core::resource::cities::CitiesPathParameters, Context, ExecutionError}; use axum::{ @@ -15,6 +16,7 @@ use axum::{ use axum_extra::extract::OptionalQuery; use effortless::api::PaginationParameters; use entity::wrappers::{ + census::CensusFromCityPost, city::CityPost, submission::{SubmissionPatch, SubmissionPost}, }; @@ -27,7 +29,7 @@ pub fn routes() -> Router { .route("/cities/:country/:region/:name", get(get_city)) .route( "/cities/:country/:region/:name/census", - get(get_city_censuses), + get(get_city_censuses).post(post_city_census), ) .route( "/cities/:country/:region/:name/ratings", @@ -141,6 +143,16 @@ async fn post_cities_submissions( .map(|v| (StatusCode::CREATED, Json(v))) } +#[axum::debug_handler] +async fn post_city_census( + Path(params): Path, + Json(census): Json, +) -> Result<(StatusCode, Json), ExecutionError> { + post_cities_census_adaptor(¶ms.country, ¶ms.region, ¶ms.name, census) + .await + .map(|v| (StatusCode::CREATED, Json(v))) +} + #[cfg(test)] mod tests { use axum::extract::Query;