First functional commit
This commit is contained in:
commit
54a576e853
|
@ -0,0 +1 @@
|
||||||
|
/target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "remax-types"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
chrono = { version = "0.4.23", features = [ "serde" ] }
|
||||||
|
chrono-tz = "0.8"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
uuid = { version = "1.3.0", features = ["serde"] }
|
||||||
|
format_num = "0.1.0"
|
||||||
|
sqlx = { version = "0.6.0", features = [ "runtime-tokio-rustls", "postgres", "chrono", "uuid" ] }
|
||||||
|
bincode = "1.3.3"
|
|
@ -0,0 +1,15 @@
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Agent {
|
||||||
|
pub id: Uuid,
|
||||||
|
#[serde(rename = "fullName")]
|
||||||
|
pub full_name: String,
|
||||||
|
#[serde(rename = "timeCreated")]
|
||||||
|
pub time_created: DateTime<Utc>,
|
||||||
|
#[serde(rename = "lastUpdated")]
|
||||||
|
pub last_updated: DateTime<Utc>,
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct ContactInformation {
|
||||||
|
#[serde(rename = "agentId")]
|
||||||
|
pub agent_id: Uuid,
|
||||||
|
#[serde(rename = "phoneNumber")]
|
||||||
|
pub phone_number: String,
|
||||||
|
pub email: String,
|
||||||
|
#[serde(rename = "profilePictureUrl")]
|
||||||
|
pub profile_picture_url: Option<String>,
|
||||||
|
/// This is the message to be sent to this user on every platform. So for whatsapp
|
||||||
|
/// it will be the wa.me link message that gets placed in the chat when a user clicks on the link.
|
||||||
|
#[serde(rename = "defaultMessage")]
|
||||||
|
pub default_message: String,
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod property;
|
|
@ -0,0 +1,24 @@
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum PropertyFilter {
|
||||||
|
// By Time
|
||||||
|
Before(DateTime<Utc>),
|
||||||
|
After(DateTime<Utc>),
|
||||||
|
|
||||||
|
// By Word matching
|
||||||
|
Title(String),
|
||||||
|
|
||||||
|
// By cost
|
||||||
|
CheaperThan(u64),
|
||||||
|
MoreExpensiveThan(u64),
|
||||||
|
|
||||||
|
// By Contract type
|
||||||
|
ContractType(String),
|
||||||
|
|
||||||
|
// By Size
|
||||||
|
BiggerOrEqualTo(u32),
|
||||||
|
SmallerOrEqualTo(u32),
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Location {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub country: String,
|
||||||
|
pub province: String,
|
||||||
|
pub city: String,
|
||||||
|
pub district: Option<String>,
|
||||||
|
#[serde(rename = "googleMapsUrl")]
|
||||||
|
pub google_maps_url: Option<String>,
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
pub mod agent;
|
||||||
|
pub mod property;
|
||||||
|
pub mod location;
|
||||||
|
pub mod contact_info;
|
||||||
|
pub mod property_details;
|
||||||
|
pub mod filters;
|
||||||
|
pub mod money;
|
|
@ -0,0 +1,85 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use format_num::NumberFormat;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use sqlx::{Postgres, postgres::{PgArgumentBuffer, PgValueRef, PgTypeInfo}, encode::IsNull, error::BoxDynError};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum Currency {
|
||||||
|
#[default]
|
||||||
|
Usd,
|
||||||
|
Dop,
|
||||||
|
Eur,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub struct Money {
|
||||||
|
pub amount: f64,
|
||||||
|
pub currency: Currency,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Money {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let number_formatter = NumberFormat::new();
|
||||||
|
let amount_fmted = number_formatter.format(".2f", self.amount);
|
||||||
|
match self.currency {
|
||||||
|
Currency::Usd => write!(f, "US${}", amount_fmted),
|
||||||
|
Currency::Dop => write!(f, "RD${}", amount_fmted),
|
||||||
|
Currency::Eur => write!(f, "EUR€{}", amount_fmted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Encode<'_, Postgres> for Currency {
|
||||||
|
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||||
|
let encoded_value = bincode::serialize(self).unwrap();
|
||||||
|
<Vec<u8> as sqlx::Encode<Postgres>>::encode(encoded_value, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Decode<'_, Postgres> for Currency {
|
||||||
|
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||||
|
let column = value.as_bytes()?;
|
||||||
|
match bincode::deserialize(column) {
|
||||||
|
Ok(listing_state) => Ok(listing_state),
|
||||||
|
Err(error) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Type<Postgres> for Currency {
|
||||||
|
fn type_info() -> PgTypeInfo {
|
||||||
|
PgTypeInfo::with_name("bytea")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||||
|
*ty == Self::type_info()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Encode<'_, Postgres> for Money {
|
||||||
|
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||||
|
let encoded_value = bincode::serialize(self).unwrap();
|
||||||
|
<Vec<u8> as sqlx::Encode<Postgres>>::encode(encoded_value, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Decode<'_, Postgres> for Money {
|
||||||
|
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||||
|
let column = value.as_bytes()?;
|
||||||
|
match bincode::deserialize(column) {
|
||||||
|
Ok(listing_state) => Ok(listing_state),
|
||||||
|
Err(error) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Type<Postgres> for Money {
|
||||||
|
fn type_info() -> PgTypeInfo {
|
||||||
|
PgTypeInfo::with_name("bytea")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||||
|
*ty == Self::type_info()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use sqlx::{Postgres, postgres::{PgValueRef, PgTypeInfo, PgArgumentBuffer}, error::BoxDynError, encode::IsNull};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
|
pub struct Property {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub title: String,
|
||||||
|
pub description: String,
|
||||||
|
#[serde(rename = "agentId")]
|
||||||
|
pub agent_id: Uuid,
|
||||||
|
pub state: ListingState,
|
||||||
|
#[serde(rename = "timeCreated")]
|
||||||
|
pub time_created: DateTime<Utc>,
|
||||||
|
#[serde(rename = "lastUpdated")]
|
||||||
|
pub last_updated: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
|
pub enum ListingState {
|
||||||
|
#[default]
|
||||||
|
Draft,
|
||||||
|
Archived,
|
||||||
|
Sold,
|
||||||
|
Listed,
|
||||||
|
Deleted,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl sqlx::Encode<'_, Postgres> for ListingState {
|
||||||
|
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||||
|
let encoded_value = bincode::serialize(self).unwrap();
|
||||||
|
<Vec<u8> as sqlx::Encode<Postgres>>::encode(encoded_value, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Decode<'_, Postgres> for ListingState {
|
||||||
|
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||||
|
let column = value.as_bytes()?;
|
||||||
|
match bincode::deserialize(column) {
|
||||||
|
Ok(listing_state) => Ok(listing_state),
|
||||||
|
Err(error) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Type<Postgres> for ListingState {
|
||||||
|
fn type_info() -> PgTypeInfo {
|
||||||
|
PgTypeInfo::with_name("bytea")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||||
|
*ty == Self::type_info()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use sqlx::{Postgres, postgres::{PgArgumentBuffer, PgValueRef, PgTypeInfo}, encode::IsNull, error::BoxDynError};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use super::money::Money;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd, Default)]
|
||||||
|
pub struct PropertyDetails {
|
||||||
|
#[serde(rename = "propertyId")]
|
||||||
|
pub property_id: Uuid,
|
||||||
|
pub meters: f32,
|
||||||
|
#[serde(rename = "listingType")]
|
||||||
|
pub listing_type: ListingType,
|
||||||
|
#[serde(rename = "photoUrls")]
|
||||||
|
pub photo_urls: Photos,
|
||||||
|
#[serde(rename = "locationId")]
|
||||||
|
pub location_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub enum ListingType {
|
||||||
|
Rent(Money),
|
||||||
|
Sale(Money),
|
||||||
|
/// Sale first, Rent Second
|
||||||
|
Both(Money, Money),
|
||||||
|
}
|
||||||
|
impl Default for ListingType {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Sale(Money::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd, Default)]
|
||||||
|
pub struct Photos {
|
||||||
|
pub photos: Vec<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Database implementations
|
||||||
|
|
||||||
|
impl sqlx::Encode<'_, Postgres> for Photos {
|
||||||
|
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||||
|
let encoded_value = bincode::serialize(self).unwrap();
|
||||||
|
<Vec<u8> as sqlx::Encode<Postgres>>::encode(encoded_value, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Decode<'_, Postgres> for Photos {
|
||||||
|
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||||
|
let column = value.as_bytes()?;
|
||||||
|
match bincode::deserialize(column) {
|
||||||
|
Ok(listing_state) => Ok(listing_state),
|
||||||
|
Err(error) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Type<Postgres> for Photos {
|
||||||
|
fn type_info() -> PgTypeInfo {
|
||||||
|
PgTypeInfo::with_name("bytea")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||||
|
*ty == Self::type_info()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl sqlx::Encode<'_, Postgres> for ListingType {
|
||||||
|
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||||
|
let encoded_value = bincode::serialize(self).unwrap();
|
||||||
|
<Vec<u8> as sqlx::Encode<Postgres>>::encode(encoded_value, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Decode<'_, Postgres> for ListingType {
|
||||||
|
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||||
|
let column = value.as_bytes()?;
|
||||||
|
match bincode::deserialize(column) {
|
||||||
|
Ok(listing_state) => Ok(listing_state),
|
||||||
|
Err(error) => Err(error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl sqlx::Type<Postgres> for ListingType {
|
||||||
|
fn type_info() -> PgTypeInfo {
|
||||||
|
PgTypeInfo::with_name("bytea")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||||
|
*ty == Self::type_info()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::domain::{agent::Agent, contact_info::ContactInformation};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct AgentContainer {
|
||||||
|
pub agent: Agent,
|
||||||
|
pub contact: ContactInformation,
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod property;
|
||||||
|
pub mod agent;
|
|
@ -0,0 +1,18 @@
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
use crate::domain::{property::Property, property_details::PropertyDetails, location::Location};
|
||||||
|
|
||||||
|
use super::agent::AgentContainer;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub struct PropertyContainer {
|
||||||
|
pub property: Property,
|
||||||
|
pub details: PropertyDetails,
|
||||||
|
pub location: Location,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub struct ListingContainer {
|
||||||
|
property: PropertyContainer,
|
||||||
|
agent: AgentContainer,
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod domain;
|
||||||
|
pub mod dto;
|
Loading…
Reference in New Issue