Added arrangement, more property fields, and impls
This commit is contained in:
parent
1b4600ec21
commit
8de10c4e3b
|
@ -0,0 +1,56 @@
|
||||||
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
|
use sqlx::{Postgres, postgres::{PgArgumentBuffer, PgValueRef, PgTypeInfo}, encode::IsNull, error::BoxDynError};
|
||||||
|
|
||||||
|
use crate::domain::error::FromStrError;
|
||||||
|
|
||||||
|
use super::ArrangementType;
|
||||||
|
|
||||||
|
impl Display for ArrangementType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ArrangementType::Rent => write!(f, "Rent"),
|
||||||
|
ArrangementType::Sale => write!(f, "Sale"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ArrangementType {
|
||||||
|
type Err = FromStrError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"Rent" => Ok(Self::Rent),
|
||||||
|
"Sale" => Ok(Self::Sale),
|
||||||
|
_ => Err(FromStrError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "sqlx")]
|
||||||
|
impl sqlx::Encode<'_, Postgres> for ArrangementType {
|
||||||
|
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||||
|
let binding = serde_json::to_string(self).unwrap();
|
||||||
|
<&str as sqlx::Encode<Postgres>>::encode(&binding, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "sqlx")]
|
||||||
|
impl sqlx::Decode<'_, Postgres> for ArrangementType {
|
||||||
|
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||||
|
let column = value.as_str()?;
|
||||||
|
match serde_json::from_str(column) {
|
||||||
|
Ok(listing_state) => Ok(listing_state),
|
||||||
|
Err(error) => Err(Box::new(error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "sqlx")]
|
||||||
|
impl sqlx::Type<Postgres> for ArrangementType {
|
||||||
|
fn type_info() -> PgTypeInfo {
|
||||||
|
PgTypeInfo::with_name("VARCHAR")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||||
|
*ty == Self::type_info()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
pub mod impls;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum ArrangementType {
|
||||||
|
#[default]
|
||||||
|
Rent,
|
||||||
|
Sale,
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
|
use sqlx::{Postgres, postgres::{PgArgumentBuffer, PgValueRef, PgTypeInfo}, encode::IsNull, error::BoxDynError};
|
||||||
|
|
||||||
|
use crate::domain::error::FromStrError;
|
||||||
|
|
||||||
|
use super::FrameFormat;
|
||||||
|
|
||||||
|
|
||||||
|
impl Display for FrameFormat {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
FrameFormat::Landscape => write!(f, "Landscape"),
|
||||||
|
FrameFormat::Instagram => write!(f, "Instagram"),
|
||||||
|
FrameFormat::Portrait => write!(f, "Portrait"),
|
||||||
|
FrameFormat::Square => write!(f, "Square")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for FrameFormat {
|
||||||
|
type Err = FromStrError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"Landscape" => Ok(Self::Landscape),
|
||||||
|
"Instagram" => Ok(Self::Instagram),
|
||||||
|
"Portrait" => Ok(Self::Portrait),
|
||||||
|
"Square" => Ok(Self::Square),
|
||||||
|
_ => Err(FromStrError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "sqlx")]
|
||||||
|
impl sqlx::Encode<'_, Postgres> for FrameFormat {
|
||||||
|
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||||
|
let binding = self.to_string();
|
||||||
|
<&str as sqlx::Encode<Postgres>>::encode(&binding, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "sqlx")]
|
||||||
|
impl sqlx::Decode<'_, Postgres> for FrameFormat {
|
||||||
|
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||||
|
let column = value.as_str()?;
|
||||||
|
match Self::from_str(column) {
|
||||||
|
Ok(listing_state) => Ok(listing_state),
|
||||||
|
Err(error) => Err(Box::new(error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "sqlx")]
|
||||||
|
impl sqlx::Type<Postgres> for FrameFormat {
|
||||||
|
fn type_info() -> PgTypeInfo {
|
||||||
|
PgTypeInfo::with_name("VARCHAR")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||||
|
*ty == Self::type_info()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
pub mod impls;
|
||||||
|
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
/// Allows realtors to pick the size of each property to fit the carroussel.
|
||||||
|
/// This is easy for agents to use and is better than having them pick what size everything should be.
|
||||||
|
/// All sizes are in w x h in squares
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum FrameFormat {
|
||||||
|
/// 2x1
|
||||||
|
#[default]
|
||||||
|
Landscape,
|
||||||
|
/// 2x2
|
||||||
|
Instagram,
|
||||||
|
/// 1x2
|
||||||
|
Portrait,
|
||||||
|
// 1x1
|
||||||
|
Square,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameFormat {
|
||||||
|
pub fn get_width(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
FrameFormat::Landscape => 2,
|
||||||
|
FrameFormat::Instagram => 2,
|
||||||
|
FrameFormat::Portrait => 1,
|
||||||
|
FrameFormat::Square => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get_height(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
FrameFormat::Landscape => 1,
|
||||||
|
FrameFormat::Instagram => 2,
|
||||||
|
FrameFormat::Portrait => 2,
|
||||||
|
FrameFormat::Square => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,9 @@ pub mod realtor;
|
||||||
pub mod thing_pk;
|
pub mod thing_pk;
|
||||||
pub mod trackable;
|
pub mod trackable;
|
||||||
pub mod view;
|
pub mod view;
|
||||||
|
pub mod format;
|
||||||
|
pub mod price;
|
||||||
|
pub mod arrangement;
|
||||||
|
pub mod project_type;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod project_type;
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use super::arrangement::ArrangementType;
|
||||||
|
|
||||||
|
|
||||||
|
/// This is what lets the backend know what a property sells for/rents for.
|
||||||
|
/// Store at least one of these per Property.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub struct PropertyPrice {
|
||||||
|
#[serde(rename = "propertyId")]
|
||||||
|
pub property_id: Uuid,
|
||||||
|
pub price: f64,
|
||||||
|
pub currency: String,
|
||||||
|
pub arrangement: ArrangementType,
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use super::{media::MediaList, property_sale_type::PropertySaleType, property_type::PropertyType};
|
use super::{media::MediaList, property_sale_type::PropertySaleType, property_type::PropertyType, format::FrameFormat};
|
||||||
|
|
||||||
/// A property can belong to a project, or not. It should always belong to a realtor.
|
/// A property can belong to a project, or not. It should always belong to a realtor.
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, PartialOrd)]
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, PartialOrd)]
|
||||||
|
@ -17,20 +17,22 @@ pub struct Property {
|
||||||
pub property_type: PropertyType,
|
pub property_type: PropertyType,
|
||||||
#[serde(rename = "propertySaleType")]
|
#[serde(rename = "propertySaleType")]
|
||||||
pub property_sale_type: PropertySaleType,
|
pub property_sale_type: PropertySaleType,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
pub country: String,
|
||||||
pub country: Option<String>,
|
pub city: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
pub district: String,
|
||||||
pub city: Option<String>,
|
/// This gives the realtor the option to order the projects/properties
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "orderIndex")]
|
||||||
pub district: Option<String>,
|
pub order_index: i32,
|
||||||
#[serde(rename = "priceUsd")]
|
#[serde(rename = "thumbnailFormat")]
|
||||||
pub price_usd: f64,
|
pub thumbnail_format: FrameFormat,
|
||||||
/// Amount of rooms in unit
|
/// Amount of rooms in unit
|
||||||
pub rooms: i16,
|
pub rooms: i16,
|
||||||
/// Amount of bathrooms in unit
|
/// Amount of bathrooms in unit
|
||||||
pub bathrooms: f32,
|
pub bathrooms: f32,
|
||||||
/// In meters squared
|
/// In meters squared
|
||||||
pub area: f32,
|
pub area: f32,
|
||||||
|
#[serde(rename = "parkingSpots")]
|
||||||
|
pub parking_spots: i16,
|
||||||
#[serde(rename = "adminTag")]
|
#[serde(rename = "adminTag")]
|
||||||
pub admin_tag: Option<String>,
|
pub admin_tag: Option<String>,
|
||||||
#[serde(rename = "timeCreated")]
|
#[serde(rename = "timeCreated")]
|
||||||
|
|
|
@ -54,7 +54,7 @@ impl sqlx::Decode<'_, Postgres> for ThingPk {
|
||||||
#[cfg(feature = "sqlx")]
|
#[cfg(feature = "sqlx")]
|
||||||
impl sqlx::Type<Postgres> for ThingPk {
|
impl sqlx::Type<Postgres> for ThingPk {
|
||||||
fn type_info() -> PgTypeInfo {
|
fn type_info() -> PgTypeInfo {
|
||||||
PgTypeInfo::with_name("TEXT")
|
PgTypeInfo::with_name("VARCHAR")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)]
|
||||||
|
pub enum Filter {
|
||||||
|
Country(String),
|
||||||
|
City(String),
|
||||||
|
District(String),
|
||||||
|
|
||||||
|
PriceGreaterThan(f64),
|
||||||
|
PriceLessThan(f64),
|
||||||
|
|
||||||
|
Rooms(i32),
|
||||||
|
Bathrooms(i32),
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
pub mod payloads;
|
pub mod payloads;
|
||||||
|
pub mod filter;
|
|
@ -2,10 +2,8 @@ use chrono::{NaiveDate, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::domain::{
|
use crate::domain::{project_type::ProjectType, project_state::ProjectState, project_condition::ProjectCondition, media::MediaList, project::Project};
|
||||||
media::MediaList, project::Project, project_condition::ProjectCondition,
|
|
||||||
project_state::ProjectState, project_type::ProjectType,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct ProjectForCreationPayload {
|
pub struct ProjectForCreationPayload {
|
||||||
|
@ -32,6 +30,8 @@ pub struct ProjectForCreationPayload {
|
||||||
#[serde(rename = "orderIndex")]
|
#[serde(rename = "orderIndex")]
|
||||||
pub order_index: i32,
|
pub order_index: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl From<ProjectForCreationPayload> for Project {
|
impl From<ProjectForCreationPayload> for Project {
|
||||||
fn from(value: ProjectForCreationPayload) -> Self {
|
fn from(value: ProjectForCreationPayload) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -54,4 +54,4 @@ impl From<ProjectForCreationPayload> for Project {
|
||||||
last_updated: Utc::now(),
|
last_updated: Utc::now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::domain::{
|
use crate::domain::{
|
||||||
media::MediaList, property::Property, property_sale_type::PropertySaleType,
|
media::MediaList, property::Property, property_sale_type::PropertySaleType,
|
||||||
property_type::PropertyType,
|
property_type::PropertyType, format::FrameFormat,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A property can belong to a project, or not. It should always belong to a realtor.
|
/// A property can belong to a project, or not. It should always belong to a realtor.
|
||||||
|
@ -19,20 +19,22 @@ pub struct PropertyForCreationPayload {
|
||||||
pub property_type: PropertyType,
|
pub property_type: PropertyType,
|
||||||
#[serde(rename = "propertySaleType")]
|
#[serde(rename = "propertySaleType")]
|
||||||
pub property_sale_type: PropertySaleType,
|
pub property_sale_type: PropertySaleType,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
pub country: String,
|
||||||
pub country: Option<String>,
|
pub city: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
pub district: String,
|
||||||
pub city: Option<String>,
|
/// This gives the realtor the option to order the projects/properties. On birth,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "orderIndex")]
|
||||||
pub district: Option<String>,
|
pub order_index: i32,
|
||||||
#[serde(rename = "priceUsd")]
|
#[serde(rename = "thumbnailFormat")]
|
||||||
pub price_usd: f64,
|
pub thumbnail_format: FrameFormat,
|
||||||
/// Amount of rooms in unit
|
/// Amount of rooms in unit
|
||||||
pub rooms: i16,
|
pub rooms: i16,
|
||||||
/// Amount of bathrooms in unit
|
/// Amount of bathrooms in unit
|
||||||
pub bathrooms: f32,
|
pub bathrooms: f32,
|
||||||
/// In meters squared
|
/// In meters squared
|
||||||
pub area: f32,
|
pub area: f32,
|
||||||
|
#[serde(rename = "parkingSpots")]
|
||||||
|
pub parking_spots: i16,
|
||||||
#[serde(rename = "adminTag")]
|
#[serde(rename = "adminTag")]
|
||||||
pub admin_tag: Option<String>,
|
pub admin_tag: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -49,10 +51,12 @@ impl From<PropertyForCreationPayload> for Property {
|
||||||
country: value.country,
|
country: value.country,
|
||||||
city: value.city,
|
city: value.city,
|
||||||
district: value.district,
|
district: value.district,
|
||||||
price_usd: value.price_usd,
|
order_index: value.order_index,
|
||||||
|
thumbnail_format: value.thumbnail_format,
|
||||||
rooms: value.rooms,
|
rooms: value.rooms,
|
||||||
bathrooms: value.bathrooms,
|
bathrooms: value.bathrooms,
|
||||||
area: value.area,
|
area: value.area,
|
||||||
|
parking_spots: value.parking_spots,
|
||||||
admin_tag: value.admin_tag,
|
admin_tag: value.admin_tag,
|
||||||
time_created: Utc::now(),
|
time_created: Utc::now(),
|
||||||
last_updated: Utc::now(),
|
last_updated: Utc::now(),
|
||||||
|
|
Loading…
Reference in New Issue