diff --git a/sql/project/fetch_with_realtor_id.sql b/sql/project/fetch_with_realtor_id.sql new file mode 100644 index 0000000..54857fc --- /dev/null +++ b/sql/project/fetch_with_realtor_id.sql @@ -0,0 +1,19 @@ +SELECT + id, + title, + description, + realtor_id, + media as "media: _", + project_condition as "project_condition: _", + project_type as "project_type: _", + project_state as "project_state: _", + country, + city, + district, + admin_tag, + floors, + finish_date, + order_index, + time_created, + last_updated +FROM project WHERE realtor_id = $1; diff --git a/sql/property/fetch_with_realtor_id.sql b/sql/property/fetch_with_realtor_id.sql new file mode 100644 index 0000000..4731e5d --- /dev/null +++ b/sql/property/fetch_with_realtor_id.sql @@ -0,0 +1,18 @@ +SELECT + id, + project_id, + realtor_id, + media as "media: _", + property_type as "property_type: _", + property_sale_type as "property_sale_type: _", + country, + city, + district, + price_usd, + rooms, + bathrooms, + area, + admin_tag, + time_created, + last_updated +FROM property WHERE realtor_id = $1; \ No newline at end of file diff --git a/sqlx-data.json b/sqlx-data.json index 48aa927..d614f7f 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -116,6 +116,122 @@ }, "query": "SELECT \n id,\n title,\n description,\n realtor_id,\n media as \"media: _\",\n project_condition as \"project_condition: _\",\n project_type as \"project_type: _\",\n project_state as \"project_state: _\",\n country,\n city, \n district,\n admin_tag,\n floors,\n finish_date,\n order_index,\n time_created,\n last_updated\nFROM project WHERE id = $1;\n" }, + "066b243662a9077b8c5ce72277930c746558b1725a15faa7c235b63b00fde59c": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "title", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "description", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "realtor_id", + "ordinal": 3, + "type_info": "Uuid" + }, + { + "name": "media: _", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "project_condition: _", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "project_type: _", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "project_state: _", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "country", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "city", + "ordinal": 9, + "type_info": "Varchar" + }, + { + "name": "district", + "ordinal": 10, + "type_info": "Varchar" + }, + { + "name": "admin_tag", + "ordinal": 11, + "type_info": "Varchar" + }, + { + "name": "floors", + "ordinal": 12, + "type_info": "Int2" + }, + { + "name": "finish_date", + "ordinal": 13, + "type_info": "Date" + }, + { + "name": "order_index", + "ordinal": 14, + "type_info": "Int4" + }, + { + "name": "time_created", + "ordinal": 15, + "type_info": "Timestamptz" + }, + { + "name": "last_updated", + "ordinal": 16, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Uuid" + ] + } + }, + "query": "SELECT \n id,\n title,\n description,\n realtor_id,\n media as \"media: _\",\n project_condition as \"project_condition: _\",\n project_type as \"project_type: _\",\n project_state as \"project_state: _\",\n country,\n city, \n district,\n admin_tag,\n floors,\n finish_date,\n order_index,\n time_created,\n last_updated\nFROM project WHERE realtor_id = $1;\n" + }, "1de871eb06903280d3be4e4ef8f67cde596807784e726ff62d03c2c9f6d6ba76": { "describe": { "columns": [ @@ -761,6 +877,116 @@ }, "query": "INSERT INTO view (\n id, thing_id, thing_pk, trackable_id, time_created\n) VALUES (\n $1, $2, $3, $4, $5\n) RETURNING \nid, thing_id, thing_pk as \"thing_pk: _\", trackable_id, time_created" }, + "9affd78ec46e47dc9b7239e41c6e88b3aa96f48bf95ffe8faae35fcee6f5af9f": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "project_id", + "ordinal": 1, + "type_info": "Uuid" + }, + { + "name": "realtor_id", + "ordinal": 2, + "type_info": "Uuid" + }, + { + "name": "media: _", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "property_type: _", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "property_sale_type: _", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "country", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "city", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "district", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "price_usd", + "ordinal": 9, + "type_info": "Float8" + }, + { + "name": "rooms", + "ordinal": 10, + "type_info": "Int2" + }, + { + "name": "bathrooms", + "ordinal": 11, + "type_info": "Float4" + }, + { + "name": "area", + "ordinal": 12, + "type_info": "Float4" + }, + { + "name": "admin_tag", + "ordinal": 13, + "type_info": "Varchar" + }, + { + "name": "time_created", + "ordinal": 14, + "type_info": "Timestamptz" + }, + { + "name": "last_updated", + "ordinal": 15, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + true, + false, + false + ], + "parameters": { + "Left": [ + "Uuid" + ] + } + }, + "query": "SELECT \n id,\n project_id,\n realtor_id,\n media as \"media: _\",\n property_type as \"property_type: _\",\n property_sale_type as \"property_sale_type: _\",\n country,\n city,\n district,\n price_usd,\n rooms,\n bathrooms,\n area,\n admin_tag,\n time_created,\n last_updated\nFROM property WHERE realtor_id = $1;" + }, "a6525881c04a3ddf038d566b8a41dc2e4670a20c0c6e4a0687a927538661db56": { "describe": { "columns": [ diff --git a/src/dao/project.rs b/src/dao/project.rs index fc34d22..f28c1f4 100644 --- a/src/dao/project.rs +++ b/src/dao/project.rs @@ -1,8 +1,8 @@ use realtor_lp_types::domain::project::Project; -use sqlx::PgPool; +use sqlx::{PgPool, Transaction, Postgres}; use uuid::Uuid; -pub async fn insert_project(conn: &PgPool, project: Project) -> Result { +pub async fn insert_project<'a>(transaction: &mut Transaction<'a, Postgres>, project: Project) -> Result { sqlx::query_file_as!( Project, "sql/project/insert.sql", @@ -23,7 +23,7 @@ pub async fn insert_project(conn: &PgPool, project: Project) -> Result Result { +pub async fn fetch_with_realtor_id( + conn: &PgPool, + realtor_id: &Uuid, +) -> Result, sqlx::Error> { + sqlx::query_file_as!(Project, "sql/project/fetch_with_realtor_id.sql", realtor_id) + .fetch_all(conn) + .await +} + +pub async fn update_project<'a>(transaction: &mut Transaction<'a, Postgres>, project: Project) -> Result { sqlx::query_file_as!( Project, "sql/project/update.sql", @@ -57,6 +66,6 @@ pub async fn update_project(conn: &PgPool, project: Project) -> Result Result { +pub async fn insert_property<'a>(transaction: &mut Transaction<'a, Postgres>, property: Property) -> Result { sqlx::query_file_as!( Property, "sql/property/insert.sql", @@ -22,7 +22,7 @@ pub async fn insert_property(conn: &PgPool, property: Property) -> Result Result { +pub async fn fetch_with_realtor_id( + conn: &PgPool, + realtor_id: &Uuid, +) -> Result, sqlx::Error> { + sqlx::query_file_as!(Property, "sql/property/fetch_with_realtor_id.sql", realtor_id) + .fetch_all(conn) + .await +} + +pub async fn update_property<'a>(transaction: &mut Transaction<'a, Postgres>, property: Property) -> Result { sqlx::query_file_as!( Property, "sql/property/update.sql", @@ -55,6 +64,6 @@ pub async fn update_property(conn: &PgPool, property: Property) -> Result( + tx: &mut Transaction<'a, Postgres>, trackable: Trackable, ) -> Result { sqlx::query_file_as!( @@ -17,7 +17,7 @@ pub async fn insert_trackable( trackable.user_agent, trackable.time_created ) - .fetch_one(conn) + .fetch_one(tx) .await } diff --git a/src/routes/click.rs b/src/routes/click.rs index 8b13789..00492d6 100644 --- a/src/routes/click.rs +++ b/src/routes/click.rs @@ -1 +1,12 @@ +use actix_web_utils::extensions::typed_response::TypedHttpResponse; +use realtor_lp_types::{domain::click::Click, dto::payloads::click::ClickForCreationPayload}; +use sqlx::PgPool; +use crate::{success, handle_tx, handle_db_write_op, dao}; + + +pub async fn new_click(conn: &PgPool, click: ClickForCreationPayload) -> TypedHttpResponse<()> { + let mut transaction = handle_tx!(conn.begin()); + handle_db_write_op!(dao::click::insert_click(conn, click.into()), transaction); + success!(()) +} \ No newline at end of file diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 0aa36e4..6727f6b 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,7 +1,14 @@ +#[allow(unused)] pub mod click; +#[allow(unused)] pub mod main_router; +#[allow(unused)] pub mod project; +#[allow(unused)] pub mod property; +#[allow(unused)] pub mod realtor; +#[allow(unused)] pub mod trackable; +#[allow(unused)] pub mod view; diff --git a/src/routes/project.rs b/src/routes/project.rs index 8b13789..e9a5f5c 100644 --- a/src/routes/project.rs +++ b/src/routes/project.rs @@ -1 +1,17 @@ +use actix_web_utils::extensions::typed_response::TypedHttpResponse; +use realtor_lp_types::{domain::project::Project, dto::payloads::project::ProjectForCreationPayload}; +use sqlx::PgPool; +use uuid::Uuid; +use crate::{success, handle_db_write_op, handle_tx, dao, handle_db_read_op, unwrap_or_not_found}; + + +pub async fn create_project(conn: &PgPool, project: ProjectForCreationPayload) -> TypedHttpResponse { + unwrap_or_not_found!(handle_db_read_op!(dao::realtor::get_realtor_with_id(conn, &project.realtor_id)), "Realtor"); + let mut transaction = handle_tx!(conn.begin()); + success!(handle_db_write_op!(dao::project::insert_project(&mut transaction, project.into()), transaction)); +} + +pub async fn fetch_realtor_projects(conn: &PgPool, realtor_id: Uuid) -> TypedHttpResponse> { + success!(handle_db_read_op!(dao::project::fetch_with_realtor_id(conn, &realtor_id))) +} \ No newline at end of file diff --git a/src/routes/property.rs b/src/routes/property.rs index 8b13789..b0811cc 100644 --- a/src/routes/property.rs +++ b/src/routes/property.rs @@ -1 +1,44 @@ +use actix_web_utils::extensions::typed_response::TypedHttpResponse; +use err::MessageResource; +use realtor_lp_types::{dto::payloads::property::PropertyForCreationPayload, domain::property::Property}; +use sqlx::PgPool; +use uuid::Uuid; +use crate::{handle_tx, handle_db_write_op, dao, success, unwrap_or_not_found, handle_db_read_op}; + + +pub async fn create_property(conn: &PgPool, property: PropertyForCreationPayload) -> TypedHttpResponse { + let mut transaction = handle_tx!(conn.begin()); + let realtor = unwrap_or_not_found!(handle_db_read_op!(dao::realtor::get_realtor_with_id(conn, &property.realtor_id)), "Realtor"); + + // Check for project existing + match property.project_id { + Some(project_id) => { + let project = unwrap_or_not_found!(handle_db_read_op!(dao::project::get_project_with_id(conn, &project_id)), "Project"); + if project.realtor_id != realtor.id { + return TypedHttpResponse::return_standard_error(400, MessageResource::new_from_str("Realtor Id in project does not match realtor id in property.")) + } + }, + None => {}, + }; + success!(handle_db_write_op!(dao::property::insert_property(&mut transaction, property.into()), transaction)) +} + +pub async fn udpate_property(conn: &PgPool, property_id: Uuid, property: PropertyForCreationPayload) -> TypedHttpResponse { + let mut transaction = handle_tx!(conn.begin()); + let realtor = unwrap_or_not_found!(handle_db_read_op!(dao::realtor::get_realtor_with_id(conn, &property.realtor_id)), "Realtor"); + + // Check for project existing + match property.project_id { + Some(project_id) => { + let project = unwrap_or_not_found!(handle_db_read_op!(dao::project::get_project_with_id(conn, &project_id)), "Project"); + if project.realtor_id != realtor.id { + return TypedHttpResponse::return_standard_error(400, MessageResource::new_from_str("Realtor Id in project does not match realtor id in property.")) + } + }, + None => {}, + }; + let mut property_insertable: Property = property.into(); + property_insertable.id = property_id; + success!(handle_db_write_op!(dao::property::update_property(&mut transaction, property_insertable), transaction)) +} \ No newline at end of file diff --git a/src/routes/realtor.rs b/src/routes/realtor.rs index 8b13789..eb16feb 100644 --- a/src/routes/realtor.rs +++ b/src/routes/realtor.rs @@ -1 +1,27 @@ +use actix_web_utils::extensions::typed_response::TypedHttpResponse; +use realtor_lp_types::{domain::realtor::Realtor, dto::payloads::realtor::RealtorForCreationPayload}; +use sqlx::PgPool; +use uuid::Uuid; +use crate::{success, handle_tx, dao, handle_db_write_op, handle_db_read_op, unwrap_or_not_found}; + + +pub async fn new_realtor_profile(conn: &PgPool, realtor: RealtorForCreationPayload) -> TypedHttpResponse { + let mut transaction = handle_tx!(conn.begin()); + success!(handle_db_write_op!(dao::realtor::insert_realtor(conn, realtor.into()), transaction)); +} + +pub async fn update_realtor_profile(conn: &PgPool, realtor_id: Uuid, realtor: RealtorForCreationPayload) -> TypedHttpResponse { + let mut transaction = handle_tx!(conn.begin()); + let mut realtor_insertable: Realtor = realtor.into(); + realtor_insertable.id = realtor_id; + success!(handle_db_write_op!(dao::realtor::update_realtor(conn, realtor_insertable), transaction)); +} + +pub async fn get_realtor_by_shortcode(conn: &PgPool, realtor_shortcode: String,) -> TypedHttpResponse { + success!(unwrap_or_not_found!(handle_db_read_op!(dao::realtor::get_realtor_with_shortcode(conn, &realtor_shortcode)), "Realtors")) +} + +pub async fn get_realtor_with_id(conn: &PgPool, realtor_id: Uuid) -> TypedHttpResponse { + success!(unwrap_or_not_found!(handle_db_read_op!(dao::realtor::get_realtor_with_id(conn, &realtor_id)), "Realtors")) +} \ No newline at end of file diff --git a/src/routes/trackable.rs b/src/routes/trackable.rs index 8b13789..a2264bf 100644 --- a/src/routes/trackable.rs +++ b/src/routes/trackable.rs @@ -1 +1,17 @@ +use actix_web_utils::extensions::typed_response::TypedHttpResponse; +use realtor_lp_types::{domain::trackable::Trackable, dto::payloads::trackable::TrackableForCreationPayload}; +use sqlx::PgPool; +use uuid::Uuid; +use crate::{dao, success, handle_tx, handle_db_write_op, handle_db_read_op, unwrap_or_not_found}; + + +pub async fn create_trackable_profile(conn: &PgPool, trackable: TrackableForCreationPayload) -> TypedHttpResponse { + let mut transaction = handle_tx!(conn.begin()); + let persisted_trackable = handle_db_write_op!(dao::trackable::insert_trackable(&mut transaction, trackable.into()), transaction); + success!(persisted_trackable) +} + +pub async fn validate_trackable_id(conn: &PgPool, trackable_id: Uuid) -> TypedHttpResponse { + success!(unwrap_or_not_found!(handle_db_read_op!(dao::trackable::get_trackable_with_id(conn, &trackable_id)), "Trackables")) +} \ No newline at end of file